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
This commit is contained in:
Goffi 2017-10-31 23:11:13 +01:00
commit a68772cdeb

View file

@ -215,8 +215,11 @@ class XEP_0050(object):
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 @@ class XEP_0050(object):
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 @@ class XEP_0050(object):
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 @@ class XEP_0050(object):
@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 @@ class XEP_0050(object):
# 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 @@ class XEP_0050(object):
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 @@ class XEP_0050(object):
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