changeset 1616:1e05b776a55b

plugin XEP-0166: session-info action handling
author Goffi <goffi@goffi.org>
date Tue, 17 Nov 2015 19:40:37 +0100
parents a1e5bcd9a6eb
children d05f9179fe22
files src/plugins/plugin_xep_0166.py
diffstat 1 files changed, 61 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0166.py	Tue Nov 17 19:39:08 2015 +0100
+++ b/src/plugins/plugin_xep_0166.py	Tue Nov 17 19:40:37 2015 +0100
@@ -25,7 +25,6 @@
 from sat.core import exceptions
 from twisted.words.protocols.jabber import jid
 from twisted.internet import defer
-# from wokkel import disco, iwokkel, data_form, compat
 from wokkel import disco, iwokkel
 from twisted.words.protocols.jabber import error
 from twisted.words.protocols.jabber import xmlstream
@@ -74,6 +73,7 @@
     A_SESSION_INITIATE = "session-initiate"
     A_SESSION_ACCEPT = "session-accept"
     A_SESSION_TERMINATE = "session-terminate"
+    A_SESSION_INFO = "session-info"
     A_TRANSPORT_INFO = "transport-info"
     # non standard actions
     A_PREPARE_INITIATOR = "prepare-initiator" # initiator must prepare tranfer
@@ -257,6 +257,16 @@
 
         return iq_elt, context_elt
 
+    def buildSessionInfo(self, session, profile=C.PROF_KEY_NONE):
+        """Build a session-info action
+
+        @param session(dict): jingle session data
+        @param profile: %(doc_profile)s
+        @return (tuple[domish.Element, domish.Element]): parent <iq> element, <jingle> element
+        """
+        client = self.host.getClient(profile)
+        return  self._buildJingleElt(client, session, XEP_0166.A_SESSION_INFO)
+
     @defer.inlineCallbacks
     def initiate(self, peer_jid, contents, profile=C.PROF_KEY_NONE):
         """Send a session initiation request
@@ -439,6 +449,8 @@
             self.onSessionTerminate(client, request, jingle_elt, session)
         elif action == XEP_0166.A_SESSION_ACCEPT:
             self.onSessionAccept(client, request, jingle_elt, session)
+        elif action == XEP_0166.A_SESSION_INFO:
+            self.onSessionInfo(client, request, jingle_elt, session)
         elif action == XEP_0166.A_TRANSPORT_INFO:
             self.onTransportInfo(client, request, jingle_elt, session)
         else:
@@ -541,7 +553,9 @@
 
                 content_data['transport_elt'] = transport_elt
 
-    def _callPlugins(self, action, session, app_method_name='jingleHandler', transp_method_name='jingleHandler', app_default_cb=None, transp_default_cb=None, delete=True, elements=True, profile=C.PROF_KEY_NONE):
+    def _callPlugins(self, action, session, app_method_name='jingleHandler', transp_method_name='jingleHandler',
+        app_default_cb=None, transp_default_cb=None, delete=True,
+        elements=True, force_element=None, profile=C.PROF_KEY_NONE):
         """Call application and transport plugin methods for all contents
 
         @param action(unicode): jingle action name
@@ -557,9 +571,12 @@
         @param delete(bool): if True, remove desc_elt and transport_elt from session
             ignored if elements is False
         @param elements(bool): True if elements(desc_elt and tranport_elt) must be managed
-            must be True if _callPlugins is use in a request, and False if it used after a request (i.e. on <iq> result or error)
+            must be True if _callPlugins is used in a request, and False if it used after a request (i.e. on <iq> result or error)
+        @param force_element(None, domish.Element, object): if elements is None, it is used as element parameter
+            else it is ignored
         @param profile(unicode): %(doc_profile)s
         @return (list[defer.Deferred]): list of launched Deferred
+        @raise exceptions.NotFound: method is not implemented
         """
         contents_dict = session['contents']
         defers_list = []
@@ -577,13 +594,12 @@
                     if default_cb is not None:
                         method = default_cb
                     else:
-                        raise exceptions.InternalError(u'{} not implemented !'.format(method_name))
-                finally:
-                    if elements:
-                        elt = content_data.pop(elt_name) if delete else content_data[elt_name]
-                    else:
-                        elt = None
-                    d = defer.maybeDeferred(method, action, session, content_name, elt, profile)
+                        raise exceptions.NotFound(u'{} not implemented !'.format(method_name))
+                if elements:
+                    elt = content_data.pop(elt_name) if delete else content_data[elt_name]
+                else:
+                    elt = force_element
+                d = defer.maybeDeferred(method, action, session, content_name, elt, profile)
                 defers_list.append(d)
 
         return defers_list
@@ -715,6 +731,41 @@
         # after negociations we start the transfer
         negociate_dlist.addCallback(lambda dummy: self._callPlugins(XEP_0166.A_START, session, app_method_name=None, elements=False, profile=client.profile))
 
+    def _onSessionCb(self, result, client, request, jingle_elt, session):
+        client.xmlstream.send(xmlstream.toResponse(request, 'result'))
+
+    def _onSessionEb(self, failure_, client, request, jingle_elt, session):
+        log.error(u"Error while handling onSessionInfo: {}".format(failure_.value))
+        # XXX: only error managed so far, maybe some applications/transports need more
+        self.sendError('feature-not-implemented', None, request, 'unsupported-info', client.profile)
+
+    def onSessionInfo(self, client, request, jingle_elt, session):
+        """Method called when a session-info action is received from other peer
+
+        This method is only called for initiator
+        @param client: %(doc_client)s
+        @param request(domish.Element): full <iq> request
+        @param jingle_elt(domish.Element): the <jingle> element
+        @param session(dict): session data
+        """
+        if not jingle_elt.children:
+            # this is a session ping, see XEP-0166 ยง6.8
+            client.xmlstream.send(xmlstream.toResponse(request, 'result'))
+            return
+
+        try:
+            # XXX: session-info is most likely only used for application, so we don't call transport plugins
+            #      if a future transport use it, this behaviour must be adapted
+            defers = self._callPlugins(XEP_0166.A_SESSION_INFO, session, 'jingleSessionInfo', None,
+                elements=False, force_element=jingle_elt, profile=client.profile)
+        except exceptions.NotFound as e:
+            self._onSessionEb(failure.Failure(e), client, request, jingle_elt, session)
+            return
+
+        dlist = defer.DeferredList(defers, fireOnOneErrback=True)
+        dlist.addCallback(self._onSessionCb, client, request, jingle_elt, session)
+        dlist.addErrback(self._onSessionCb, client, request, jingle_elt, session)
+
     def onTransportInfo(self, client, request, jingle_elt, session):
         """Method called when a transport-info action is received from other peer