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 })