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 []