Mercurial > libervia-backend
comparison src/plugins/plugin_xep_0096.py @ 391:c34fd9d6242e
spelling
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 29 Sep 2011 14:59:14 +0200 |
parents | deeebf697d9a |
children | 8f3551ceee17 |
comparison
equal
deleted
inserted
replaced
390:8e87af2e2d1f | 391:c34fd9d6242e |
---|---|
44 "type": "XEP", | 44 "type": "XEP", |
45 "protocols": ["XEP-0096"], | 45 "protocols": ["XEP-0096"], |
46 "dependencies": ["XEP-0020", "XEP-0095", "XEP-0065", "XEP-0047"], | 46 "dependencies": ["XEP-0020", "XEP-0095", "XEP-0065", "XEP-0047"], |
47 "main": "XEP_0096", | 47 "main": "XEP_0096", |
48 "handler": "no", | 48 "handler": "no", |
49 "description": _("""Implementation of SI File Transfert""") | 49 "description": _("""Implementation of SI File Transfer""") |
50 } | 50 } |
51 | 51 |
52 class XEP_0096(): | 52 class XEP_0096(): |
53 | 53 |
54 def __init__(self, host): | 54 def __init__(self, host): |
55 info(_("Plugin XEP_0096 initialization")) | 55 info(_("Plugin XEP_0096 initialization")) |
56 self.host = host | 56 self.host = host |
57 self._waiting_for_approval = {} #key = id, value = [transfert data, IdelayedCall Reactor timeout, | 57 self._waiting_for_approval = {} #key = id, value = [transfer data, IdelayedCall Reactor timeout, |
58 # current stream method, [failed stream methods], profile] | 58 # current stream method, [failed stream methods], profile] |
59 self.managed_stream_m = [#self.host.plugins["XEP-0065"].NS_BS, | 59 self.managed_stream_m = [#self.host.plugins["XEP-0065"].NS_BS, |
60 self.host.plugins["XEP-0047"].NAMESPACE] #Stream methods managed | 60 self.host.plugins["XEP-0047"].NAMESPACE] #Stream methods managed |
61 self.host.plugins["XEP-0095"].registerSIProfile(PROFILE_NAME, self.transfertRequest) | 61 self.host.plugins["XEP-0095"].registerSIProfile(PROFILE_NAME, self.transferRequest) |
62 host.bridge.addMethod("sendFile", ".plugin", in_sign='ssa{ss}s', out_sign='s', method=self.sendFile) | 62 host.bridge.addMethod("sendFile", ".plugin", in_sign='ssa{ss}s', out_sign='s', method=self.sendFile) |
63 | 63 |
64 def _kill_id(self, approval_id): | 64 def _kill_id(self, approval_id): |
65 """Delete a waiting_for_approval id, called after timeout | 65 """Delete a waiting_for_approval id, called after timeout |
66 @param approval_id: id of _waiting_for_approval""" | 66 @param approval_id: id of _waiting_for_approval""" |
67 info(_("SI File Transfert: TimeOut reached for id %s") % approval_id); | 67 info(_("SI File Transfer: TimeOut reached for id %s") % approval_id); |
68 try: | 68 try: |
69 del self._waiting_for_approval[approval_id] | 69 del self._waiting_for_approval[approval_id] |
70 except KeyError: | 70 except KeyError: |
71 warning(_("kill id called on a non existant approval id")) | 71 warning(_("kill id called on a non existant approval id")) |
72 | 72 |
73 def transfertRequest(self, from_jid, si_id, si_mime_type, si_el, profile): | 73 def transferRequest(self, from_jid, si_id, si_mime_type, si_el, profile): |
74 """Called when a file transfert is requested | 74 """Called when a file transfer is requested |
75 @param from_jid: jid of the sender | 75 @param from_jid: jid of the sender |
76 @param si_id: Stream Initiation session id | 76 @param si_id: Stream Initiation session id |
77 @param si_mime_type: Mime type of the file (or default "application/octet-stream" if unknown) | 77 @param si_mime_type: Mime type of the file (or default "application/octet-stream" if unknown) |
78 @param si_el: domish.Element of the request | 78 @param si_el: domish.Element of the request |
79 @param profile: %(doc_profile)s""" | 79 @param profile: %(doc_profile)s""" |
80 info (_("XEP-0096 file transfert requested")) | 80 info (_("XEP-0096 file transfer requested")) |
81 debug(si_el.toXml()) | 81 debug(si_el.toXml()) |
82 filename = "" | 82 filename = "" |
83 file_size = "" | 83 file_size = "" |
84 file_date = None | 84 file_date = None |
85 file_hash = None | 85 file_hash = None |
121 else: | 121 else: |
122 warning(_("No feature element found")) | 122 warning(_("No feature element found")) |
123 self.host.plugins["XEP-0095"].sendBadRequestError(si_id, from_jid, profile) | 123 self.host.plugins["XEP-0095"].sendBadRequestError(si_id, from_jid, profile) |
124 return | 124 return |
125 | 125 |
126 #if we are here, the transfert can start, we just need user's agreement | 126 #if we are here, the transfer can start, we just need user's agreement |
127 data={ "filename":filename, "from":from_jid, "size":file_size, "date":file_date, "hash":file_hash, "desc":file_desc, "can_range": str(can_range) } | 127 data={ "filename":filename, "from":from_jid, "size":file_size, "date":file_date, "hash":file_hash, "desc":file_desc, "can_range": str(can_range) } |
128 self._waiting_for_approval[si_id] = [data, reactor.callLater(300, self._kill_id, si_id), stream_method, [], profile] | 128 self._waiting_for_approval[si_id] = [data, reactor.callLater(300, self._kill_id, si_id), stream_method, [], profile] |
129 | 129 |
130 self.host.askConfirmation(si_id, "FILE_TRANSFERT", data, self.confirmationCB) | 130 self.host.askConfirmation(si_id, "FILE_TRANSFER", data, self.confirmationCB) |
131 | 131 |
132 | 132 |
133 def _getFileObject(self, dest_path, can_range = False): | 133 def _getFileObject(self, dest_path, can_range = False): |
134 """Open file, put file pointer to the end if the file if needed | 134 """Open file, put file pointer to the end if the file if needed |
135 @param dest_path: path of the destination file | 135 @param dest_path: path of the destination file |
137 @return: File Object""" | 137 @return: File Object""" |
138 return open(dest_path, "ab" if can_range else "wb") | 138 return open(dest_path, "ab" if can_range else "wb") |
139 | 139 |
140 def confirmationCB(self, id, accepted, frontend_data): | 140 def confirmationCB(self, id, accepted, frontend_data): |
141 """Called on confirmation answer | 141 """Called on confirmation answer |
142 @param id: file transfert session id | 142 @param id: file transfer session id |
143 @param accepted: True if file transfert is accepted | 143 @param accepted: True if file transfer is accepted |
144 @param frontend_data: data sent by frontend""" | 144 @param frontend_data: data sent by frontend""" |
145 data, timeout, stream_method, failed_methods, profile = self._waiting_for_approval[id] | 145 data, timeout, stream_method, failed_methods, profile = self._waiting_for_approval[id] |
146 can_range = data['can_range'] == "True" | 146 can_range = data['can_range'] == "True" |
147 range_offset = 0 | 147 range_offset = 0 |
148 if accepted: | 148 if accepted: |
159 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: | 159 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: |
160 file_obj = self._getFileObject(dest_path, can_range) | 160 file_obj = self._getFileObject(dest_path, can_range) |
161 range_offset = file_obj.tell() | 161 range_offset = file_obj.tell() |
162 self.host.plugins["XEP-0047"].prepareToReceive(jid.JID(data['from']), id, file_obj, int(data["size"]), self._transferSucceeded, self._transferFailed) | 162 self.host.plugins["XEP-0047"].prepareToReceive(jid.JID(data['from']), id, file_obj, int(data["size"]), self._transferSucceeded, self._transferFailed) |
163 else: | 163 else: |
164 error(_("Unknown stream method, this should not happen at this stage, cancelling transfert")) | 164 error(_("Unknown stream method, this should not happen at this stage, cancelling transfer")) |
165 del(self._waiting_for_approval[id]) | 165 del(self._waiting_for_approval[id]) |
166 return | 166 return |
167 | 167 |
168 #we can send the iq result | 168 #we can send the iq result |
169 feature_elt = self.host.plugins["XEP-0020"].chooseOption({'stream-method':stream_method}) | 169 feature_elt = self.host.plugins["XEP-0020"].chooseOption({'stream-method':stream_method}) |
174 range_elt['offset'] = str(range_offset) | 174 range_elt['offset'] = str(range_offset) |
175 #TODO: manage range length | 175 #TODO: manage range length |
176 misc_elts.append(range_elt) | 176 misc_elts.append(range_elt) |
177 self.host.plugins["XEP-0095"].acceptStream(id, data['from'], feature_elt, misc_elts, profile) | 177 self.host.plugins["XEP-0095"].acceptStream(id, data['from'], feature_elt, misc_elts, profile) |
178 else: | 178 else: |
179 debug (_("Transfert [%s] refused"), id) | 179 debug (_("Transfer [%s] refused"), id) |
180 self.host.plugins["XEP-0095"].sendRejectedError (id, data['from'], profile=profile) | 180 self.host.plugins["XEP-0095"].sendRejectedError (id, data['from'], profile=profile) |
181 del(self._waiting_for_approval[id]) | 181 del(self._waiting_for_approval[id]) |
182 | 182 |
183 def _transferSucceeded(self, sid, file_obj, stream_method): | 183 def _transferSucceeded(self, sid, file_obj, stream_method): |
184 """Called by the stream method when transfert successfuly finished | 184 """Called by the stream method when transfer successfuly finished |
185 @param id: stream id""" | 185 @param id: stream id""" |
186 file_obj.close() | 186 file_obj.close() |
187 info(_('Transfert %s successfuly finished') % sid) | 187 info(_('Transfer %s successfuly finished') % sid) |
188 del(self._waiting_for_approval[sid]) | 188 del(self._waiting_for_approval[sid]) |
189 | 189 |
190 def _transferFailed(self, sid, file_obj, stream_method, reason): | 190 def _transferFailed(self, sid, file_obj, stream_method, reason): |
191 """Called when something went wrong with the transfert | 191 """Called when something went wrong with the transfer |
192 @param id: stream id | 192 @param id: stream id |
193 @param reason: can be TIMEOUT, IO_ERROR, PROTOCOL_ERROR""" | 193 @param reason: can be TIMEOUT, IO_ERROR, PROTOCOL_ERROR""" |
194 data, timeout, stream_method, failed_methods, profile = self._waiting_for_approval[sid] | 194 data, timeout, stream_method, failed_methods, profile = self._waiting_for_approval[sid] |
195 warning(_('Transfert %(id)s failed with stream method %(s_method)s') % { 'id': sid, | 195 warning(_('Transfer %(id)s failed with stream method %(s_method)s') % { 'id': sid, |
196 's_method': stream_method }) | 196 's_method': stream_method }) |
197 filepath = file_obj.name | 197 filepath = file_obj.name |
198 file_obj.close() | 198 file_obj.close() |
199 os.remove(filepath) | 199 os.remove(filepath) |
200 #TODO: session remenber (within a time limit) when a stream method fail, and avoid that stream method with full jid for the rest of the session | 200 #TODO: session remenber (within a time limit) when a stream method fail, and avoid that stream method with full jid for the rest of the session |
201 warning(_("All stream methods failed, can't transfert the file")) | 201 warning(_("All stream methods failed, can't transfer the file")) |
202 self.host.plugins["XEP-0095"].sendFailedError(id, data['from'], profile) | 202 self.host.plugins["XEP-0095"].sendFailedError(id, data['from'], profile) |
203 del(self._waiting_for_approval[id]) | 203 del(self._waiting_for_approval[id]) |
204 | 204 |
205 def fileCb(self, profile, filepath, sid, size, IQ): | 205 def fileCb(self, profile, filepath, sid, size, IQ): |
206 if IQ['type'] == "error": | 206 if IQ['type'] == "error": |
207 stanza_err = jab_error.exceptionFromStanza(IQ) | 207 stanza_err = jab_error.exceptionFromStanza(IQ) |
208 if stanza_err.code == '403' and stanza_err.condition == 'forbidden': | 208 if stanza_err.code == '403' and stanza_err.condition == 'forbidden': |
209 debug(_("File transfert refused by %s") % IQ['from']) | 209 debug(_("File transfer refused by %s") % IQ['from']) |
210 self.host.bridge.newAlert(_("The contact %s refused your file") % IQ['from'], _("File refused"), "INFO", profile) | 210 self.host.bridge.newAlert(_("The contact %s refused your file") % IQ['from'], _("File refused"), "INFO", profile) |
211 else: | 211 else: |
212 warning(_("Error during file transfert with %s") % IQ['from']) | 212 warning(_("Error during file transfer with %s") % IQ['from']) |
213 self.host.bridge.newAlert(_("Something went wrong during the file transfer session intialisation with %s") % IQ['from'], _("File transfer error"), "ERROR", profile) | 213 self.host.bridge.newAlert(_("Something went wrong during the file transfer session intialisation with %s") % IQ['from'], _("File transfer error"), "ERROR", profile) |
214 return | 214 return |
215 | 215 |
216 si_elt = IQ.firstChildElement() | 216 si_elt = IQ.firstChildElement() |
217 | 217 |
246 offer["to"]=answer['from'] | 246 offer["to"]=answer['from'] |
247 query=offer.addElement('query', 'http://jabber.org/protocol/ibb') | 247 query=offer.addElement('query', 'http://jabber.org/protocol/ibb') |
248 #query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams') | 248 #query=offer.addElement('query', 'http://jabber.org/protocol/bytestreams') |
249 query['mode']='tcp' | 249 query['mode']='tcp' |
250 streamhost=query.addElement('streamhost') | 250 streamhost=query.addElement('streamhost') |
251 streamhost['host']=self.host.memory.getParamA("IP", "File Transfert") | 251 streamhost['host']=self.host.memory.getParamA("IP", "File Transfer") |
252 streamhost['port']=self.host.memory.getParamA("Port", "File Transfert") | 252 streamhost['port']=self.host.memory.getParamA("Port", "File Transfer") |
253 streamhost['jid']=current_jid.full() | 253 streamhost['jid']=current_jid.full() |
254 offer.send()""" | 254 offer.send()""" |
255 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: | 255 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: |
256 file_obj = open(filepath, 'r') | 256 file_obj = open(filepath, 'r') |
257 if range_offset: | 257 if range_offset: |
265 @to_jid: recipient | 265 @to_jid: recipient |
266 @filepath: absolute path to the file to send | 266 @filepath: absolute path to the file to send |
267 @data: dictionnary with the optional following keys: | 267 @data: dictionnary with the optional following keys: |
268 - "description": description of the file | 268 - "description": description of the file |
269 @param profile_key: %(doc_profile_key)s | 269 @param profile_key: %(doc_profile_key)s |
270 @return: an unique id to identify the transfert | 270 @return: an unique id to identify the transfer |
271 """ | 271 """ |
272 profile = self.host.memory.getProfileName(profile_key) | 272 profile = self.host.memory.getProfileName(profile_key) |
273 if not profile: | 273 if not profile: |
274 warning(_("Trying to send a file from an unknown profile")) | 274 warning(_("Trying to send a file from an unknown profile")) |
275 return "" | 275 return "" |
296 info(_('Transfer %s successfuly finished') % sid) | 296 info(_('Transfer %s successfuly finished') % sid) |
297 file_obj.close() | 297 file_obj.close() |
298 | 298 |
299 def sendFailureCb(self, sid, file_obj, stream_method, reason): | 299 def sendFailureCb(self, sid, file_obj, stream_method, reason): |
300 file_obj.close() | 300 file_obj.close() |
301 warning(_('Transfert %(id)s failed with stream method %(s_method)s') % { 'id': sid, s_method: stream_method }) | 301 warning(_('Transfer %(id)s failed with stream method %(s_method)s') % { 'id': sid, s_method: stream_method }) |