comparison src/plugins/plugin_xep_0096.py @ 594:e629371a28d3

Fix pep8 support in src/plugins.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 18 Jan 2013 17:55:35 +0100
parents beaf6bec2fcd
children 84a6e83157c2
comparison
equal deleted inserted replaced
593:70bae685d05c 594:e629371a28d3
21 21
22 from logging import debug, info, warning, error 22 from logging import debug, info, warning, error
23 from twisted.words.xish import domish 23 from twisted.words.xish import domish
24 from twisted.words.protocols.jabber import jid 24 from twisted.words.protocols.jabber import jid
25 from twisted.words.protocols.jabber import error as jab_error 25 from twisted.words.protocols.jabber import error as jab_error
26 import os, os.path 26 import os
27 from twisted.internet import reactor 27 from twisted.internet import reactor
28 from sat.core.exceptions import ProfileNotInCacheError 28 from sat.core.exceptions import ProfileNotInCacheError
29
30 29
31 from wokkel import data_form 30 from wokkel import data_form
32 31
33 IQ_SET = '/iq[@type="set"]' 32 IQ_SET = '/iq[@type="set"]'
34 PROFILE_NAME = "file-transfer" 33 PROFILE_NAME = "file-transfer"
35 PROFILE = "http://jabber.org/protocol/si/profile/" + PROFILE_NAME 34 PROFILE = "http://jabber.org/protocol/si/profile/" + PROFILE_NAME
36 35
37 PLUGIN_INFO = { 36 PLUGIN_INFO = {
38 "name": "XEP 0096 Plugin", 37 "name": "XEP 0096 Plugin",
39 "import_name": "XEP-0096", 38 "import_name": "XEP-0096",
40 "type": "XEP", 39 "type": "XEP",
41 "protocols": ["XEP-0096"], 40 "protocols": ["XEP-0096"],
42 "dependencies": ["XEP-0020", "XEP-0095", "XEP-0065", "XEP-0047"], 41 "dependencies": ["XEP-0020", "XEP-0095", "XEP-0065", "XEP-0047"],
43 "main": "XEP_0096", 42 "main": "XEP_0096",
44 "handler": "no", 43 "handler": "no",
45 "description": _("""Implementation of SI File Transfer""") 44 "description": _("""Implementation of SI File Transfer""")
46 } 45 }
46
47 47
48 class XEP_0096(object): 48 class XEP_0096(object):
49 49
50 def __init__(self, host): 50 def __init__(self, host):
51 info(_("Plugin XEP_0096 initialization")) 51 info(_("Plugin XEP_0096 initialization"))
52 self.host = host 52 self.host = host
53 self.managed_stream_m = [self.host.plugins["XEP-0065"].NAMESPACE, 53 self.managed_stream_m = [self.host.plugins["XEP-0065"].NAMESPACE,
54 self.host.plugins["XEP-0047"].NAMESPACE] #Stream methods managed 54 self.host.plugins["XEP-0047"].NAMESPACE] # Stream methods managed
55 self.host.plugins["XEP-0095"].registerSIProfile(PROFILE_NAME, self.transferRequest) 55 self.host.plugins["XEP-0095"].registerSIProfile(PROFILE_NAME, self.transferRequest)
56 host.bridge.addMethod("sendFile", ".plugin", in_sign='ssa{ss}s', out_sign='s', method=self.sendFile) 56 host.bridge.addMethod("sendFile", ".plugin", in_sign='ssa{ss}s', out_sign='s', method=self.sendFile)
57 57
58 def profileConnected(self, profile): 58 def profileConnected(self, profile):
59 client = self.host.getClient(profile) 59 client = self.host.getClient(profile)
60 client._xep_0096_waiting_for_approval = {} #key = id, value = [transfer data, IdelayedCall Reactor timeout, 60 client._xep_0096_waiting_for_approval = {} # key = id, value = [transfer data, IdelayedCall Reactor timeout,
61 # current stream method, [failed stream methods], profile] 61 # current stream method, [failed stream methods], profile]
62 62
63 def _kill_id(self, approval_id, profile): 63 def _kill_id(self, approval_id, profile):
64 """Delete a waiting_for_approval id, called after timeout 64 """Delete a waiting_for_approval id, called after timeout
65 @param approval_id: id of _xep_0096_waiting_for_approval""" 65 @param approval_id: id of _xep_0096_waiting_for_approval"""
76 @param from_jid: jid of the sender 76 @param from_jid: jid of the sender
77 @param si_id: Stream Initiation session id 77 @param si_id: Stream Initiation session id
78 @param si_mime_type: Mime type of the file (or default "application/octet-stream" if unknown) 78 @param si_mime_type: Mime type of the file (or default "application/octet-stream" if unknown)
79 @param si_el: domish.Element of the request 79 @param si_el: domish.Element of the request
80 @param profile: %(doc_profile)s""" 80 @param profile: %(doc_profile)s"""
81 info (_("XEP-0096 file transfer requested")) 81 info(_("XEP-0096 file transfer requested"))
82 debug(si_el.toXml()) 82 debug(si_el.toXml())
83 client = self.host.getClient(profile) 83 client = self.host.getClient(profile)
84 if not client: 84 if not client:
85 raise ProfileNotInCacheError 85 raise ProfileNotInCacheError
86 filename = "" 86 filename = ""
96 file_el = file_elts[0] 96 file_el = file_elts[0]
97 filename = file_el["name"] 97 filename = file_el["name"]
98 file_size = file_el["size"] 98 file_size = file_el["size"]
99 file_date = file_el.getAttribute("date", "") 99 file_date = file_el.getAttribute("date", "")
100 file_hash = file_el.getAttribute("hash", "") 100 file_hash = file_el.getAttribute("hash", "")
101 info (_("File proposed: name=[%(name)s] size=%(size)s") % {'name':filename, 'size':file_size}) 101 info(_("File proposed: name=[%(name)s] size=%(size)s") % {'name': filename, 'size': file_size})
102 for file_child_el in file_el.elements(): 102 for file_child_el in file_el.elements():
103 if file_child_el.name == "desc": 103 if file_child_el.name == "desc":
104 file_desc = unicode(file_child_el) 104 file_desc = unicode(file_child_el)
105 elif file_child_el.name == "range": 105 elif file_child_el.name == "range":
106 can_range = True 106 can_range = True
111 111
112 if feature_elts: 112 if feature_elts:
113 feature_el = feature_elts[0] 113 feature_el = feature_elts[0]
114 form = data_form.Form.fromElement(feature_el.firstChildElement()) 114 form = data_form.Form.fromElement(feature_el.firstChildElement())
115 try: 115 try:
116 stream_method = self.host.plugins["XEP-0020"].negociate(feature_el, 'stream-method',self.managed_stream_m) 116 stream_method = self.host.plugins["XEP-0020"].negociate(feature_el, 'stream-method', self.managed_stream_m)
117 except KeyError: 117 except KeyError:
118 warning(_("No stream method found")) 118 warning(_("No stream method found"))
119 self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile) 119 self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile)
120 return 120 return
121 if not stream_method: 121 if not stream_method:
126 warning(_("No feature element found")) 126 warning(_("No feature element found"))
127 self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile) 127 self.host.plugins["XEP-0095"].sendBadRequestError(iq_id, from_jid, profile)
128 return 128 return
129 129
130 #if we are here, the transfer can start, we just need user's agreement 130 #if we are here, the transfer can start, we just need user's agreement
131 data={ "filename":filename, "id": iq_id, "from":from_jid, "size":file_size, "date":file_date, "hash":file_hash, "desc":file_desc, "can_range": str(can_range) } 131 data = {"filename": filename, "id": iq_id, "from": from_jid, "size": file_size, "date": file_date, "hash": file_hash, "desc": file_desc, "can_range": str(can_range)}
132 client._xep_0096_waiting_for_approval[si_id] = [data, reactor.callLater(300, self._kill_id, si_id, profile), stream_method, []] 132 client._xep_0096_waiting_for_approval[si_id] = [data, reactor.callLater(300, self._kill_id, si_id, profile), stream_method, []]
133 133
134 self.host.askConfirmation(si_id, "FILE_TRANSFER", data, self.confirmationCB, profile) 134 self.host.askConfirmation(si_id, "FILE_TRANSFER", data, self.confirmationCB, profile)
135 135
136 136 def _getFileObject(self, dest_path, can_range=False):
137 def _getFileObject(self, dest_path, can_range = False):
138 """Open file, put file pointer to the end if the file if needed 137 """Open file, put file pointer to the end if the file if needed
139 @param dest_path: path of the destination file 138 @param dest_path: path of the destination file
140 @param can_range: True if the file pointer can be moved 139 @param can_range: True if the file pointer can be moved
141 @return: File Object""" 140 @return: File Object"""
142 return open(dest_path, "ab" if can_range else "wb") 141 return open(dest_path, "ab" if can_range else "wb")
173 error(_("Unknown stream method, this should not happen at this stage, cancelling transfer")) 172 error(_("Unknown stream method, this should not happen at this stage, cancelling transfer"))
174 del(client._xep_0096_waiting_for_approval[sid]) 173 del(client._xep_0096_waiting_for_approval[sid])
175 return 174 return
176 175
177 #we can send the iq result 176 #we can send the iq result
178 feature_elt = self.host.plugins["XEP-0020"].chooseOption({'stream-method':stream_method}) 177 feature_elt = self.host.plugins["XEP-0020"].chooseOption({'stream-method': stream_method})
179 misc_elts = [] 178 misc_elts = []
180 misc_elts.append(domish.Element((PROFILE, "file"))) 179 misc_elts.append(domish.Element((PROFILE, "file")))
181 if can_range: 180 if can_range:
182 range_elt = domish.Element((None, "range")) 181 range_elt = domish.Element((None, "range"))
183 range_elt['offset'] = str(range_offset) 182 range_elt['offset'] = str(range_offset)
184 #TODO: manage range length 183 #TODO: manage range length
185 misc_elts.append(range_elt) 184 misc_elts.append(range_elt)
186 self.host.plugins["XEP-0095"].acceptStream(data["id"], data['from'], feature_elt, misc_elts, profile) 185 self.host.plugins["XEP-0095"].acceptStream(data["id"], data['from'], feature_elt, misc_elts, profile)
187 else: 186 else:
188 debug (_("Transfer [%s] refused"), sid) 187 debug(_("Transfer [%s] refused"), sid)
189 self.host.plugins["XEP-0095"].sendRejectedError (data["id"], data['from'], profile=profile) 188 self.host.plugins["XEP-0095"].sendRejectedError(data["id"], data['from'], profile=profile)
190 del(client._xep_0096_waiting_for_approval[sid]) 189 del(client._xep_0096_waiting_for_approval[sid])
191 190
192 def _transferSucceeded(self, sid, file_obj, stream_method, profile): 191 def _transferSucceeded(self, sid, file_obj, stream_method, profile):
193 """Called by the stream method when transfer successfuly finished 192 """Called by the stream method when transfer successfuly finished
194 @param id: stream id""" 193 @param id: stream id"""
205 @param reason: can be TIMEOUT, IO_ERROR, PROTOCOL_ERROR""" 204 @param reason: can be TIMEOUT, IO_ERROR, PROTOCOL_ERROR"""
206 client = self.host.getClient(profile) 205 client = self.host.getClient(profile)
207 if not client: 206 if not client:
208 raise ProfileNotInCacheError 207 raise ProfileNotInCacheError
209 data, timeout, stream_method, failed_methods = client._xep_0096_waiting_for_approval[sid] 208 data, timeout, stream_method, failed_methods = client._xep_0096_waiting_for_approval[sid]
210 warning(_('Transfer %(id)s failed with stream method %(s_method)s: %(reason)s') % { 'id': sid, 209 warning(_('Transfer %(id)s failed with stream method %(s_method)s: %(reason)s') % {
211 's_method': stream_method, 210 'id': sid,
212 'reason': reason}) 211 's_method': stream_method,
212 'reason': reason})
213 filepath = file_obj.name 213 filepath = file_obj.name
214 file_obj.close() 214 file_obj.close()
215 os.remove(filepath) 215 os.remove(filepath)
216 #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 216 #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
217 warning(_("All stream methods failed, can't transfer the file")) 217 warning(_("All stream methods failed, can't transfer the file"))
253 range_elt = range_elts[0] 253 range_elt = range_elts[0]
254 range_offset = range_elt.getAttribute("offset", 0) 254 range_offset = range_elt.getAttribute("offset", 0)
255 range_length = range_elt.getAttribute("length") 255 range_length = range_elt.getAttribute("length")
256 256
257 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE: 257 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE:
258 file_obj = open(filepath, 'r') 258 file_obj = open(filepath, 'r')
259 if range_offset: 259 if range_offset:
260 file_obj.seek(range_offset) 260 file_obj.seek(range_offset)
261 self.host.plugins["XEP-0065"].startStream(file_obj, jid.JID(IQ['from']), sid, range_length, self.sendSuccessCb, self.sendFailureCb, size, profile) 261 self.host.plugins["XEP-0065"].startStream(file_obj, jid.JID(IQ['from']), sid, range_length, self.sendSuccessCb, self.sendFailureCb, size, profile)
262 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: 262 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE:
263 file_obj = open(filepath, 'r') 263 file_obj = open(filepath, 'r')
264 if range_offset: 264 if range_offset:
265 file_obj.seek(range_offset) 265 file_obj.seek(range_offset)
266 self.host.plugins["XEP-0047"].startStream(file_obj, jid.JID(IQ['from']), sid, range_length, self.sendSuccessCb, self.sendFailureCb, size, profile) 266 self.host.plugins["XEP-0047"].startStream(file_obj, jid.JID(IQ['from']), sid, range_length, self.sendSuccessCb, self.sendFailureCb, size, profile)
267 else: 267 else:
268 warning(_("Invalid stream method received")) 268 warning(_("Invalid stream method received"))
269 269
270 def sendFile(self, to_jid, filepath, data={}, profile_key='@NONE@'): 270 def sendFile(self, to_jid, filepath, data={}, profile_key='@NONE@'):
271 """send a file using XEP-0096 271 """send a file using XEP-0096
284 284
285 file_transfer_elts = [] 285 file_transfer_elts = []
286 286
287 statinfo = os.stat(filepath) 287 statinfo = os.stat(filepath)
288 file_elt = domish.Element((PROFILE, 'file')) 288 file_elt = domish.Element((PROFILE, 'file'))
289 file_elt['name']=os.path.basename(filepath) 289 file_elt['name'] = os.path.basename(filepath)
290 size = file_elt['size']=str(statinfo.st_size) 290 size = file_elt['size'] = str(statinfo.st_size)
291 file_transfer_elts.append(file_elt) 291 file_transfer_elts.append(file_elt)
292 292
293 file_transfer_elts.append(domish.Element((None,'range'))) 293 file_transfer_elts.append(domish.Element((None, 'range')))
294 294
295 sid, offer = self.host.plugins["XEP-0095"].proposeStream(jid.JID(to_jid), PROFILE, feature_elt, file_transfer_elts, profile_key = profile) 295 sid, offer = self.host.plugins["XEP-0095"].proposeStream(jid.JID(to_jid), PROFILE, feature_elt, file_transfer_elts, profile_key=profile)
296 offer.addCallback(self.fileCb, filepath, sid, size, profile) 296 offer.addCallback(self.fileCb, filepath, sid, size, profile)
297 return sid 297 return sid
298 298
299 def sendSuccessCb(self, sid, file_obj, stream_method, profile): 299 def sendSuccessCb(self, sid, file_obj, stream_method, profile):
300 info(_('Transfer %s successfuly finished [%s]') % (sid, profile)) 300 info(_('Transfer %s successfuly finished [%s]') % (sid, profile))
301 file_obj.close() 301 file_obj.close()
302 302
303 def sendFailureCb(self, sid, file_obj, stream_method, reason, profile): 303 def sendFailureCb(self, sid, file_obj, stream_method, reason, profile):
304 file_obj.close() 304 file_obj.close()
305 warning(_('Transfer %(id)s failed with stream method %(s_method)s: %(reason)s [%(profile)s') % { 'id': sid, "s_method": stream_method, 'reason': reason, 'profile': profile }) 305 warning(_('Transfer %(id)s failed with stream method %(s_method)s: %(reason)s [%(profile)s') % {'id': sid, "s_method": stream_method, 'reason': reason, 'profile': profile})