# HG changeset patch # User Goffi # Date 1509487873 -3600 # Node ID 1e5b2c35964e873af8df32e7a0171c3d8089ae4f # Parent f4b6176eb65fe74518c232bfb79a2df5df028db9 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 diff -r f4b6176eb65f -r 1e5b2c35964e src/plugins/plugin_xep_0050.py --- 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