diff src/plugins/plugin_xep_0050.py @ 2406:1e5b2c35964e

plugin XEP-0050: renamed "requestCommandsList" method to "list" + added a run command + fixes: - XMLUI cancellation is fixed - when called from bridge, "list" (adHocList) command doesn't prepend instructions
author Goffi <goffi@goffi.org>
date Tue, 31 Oct 2017 23:11:13 +0100
parents 918e38622a48
children 8b37a62336c3
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0050.py	Tue Oct 31 23:07:26 2017 +0100
+++ b/src/plugins/plugin_xep_0050.py	Tue Oct 31 23:11:13 2017 +0100
@@ -215,8 +215,11 @@
         self.host = host
         self.requesting = Sessions()
         self.answering = {}
-        host.bridge.addMethod("requestCommand", ".plugin", in_sign='ss', out_sign='s',
-                              method=self._requestCommandsList,
+        host.bridge.addMethod("adHocRun", ".plugin", in_sign='sss', out_sign='s',
+                              method=self._run,
+                              async=True)
+        host.bridge.addMethod("adHocList", ".plugin", in_sign='ss', out_sign='s',
+                              method=self._list,
                               async=True)
         self.__requesting_id = host.registerCallback(self._requestingEntity, with_data=True)
         host.importMenu((D_("Service"), D_("Commands")), self._commandsMenu, security_limit=2, help_string=D_("Execute ad-hoc commands"))
@@ -233,12 +236,13 @@
         except KeyError:
             pass
 
-    def _items2XMLUI(self, items):
+    def _items2XMLUI(self, items, no_instructions):
         """ Convert discovery items to XMLUI dialog """
         # TODO: manage items on different jids
         form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id)
 
-        form_ui.addText(_("Please select a command"), 'instructions')
+        if not no_instructions:
+            form_ui.addText(_("Please select a command"), 'instructions')
 
         options = [(item.nodeIdentifier, item.name) for item in items]
         form_ui.addList("node", options)
@@ -331,6 +335,16 @@
         return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id)
 
     def _requestingEntity(self, data, profile):
+        def serialise(ret_data):
+            if 'xmlui' in ret_data:
+                ret_data['xmlui'] = ret_data['xmlui'].toXml()
+            return ret_data
+
+        d = self.requestingEntity(data, profile)
+        d.addCallback(serialise)
+        return d
+
+    def requestingEntity(self, data, profile):
         """
         request and entity and create XMLUI accordingly
         @param data: data returned by previous XMLUI (first one must come from self._commandsMenu)
@@ -338,25 +352,28 @@
         @return: callback dict result (with "xmlui" corresponding to the answering dialog, or empty if it's finished without error)
 
         """
+        if C.bool(data.get('cancelled', C.BOOL_FALSE)):
+            return defer.succeed({})
+        client = self.host.getClient(profile)
         # TODO: cancel, prev and next are not managed
         # TODO: managed answerer errors
         # TODO: manage nodes with a non data form payload
         if "session_id" not in data:
             # we just had the jid, we now request it for the available commands
-            session_id, session_data = self.requesting.newSession(profile=profile)
+            session_id, session_data = self.requesting.newSession(profile=client.profile)
             entity = jid.JID(data[xml_tools.SAT_FORM_PREFIX+'jid'])
             session_data['jid'] = entity
-            d = self.requestCommandsList(entity, profile)
+            d = self.list(client, entity)
 
             def sendItems(xmlui):
                 xmlui.session_id = session_id # we need to keep track of the session
-                return {'xmlui': xmlui.toXml()}
+                return {'xmlui': xmlui}
 
             d.addCallback(sendItems)
         else:
             # we have started a several forms sessions
             try:
-                session_data = self.requesting.profileGet(data["session_id"], profile)
+                session_data = self.requesting.profileGet(data["session_id"], client.profile)
             except KeyError:
                 log.warning ("session id doesn't exist, session has probably expired")
                 # TODO: send error dialog
