From db47f17ea997bb4a38c4f306a0fa02724a713a84 Mon Sep 17 00:00:00 2001 From: David Rousselie Date: Wed, 27 Jun 2007 08:06:37 +0200 Subject: [PATCH] Implement 'list' ad-hoc command darcs-hash:20070627060637-86b55-c56b45c11cfd4d264ae5c5f351e1f201c222dff1.gz --- src/jcl/jabber/command.py | 38 ++++++++++++++++++++++++- src/jcl/jabber/component.py | 23 ++++++++++++++-- src/jcl/jabber/tests/component.py | 46 +++++++++++++++++++++++++++++-- 3 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/jcl/jabber/command.py b/src/jcl/jabber/command.py index b3a5200..9b0222c 100644 --- a/src/jcl/jabber/command.py +++ b/src/jcl/jabber/command.py @@ -21,9 +21,13 @@ ## from pyxmpp.jabber.disco import DiscoInfo, DiscoItems, DiscoItem, DiscoIdentity +from pyxmpp.jabber.dataforms import Form, Field import jcl from jcl.jabber import DiscoHandler +from jcl.model.account import Account + +COMMAND_NS = "http://jabber.org/protocol/commands" class CommandManager(object): """Handle Ad-Hoc commands""" @@ -62,6 +66,14 @@ class CommandManager(object): else: return disco_info + def apply_command_action(self, info_query, command, action): + """Apply action on command""" + action_command_method = action + "_" + command + if hasattr(self, action_command_method): + return getattr(self, action_command_method)(info_query) + else: + return None + command_manager = CommandManager() class JCLCommandManager(CommandManager): @@ -74,13 +86,37 @@ class JCLCommandManager(CommandManager): def get_list_info(self, disco_info, lang_class): """Return infos for 'list' command""" - disco_info.add_feature("http://jabber.org/protocol/commands") + disco_info.add_feature(COMMAND_NS) DiscoIdentity(disco_info, self.get_command_desc("list", lang_class), "automation", "command-node") return disco_info + def execute_list(self, info_query): + """Execute command 'list'. List accounts""" + response = info_query.make_result_response() + command_node = response.set_new_content(COMMAND_NS, "command") + command_node.setProp("node", "list") + command_node.setProp("status", "completed") + #command_node.setProp("sessionid", "????") # TODO + result_form = Form(xmlnode_or_type="result", + title="Registered account") # TODO : add to Lang + result_form.reported_fields.append(Field(name="name", + field_type="fixed", + label="Account name")) # TODO: add to Lang + bare_from_jid = unicode(info_query.get_from().bare()) + self.account_manager.db_connect() + accounts = Account.select(Account.q.user_jid == bare_from_jid) + for _account in accounts: + fields = [Field(name="name", + field_type="fixed", + value=_account.name)] + result_form.add_item(fields) + self.account_manager.db_disconnect() + result_form.as_xml(command_node) + return [response] + class CommandDiscoGetInfoHandler(DiscoHandler): """Handle Ad-Hoc command disco get info requests""" diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py index d75ec91..1194ba7 100644 --- a/src/jcl/jabber/component.py +++ b/src/jcl/jabber/component.py @@ -200,6 +200,9 @@ class JCLComponent(Component, object): self.stream.set_iq_set_handler("query", "jabber:iq:gateway", self.handle_set_gateway) + self.stream.set_iq_set_handler("command", command.COMMAND_NS, + self.handle_command) + self.stream.set_presence_handler("available", self.handle_presence_available) @@ -568,6 +571,23 @@ class JCLComponent(Component, object): self.apply_registered_behavior(self.msg_handlers, message, False) return 1 + def handle_command(self, info_query): + """ + Handle command IQ + """ + self.__logger.debug("COMMAND") + _command = info_query.xpath_eval("c:command", + {"c": command.COMMAND_NS})[0] + command_node = _command.prop("node") + action = _command.prop("action") + if action is None: + action = "execute" + result = command.command_manager.apply_command_action(info_query, + command_node, + action) + self.send_stanzas(result) + return 1 + ########################################################################### # Utils ########################################################################### @@ -575,7 +595,6 @@ class JCLComponent(Component, object): """ """ self.send_stanzas(self.account_manager.send_error(_account, exception)) type, value, stack = sys.exc_info() - # TODO : not checking email here self.__logger.debug("Error: %s\n%s" % (exception, "".join(traceback.format_exception (type, value, stack, 5)))) @@ -641,7 +660,7 @@ class AccountManager(object): if not node: disco_info = DiscoInfo() disco_info.add_feature("jabber:iq:version") - disco_info.add_feature("http://jabber.org/protocol/commands") + disco_info.add_feature(command.COMMAND_NS) if not self.has_multiple_account_type: disco_info.add_feature("jabber:iq:register") DiscoIdentity(disco_info, name, diff --git a/src/jcl/jabber/tests/component.py b/src/jcl/jabber/tests/component.py index 603c92c..e74e3d7 100644 --- a/src/jcl/jabber/tests/component.py +++ b/src/jcl/jabber/tests/component.py @@ -73,13 +73,14 @@ class MockStream(object): self.sent.append(iq) def set_iq_set_handler(self, iq_type, ns, handler): - if not iq_type in ["query"]: + if not iq_type in ["query", "command"]: raise Exception("IQ type unknown: " + iq_type) if not ns in ["jabber:iq:version", "jabber:iq:register", "jabber:iq:gateway", "http://jabber.org/protocol/disco#items", - "http://jabber.org/protocol/disco#info"]: + "http://jabber.org/protocol/disco#info", + "http://jabber.org/protocol/commands"]: raise Exception("Unknown namespace: " + ns) if handler is None: raise Exception("Handler must not be None") @@ -744,7 +745,7 @@ class JCLComponent_TestCase(unittest.TestCase): item = disco_items.get_items()[0] self.assertEquals(item.get_node(), "list") self.assertEquals(item.get_name(), Lang.en.command_list) - + ########################################################################### # 'handle_get_version' tests ########################################################################### @@ -2485,6 +2486,45 @@ class JCLComponent_TestCase(unittest.TestCase): self.comp.send_stanzas(None) self.assertEquals(len(self.comp.stream.sent), 0) + + ########################################################################### + # 'handle_command' tests + ########################################################################### + def test_handle_command_execute_list(self): + self.comp.stream = MockStream() + self.comp.stream_class = MockStream + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = ExampleAccount(user_jid="user1@test.com", + name="account11", + jid="account11@jcl.test.com") + account12 = Example2Account(user_jid="user1@test.com", + name="account12", + jid="account12@jcl.test.com") + account2 = ExampleAccount(user_jid="user2@test.com", + name="account2", + jid="account2@jcl.test.com") + del account.hub.threadConnection + info_query = Iq(stanza_type="set", + from_jid="user1@test.com", + to_jid="jcl.test.com") + command_node = info_query.set_new_content("http://jabber.org/protocol/commands", + "command") + command_node.setProp("node", "list") + command_node.setProp("action", "execute") + self.comp.handle_command(info_query) + result = self.comp.stream.sent + self.assertNotEquals(result, None) + self.assertEquals(len(result), 1) + command_result = result[0].xpath_eval("c:command", + {"c": "http://jabber.org/protocol/commands"}) + self.assertEquals(len(command_result), 1) + self.assertEquals(command_result[0].prop("status"), "completed") + # TODO : test sessionid prop, usage (cf XEP) ? + items = result[0].xpath_eval("c:command/data:x/data:item", + {"c": "http://jabber.org/protocol/commands", + "data": "jabber:x:data"}) + self.assertEquals(len(items), 2) + class Handler_TestCase(unittest.TestCase): def setUp(self): self.handler = Handler()