Mercurial > libervia-backend
comparison plugins/plugin_xep_0096.py @ 64:d46f849664aa
SàT: multi-profile, plugins updated
- core: 2 new convenient methods: getJidNStream and getClient
- new param in plugin info: "handler" to know if there is a handler to plug on profiles clients
- plugins with handler now use an other class which is returned to profile client with the new method "getHandler" and pluged when connecting
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 30 Jan 2010 16:17:33 +1100 |
parents | a5b5fb5fc9fd |
children | 86f1f7f6d332 |
comparison
equal
deleted
inserted
replaced
63:0db25931b60d | 64:d46f849664aa |
---|---|
20 """ | 20 """ |
21 | 21 |
22 from logging import debug, info, error | 22 from logging import debug, info, error |
23 from twisted.words.xish import domish | 23 from twisted.words.xish import domish |
24 from twisted.internet import protocol | 24 from twisted.internet import protocol |
25 from twisted.words.protocols.jabber import client, jid, xmlstream | 25 from twisted.words.protocols.jabber import client, jid |
26 from twisted.words.protocols.jabber import error as jab_error | 26 from twisted.words.protocols.jabber import error as jab_error |
27 import os.path | 27 import os.path |
28 from twisted.internet import reactor #FIXME best way ??? | 28 from twisted.internet import reactor #FIXME best way ??? |
29 import pdb | 29 import pdb |
30 | 30 |
46 "import_name": "XEP_0096", | 46 "import_name": "XEP_0096", |
47 "type": "XEP", | 47 "type": "XEP", |
48 "protocols": ["XEP-0096"], | 48 "protocols": ["XEP-0096"], |
49 "dependencies": ["XEP_0065"], | 49 "dependencies": ["XEP_0065"], |
50 "main": "XEP_0096", | 50 "main": "XEP_0096", |
51 "handler": "yes", | |
51 "description": """Implementation of SI File Transfert""" | 52 "description": """Implementation of SI File Transfert""" |
52 } | 53 } |
53 | 54 |
54 class XEP_0096(XMPPHandler): | 55 class XEP_0096(): |
55 implements(iwokkel.IDisco) | |
56 | 56 |
57 def __init__(self, host): | 57 def __init__(self, host): |
58 info("Plugin XEP_0096 initialization") | 58 info("Plugin XEP_0096 initialization") |
59 self.host = host | 59 self.host = host |
60 self._waiting_for_approval = {} | 60 self._waiting_for_approval = {} |
61 host.bridge.addMethod("sendFile", ".communication", in_sign='ss', out_sign='s', method=self.sendFile) | 61 host.bridge.addMethod("sendFile", ".communication", in_sign='sss', out_sign='s', method=self.sendFile) |
62 | 62 |
63 def connectionInitialized(self): | 63 def getHandler(self): |
64 self.xmlstream.addObserver(SI_REQUEST, self.xep_96) | 64 return XEP_0096_handler(self) |
65 | 65 |
66 | 66 def xep_96(self, IQ, profile): |
67 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | |
68 return [disco.DiscoFeature(NS_SI)] | |
69 | |
70 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | |
71 return [] | |
72 | |
73 def xep_96(self, IQ): | |
74 info ("XEP-0096 management") | 67 info ("XEP-0096 management") |
75 IQ.handled=True | 68 IQ.handled=True |
76 SI_elem = IQ.firstChildElement() | 69 SI_elem = IQ.firstChildElement() |
77 debug(SI_elem.toXml()) | 70 debug(SI_elem.toXml()) |
78 filename = "" | 71 filename = "" |
82 info ("File proposed: name=[%s] size=%s", element['name'], element['size']) | 75 info ("File proposed: name=[%s] size=%s", element['name'], element['size']) |
83 filename = element["name"] | 76 filename = element["name"] |
84 file_size = element["size"] | 77 file_size = element["size"] |
85 elif element.name == "feature": | 78 elif element.name == "feature": |
86 from_jid = IQ["from"] | 79 from_jid = IQ["from"] |
87 self._waiting_for_approval[IQ["id"]] = (element, from_jid, file_size) | 80 self._waiting_for_approval[IQ["id"]] = (element, from_jid, file_size, profile) |
88 data={ "filename":filename, "from":from_jid, "size":file_size } | 81 data={ "filename":filename, "from":from_jid, "size":file_size } |
89 self.host.askConfirmation(IQ["id"], "FILE_TRANSFERT", data, self.confirmationCB) | 82 self.host.askConfirmation(IQ["id"], "FILE_TRANSFERT", data, self.confirmationCB) |
90 | 83 |
91 def confirmationCB(self, id, accepted, data): | 84 def confirmationCB(self, id, accepted, data): |
92 """Called on confirmation answer""" | 85 """Called on confirmation answer""" |
104 | 97 |
105 if ( not self._waiting_for_approval.has_key(id) ): | 98 if ( not self._waiting_for_approval.has_key(id) ): |
106 error ("Approved unknow id !") | 99 error ("Approved unknow id !") |
107 #TODO: manage this (maybe approved by several frontends) | 100 #TODO: manage this (maybe approved by several frontends) |
108 else: | 101 else: |
109 element, from_id, size = self._waiting_for_approval[id] | 102 element, from_id, size, profile = self._waiting_for_approval[id] |
110 del(self._waiting_for_approval[id]) | 103 del(self._waiting_for_approval[id]) |
111 self.negociate(element, id, from_id) | 104 self.negociate(element, id, from_id, profile) |
112 | 105 |
113 def negociate(self, feat_elem, id, to_jid): | 106 def negociate(self, feat_elem, id, to_jid, profile): |
114 #TODO: put this in a plugin | 107 #TODO: put this in a plugin |
115 #FIXME: over ultra mega ugly, need to be generic | 108 #FIXME: over ultra mega ugly, need to be generic |
109 client = self.host.getClient(profile) | |
110 assert(client) | |
116 info ("Feature negociation") | 111 info ("Feature negociation") |
117 data = feat_elem.firstChildElement() | 112 data = feat_elem.firstChildElement() |
118 field = data.firstChildElement() | 113 field = data.firstChildElement() |
119 #FIXME: several options ! Q&D code for test only | 114 #FIXME: several options ! Q&D code for test only |
120 option = field.firstChildElement() | 115 option = field.firstChildElement() |
132 x['type'] = 'submit' | 127 x['type'] = 'submit' |
133 field = x.addElement('field') | 128 field = x.addElement('field') |
134 field['var'] = 'stream-method' | 129 field['var'] = 'stream-method' |
135 value = field.addElement('value') | 130 value = field.addElement('value') |
136 value.addContent('http://jabber.org/protocol/bytestreams') | 131 value.addContent('http://jabber.org/protocol/bytestreams') |
137 self.host.xmlstream.send(result) | 132 client.xmlstream.send(result) |
138 | 133 |
139 def fileCB(self, answer): | 134 def fileCB(self, answer, xmlstream, current_jid): |
140 if answer['type']=="result": #FIXME FIXME FIXME ugly ugly ugly ! and temp FIXME FIXME FIXME | 135 if answer['type']=="result": #FIXME FIXME FIXME ugly ugly ugly ! and temp FIXME FIXME FIXME |
141 info("SENDING UGLY ANSWER") | 136 info("SENDING UGLY ANSWER") |
142 offer=client.IQ(self.host.xmlstream,'set') | 137 offer=client.IQ(xmlstream,'set') |
143 offer["from"]=self.host.me.full() | 138 offer["from"]=current_jid.full() |
144 offer["to"]=answer['from'] | 139 offer["to"]=answer['from'] |
145 query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams') | 140 query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams') |
146 query['mode']='tcp' | 141 query['mode']='tcp' |
147 streamhost=query.addElement('streamhost') | 142 streamhost=query.addElement('streamhost') |
148 streamhost['host']=self.host.memory.getParamA("IP", "File Transfert") | 143 streamhost['host']=self.host.memory.getParamA("IP", "File Transfert") |
149 streamhost['port']=self.host.memory.getParamA("Port", "File Transfert") | 144 streamhost['port']=self.host.memory.getParamA("Port", "File Transfert") |
150 streamhost['jid']=self.host.me.full() | 145 streamhost['jid']=current_jid.full() |
151 offer.send() | 146 offer.send() |
152 | 147 |
153 | 148 def sendFile(self, to, filepath, profile_key='@DEFAULT@'): |
154 | |
155 | |
156 def sendFile(self, to, filepath): | |
157 """send a file using XEP-0096 | 149 """send a file using XEP-0096 |
158 Return an unique id to identify the transfert | 150 Return an unique id to identify the transfert |
159 """ | 151 """ |
152 current_jid, xmlstream = self.host.getJidNStream(profile_key) | |
153 if not xmlstream: | |
154 error ('Asking profile for an non-existant or not connected profile') | |
155 return "" | |
160 debug ("sendfile (%s) to %s", filepath, to ) | 156 debug ("sendfile (%s) to %s", filepath, to ) |
161 print type(filepath), type(to) | 157 print type(filepath), type(to) |
162 | 158 |
163 statinfo = os.stat(filepath) | 159 statinfo = os.stat(filepath) |
164 | 160 |
165 offer=client.IQ(self.host.xmlstream,'set') | 161 offer=client.IQ(xmlstream,'set') |
166 debug ("Transfert ID: %s", offer["id"]) | 162 debug ("Transfert ID: %s", offer["id"]) |
167 | 163 |
168 self.host.plugins["XEP_0065"].sendFile(offer["id"], filepath, str(statinfo.st_size)) | 164 self.host.plugins["XEP_0065"].sendFile(offer["id"], filepath, str(statinfo.st_size)) |
169 | 165 |
170 offer["from"]=self.host.me.full() | 166 offer["from"]=current_jid.full() |
171 offer["to"]=jid.JID(to).full() | 167 offer["to"]=jid.JID(to).full() |
172 si=offer.addElement('si','http://jabber.org/protocol/si') | 168 si=offer.addElement('si','http://jabber.org/protocol/si') |
173 si["mime-type"]='text/plain' | 169 si["mime-type"]='text/plain' |
174 si["profile"]='http://jabber.org/protocol/si/profile/file-transfer' | 170 si["profile"]='http://jabber.org/protocol/si/profile/file-transfer' |
175 file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer') | 171 file = si.addElement('file', 'http://jabber.org/protocol/si/profile/file-transfer') |
188 field['type']='list-single' | 184 field['type']='list-single' |
189 field['var']='stream-method' | 185 field['var']='stream-method' |
190 option = field.addElement('option') | 186 option = field.addElement('option') |
191 value = option.addElement('value', content='http://jabber.org/protocol/bytestreams') | 187 value = option.addElement('value', content='http://jabber.org/protocol/bytestreams') |
192 | 188 |
193 offer.addCallback(self.fileCB) | 189 offer.addCallback(self.fileCB, current_jid = current_jid, xmlstream = xmlstream) |
194 offer.send() | 190 offer.send() |
195 return offer["id"] #XXX: using IQ id as file transfert id seems OK as IQ id are required | 191 return offer["id"] #XXX: using IQ id as file transfert id seems OK as IQ id are required |
196 | 192 |
193 class XEP_0096_handler(XMPPHandler): | |
194 implements(iwokkel.IDisco) | |
195 | |
196 def __init__(self, plugin_parent): | |
197 self.plugin_parent = plugin_parent | |
198 self.host = plugin_parent.host | |
199 | |
200 def connectionInitialized(self): | |
201 self.xmlstream.addObserver(SI_REQUEST, self.plugin_parent.xep_96, profile = self.parent.profile) | |
202 | |
203 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | |
204 return [disco.DiscoFeature(NS_SI)] | |
205 | |
206 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | |
207 return [] | |
208 |