@@ -370,8 +387,6 @@
                 # it's the first time we know the node, we save it in session data
                 session_data['node'] = data[xml_tools.SAT_FORM_PREFIX+'node']
 
-            client = self.host.getClient(profile)
-
             # we request execute node's command
             iq_elt = compat.IQ(client.xmlstream, 'set')
             iq_elt['to'] = entity.full()
@@ -388,7 +403,7 @@
             command_elt.addChild(xml_tools.XMLUIResultToElt(data)) # We add the XMLUI result to the command payload
             d = iq_elt.send()
             d.addCallback(self._commandsAnswer2XMLUI, session_id, session_data)
-            d.addCallback(lambda xmlui: {'xmlui': xmlui.toXml()} if xmlui is not None else {})
+            d.addCallback(lambda xmlui: {'xmlui': xmlui} if xmlui is not None else {})
 
         return d
 
@@ -446,24 +461,57 @@
 
         return (payload, status, None, note)
 
-    def _requestCommandsList(self, to_jid_s, profile_key):
-        d = self.requestCommandsList(jid.JID(to_jid_s), profile_key)
+    def _run(self, service_jid_s='', node='', profile_key=C.PROF_KEY_NONE):
+        client = self.host.getClient(profile_key)
+        service_jid = jid.JID(service_jid_s) if service_jid_s else None
+        d = self.run(client, service_jid, node or None)
         d.addCallback(lambda xmlui: xmlui.toXml())
         return d
 
-    def requestCommandsList(self, to_jid, profile_key):
-        """ Request available commands
-        @param to_jid: the entity answering the commands
-        @param profile_key: %(doc_profile)s
+    @defer.inlineCallbacks
+    def run(self, client, service_jid=None, node=None):
+        """run an ad-hoc command
 
+        @param service_jid(jid.JID, None): jid of the ad-hoc service
+            None to use profile's server
+        @param node(unicode, None): node of the ad-hoc commnad
+            None to get initial list
+        @return(unicode): command page XMLUI
         """
+        if service_jid is None:
+            service_jid = jid.JID(client.jid.host)
+        session_id, session_data = self.requesting.newSession(profile=client.profile)
+        session_data['jid'] = service_jid
+        if node is None:
+            xmlui = yield self.list(client, service_jid)
+        else:
+            session_data['node'] = node
+            cb_data = yield self.requestingEntity({'session_id': session_id}, client.profile)
+            xmlui = cb_data['xmlui']
+
+        xmlui.session_id = session_id
+        defer.returnValue(xmlui)
+
+    def _list(self, to_jid_s, profile_key):
         client = self.host.getClient(profile_key)
-        d = client.disco.requestItems(to_jid, NS_COMMANDS)
-        d.addCallback(self._items2XMLUI)
+        to_jid = jid.JID(to_jid_s) if to_jid_s else None
+        d = self.list(client, to_jid, no_instructions=True)
+        d.addCallback(lambda xmlui: xmlui.toXml())
         return d
 
-    def addAdHocCommand(self, callback, label, node=None, features = None, timeout = 600, allowed_jids = None, allowed_groups = None,
-                        allowed_magics = None, forbidden_jids = None, forbidden_groups = None, profile_key=C.PROF_KEY_NONE):
+    def list(self, client, to_jid, no_instructions=False):
+        """Request available commands
+
+        @param to_jid(jid.JID, None): the entity answering the commands
+            None to use profile's server
+        @param no_instructions(bool): if True, don't add instructions widget
+        """
+        d = self.host.getDiscoItems(client, to_jid, NS_COMMANDS)
+        d.addCallback(self._items2XMLUI, no_instructions)
+        return d
+
+    def addAdHocCommand(self, callback, label, node=None, features=None, timeout=600, allowed_jids=None, allowed_groups=None,
+                        allowed_magics=None, forbidden_jids=None, forbidden_groups=None, profile_key=C.PROF_KEY_NONE):
         """Add an ad-hoc command for the current profile
 
         @param callback: method associated with this ad-hoc command which return the payload data (see AdHocCommand._sendAnswer), can return a deferred