Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0234.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 3e4e78de9cca |
children | 378188abe941 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 from sat.core.constants import Const as C | 21 from sat.core.constants import Const as C |
22 from sat.core.log import getLogger | 22 from sat.core.log import getLogger |
23 | |
23 log = getLogger(__name__) | 24 log = getLogger(__name__) |
24 from sat.core import exceptions | 25 from sat.core import exceptions |
25 from wokkel import disco, iwokkel | 26 from wokkel import disco, iwokkel |
26 from zope.interface import implements | 27 from zope.interface import implements |
27 from sat.tools import utils | 28 from sat.tools import utils |
38 from collections import namedtuple | 39 from collections import namedtuple |
39 from sat.tools.common import regex | 40 from sat.tools.common import regex |
40 import mimetypes | 41 import mimetypes |
41 | 42 |
42 | 43 |
43 NS_JINGLE_FT = 'urn:xmpp:jingle:apps:file-transfer:5' | 44 NS_JINGLE_FT = "urn:xmpp:jingle:apps:file-transfer:5" |
44 | 45 |
45 PLUGIN_INFO = { | 46 PLUGIN_INFO = { |
46 C.PI_NAME: "Jingle File Transfer", | 47 C.PI_NAME: "Jingle File Transfer", |
47 C.PI_IMPORT_NAME: "XEP-0234", | 48 C.PI_IMPORT_NAME: "XEP-0234", |
48 C.PI_TYPE: "XEP", | 49 C.PI_TYPE: "XEP", |
49 C.PI_MODES: C.PLUG_MODE_BOTH, | 50 C.PI_MODES: C.PLUG_MODE_BOTH, |
50 C.PI_PROTOCOLS: ["XEP-0234"], | 51 C.PI_PROTOCOLS: ["XEP-0234"], |
51 C.PI_DEPENDENCIES: ["XEP-0166", "XEP-0300", "FILE"], | 52 C.PI_DEPENDENCIES: ["XEP-0166", "XEP-0300", "FILE"], |
52 C.PI_MAIN: "XEP_0234", | 53 C.PI_MAIN: "XEP_0234", |
53 C.PI_HANDLER: "yes", | 54 C.PI_HANDLER: "yes", |
54 C.PI_DESCRIPTION: _("""Implementation of Jingle File Transfer""") | 55 C.PI_DESCRIPTION: _("""Implementation of Jingle File Transfer"""), |
55 } | 56 } |
56 | 57 |
57 EXTRA_ALLOWED = {u'path', u'namespace', u'file_desc', u'file_hash'} | 58 EXTRA_ALLOWED = {u"path", u"namespace", u"file_desc", u"file_hash"} |
58 Range = namedtuple('Range', ('offset', 'length')) | 59 Range = namedtuple("Range", ("offset", "length")) |
59 | 60 |
60 | 61 |
61 class XEP_0234(object): | 62 class XEP_0234(object): |
62 # TODO: assure everything is closed when file is sent or session terminate is received | 63 # TODO: assure everything is closed when file is sent or session terminate is received |
63 # TODO: call self._f.unregister when unloading order will be managing (i.e. when dependencies will be unloaded at the end) | 64 # TODO: call self._f.unregister when unloading order will be managing (i.e. when dependencies will be unloaded at the end) |
64 Range = Range # we copy the class here, so it can be used by other plugins | 65 Range = Range # we copy the class here, so it can be used by other plugins |
65 | 66 |
66 def __init__(self, host): | 67 def __init__(self, host): |
67 log.info(_("plugin Jingle File Transfer initialization")) | 68 log.info(_("plugin Jingle File Transfer initialization")) |
68 self.host = host | 69 self.host = host |
69 host.registerNamespace('jingle-ft', NS_JINGLE_FT) | 70 host.registerNamespace("jingle-ft", NS_JINGLE_FT) |
70 self._j = host.plugins["XEP-0166"] # shortcut to access jingle | 71 self._j = host.plugins["XEP-0166"] # shortcut to access jingle |
71 self._j.registerApplication(NS_JINGLE_FT, self) | 72 self._j.registerApplication(NS_JINGLE_FT, self) |
72 self._f = host.plugins["FILE"] | 73 self._f = host.plugins["FILE"] |
73 self._f.register(NS_JINGLE_FT, self.fileJingleSend, priority = 10000, method_name=u"Jingle") | 74 self._f.register( |
75 NS_JINGLE_FT, self.fileJingleSend, priority=10000, method_name=u"Jingle" | |
76 ) | |
74 self._hash = self.host.plugins["XEP-0300"] | 77 self._hash = self.host.plugins["XEP-0300"] |
75 host.bridge.addMethod("fileJingleSend", ".plugin", in_sign='ssssa{ss}s', out_sign='', method=self._fileJingleSend, async=True) | 78 host.bridge.addMethod( |
76 host.bridge.addMethod("fileJingleRequest", ".plugin", in_sign='sssssa{ss}s', out_sign='s', method=self._fileJingleRequest, async=True) | 79 "fileJingleSend", |
80 ".plugin", | |
81 in_sign="ssssa{ss}s", | |
82 out_sign="", | |
83 method=self._fileJingleSend, | |
84 async=True, | |
85 ) | |
86 host.bridge.addMethod( | |
87 "fileJingleRequest", | |
88 ".plugin", | |
89 in_sign="sssssa{ss}s", | |
90 out_sign="s", | |
91 method=self._fileJingleRequest, | |
92 async=True, | |
93 ) | |
77 | 94 |
78 def getHandler(self, client): | 95 def getHandler(self, client): |
79 return XEP_0234_handler() | 96 return XEP_0234_handler() |
80 | 97 |
81 def getProgressId(self, session, content_name): | 98 def getProgressId(self, session, content_name): |
83 | 100 |
84 @param session(dict): jingle session | 101 @param session(dict): jingle session |
85 @param content_name(unicode): name of the content | 102 @param content_name(unicode): name of the content |
86 @return (unicode): unique progress id | 103 @return (unicode): unique progress id |
87 """ | 104 """ |
88 return u'{}_{}'.format(session['id'], content_name) | 105 return u"{}_{}".format(session["id"], content_name) |
89 | 106 |
90 # generic methods | 107 # generic methods |
91 | 108 |
92 def buildFileElement(self, name, file_hash=None, hash_algo=None, size=None, mime_type=None, desc=None, | 109 def buildFileElement( |
93 modified=None, transfer_range=None, path=None, namespace=None, file_elt=None, **kwargs): | 110 self, |
111 name, | |
112 file_hash=None, | |
113 hash_algo=None, | |
114 size=None, | |
115 mime_type=None, | |
116 desc=None, | |
117 modified=None, | |
118 transfer_range=None, | |
119 path=None, | |
120 namespace=None, | |
121 file_elt=None, | |
122 **kwargs | |
123 ): | |
94 """Generate a <file> element with available metadata | 124 """Generate a <file> element with available metadata |
95 | 125 |
96 @param file_hash(unicode, None): hash of the file | 126 @param file_hash(unicode, None): hash of the file |
97 empty string to set <hash-used/> element | 127 empty string to set <hash-used/> element |
98 @param hash_algo(unicode, None): hash algorithm used | 128 @param hash_algo(unicode, None): hash algorithm used |
107 @param **kwargs: data for plugin extension (ignored by default) | 137 @param **kwargs: data for plugin extension (ignored by default) |
108 @return (domish.Element): generated element | 138 @return (domish.Element): generated element |
109 @trigger XEP-0234_buildFileElement(file_elt, extra_args): can be used to extend elements to add | 139 @trigger XEP-0234_buildFileElement(file_elt, extra_args): can be used to extend elements to add |
110 """ | 140 """ |
111 if file_elt is None: | 141 if file_elt is None: |
112 file_elt = domish.Element((NS_JINGLE_FT, u'file')) | 142 file_elt = domish.Element((NS_JINGLE_FT, u"file")) |
113 for name, value in ((u'name', name), (u'size', size), ('media-type', mime_type), | 143 for name, value in ( |
114 (u'desc', desc), (u'path', path), (u'namespace', namespace)): | 144 (u"name", name), |
145 (u"size", size), | |
146 ("media-type", mime_type), | |
147 (u"desc", desc), | |
148 (u"path", path), | |
149 (u"namespace", namespace), | |
150 ): | |
115 if value is not None: | 151 if value is not None: |
116 file_elt.addElement(name, content=unicode(value)) | 152 file_elt.addElement(name, content=unicode(value)) |
117 | 153 |
118 if modified is not None: | 154 if modified is not None: |
119 if isinstance(modified, int): | 155 if isinstance(modified, int): |
120 file_elt.addElement(u'date', utils.xmpp_date(modified or None)) | 156 file_elt.addElement(u"date", utils.xmpp_date(modified or None)) |
121 else: | 157 else: |
122 file_elt.addElement(u'date', modified) | 158 file_elt.addElement(u"date", modified) |
123 elif 'created' in kwargs: | 159 elif "created" in kwargs: |
124 file_elt.addElement(u'date', utils.xmpp_date(kwargs.pop('created'))) | 160 file_elt.addElement(u"date", utils.xmpp_date(kwargs.pop("created"))) |
125 | 161 |
126 range_elt = file_elt.addElement(u'range') | 162 range_elt = file_elt.addElement(u"range") |
127 if transfer_range is not None: | 163 if transfer_range is not None: |
128 if transfer_range.offset is not None: | 164 if transfer_range.offset is not None: |
129 range_elt[u'offset'] = transfer_range.offset | 165 range_elt[u"offset"] = transfer_range.offset |
130 if transfer_range.length is not None: | 166 if transfer_range.length is not None: |
131 range_elt[u'length'] = transfer_range.length | 167 range_elt[u"length"] = transfer_range.length |
132 if file_hash is not None: | 168 if file_hash is not None: |
133 if not file_hash: | 169 if not file_hash: |
134 file_elt.addChild(self._hash.buildHashUsedElt()) | 170 file_elt.addChild(self._hash.buildHashUsedElt()) |
135 else: | 171 else: |
136 file_elt.addChild(self._hash.buildHashElt(file_hash, hash_algo)) | 172 file_elt.addChild(self._hash.buildHashElt(file_hash, hash_algo)) |
137 elif hash_algo is not None: | 173 elif hash_algo is not None: |
138 file_elt.addChild(self._hash.buildHashUsedElt(hash_algo)) | 174 file_elt.addChild(self._hash.buildHashUsedElt(hash_algo)) |
139 self.host.trigger.point(u'XEP-0234_buildFileElement', file_elt, extra_args=kwargs) | 175 self.host.trigger.point(u"XEP-0234_buildFileElement", file_elt, extra_args=kwargs) |
140 if kwargs: | 176 if kwargs: |
141 for kw in kwargs: | 177 for kw in kwargs: |
142 log.debug('ignored keyword: {}'.format(kw)) | 178 log.debug("ignored keyword: {}".format(kw)) |
143 return file_elt | 179 return file_elt |
144 | 180 |
145 def buildFileElementFromDict(self, file_data, **kwargs): | 181 def buildFileElementFromDict(self, file_data, **kwargs): |
146 """like buildFileElement but get values from a file_data dict | 182 """like buildFileElement but get values from a file_data dict |
147 | 183 |
149 @param **kwargs: data to override | 185 @param **kwargs: data to override |
150 """ | 186 """ |
151 if kwargs: | 187 if kwargs: |
152 file_data = file_data.copy() | 188 file_data = file_data.copy() |
153 file_data.update(kwargs) | 189 file_data.update(kwargs) |
154 return self. buildFileElement(**file_data) | 190 return self.buildFileElement(**file_data) |
155 | 191 |
156 | 192 def parseFileElement( |
157 def parseFileElement(self, file_elt, file_data=None, given=False, parent_elt=None, keep_empty_range=False): | 193 self, |
194 file_elt, | |
195 file_data=None, | |
196 given=False, | |
197 parent_elt=None, | |
198 keep_empty_range=False, | |
199 ): | |
158 """Parse a <file> element and file dictionary accordingly | 200 """Parse a <file> element and file dictionary accordingly |
159 | 201 |
160 @param file_data(dict, None): dict where the data will be set | 202 @param file_data(dict, None): dict where the data will be set |
161 following keys will be set (and overwritten if they already exist): | 203 following keys will be set (and overwritten if they already exist): |
162 name, file_hash, hash_algo, size, mime_type, desc, path, namespace, range | 204 name, file_hash, hash_algo, size, mime_type, desc, path, namespace, range |
171 @raise exceptions.NotFound: there is not <file> element in parent_elt | 213 @raise exceptions.NotFound: there is not <file> element in parent_elt |
172 @raise exceptions.DataError: if file_elt uri is not NS_JINGLE_FT | 214 @raise exceptions.DataError: if file_elt uri is not NS_JINGLE_FT |
173 """ | 215 """ |
174 if parent_elt is not None: | 216 if parent_elt is not None: |
175 if file_elt is not None: | 217 if file_elt is not None: |
176 raise exceptions.InternalError(u'file_elt must be None if parent_elt is set') | 218 raise exceptions.InternalError( |
219 u"file_elt must be None if parent_elt is set" | |
220 ) | |
177 try: | 221 try: |
178 file_elt = next(parent_elt.elements(NS_JINGLE_FT, u'file')) | 222 file_elt = next(parent_elt.elements(NS_JINGLE_FT, u"file")) |
179 except StopIteration: | 223 except StopIteration: |
180 raise exceptions.NotFound() | 224 raise exceptions.NotFound() |
181 else: | 225 else: |
182 if not file_elt or file_elt.uri != NS_JINGLE_FT: | 226 if not file_elt or file_elt.uri != NS_JINGLE_FT: |
183 raise exceptions.DataError(u'invalid <file> element: {stanza}'.format(stanza = file_elt.toXml())) | 227 raise exceptions.DataError( |
228 u"invalid <file> element: {stanza}".format(stanza=file_elt.toXml()) | |
229 ) | |
184 | 230 |
185 if file_data is None: | 231 if file_data is None: |
186 file_data = {} | 232 file_data = {} |
187 | 233 |
188 for name in (u'name', u'desc', u'path', u'namespace'): | 234 for name in (u"name", u"desc", u"path", u"namespace"): |
189 try: | 235 try: |
190 file_data[name] = unicode(next(file_elt.elements(NS_JINGLE_FT, name))) | 236 file_data[name] = unicode(next(file_elt.elements(NS_JINGLE_FT, name))) |
191 except StopIteration: | 237 except StopIteration: |
192 pass | 238 pass |
193 | 239 |
194 | 240 name = file_data.get(u"name") |
195 name = file_data.get(u'name') | 241 if name == u"..": |
196 if name == u'..': | |
197 # we don't want to go to parent dir when joining to a path | 242 # we don't want to go to parent dir when joining to a path |
198 name = u'--' | 243 name = u"--" |
199 file_data[u'name'] = name | 244 file_data[u"name"] = name |
200 elif name is not None and u'/' in name or u'\\' in name: | 245 elif name is not None and u"/" in name or u"\\" in name: |
201 file_data[u'name'] = regex.pathEscape(name) | 246 file_data[u"name"] = regex.pathEscape(name) |
202 | 247 |
203 try: | 248 try: |
204 file_data[u'mime_type'] = unicode(next(file_elt.elements(NS_JINGLE_FT, u'media-type'))) | 249 file_data[u"mime_type"] = unicode( |
250 next(file_elt.elements(NS_JINGLE_FT, u"media-type")) | |
251 ) | |
205 except StopIteration: | 252 except StopIteration: |
206 pass | 253 pass |
207 | 254 |
208 try: | 255 try: |
209 file_data[u'size'] = int(unicode(next(file_elt.elements(NS_JINGLE_FT, u'size')))) | 256 file_data[u"size"] = int( |
257 unicode(next(file_elt.elements(NS_JINGLE_FT, u"size"))) | |
258 ) | |
210 except StopIteration: | 259 except StopIteration: |
211 pass | 260 pass |
212 | 261 |
213 try: | 262 try: |
214 file_data[u'modified'] = date_utils.date_parse(next(file_elt.elements(NS_JINGLE_FT, u'date'))) | 263 file_data[u"modified"] = date_utils.date_parse( |
264 next(file_elt.elements(NS_JINGLE_FT, u"date")) | |
265 ) | |
215 except StopIteration: | 266 except StopIteration: |
216 pass | 267 pass |
217 | 268 |
218 try: | 269 try: |
219 range_elt = file_elt.elements(NS_JINGLE_FT, u'range').next() | 270 range_elt = file_elt.elements(NS_JINGLE_FT, u"range").next() |
220 except StopIteration: | 271 except StopIteration: |
221 pass | 272 pass |
222 else: | 273 else: |
223 offset = range_elt.getAttribute('offset') | 274 offset = range_elt.getAttribute("offset") |
224 length = range_elt.getAttribute('length') | 275 length = range_elt.getAttribute("length") |
225 if offset or length or keep_empty_range: | 276 if offset or length or keep_empty_range: |
226 file_data[u'transfer_range'] = Range(offset=offset, length=length) | 277 file_data[u"transfer_range"] = Range(offset=offset, length=length) |
227 | 278 |
228 prefix = u'given_' if given else u'' | 279 prefix = u"given_" if given else u"" |
229 hash_algo_key, hash_key = u'hash_algo', prefix + u'file_hash' | 280 hash_algo_key, hash_key = u"hash_algo", prefix + u"file_hash" |
230 try: | 281 try: |
231 file_data[hash_algo_key], file_data[hash_key] = self._hash.parseHashElt(file_elt) | 282 file_data[hash_algo_key], file_data[hash_key] = self._hash.parseHashElt( |
283 file_elt | |
284 ) | |
232 except exceptions.NotFound: | 285 except exceptions.NotFound: |
233 pass | 286 pass |
234 | 287 |
235 self.host.trigger.point(u'XEP-0234_parseFileElement', file_elt, file_data) | 288 self.host.trigger.point(u"XEP-0234_parseFileElement", file_elt, file_data) |
236 | 289 |
237 return file_data | 290 return file_data |
238 | 291 |
239 # bridge methods | 292 # bridge methods |
240 | 293 |
241 def _fileJingleSend(self, peer_jid, filepath, name="", file_desc="", extra=None, profile=C.PROF_KEY_NONE): | 294 def _fileJingleSend( |
295 self, | |
296 peer_jid, | |
297 filepath, | |
298 name="", | |
299 file_desc="", | |
300 extra=None, | |
301 profile=C.PROF_KEY_NONE, | |
302 ): | |
242 client = self.host.getClient(profile) | 303 client = self.host.getClient(profile) |
243 return self.fileJingleSend(client, jid.JID(peer_jid), filepath, name or None, file_desc or None, extra or None) | 304 return self.fileJingleSend( |
305 client, | |
306 jid.JID(peer_jid), | |
307 filepath, | |
308 name or None, | |
309 file_desc or None, | |
310 extra or None, | |
311 ) | |
244 | 312 |
245 @defer.inlineCallbacks | 313 @defer.inlineCallbacks |
246 def fileJingleSend(self, client, peer_jid, filepath, name, file_desc=None, extra=None): | 314 def fileJingleSend( |
315 self, client, peer_jid, filepath, name, file_desc=None, extra=None | |
316 ): | |
247 """Send a file using jingle file transfer | 317 """Send a file using jingle file transfer |
248 | 318 |
249 @param peer_jid(jid.JID): destinee jid | 319 @param peer_jid(jid.JID): destinee jid |
250 @param filepath(str): absolute path of the file | 320 @param filepath(str): absolute path of the file |
251 @param name(unicode, None): name of the file | 321 @param name(unicode, None): name of the file |
254 """ | 324 """ |
255 progress_id_d = defer.Deferred() | 325 progress_id_d = defer.Deferred() |
256 if extra is None: | 326 if extra is None: |
257 extra = {} | 327 extra = {} |
258 if file_desc is not None: | 328 if file_desc is not None: |
259 extra['file_desc'] = file_desc | 329 extra["file_desc"] = file_desc |
260 yield self._j.initiate(client, | 330 yield self._j.initiate( |
261 peer_jid, | 331 client, |
262 [{'app_ns': NS_JINGLE_FT, | 332 peer_jid, |
263 'senders': self._j.ROLE_INITIATOR, | 333 [ |
264 'app_kwargs': {'filepath': filepath, | 334 { |
265 'name': name, | 335 "app_ns": NS_JINGLE_FT, |
266 'extra': extra, | 336 "senders": self._j.ROLE_INITIATOR, |
267 'progress_id_d': progress_id_d}, | 337 "app_kwargs": { |
268 }]) | 338 "filepath": filepath, |
339 "name": name, | |
340 "extra": extra, | |
341 "progress_id_d": progress_id_d, | |
342 }, | |
343 } | |
344 ], | |
345 ) | |
269 progress_id = yield progress_id_d | 346 progress_id = yield progress_id_d |
270 defer.returnValue(progress_id) | 347 defer.returnValue(progress_id) |
271 | 348 |
272 def _fileJingleRequest(self, peer_jid, filepath, name="", file_hash="", hash_algo="", extra=None, profile=C.PROF_KEY_NONE): | 349 def _fileJingleRequest( |
350 self, | |
351 peer_jid, | |
352 filepath, | |
353 name="", | |
354 file_hash="", | |
355 hash_algo="", | |
356 extra=None, | |
357 profile=C.PROF_KEY_NONE, | |
358 ): | |
273 client = self.host.getClient(profile) | 359 client = self.host.getClient(profile) |
274 return self.fileJingleRequest(client, jid.JID(peer_jid), filepath, name or None, file_hash or None, hash_algo or None, extra or None) | 360 return self.fileJingleRequest( |
361 client, | |
362 jid.JID(peer_jid), | |
363 filepath, | |
364 name or None, | |
365 file_hash or None, | |
366 hash_algo or None, | |
367 extra or None, | |
368 ) | |
275 | 369 |
276 @defer.inlineCallbacks | 370 @defer.inlineCallbacks |
277 def fileJingleRequest(self, client, peer_jid, filepath, name=None, file_hash=None, hash_algo=None, extra=None): | 371 def fileJingleRequest( |
372 self, | |
373 client, | |
374 peer_jid, | |
375 filepath, | |
376 name=None, | |
377 file_hash=None, | |
378 hash_algo=None, | |
379 extra=None, | |
380 ): | |
278 """Request a file using jingle file transfer | 381 """Request a file using jingle file transfer |
279 | 382 |
280 @param peer_jid(jid.JID): destinee jid | 383 @param peer_jid(jid.JID): destinee jid |
281 @param filepath(str): absolute path where the file will be downloaded | 384 @param filepath(str): absolute path where the file will be downloaded |
282 @param name(unicode, None): name of the file | 385 @param name(unicode, None): name of the file |
287 if extra is None: | 390 if extra is None: |
288 extra = {} | 391 extra = {} |
289 if file_hash is not None: | 392 if file_hash is not None: |
290 if hash_algo is None: | 393 if hash_algo is None: |
291 raise ValueError(_(u"hash_algo must be set if file_hash is set")) | 394 raise ValueError(_(u"hash_algo must be set if file_hash is set")) |
292 extra['file_hash'] = file_hash | 395 extra["file_hash"] = file_hash |
293 extra['hash_algo'] = hash_algo | 396 extra["hash_algo"] = hash_algo |
294 else: | 397 else: |
295 if hash_algo is not None: | 398 if hash_algo is not None: |
296 raise ValueError(_(u"file_hash must be set if hash_algo is set")) | 399 raise ValueError(_(u"file_hash must be set if hash_algo is set")) |
297 yield self._j.initiate(client, | 400 yield self._j.initiate( |
298 peer_jid, | 401 client, |
299 [{'app_ns': NS_JINGLE_FT, | 402 peer_jid, |
300 'senders': self._j.ROLE_RESPONDER, | 403 [ |
301 'app_kwargs': {'filepath': filepath, | 404 { |
302 'name': name, | 405 "app_ns": NS_JINGLE_FT, |
303 'extra': extra, | 406 "senders": self._j.ROLE_RESPONDER, |
304 'progress_id_d': progress_id_d}, | 407 "app_kwargs": { |
305 }]) | 408 "filepath": filepath, |
409 "name": name, | |
410 "extra": extra, | |
411 "progress_id_d": progress_id_d, | |
412 }, | |
413 } | |
414 ], | |
415 ) | |
306 progress_id = yield progress_id_d | 416 progress_id = yield progress_id_d |
307 defer.returnValue(progress_id) | 417 defer.returnValue(progress_id) |
308 | 418 |
309 # jingle callbacks | 419 # jingle callbacks |
310 | 420 |
311 def jingleSessionInit(self, client, session, content_name, filepath, name, extra, progress_id_d): | 421 def jingleSessionInit( |
422 self, client, session, content_name, filepath, name, extra, progress_id_d | |
423 ): | |
312 if extra is None: | 424 if extra is None: |
313 extra = {} | 425 extra = {} |
314 else: | 426 else: |
315 if not EXTRA_ALLOWED.issuperset(extra): | 427 if not EXTRA_ALLOWED.issuperset(extra): |
316 raise ValueError(_(u"only the following keys are allowed in extra: {keys}").format( | 428 raise ValueError( |
317 keys=u', '.join(EXTRA_ALLOWED))) | 429 _(u"only the following keys are allowed in extra: {keys}").format( |
430 keys=u", ".join(EXTRA_ALLOWED) | |
431 ) | |
432 ) | |
318 progress_id_d.callback(self.getProgressId(session, content_name)) | 433 progress_id_d.callback(self.getProgressId(session, content_name)) |
319 content_data = session['contents'][content_name] | 434 content_data = session["contents"][content_name] |
320 application_data = content_data['application_data'] | 435 application_data = content_data["application_data"] |
321 assert 'file_path' not in application_data | 436 assert "file_path" not in application_data |
322 application_data['file_path'] = filepath | 437 application_data["file_path"] = filepath |
323 file_data = application_data['file_data'] = {} | 438 file_data = application_data["file_data"] = {} |
324 desc_elt = domish.Element((NS_JINGLE_FT, 'description')) | 439 desc_elt = domish.Element((NS_JINGLE_FT, "description")) |
325 file_elt = desc_elt.addElement("file") | 440 file_elt = desc_elt.addElement("file") |
326 | 441 |
327 if content_data[u'senders'] == self._j.ROLE_INITIATOR: | 442 if content_data[u"senders"] == self._j.ROLE_INITIATOR: |
328 # we send a file | 443 # we send a file |
329 if name is None: | 444 if name is None: |
330 name = os.path.basename(filepath) | 445 name = os.path.basename(filepath) |
331 file_data[u'date'] = utils.xmpp_date() | 446 file_data[u"date"] = utils.xmpp_date() |
332 file_data[u'desc'] = extra.pop(u'file_desc', u'') | 447 file_data[u"desc"] = extra.pop(u"file_desc", u"") |
333 file_data[u'name'] = name | 448 file_data[u"name"] = name |
334 mime_type = mimetypes.guess_type(name, strict=False)[0] | 449 mime_type = mimetypes.guess_type(name, strict=False)[0] |
335 if mime_type is not None: | 450 if mime_type is not None: |
336 file_data[u'mime_type'] = mime_type | 451 file_data[u"mime_type"] = mime_type |
337 file_data[u'size'] = os.path.getsize(filepath) | 452 file_data[u"size"] = os.path.getsize(filepath) |
338 if u'namespace' in extra: | 453 if u"namespace" in extra: |
339 file_data[u'namespace'] = extra[u'namespace'] | 454 file_data[u"namespace"] = extra[u"namespace"] |
340 if u'path' in extra: | 455 if u"path" in extra: |
341 file_data[u'path'] = extra[u'path'] | 456 file_data[u"path"] = extra[u"path"] |
342 self.buildFileElementFromDict(file_data, file_elt=file_elt, file_hash=u'') | 457 self.buildFileElementFromDict(file_data, file_elt=file_elt, file_hash=u"") |
343 else: | 458 else: |
344 # we request a file | 459 # we request a file |
345 file_hash = extra.pop(u'file_hash', u'') | 460 file_hash = extra.pop(u"file_hash", u"") |
346 if not name and not file_hash: | 461 if not name and not file_hash: |
347 raise ValueError(_(u'you need to provide at least name or file hash')) | 462 raise ValueError(_(u"you need to provide at least name or file hash")) |
348 if name: | 463 if name: |
349 file_data[u'name'] = name | 464 file_data[u"name"] = name |
350 if file_hash: | 465 if file_hash: |
351 file_data[u'file_hash'] = file_hash | 466 file_data[u"file_hash"] = file_hash |
352 file_data[u'hash_algo'] = extra[u'hash_algo'] | 467 file_data[u"hash_algo"] = extra[u"hash_algo"] |
353 else: | 468 else: |
354 file_data[u'hash_algo'] = self._hash.getDefaultAlgo() | 469 file_data[u"hash_algo"] = self._hash.getDefaultAlgo() |
355 if u'namespace' in extra: | 470 if u"namespace" in extra: |
356 file_data[u'namespace'] = extra[u'namespace'] | 471 file_data[u"namespace"] = extra[u"namespace"] |
357 if u'path' in extra: | 472 if u"path" in extra: |
358 file_data[u'path'] = extra[u'path'] | 473 file_data[u"path"] = extra[u"path"] |
359 self.buildFileElementFromDict(file_data, file_elt=file_elt) | 474 self.buildFileElementFromDict(file_data, file_elt=file_elt) |
360 | 475 |
361 return desc_elt | 476 return desc_elt |
362 | 477 |
363 def jingleRequestConfirmation(self, client, action, session, content_name, desc_elt): | 478 def jingleRequestConfirmation(self, client, action, session, content_name, desc_elt): |
364 """This method request confirmation for a jingle session""" | 479 """This method request confirmation for a jingle session""" |
365 content_data = session['contents'][content_name] | 480 content_data = session["contents"][content_name] |
366 senders = content_data[u'senders'] | 481 senders = content_data[u"senders"] |
367 if senders not in (self._j.ROLE_INITIATOR, self._j.ROLE_RESPONDER): | 482 if senders not in (self._j.ROLE_INITIATOR, self._j.ROLE_RESPONDER): |
368 log.warning(u"Bad sender, assuming initiator") | 483 log.warning(u"Bad sender, assuming initiator") |
369 senders = content_data[u'senders'] = self._j.ROLE_INITIATOR | 484 senders = content_data[u"senders"] = self._j.ROLE_INITIATOR |
370 # first we grab file informations | 485 # first we grab file informations |
371 try: | 486 try: |
372 file_elt = desc_elt.elements(NS_JINGLE_FT, 'file').next() | 487 file_elt = desc_elt.elements(NS_JINGLE_FT, "file").next() |
373 except StopIteration: | 488 except StopIteration: |
374 raise failure.Failure(exceptions.DataError) | 489 raise failure.Failure(exceptions.DataError) |
375 file_data = {'progress_id': self.getProgressId(session, content_name)} | 490 file_data = {"progress_id": self.getProgressId(session, content_name)} |
376 | 491 |
377 if senders == self._j.ROLE_RESPONDER: | 492 if senders == self._j.ROLE_RESPONDER: |
378 # we send the file | 493 # we send the file |
379 return self._fileSendingRequestConf(client, session, content_data, content_name, file_data, file_elt) | 494 return self._fileSendingRequestConf( |
495 client, session, content_data, content_name, file_data, file_elt | |
496 ) | |
380 else: | 497 else: |
381 # we receive the file | 498 # we receive the file |
382 return self._fileReceivingRequestConf(client, session, content_data, content_name, file_data, file_elt) | 499 return self._fileReceivingRequestConf( |
500 client, session, content_data, content_name, file_data, file_elt | |
501 ) | |
383 | 502 |
384 @defer.inlineCallbacks | 503 @defer.inlineCallbacks |
385 def _fileSendingRequestConf(self, client, session, content_data, content_name, file_data, file_elt): | 504 def _fileSendingRequestConf( |
505 self, client, session, content_data, content_name, file_data, file_elt | |
506 ): | |
386 """parse file_elt, and handle file retrieving/permission checking""" | 507 """parse file_elt, and handle file retrieving/permission checking""" |
387 self.parseFileElement(file_elt, file_data) | 508 self.parseFileElement(file_elt, file_data) |
388 content_data['application_data']['file_data'] = file_data | 509 content_data["application_data"]["file_data"] = file_data |
389 finished_d = content_data['finished_d'] = defer.Deferred() | 510 finished_d = content_data["finished_d"] = defer.Deferred() |
390 | 511 |
391 # confirmed_d is a deferred returning confimed value (only used if cont is False) | 512 # confirmed_d is a deferred returning confimed value (only used if cont is False) |
392 cont, confirmed_d = self.host.trigger.returnPoint("XEP-0234_fileSendingRequest", client, session, content_data, content_name, file_data, file_elt) | 513 cont, confirmed_d = self.host.trigger.returnPoint( |
514 "XEP-0234_fileSendingRequest", | |
515 client, | |
516 session, | |
517 content_data, | |
518 content_name, | |
519 file_data, | |
520 file_elt, | |
521 ) | |
393 if not cont: | 522 if not cont: |
394 confirmed = yield confirmed_d | 523 confirmed = yield confirmed_d |
395 if confirmed: | 524 if confirmed: |
396 args = [client, session, content_name, content_data] | 525 args = [client, session, content_name, content_data] |
397 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | 526 finished_d.addCallbacks( |
527 self._finishedCb, self._finishedEb, args, None, args | |
528 ) | |
398 defer.returnValue(confirmed) | 529 defer.returnValue(confirmed) |
399 | 530 |
400 log.warning(_(u'File continue is not implemented yet')) | 531 log.warning(_(u"File continue is not implemented yet")) |
401 defer.returnValue(False) | 532 defer.returnValue(False) |
402 | 533 |
403 def _fileReceivingRequestConf(self, client, session, content_data, content_name, file_data, file_elt): | 534 def _fileReceivingRequestConf( |
535 self, client, session, content_data, content_name, file_data, file_elt | |
536 ): | |
404 """parse file_elt, and handle user permission/file opening""" | 537 """parse file_elt, and handle user permission/file opening""" |
405 self.parseFileElement(file_elt, file_data, given=True) | 538 self.parseFileElement(file_elt, file_data, given=True) |
406 try: | 539 try: |
407 hash_algo, file_data['given_file_hash'] = self._hash.parseHashElt(file_elt) | 540 hash_algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) |
408 except exceptions.NotFound: | 541 except exceptions.NotFound: |
409 try: | 542 try: |
410 hash_algo = self._hash.parseHashUsedElt(file_elt) | 543 hash_algo = self._hash.parseHashUsedElt(file_elt) |
411 except exceptions.NotFound: | 544 except exceptions.NotFound: |
412 raise failure.Failure(exceptions.DataError) | 545 raise failure.Failure(exceptions.DataError) |
413 | 546 |
414 if hash_algo is not None: | 547 if hash_algo is not None: |
415 file_data['hash_algo'] = hash_algo | 548 file_data["hash_algo"] = hash_algo |
416 file_data['hash_hasher'] = hasher = self._hash.getHasher(hash_algo) | 549 file_data["hash_hasher"] = hasher = self._hash.getHasher(hash_algo) |
417 file_data['data_cb'] = lambda data: hasher.update(data) | 550 file_data["data_cb"] = lambda data: hasher.update(data) |
418 | 551 |
419 try: | 552 try: |
420 file_data['size'] = int(file_data['size']) | 553 file_data["size"] = int(file_data["size"]) |
421 except ValueError: | 554 except ValueError: |
422 raise failure.Failure(exceptions.DataError) | 555 raise failure.Failure(exceptions.DataError) |
423 | 556 |
424 name = file_data['name'] | 557 name = file_data["name"] |
425 if '/' in name or '\\' in name: | 558 if "/" in name or "\\" in name: |
426 log.warning(u"File name contain path characters, we replace them: {}".format(name)) | 559 log.warning( |
427 file_data['name'] = name.replace('/', '_').replace('\\', '_') | 560 u"File name contain path characters, we replace them: {}".format(name) |
428 | 561 ) |
429 content_data['application_data']['file_data'] = file_data | 562 file_data["name"] = name.replace("/", "_").replace("\\", "_") |
563 | |
564 content_data["application_data"]["file_data"] = file_data | |
430 | 565 |
431 # now we actualy request permission to user | 566 # now we actualy request permission to user |
432 def gotConfirmation(confirmed): | 567 def gotConfirmation(confirmed): |
433 if confirmed: | 568 if confirmed: |
434 args = [client, session, content_name, content_data] | 569 args = [client, session, content_name, content_data] |
435 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | 570 finished_d.addCallbacks( |
571 self._finishedCb, self._finishedEb, args, None, args | |
572 ) | |
436 return confirmed | 573 return confirmed |
437 | 574 |
438 # deferred to track end of transfer | 575 # deferred to track end of transfer |
439 finished_d = content_data['finished_d'] = defer.Deferred() | 576 finished_d = content_data["finished_d"] = defer.Deferred() |
440 d = self._f.getDestDir(client, session['peer_jid'], content_data, file_data, stream_object=True) | 577 d = self._f.getDestDir( |
578 client, session["peer_jid"], content_data, file_data, stream_object=True | |
579 ) | |
441 d.addCallback(gotConfirmation) | 580 d.addCallback(gotConfirmation) |
442 return d | 581 return d |
443 | 582 |
444 def jingleHandler(self, client, action, session, content_name, desc_elt): | 583 def jingleHandler(self, client, action, session, content_name, desc_elt): |
445 content_data = session['contents'][content_name] | 584 content_data = session["contents"][content_name] |
446 application_data = content_data['application_data'] | 585 application_data = content_data["application_data"] |
447 if action in (self._j.A_ACCEPTED_ACK,): | 586 if action in (self._j.A_ACCEPTED_ACK,): |
448 pass | 587 pass |
449 elif action == self._j.A_SESSION_INITIATE: | 588 elif action == self._j.A_SESSION_INITIATE: |
450 file_elt = desc_elt.elements(NS_JINGLE_FT, 'file').next() | 589 file_elt = desc_elt.elements(NS_JINGLE_FT, "file").next() |
451 try: | 590 try: |
452 file_elt.elements(NS_JINGLE_FT, 'range').next() | 591 file_elt.elements(NS_JINGLE_FT, "range").next() |
453 except StopIteration: | 592 except StopIteration: |
454 # initiator doesn't manage <range>, but we do so we advertise it | 593 # initiator doesn't manage <range>, but we do so we advertise it |
455 # FIXME: to be checked | 594 # FIXME: to be checked |
456 log.debug("adding <range> element") | 595 log.debug("adding <range> element") |
457 file_elt.addElement('range') | 596 file_elt.addElement("range") |
458 elif action == self._j.A_SESSION_ACCEPT: | 597 elif action == self._j.A_SESSION_ACCEPT: |
459 assert not 'stream_object' in content_data | 598 assert not "stream_object" in content_data |
460 file_data = application_data['file_data'] | 599 file_data = application_data["file_data"] |
461 file_path = application_data['file_path'] | 600 file_path = application_data["file_path"] |
462 senders = content_data[u'senders'] | 601 senders = content_data[u"senders"] |
463 if senders != session[u'role']: | 602 if senders != session[u"role"]: |
464 # we are receiving the file | 603 # we are receiving the file |
465 try: | 604 try: |
466 # did the responder specified the size of the file? | 605 # did the responder specified the size of the file? |
467 file_elt = next(desc_elt.elements(NS_JINGLE_FT, u'file')) | 606 file_elt = next(desc_elt.elements(NS_JINGLE_FT, u"file")) |
468 size_elt = next(file_elt.elements(NS_JINGLE_FT, u'size')) | 607 size_elt = next(file_elt.elements(NS_JINGLE_FT, u"size")) |
469 size = int(unicode(size_elt)) | 608 size = int(unicode(size_elt)) |
470 except (StopIteration, ValueError): | 609 except (StopIteration, ValueError): |
471 size = None | 610 size = None |
472 # XXX: hash security is not critical here, so we just take the higher mandatory one | 611 # XXX: hash security is not critical here, so we just take the higher mandatory one |
473 hasher = file_data['hash_hasher'] = self._hash.getHasher() | 612 hasher = file_data["hash_hasher"] = self._hash.getHasher() |
474 content_data['stream_object'] = stream.FileStreamObject( | 613 content_data["stream_object"] = stream.FileStreamObject( |
475 self.host, | 614 self.host, |
476 client, | 615 client, |
477 file_path, | 616 file_path, |
478 mode='wb', | 617 mode="wb", |
479 uid=self.getProgressId(session, content_name), | 618 uid=self.getProgressId(session, content_name), |
480 size=size, | 619 size=size, |
481 data_cb=lambda data: hasher.update(data), | 620 data_cb=lambda data: hasher.update(data), |
482 ) | 621 ) |
483 else: | 622 else: |
484 # we are sending the file | 623 # we are sending the file |
485 size = file_data['size'] | 624 size = file_data["size"] |
486 # XXX: hash security is not critical here, so we just take the higher mandatory one | 625 # XXX: hash security is not critical here, so we just take the higher mandatory one |
487 hasher = file_data['hash_hasher'] = self._hash.getHasher() | 626 hasher = file_data["hash_hasher"] = self._hash.getHasher() |
488 content_data['stream_object'] = stream.FileStreamObject( | 627 content_data["stream_object"] = stream.FileStreamObject( |
489 self.host, | 628 self.host, |
490 client, | 629 client, |
491 file_path, | 630 file_path, |
492 uid=self.getProgressId(session, content_name), | 631 uid=self.getProgressId(session, content_name), |
493 size=size, | 632 size=size, |
494 data_cb=lambda data: hasher.update(data), | 633 data_cb=lambda data: hasher.update(data), |
495 ) | 634 ) |
496 finished_d = content_data['finished_d'] = defer.Deferred() | 635 finished_d = content_data["finished_d"] = defer.Deferred() |
497 args = [client, session, content_name, content_data] | 636 args = [client, session, content_name, content_data] |
498 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | 637 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) |
499 else: | 638 else: |
500 log.warning(u"FIXME: unmanaged action {}".format(action)) | 639 log.warning(u"FIXME: unmanaged action {}".format(action)) |
501 return desc_elt | 640 return desc_elt |
504 """Called on session-info action | 643 """Called on session-info action |
505 | 644 |
506 manage checksum, and ignore <received/> element | 645 manage checksum, and ignore <received/> element |
507 """ | 646 """ |
508 # TODO: manage <received/> element | 647 # TODO: manage <received/> element |
509 content_data = session['contents'][content_name] | 648 content_data = session["contents"][content_name] |
510 elts = [elt for elt in jingle_elt.elements() if elt.uri == NS_JINGLE_FT] | 649 elts = [elt for elt in jingle_elt.elements() if elt.uri == NS_JINGLE_FT] |
511 if not elts: | 650 if not elts: |
512 return | 651 return |
513 for elt in elts: | 652 for elt in elts: |
514 if elt.name == 'received': | 653 if elt.name == "received": |
515 pass | 654 pass |
516 elif elt.name == 'checksum': | 655 elif elt.name == "checksum": |
517 # we have received the file hash, we need to parse it | 656 # we have received the file hash, we need to parse it |
518 if content_data['senders'] == session['role']: | 657 if content_data["senders"] == session["role"]: |
519 log.warning(u"unexpected checksum received while we are the file sender") | 658 log.warning( |
659 u"unexpected checksum received while we are the file sender" | |
660 ) | |
520 raise exceptions.DataError | 661 raise exceptions.DataError |
521 info_content_name = elt['name'] | 662 info_content_name = elt["name"] |
522 if info_content_name != content_name: | 663 if info_content_name != content_name: |
523 # it was for an other content... | 664 # it was for an other content... |
524 return | 665 return |
525 file_data = content_data['application_data']['file_data'] | 666 file_data = content_data["application_data"]["file_data"] |
526 try: | 667 try: |
527 file_elt = elt.elements((NS_JINGLE_FT, 'file')).next() | 668 file_elt = elt.elements((NS_JINGLE_FT, "file")).next() |
528 except StopIteration: | 669 except StopIteration: |
529 raise exceptions.DataError | 670 raise exceptions.DataError |
530 algo, file_data['given_file_hash'] = self._hash.parseHashElt(file_elt) | 671 algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) |
531 if algo != file_data.get('hash_algo'): | 672 if algo != file_data.get("hash_algo"): |
532 log.warning(u"Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]" | 673 log.warning( |
533 .format(peer_algo=algo, our_algo=file_data.get('hash_algo'), profile=client.profile)) | 674 u"Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]".format( |
675 peer_algo=algo, | |
676 our_algo=file_data.get("hash_algo"), | |
677 profile=client.profile, | |
678 ) | |
679 ) | |
534 else: | 680 else: |
535 self._receiverTryTerminate(client, session, content_name, content_data) | 681 self._receiverTryTerminate( |
682 client, session, content_name, content_data | |
683 ) | |
536 else: | 684 else: |
537 raise NotImplementedError | 685 raise NotImplementedError |
538 | 686 |
539 def jingleTerminate(self, client, action, session, content_name, jingle_elt): | 687 def jingleTerminate(self, client, action, session, content_name, jingle_elt): |
540 if jingle_elt.decline: | 688 if jingle_elt.decline: |
541 # progress is the only way to tell to frontends that session has been declined | 689 # progress is the only way to tell to frontends that session has been declined |
542 progress_id = self.getProgressId(session, content_name) | 690 progress_id = self.getProgressId(session, content_name) |
543 self.host.bridge.progressError(progress_id, C.PROGRESS_ERROR_DECLINED, client.profile) | 691 self.host.bridge.progressError( |
692 progress_id, C.PROGRESS_ERROR_DECLINED, client.profile | |
693 ) | |
544 | 694 |
545 def _sendCheckSum(self, client, session, content_name, content_data): | 695 def _sendCheckSum(self, client, session, content_name, content_data): |
546 """Send the session-info with the hash checksum""" | 696 """Send the session-info with the hash checksum""" |
547 file_data = content_data['application_data']['file_data'] | 697 file_data = content_data["application_data"]["file_data"] |
548 hasher = file_data['hash_hasher'] | 698 hasher = file_data["hash_hasher"] |
549 hash_ = hasher.hexdigest() | 699 hash_ = hasher.hexdigest() |
550 log.debug(u"Calculated hash: {}".format(hash_)) | 700 log.debug(u"Calculated hash: {}".format(hash_)) |
551 iq_elt, jingle_elt = self._j.buildSessionInfo(client, session) | 701 iq_elt, jingle_elt = self._j.buildSessionInfo(client, session) |
552 checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, 'checksum')) | 702 checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, "checksum")) |
553 checksum_elt['creator'] = content_data['creator'] | 703 checksum_elt["creator"] = content_data["creator"] |
554 checksum_elt['name'] = content_name | 704 checksum_elt["name"] = content_name |
555 file_elt = checksum_elt.addElement('file') | 705 file_elt = checksum_elt.addElement("file") |
556 file_elt.addChild(self._hash.buildHashElt(hash_)) | 706 file_elt.addChild(self._hash.buildHashElt(hash_)) |
557 iq_elt.send() | 707 iq_elt.send() |
558 | 708 |
559 def _receiverTryTerminate(self, client, session, content_name, content_data, last_try=False): | 709 def _receiverTryTerminate( |
710 self, client, session, content_name, content_data, last_try=False | |
711 ): | |
560 """Try to terminate the session | 712 """Try to terminate the session |
561 | 713 |
562 This method must only be used by the receiver. | 714 This method must only be used by the receiver. |
563 It check if transfer is finished, and hash available, | 715 It check if transfer is finished, and hash available, |
564 if everything is OK, it check hash and terminate the session | 716 if everything is OK, it check hash and terminate the session |
565 @param last_try(bool): if True this mean than session must be terminated even given hash is not available | 717 @param last_try(bool): if True this mean than session must be terminated even given hash is not available |
566 @return (bool): True if session was terminated | 718 @return (bool): True if session was terminated |
567 """ | 719 """ |
568 if not content_data.get('transfer_finished', False): | 720 if not content_data.get("transfer_finished", False): |
569 return False | 721 return False |
570 file_data = content_data['application_data']['file_data'] | 722 file_data = content_data["application_data"]["file_data"] |
571 given_hash = file_data.get('given_file_hash') | 723 given_hash = file_data.get("given_file_hash") |
572 if given_hash is None: | 724 if given_hash is None: |
573 if last_try: | 725 if last_try: |
574 log.warning(u"sender didn't sent hash checksum, we can't check the file [{profile}]".format(profile=client.profile)) | 726 log.warning( |
727 u"sender didn't sent hash checksum, we can't check the file [{profile}]".format( | |
728 profile=client.profile | |
729 ) | |
730 ) | |
575 self._j.delayedContentTerminate(client, session, content_name) | 731 self._j.delayedContentTerminate(client, session, content_name) |
576 content_data['stream_object'].close() | 732 content_data["stream_object"].close() |
577 return True | 733 return True |
578 return False | 734 return False |
579 hasher = file_data['hash_hasher'] | 735 hasher = file_data["hash_hasher"] |
580 hash_ = hasher.hexdigest() | 736 hash_ = hasher.hexdigest() |
581 | 737 |
582 if hash_ == given_hash: | 738 if hash_ == given_hash: |
583 log.info(u"Hash checked, file was successfully transfered: {}".format(hash_)) | 739 log.info(u"Hash checked, file was successfully transfered: {}".format(hash_)) |
584 progress_metadata = {'hash': hash_, | 740 progress_metadata = { |
585 'hash_algo': file_data['hash_algo'], | 741 "hash": hash_, |
586 'hash_verified': C.BOOL_TRUE | 742 "hash_algo": file_data["hash_algo"], |
587 } | 743 "hash_verified": C.BOOL_TRUE, |
744 } | |
588 error = None | 745 error = None |
589 else: | 746 else: |
590 log.warning(u"Hash mismatch, the file was not transfered correctly") | 747 log.warning(u"Hash mismatch, the file was not transfered correctly") |
591 progress_metadata=None | 748 progress_metadata = None |
592 error = u"Hash mismatch: given={algo}:{given}, calculated={algo}:{our}".format( | 749 error = u"Hash mismatch: given={algo}:{given}, calculated={algo}:{our}".format( |
593 algo = file_data['hash_algo'], | 750 algo=file_data["hash_algo"], given=given_hash, our=hash_ |
594 given = given_hash, | 751 ) |
595 our = hash_) | |
596 | 752 |
597 self._j.delayedContentTerminate(client, session, content_name) | 753 self._j.delayedContentTerminate(client, session, content_name) |
598 content_data['stream_object'].close(progress_metadata, error) | 754 content_data["stream_object"].close(progress_metadata, error) |
599 # we may have the last_try timer still active, so we try to cancel it | 755 # we may have the last_try timer still active, so we try to cancel it |
600 try: | 756 try: |
601 content_data['last_try_timer'].cancel() | 757 content_data["last_try_timer"].cancel() |
602 except (KeyError, internet_error.AlreadyCalled): | 758 except (KeyError, internet_error.AlreadyCalled): |
603 pass | 759 pass |
604 return True | 760 return True |
605 | 761 |
606 def _finishedCb(self, dummy, client, session, content_name, content_data): | 762 def _finishedCb(self, dummy, client, session, content_name, content_data): |
607 log.info(u"File transfer terminated") | 763 log.info(u"File transfer terminated") |
608 if content_data['senders'] != session['role']: | 764 if content_data["senders"] != session["role"]: |
609 # we terminate the session only if we are the receiver, | 765 # we terminate the session only if we are the receiver, |
610 # as recommanded in XEP-0234 §2 (after example 6) | 766 # as recommanded in XEP-0234 §2 (after example 6) |
611 content_data['transfer_finished'] = True | 767 content_data["transfer_finished"] = True |
612 if not self._receiverTryTerminate(client, session, content_name, content_data): | 768 if not self._receiverTryTerminate( |
769 client, session, content_name, content_data | |
770 ): | |
613 # we have not received the hash yet, we wait 5 more seconds | 771 # we have not received the hash yet, we wait 5 more seconds |
614 content_data['last_try_timer'] = reactor.callLater( | 772 content_data["last_try_timer"] = reactor.callLater( |
615 5, self._receiverTryTerminate, client, session, content_name, content_data, last_try=True) | 773 5, |
774 self._receiverTryTerminate, | |
775 client, | |
776 session, | |
777 content_name, | |
778 content_data, | |
779 last_try=True, | |
780 ) | |
616 else: | 781 else: |
617 # we are the sender, we send the checksum | 782 # we are the sender, we send the checksum |
618 self._sendCheckSum(client, session, content_name, content_data) | 783 self._sendCheckSum(client, session, content_name, content_data) |
619 content_data['stream_object'].close() | 784 content_data["stream_object"].close() |
620 | 785 |
621 def _finishedEb(self, failure, client, session, content_name, content_data): | 786 def _finishedEb(self, failure, client, session, content_name, content_data): |
622 log.warning(u"Error while streaming file: {}".format(failure)) | 787 log.warning(u"Error while streaming file: {}".format(failure)) |
623 content_data['stream_object'].close() | 788 content_data["stream_object"].close() |
624 self._j.contentTerminate(client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT) | 789 self._j.contentTerminate( |
790 client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT | |
791 ) | |
625 | 792 |
626 | 793 |
627 class XEP_0234_handler(XMPPHandler): | 794 class XEP_0234_handler(XMPPHandler): |
628 implements(iwokkel.IDisco) | 795 implements(iwokkel.IDisco) |
629 | 796 |
630 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | 797 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
631 return [disco.DiscoFeature(NS_JINGLE_FT)] | 798 return [disco.DiscoFeature(NS_JINGLE_FT)] |
632 | 799 |
633 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | 800 def getDiscoItems(self, requestor, target, nodeIdentifier=""): |
634 return [] | 801 return [] |