Mercurial > libervia-backend
view plugins/plugin_xep_0096.py @ 52:6455fb62ff83
Connection/disconnection signals
- wix, sortilege: management of this new signals
/!\ sortilege is bugged, the contact list window is not updated correctly
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 07 Jan 2010 01:55:30 +1100 |
parents | 4392f1fdb064 |
children | a5b5fb5fc9fd |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- """ SAT plugin for managing xep-0096 Copyright (C) 2009 Jérôme Poisson (goffi@goffi.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ from logging import debug, info, error from twisted.words.xish import domish from twisted.internet import protocol from twisted.words.protocols.jabber import client, jid, xmlstream from twisted.words.protocols.jabber import error as jab_error import os.path from twisted.internet import reactor #FIXME best way ??? import pdb from zope.interface import implements try: from twisted.words.protocols.xmlstream import XMPPHandler except ImportError: from wokkel.subprotocols import XMPPHandler from wokkel import disco, iwokkel IQ_SET = '/iq[@type="set"]' NS_SI = 'http://jabber.org/protocol/si' SI_REQUEST = IQ_SET + '/si[@xmlns="' + NS_SI + '"]' PLUGIN_INFO = { "name": "XEP 0096 Plugin", "import_name": "XEP_0096", "type": "XEP", "protocols": ["XEP-0096"], "dependencies": ["XEP_0065"], "main": "XEP_0096", "description": """Implementation of SI File Transfert""" } class XEP_0096(XMPPHandler): implements(iwokkel.IDisco) def __init__(self, host): info("Plugin XEP_0096 initialization") self.host = host self._waiting_for_approval = {} host.bridge.addMethod("sendFile", ".communication", in_sign='ss', out_sign='s', method=self.sendFile) def connectionInitialized(self): self.xmlstream.addObserver(SI_REQUEST, self.xep_96) def getDiscoInfo(self, requestor, target, nodeIdentifier=''): return [disco.DiscoFeature(NS_SI)] def getDiscoItems(self, requestor, target, nodeIdentifier=''): return [] def xep_96(self, IQ): info ("XEP-0096 management") IQ.handled=True SI_elem = IQ.firstChildElement() debug(SI_elem.toXml()) filename = "" file_size = "" for element in SI_elem.elements(): if element.name == "file": info ("File proposed: name=[%s] size=%s", element['name'], element['size']) filename = element["name"] file_size = element["size"] elif element.name == "feature": from_jid = IQ["from"] self._waiting_for_approval[IQ["id"]] = (element, from_jid, file_size) data={ "filename":filename, "from":from_jid, "size":file_size } self.host.askConfirmation(IQ["id"], "FILE_TRANSFERT", data, self.confirmationCB) def confirmationCB(self, id, accepted, data): """Called on confirmation answer""" if accepted: data['size'] = self._waiting_for_approval[id][2] self.host.plugins["XEP_0065"].setData(data, id) self.approved(id) else: debug ("Transfert [%s] refused", id) del(self._waiting_for_approval[id]) def approved(self, id): """must be called when a file transfert has be accepted by client""" debug ("Transfert [%s] accepted", id) if ( not self._waiting_for_approval.has_key(id) ): error ("Approved unknow id !") #TODO: manage this (maybe approved by several frontends) else: element, from_id, size = self._waiting_for_approval[id] del(self._waiting_for_approval[id]) self.negociate(element, id, from_id) def negociate(self, feat_elem, id, to_jid): #TODO: put this in a plugin #FIXME: over ultra mega ugly, need to be generic info ("Feature negociation") data = feat_elem.firstChildElement() field = data.firstChildElement() #FIXME: several options ! Q&D code for test only option = field.firstChildElement() value = option.firstChildElement() if unicode(value) == "http://jabber.org/protocol/bytestreams": #ugly, as usual, need to be entirely rewritten (just for test !) result = domish.Element(('', 'iq')) result['type'] = 'result' result['id'] = id result['to'] = to_jid si = result.addElement('si', 'http://jabber.org/protocol/si') file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer') feature = si.addElement('feature', 'http://jabber.org/protocol/feature-neg') x = feature.addElement('x', 'jabber:x:data') x['type'] = 'submit' field = x.addElement('field') field['var'] = 'stream-method' value = field.addElement('value') value.addContent('http://jabber.org/protocol/bytestreams') self.host.xmlstream.send(result) def fileCB(self, answer): if answer['type']=="result": #FIXME FIXME FIXME ugly ugly ugly ! and temp FIXME FIXME FIXME info("SENDING UGLY ANSWER") offer=client.IQ(self.host.xmlstream,'set') offer["from"]=self.host.me.full() offer["to"]=answer['from'] query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams') query['mode']='tcp' streamhost=query.addElement('streamhost') streamhost['host']=self.host.memory.getParamA("IP", "File Transfert") streamhost['port']=self.host.memory.getParamA("Port", "File Transfert") streamhost['jid']=self.host.me.full() offer.send() def sendFile(self, to, filepath): """send a file using XEP-0096 Return an unique id to identify the transfert """ debug ("sendfile (%s) to %s", filepath, to ) print type(filepath), type(to) statinfo = os.stat(filepath) offer=client.IQ(self.host.xmlstream,'set') debug ("Transfert ID: %s", offer["id"]) self.host.plugins["XEP_0065"].sendFile(offer["id"], filepath, str(statinfo.st_size)) offer["from"]=self.host.me.full() offer["to"]=jid.JID(to).full() si=offer.addElement('si','http://jabber.org/protocol/si') si["mime-type"]='text/plain' si["profile"]='http://jabber.org/protocol/si/profile/file-transfer' file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer') file['name']=os.path.basename(filepath) file['size']=str(statinfo.st_size) ### # FIXME: Ugly temporary hard coded implementation of XEP-0020 & XEP-0004, # Need to be recoded elsewhere in a more generic way ### feature=si.addElement('feature', "http://jabber.org/protocol/feature-neg") x=feature.addElement('x', "jabber:x:data") x['type']='form' field=x.addElement('field') field['type']='list-single' field['var']='stream-method' option = field.addElement('option') value = option.addElement('value', content='http://jabber.org/protocol/bytestreams') offer.addCallback(self.fileCB) offer.send() return offer["id"] #XXX: using IQ id as file transfert id seems OK as IQ id are required