Mercurial > libervia-backend
diff plugins/plugin_xep_0096.py @ 0:c4bc297b82f0
sat:
- first public release, initial commit
author | goffi@necton2 |
---|---|
date | Sat, 29 Aug 2009 13:34:59 +0200 |
parents | |
children | a06a151fc31f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/plugin_xep_0096.py Sat Aug 29 13:34:59 2009 +0200 @@ -0,0 +1,170 @@ +#!/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, error +import os.path +from twisted.internet import reactor #FIXME best way ??? + + +PLUGIN_INFO = { +"name": "XEP 0096 Plugin", +"import_name": "XEP_0096", +"type": "XEP", +"dependencies": ["XEP_0065"], +"main": "XEP_0096", +"description": """Implementation of SI File Transfert""" +} + +class XEP_0096: + def __init__(self, host): + info("Plugin XEP_0096 initialization") + self.host = host + self._waiting_for_approval = {} + host.add_IQ_cb("http://jabber.org/protocol/si", self.xep_96) + host.bridge.register("sendFile", self.sendFile) + + + def xep_96(self, IQ): + info ("XEP-0096 management") + 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.getParamV("IP", "File Transfert") + streamhost['port']=self.host.memory.getParamV("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') + 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 +