# HG changeset patch # User Goffi # Date 1447785637 -3600 # Node ID 1e05b776a55b28676850cd240800febeb71212fa # Parent a1e5bcd9a6eb7ad4a0c249584fe7594f5b1ba01c plugin XEP-0166: session-info action handling diff -r a1e5bcd9a6eb -r 1e05b776a55b src/plugins/plugin_xep_0166.py --- 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 element, 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 result or error) + must be True if _callPlugins is used in a request, and False if it used after a request (i.e. on 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 request + @param jingle_elt(domish.Element): the 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