comparison sat/plugins/plugin_xep_0166.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 69e4716d6268
children fee60f17ebac
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
1 #!/usr/bin/env python2 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 # SAT plugin for Jingle (XEP-0166) 4 # SAT plugin for Jingle (XEP-0166)
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
6 6
33 from twisted.python import failure 33 from twisted.python import failure
34 from collections import namedtuple 34 from collections import namedtuple
35 import uuid 35 import uuid
36 import time 36 import time
37 37
38 from zope.interface import implements 38 from zope.interface import implementer
39 39
40 40
41 IQ_SET = '/iq[@type="set"]' 41 IQ_SET = '/iq[@type="set"]'
42 NS_JINGLE = "urn:xmpp:jingle:1" 42 NS_JINGLE = "urn:xmpp:jingle:1"
43 NS_JINGLE_ERROR = "urn:xmpp:jingle:errors:1" 43 NS_JINGLE_ERROR = "urn:xmpp:jingle:errors:1"
111 111
112 def _delSession(self, client, sid): 112 def _delSession(self, client, sid):
113 try: 113 try:
114 del client.jingle_sessions[sid] 114 del client.jingle_sessions[sid]
115 except KeyError: 115 except KeyError:
116 log.debug(u"Jingle session id [{}] is unknown, nothing to delete".format(sid)) 116 log.debug("Jingle session id [{}] is unknown, nothing to delete".format(sid))
117 else: 117 else:
118 log.debug(u"Jingle session id [{}] deleted".format(sid)) 118 log.debug("Jingle session id [{}] deleted".format(sid))
119 119
120 ## helpers methods to build stanzas ## 120 ## helpers methods to build stanzas ##
121 121
122 def _buildJingleElt(self, client, session, action): 122 def _buildJingleElt(self, client, session, action):
123 iq_elt = client.IQ("set") 123 iq_elt = client.IQ("set")
140 if jingle_condition is not None: 140 if jingle_condition is not None:
141 iq_elt.error.addElement((NS_JINGLE_ERROR, jingle_condition)) 141 iq_elt.error.addElement((NS_JINGLE_ERROR, jingle_condition))
142 if error.STANZA_CONDITIONS[error_condition]["type"] == "cancel" and sid: 142 if error.STANZA_CONDITIONS[error_condition]["type"] == "cancel" and sid:
143 self._delSession(client, sid) 143 self._delSession(client, sid)
144 log.warning( 144 log.warning(
145 u"Error while managing jingle session, cancelling: {condition}".format( 145 "Error while managing jingle session, cancelling: {condition}".format(
146 condition=error_condition 146 condition=error_condition
147 ) 147 )
148 ) 148 )
149 client.send(iq_elt) 149 client.send(iq_elt)
150 150
151 def _terminateEb(self, failure_): 151 def _terminateEb(self, failure_):
152 log.warning(_(u"Error while terminating session: {msg}").format(msg=failure_)) 152 log.warning(_("Error while terminating session: {msg}").format(msg=failure_))
153 153
154 def terminate(self, client, reason, session): 154 def terminate(self, client, reason, session):
155 """Terminate the session 155 """Terminate the session
156 156
157 send the session-terminate action, and delete the session data 157 send the session-terminate action, and delete the session data
161 """ 161 """
162 iq_elt, jingle_elt = self._buildJingleElt( 162 iq_elt, jingle_elt = self._buildJingleElt(
163 client, session, XEP_0166.A_SESSION_TERMINATE 163 client, session, XEP_0166.A_SESSION_TERMINATE
164 ) 164 )
165 reason_elt = jingle_elt.addElement("reason") 165 reason_elt = jingle_elt.addElement("reason")
166 if isinstance(reason, basestring): 166 if isinstance(reason, str):
167 reason_elt.addElement(reason) 167 reason_elt.addElement(reason)
168 else: 168 else:
169 for elt in reason: 169 for elt in reason:
170 reason_elt.addChild(elt) 170 reason_elt.addChild(elt)
171 self._delSession(client, session["id"]) 171 self._delSession(client, session["id"])
180 180
181 @param failure_(failure.Failure): the exceptions raised 181 @param failure_(failure.Failure): the exceptions raised
182 @param sid(unicode): jingle session id 182 @param sid(unicode): jingle session id
183 """ 183 """
184 log.warning( 184 log.warning(
185 u"Error while sending jingle <iq/> stanza: {failure_}".format( 185 "Error while sending jingle <iq/> stanza: {failure_}".format(
186 failure_=failure_.value 186 failure_=failure_.value
187 ) 187 )
188 ) 188 )
189 self._delSession(client, sid) 189 self._delSession(client, sid)
190 190
225 - jingleTerminate: called on session terminate, with reason_elt 225 - jingleTerminate: called on session terminate, with reason_elt
226 May be used to clean session 226 May be used to clean session
227 """ 227 """
228 if namespace in self._applications: 228 if namespace in self._applications:
229 raise exceptions.ConflictError( 229 raise exceptions.ConflictError(
230 u"Trying to register already registered namespace {}".format(namespace) 230 "Trying to register already registered namespace {}".format(namespace)
231 ) 231 )
232 self._applications[namespace] = ApplicationData( 232 self._applications[namespace] = ApplicationData(
233 namespace=namespace, handler=handler 233 namespace=namespace, handler=handler
234 ) 234 )
235 log.debug(u"new jingle application registered") 235 log.debug("new jingle application registered")
236 236
237 def registerTransport(self, namespace, transport_type, handler, priority=0): 237 def registerTransport(self, namespace, transport_type, handler, priority=0):
238 """Register a transport plugin 238 """Register a transport plugin
239 239
240 @param namespace(unicode): the XML namespace used for this transport 240 @param namespace(unicode): the XML namespace used for this transport
250 XEP_0166.TRANSPORT_DATAGRAM, 250 XEP_0166.TRANSPORT_DATAGRAM,
251 XEP_0166.TRANSPORT_STREAMING, 251 XEP_0166.TRANSPORT_STREAMING,
252 ) 252 )
253 if namespace in self._transports: 253 if namespace in self._transports:
254 raise exceptions.ConflictError( 254 raise exceptions.ConflictError(
255 u"Trying to register already registered namespace {}".format(namespace) 255 "Trying to register already registered namespace {}".format(namespace)
256 ) 256 )
257 transport_data = TransportData( 257 transport_data = TransportData(
258 namespace=namespace, handler=handler, priority=priority 258 namespace=namespace, handler=handler, priority=priority
259 ) 259 )
260 self._type_transports[transport_type].append(transport_data) 260 self._type_transports[transport_type].append(transport_data)
261 self._type_transports[transport_type].sort( 261 self._type_transports[transport_type].sort(
262 key=lambda transport_data: transport_data.priority, reverse=True 262 key=lambda transport_data: transport_data.priority, reverse=True
263 ) 263 )
264 self._transports[namespace] = transport_data 264 self._transports[namespace] = transport_data
265 log.debug(u"new jingle transport registered") 265 log.debug("new jingle transport registered")
266 266
267 @defer.inlineCallbacks 267 @defer.inlineCallbacks
268 def transportReplace(self, client, transport_ns, session, content_name): 268 def transportReplace(self, client, transport_ns, session, content_name):
269 """Replace a transport 269 """Replace a transport
270 270
278 content_data = session["contents"][content_name] 278 content_data = session["contents"][content_name]
279 transport_data = content_data["transport_data"] 279 transport_data = content_data["transport_data"]
280 try: 280 try:
281 transport = self._transports[transport_ns] 281 transport = self._transports[transport_ns]
282 except KeyError: 282 except KeyError:
283 raise exceptions.InternalError(u"Unkown transport") 283 raise exceptions.InternalError("Unkown transport")
284 yield content_data["transport"].handler.jingleHandler( 284 yield content_data["transport"].handler.jingleHandler(
285 client, XEP_0166.A_DESTROY, session, content_name, None 285 client, XEP_0166.A_DESTROY, session, content_name, None
286 ) 286 )
287 content_data["transport"] = transport 287 content_data["transport"] = transport
288 transport_data.clear() 288 transport_data.clear()
320 context_elt = transport_elt = content_elt.addElement( 320 context_elt = transport_elt = content_elt.addElement(
321 "transport", content_data["transport"].namespace 321 "transport", content_data["transport"].namespace
322 ) 322 )
323 transport_elt["sid"] = content_data["transport_data"]["sid"] 323 transport_elt["sid"] = content_data["transport_data"]["sid"]
324 else: 324 else:
325 raise exceptions.InternalError(u"unmanaged action {}".format(action)) 325 raise exceptions.InternalError("unmanaged action {}".format(action))
326 326
327 return iq_elt, context_elt 327 return iq_elt, context_elt
328 328
329 def buildSessionInfo(self, client, session): 329 def buildSessionInfo(self, client, session):
330 """Build a session-info action 330 """Build a session-info action
353 @return D(unicode): jingle session id 353 @return D(unicode): jingle session id
354 """ 354 """
355 assert contents # there must be at least one content 355 assert contents # there must be at least one content
356 if (peer_jid == client.jid 356 if (peer_jid == client.jid
357 or client.is_component and peer_jid.host == client.jid.host): 357 or client.is_component and peer_jid.host == client.jid.host):
358 raise ValueError(_(u"You can't do a jingle session with yourself")) 358 raise ValueError(_("You can't do a jingle session with yourself"))
359 initiator = client.jid 359 initiator = client.jid
360 sid = unicode(uuid.uuid4()) 360 sid = str(uuid.uuid4())
361 # TODO: session cleaning after timeout ? 361 # TODO: session cleaning after timeout ?
362 session = client.jingle_sessions[sid] = { 362 session = client.jingle_sessions[sid] = {
363 "id": sid, 363 "id": sid,
364 "state": STATE_PENDING, 364 "state": STATE_PENDING,
365 "initiator": initiator, 365 "initiator": initiator,
381 app_ns = content["app_ns"] 381 app_ns = content["app_ns"]
382 try: 382 try:
383 application = self._applications[app_ns] 383 application = self._applications[app_ns]
384 except KeyError: 384 except KeyError:
385 raise exceptions.InternalError( 385 raise exceptions.InternalError(
386 u"No application registered for {}".format(app_ns) 386 "No application registered for {}".format(app_ns)
387 ) 387 )
388 388
389 # and the transport plugin 389 # and the transport plugin
390 transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING) 390 transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING)
391 try: 391 try:
392 transport = self._type_transports[transport_type][0] 392 transport = self._type_transports[transport_type][0]
393 except IndexError: 393 except IndexError:
394 raise exceptions.InternalError( 394 raise exceptions.InternalError(
395 u"No transport registered for {}".format(transport_type) 395 "No transport registered for {}".format(transport_type)
396 ) 396 )
397 397
398 # we build the session data 398 # we build the session data
399 content_data = { 399 content_data = {
400 "application": application, 400 "application": application,
405 "senders": content.get("senders", "both"), 405 "senders": content.get("senders", "both"),
406 } 406 }
407 try: 407 try:
408 content_name = content["name"] 408 content_name = content["name"]
409 except KeyError: 409 except KeyError:
410 content_name = unicode(uuid.uuid4()) 410 content_name = str(uuid.uuid4())
411 else: 411 else:
412 if content_name in contents_dict: 412 if content_name in contents_dict:
413 raise exceptions.InternalError( 413 raise exceptions.InternalError(
414 "There is already a content with this name" 414 "There is already a content with this name"
415 ) 415 )
469 469
470 def jingleRequestConfirmationDefault( 470 def jingleRequestConfirmationDefault(
471 self, client, action, session, content_name, desc_elt 471 self, client, action, session, content_name, desc_elt
472 ): 472 ):
473 """This method request confirmation for a jingle session""" 473 """This method request confirmation for a jingle session"""
474 log.debug(u"Using generic jingle confirmation method") 474 log.debug("Using generic jingle confirmation method")
475 return xml_tools.deferConfirm( 475 return xml_tools.deferConfirm(
476 self.host, 476 self.host,
477 _(CONFIRM_TXT).format(entity=session["peer_jid"].full()), 477 _(CONFIRM_TXT).format(entity=session["peer_jid"].full()),
478 _("Confirm Jingle session"), 478 _("Confirm Jingle session"),
479 profile=client.profile, 479 profile=client.profile,
487 The request will then be dispatched to appropriate method 487 The request will then be dispatched to appropriate method
488 according to current state 488 according to current state
489 @param request(domish.Element): received IQ request 489 @param request(domish.Element): received IQ request
490 """ 490 """
491 request.handled = True 491 request.handled = True
492 jingle_elt = request.elements(NS_JINGLE, "jingle").next() 492 jingle_elt = next(request.elements(NS_JINGLE, "jingle"))
493 493
494 # first we need the session id 494 # first we need the session id
495 try: 495 try:
496 sid = jingle_elt["sid"] 496 sid = jingle_elt["sid"]
497 if not sid: 497 if not sid:
498 raise KeyError 498 raise KeyError
499 except KeyError: 499 except KeyError:
500 log.warning(u"Received jingle request has no sid attribute") 500 log.warning("Received jingle request has no sid attribute")
501 self.sendError(client, "bad-request", None, request) 501 self.sendError(client, "bad-request", None, request)
502 return 502 return
503 503
504 # then the action 504 # then the action
505 try: 505 try:
506 action = jingle_elt["action"] 506 action = jingle_elt["action"]
507 if not action: 507 if not action:
508 raise KeyError 508 raise KeyError
509 except KeyError: 509 except KeyError:
510 log.warning(u"Received jingle request has no action") 510 log.warning("Received jingle request has no action")
511 self.sendError(client, "bad-request", None, request) 511 self.sendError(client, "bad-request", None, request)
512 return 512 return
513 513
514 peer_jid = jid.JID(request["from"]) 514 peer_jid = jid.JID(request["from"])
515 515
519 except KeyError: 519 except KeyError:
520 if action == XEP_0166.A_SESSION_INITIATE: 520 if action == XEP_0166.A_SESSION_INITIATE:
521 pass 521 pass
522 elif action == XEP_0166.A_SESSION_TERMINATE: 522 elif action == XEP_0166.A_SESSION_TERMINATE:
523 log.debug( 523 log.debug(
524 u"ignoring session terminate action (inexisting session id): {request_id} [{profile}]".format( 524 "ignoring session terminate action (inexisting session id): {request_id} [{profile}]".format(
525 request_id=sid, profile=client.profile 525 request_id=sid, profile=client.profile
526 ) 526 )
527 ) 527 )
528 return 528 return
529 else: 529 else:
530 log.warning( 530 log.warning(
531 u"Received request for an unknown session id: {request_id} [{profile}]".format( 531 "Received request for an unknown session id: {request_id} [{profile}]".format(
532 request_id=sid, profile=client.profile 532 request_id=sid, profile=client.profile
533 ) 533 )
534 ) 534 )
535 self.sendError(client, "item-not-found", None, request, "unknown-session") 535 self.sendError(client, "item-not-found", None, request, "unknown-session")
536 return 536 return
547 "started": time.time(), 547 "started": time.time(),
548 } 548 }
549 else: 549 else:
550 if session["peer_jid"] != peer_jid: 550 if session["peer_jid"] != peer_jid:
551 log.warning( 551 log.warning(
552 u"sid conflict ({}), the jid doesn't match. Can be a collision, a hack attempt, or a bad sid generation".format( 552 "sid conflict ({}), the jid doesn't match. Can be a collision, a hack attempt, or a bad sid generation".format(
553 sid 553 sid
554 ) 554 )
555 ) 555 )
556 self.sendError(client, "service-unavailable", sid, request) 556 self.sendError(client, "service-unavailable", sid, request)
557 return 557 return
558 if session["id"] != sid: 558 if session["id"] != sid:
559 log.error(u"session id doesn't match") 559 log.error("session id doesn't match")
560 self.sendError(client, "service-unavailable", sid, request) 560 self.sendError(client, "service-unavailable", sid, request)
561 raise exceptions.InternalError 561 raise exceptions.InternalError
562 562
563 if action == XEP_0166.A_SESSION_INITIATE: 563 if action == XEP_0166.A_SESSION_INITIATE:
564 self.onSessionInitiate(client, request, jingle_elt, session) 564 self.onSessionInitiate(client, request, jingle_elt, session)
575 elif action == XEP_0166.A_TRANSPORT_ACCEPT: 575 elif action == XEP_0166.A_TRANSPORT_ACCEPT:
576 self.onTransportAccept(client, request, jingle_elt, session) 576 self.onTransportAccept(client, request, jingle_elt, session)
577 elif action == XEP_0166.A_TRANSPORT_REJECT: 577 elif action == XEP_0166.A_TRANSPORT_REJECT:
578 self.onTransportReject(client, request, jingle_elt, session) 578 self.onTransportReject(client, request, jingle_elt, session)
579 else: 579 else:
580 raise exceptions.InternalError(u"Unknown action {}".format(action)) 580 raise exceptions.InternalError("Unknown action {}".format(action))
581 581
582 ## Actions callbacks ## 582 ## Actions callbacks ##
583 583
584 def _parseElements( 584 def _parseElements(
585 self, 585 self,
624 else: 624 else:
625 # the content must exist, we check it 625 # the content must exist, we check it
626 try: 626 try:
627 content_data = contents_dict[name] 627 content_data = contents_dict[name]
628 except KeyError: 628 except KeyError:
629 log.warning(u"Other peer try to access an unknown content") 629 log.warning("Other peer try to access an unknown content")
630 self.sendError(client, "bad-request", session["id"], request) 630 self.sendError(client, "bad-request", session["id"], request)
631 raise exceptions.CancelError 631 raise exceptions.CancelError
632 632
633 # application 633 # application
634 if with_application: 634 if with_application:
646 646
647 try: 647 try:
648 application = self._applications[app_ns] 648 application = self._applications[app_ns]
649 except KeyError: 649 except KeyError:
650 log.warning( 650 log.warning(
651 u"Unmanaged application namespace [{}]".format(app_ns) 651 "Unmanaged application namespace [{}]".format(app_ns)
652 ) 652 )
653 self.sendError( 653 self.sendError(
654 client, "service-unavailable", session["id"], request 654 client, "service-unavailable", session["id"], request
655 ) 655 )
656 raise exceptions.CancelError 656 raise exceptions.CancelError
659 content_data["application_data"] = {} 659 content_data["application_data"] = {}
660 else: 660 else:
661 # the content exists, we check that we have not a former desc_elt 661 # the content exists, we check that we have not a former desc_elt
662 if "desc_elt" in content_data: 662 if "desc_elt" in content_data:
663 raise exceptions.InternalError( 663 raise exceptions.InternalError(
664 u"desc_elt should not exist at this point" 664 "desc_elt should not exist at this point"
665 ) 665 )
666 666
667 content_data["desc_elt"] = desc_elt 667 content_data["desc_elt"] = desc_elt
668 668
669 # transport 669 # transport
682 682
683 try: 683 try:
684 transport = self._transports[transport_ns] 684 transport = self._transports[transport_ns]
685 except KeyError: 685 except KeyError:
686 raise exceptions.InternalError( 686 raise exceptions.InternalError(
687 u"No transport registered for namespace {}".format( 687 "No transport registered for namespace {}".format(
688 transport_ns 688 transport_ns
689 ) 689 )
690 ) 690 )
691 content_data["transport"] = transport 691 content_data["transport"] = transport
692 content_data["transport_data"] = {} 692 content_data["transport_data"] = {}
693 else: 693 else:
694 # the content exists, we check that we have not a former transport_elt 694 # the content exists, we check that we have not a former transport_elt
695 if "transport_elt" in content_data: 695 if "transport_elt" in content_data:
696 raise exceptions.InternalError( 696 raise exceptions.InternalError(
697 u"transport_elt should not exist at this point" 697 "transport_elt should not exist at this point"
698 ) 698 )
699 699
700 content_data["transport_elt"] = transport_elt 700 content_data["transport_elt"] = transport_elt
701 701
702 def _ignore(self, client, action, session, content_name, elt): 702 def _ignore(self, client, action, session, content_name, elt):
741 @return (list[defer.Deferred]): list of launched Deferred 741 @return (list[defer.Deferred]): list of launched Deferred
742 @raise exceptions.NotFound: method is not implemented 742 @raise exceptions.NotFound: method is not implemented
743 """ 743 """
744 contents_dict = session["contents"] 744 contents_dict = session["contents"]
745 defers_list = [] 745 defers_list = []
746 for content_name, content_data in contents_dict.iteritems(): 746 for content_name, content_data in contents_dict.items():
747 for method_name, handler_key, default_cb, elt_name in ( 747 for method_name, handler_key, default_cb, elt_name in (
748 (app_method_name, "application", app_default_cb, "desc_elt"), 748 (app_method_name, "application", app_default_cb, "desc_elt"),
749 (transp_method_name, "transport", transp_default_cb, "transport_elt"), 749 (transp_method_name, "transport", transp_default_cb, "transport_elt"),
750 ): 750 ):
751 if method_name is None: 751 if method_name is None:
755 try: 755 try:
756 method = getattr(handler, method_name) 756 method = getattr(handler, method_name)
757 except AttributeError: 757 except AttributeError:
758 if default_cb is None: 758 if default_cb is None:
759 raise exceptions.NotFound( 759 raise exceptions.NotFound(
760 u"{} not implemented !".format(method_name) 760 "{} not implemented !".format(method_name)
761 ) 761 )
762 else: 762 else:
763 method = default_cb 763 method = default_cb
764 if elements: 764 if elements:
765 elt = content_data.pop(elt_name) if delete else content_data[elt_name] 765 elt = content_data.pop(elt_name) if delete else content_data[elt_name]
844 def addElement(domish_elt, content_elt): 844 def addElement(domish_elt, content_elt):
845 content_elt.addChild(domish_elt) 845 content_elt.addChild(domish_elt)
846 846
847 defers_list = [] 847 defers_list = []
848 848
849 for content_name, content_data in session["contents"].iteritems(): 849 for content_name, content_data in session["contents"].items():
850 content_elt = jingle_elt.addElement("content") 850 content_elt = jingle_elt.addElement("content")
851 content_elt["creator"] = XEP_0166.ROLE_INITIATOR 851 content_elt["creator"] = XEP_0166.ROLE_INITIATOR
852 content_elt["name"] = content_name 852 content_elt["name"] = content_name
853 853
854 application = content_data["application"] 854 application = content_data["application"]
905 905
906 def onSessionTerminate(self, client, request, jingle_elt, session): 906 def onSessionTerminate(self, client, request, jingle_elt, session):
907 # TODO: check reason, display a message to user if needed 907 # TODO: check reason, display a message to user if needed
908 log.debug("Jingle Session {} terminated".format(session["id"])) 908 log.debug("Jingle Session {} terminated".format(session["id"]))
909 try: 909 try:
910 reason_elt = jingle_elt.elements(NS_JINGLE, "reason").next() 910 reason_elt = next(jingle_elt.elements(NS_JINGLE, "reason"))
911 except StopIteration: 911 except StopIteration:
912 log.warning(u"No reason given for session termination") 912 log.warning("No reason given for session termination")
913 reason_elt = jingle_elt.addElement("reason") 913 reason_elt = jingle_elt.addElement("reason")
914 914
915 terminate_defers = self._callPlugins( 915 terminate_defers = self._callPlugins(
916 client, 916 client,
917 XEP_0166.A_SESSION_TERMINATE, 917 XEP_0166.A_SESSION_TERMINATE,
935 @param client: %(doc_client)s 935 @param client: %(doc_client)s
936 @param request(domish.Element): full <iq> request 936 @param request(domish.Element): full <iq> request
937 @param jingle_elt(domish.Element): the <jingle> element 937 @param jingle_elt(domish.Element): the <jingle> element
938 @param session(dict): session data 938 @param session(dict): session data
939 """ 939 """
940 log.debug(u"Jingle session {} has been accepted".format(session["id"])) 940 log.debug("Jingle session {} has been accepted".format(session["id"]))
941 941
942 try: 942 try:
943 self._parseElements(jingle_elt, session, request, client) 943 self._parseElements(jingle_elt, session, request, client)
944 except exceptions.CancelError: 944 except exceptions.CancelError:
945 return 945 return
963 963
964 def _onSessionCb(self, result, client, request, jingle_elt, session): 964 def _onSessionCb(self, result, client, request, jingle_elt, session):
965 client.send(xmlstream.toResponse(request, "result")) 965 client.send(xmlstream.toResponse(request, "result"))
966 966
967 def _onSessionEb(self, failure_, client, request, jingle_elt, session): 967 def _onSessionEb(self, failure_, client, request, jingle_elt, session):
968 log.error(u"Error while handling onSessionInfo: {}".format(failure_.value)) 968 log.error("Error while handling onSessionInfo: {}".format(failure_.value))
969 # XXX: only error managed so far, maybe some applications/transports need more 969 # XXX: only error managed so far, maybe some applications/transports need more
970 self.sendError( 970 self.sendError(
971 client, "feature-not-implemented", None, request, "unsupported-info" 971 client, "feature-not-implemented", None, request, "unsupported-info"
972 ) 972 )
973 973
1013 @param client: %(doc_client)s 1013 @param client: %(doc_client)s
1014 @param request(domish.Element): full <iq> request 1014 @param request(domish.Element): full <iq> request
1015 @param jingle_elt(domish.Element): the <jingle> element 1015 @param jingle_elt(domish.Element): the <jingle> element
1016 @param session(dict): session data 1016 @param session(dict): session data
1017 """ 1017 """
1018 log.debug(u"Other peer wants to replace the transport") 1018 log.debug("Other peer wants to replace the transport")
1019 try: 1019 try:
1020 self._parseElements( 1020 self._parseElements(
1021 jingle_elt, session, request, client, with_application=False 1021 jingle_elt, session, request, client, with_application=False
1022 ) 1022 )
1023 except exceptions.CancelError: 1023 except exceptions.CancelError:
1026 client.send(xmlstream.toResponse(request, "result")) 1026 client.send(xmlstream.toResponse(request, "result"))
1027 1027
1028 content_name = None 1028 content_name = None
1029 to_replace = [] 1029 to_replace = []
1030 1030
1031 for content_name, content_data in session["contents"].iteritems(): 1031 for content_name, content_data in session["contents"].items():
1032 try: 1032 try:
1033 transport_elt = content_data.pop("transport_elt") 1033 transport_elt = content_data.pop("transport_elt")
1034 except KeyError: 1034 except KeyError:
1035 continue 1035 continue
1036 transport_ns = transport_elt.uri 1036 transport_ns = transport_elt.uri
1037 try: 1037 try:
1038 transport = self._transports[transport_ns] 1038 transport = self._transports[transport_ns]
1039 except KeyError: 1039 except KeyError:
1040 log.warning( 1040 log.warning(
1041 u"Other peer want to replace current transport with an unknown one: {}".format( 1041 "Other peer want to replace current transport with an unknown one: {}".format(
1042 transport_ns 1042 transport_ns
1043 ) 1043 )
1044 ) 1044 )
1045 content_name = None 1045 content_name = None
1046 break 1046 break
1091 @param client: %(doc_client)s 1091 @param client: %(doc_client)s
1092 @param request(domish.Element): full <iq> request 1092 @param request(domish.Element): full <iq> request
1093 @param jingle_elt(domish.Element): the <jingle> element 1093 @param jingle_elt(domish.Element): the <jingle> element
1094 @param session(dict): session data 1094 @param session(dict): session data
1095 """ 1095 """
1096 log.debug(u"new transport has been accepted") 1096 log.debug("new transport has been accepted")
1097 1097
1098 try: 1098 try:
1099 self._parseElements( 1099 self._parseElements(
1100 jingle_elt, session, request, client, with_application=False 1100 jingle_elt, session, request, client, with_application=False
1101 ) 1101 )
1138 @param client: %(doc_client)s 1138 @param client: %(doc_client)s
1139 @param request(domish.Element): full <iq> request 1139 @param request(domish.Element): full <iq> request
1140 @param jingle_elt(domish.Element): the <jingle> element 1140 @param jingle_elt(domish.Element): the <jingle> element
1141 @param session(dict): session data 1141 @param session(dict): session data
1142 """ 1142 """
1143 log.debug(u"Jingle session {} has been accepted".format(session["id"])) 1143 log.debug("Jingle session {} has been accepted".format(session["id"]))
1144 1144
1145 try: 1145 try:
1146 self._parseElements( 1146 self._parseElements(
1147 jingle_elt, session, request, client, with_application=False 1147 jingle_elt, session, request, client, with_application=False
1148 ) 1148 )
1150 return 1150 return
1151 1151
1152 # The parsing was OK, we send the <iq> result 1152 # The parsing was OK, we send the <iq> result
1153 client.send(xmlstream.toResponse(request, "result")) 1153 client.send(xmlstream.toResponse(request, "result"))
1154 1154
1155 for content_name, content_data in session["contents"].iteritems(): 1155 for content_name, content_data in session["contents"].items():
1156 try: 1156 try:
1157 transport_elt = content_data.pop("transport_elt") 1157 transport_elt = content_data.pop("transport_elt")
1158 except KeyError: 1158 except KeyError:
1159 continue 1159 continue
1160 else: 1160 else:
1165 content_name, 1165 content_name,
1166 transport_elt, 1166 transport_elt,
1167 ) 1167 )
1168 1168
1169 1169
1170 @implementer(iwokkel.IDisco)
1170 class XEP_0166_handler(xmlstream.XMPPHandler): 1171 class XEP_0166_handler(xmlstream.XMPPHandler):
1171 implements(iwokkel.IDisco)
1172 1172
1173 def __init__(self, plugin_parent): 1173 def __init__(self, plugin_parent):
1174 self.plugin_parent = plugin_parent 1174 self.plugin_parent = plugin_parent
1175 1175
1176 def connectionInitialized(self): 1176 def connectionInitialized(self):