Basic Ad-Hoc commands support
Support commands listing (disco get items) and command info (disco get info) darcs-hash:20070620164706-86b55-11fb94510d349169ab0450717a680db4440cd9b3.gz
This commit is contained in:
@@ -1,2 +1,29 @@
|
||||
"""Jabber related classes"""
|
||||
__revision__ = ""
|
||||
|
||||
from jcl.model.account import Account
|
||||
|
||||
class Handler(object):
|
||||
"""handling class"""
|
||||
|
||||
def filter(self, stanza, lang_class):
|
||||
"""Filter account to be processed by the handler
|
||||
return all accounts. DB connection might already be opened."""
|
||||
accounts = Account.select()
|
||||
return accounts
|
||||
|
||||
def handle(self, stanza, lang_class, accounts):
|
||||
"""Apply actions to do on given accounts
|
||||
Do nothing by default"""
|
||||
return []
|
||||
|
||||
class DiscoHandler(object):
|
||||
"""Handle disco get items requests"""
|
||||
|
||||
def filter(self, node, info_query):
|
||||
"""Filter requests to be handled"""
|
||||
return False
|
||||
|
||||
def handle(self, disco_items, node, info_query, data, lang_class):
|
||||
"""Handle disco get items request"""
|
||||
return None
|
||||
|
||||
@@ -50,7 +50,11 @@ from pyxmpp.presence import Presence
|
||||
from pyxmpp.jabber.dataforms import Form, Field, Option
|
||||
|
||||
import jcl
|
||||
from jcl.jabber.error import FieldError
|
||||
from jcl.jabber import Handler
|
||||
from jcl.error import FieldError
|
||||
import jcl.jabber.command as command
|
||||
from jcl.jabber.command import CommandDiscoGetItemsHandler, \
|
||||
CommandDiscoGetInfoHandler, CommandManager, JCLCommandManager
|
||||
from jcl.model import account
|
||||
from jcl.model.account import Account, LegacyJID
|
||||
from jcl.lang import Lang
|
||||
@@ -98,6 +102,11 @@ class JCLComponent(Component, object):
|
||||
self.unsubscribe_handlers = []
|
||||
self.available_handlers = []
|
||||
self.unavailable_handlers = []
|
||||
command.command_manager = JCLCommandManager()
|
||||
command.command_manager.component = self
|
||||
command.command_manager.account_manager = self.account_manager
|
||||
self.disco_get_items_handlers = [CommandDiscoGetItemsHandler()]
|
||||
self.disco_get_info_handlers = [CommandDiscoGetInfoHandler()]
|
||||
|
||||
self.__logger = logging.getLogger("jcl.jabber.JCLComponent")
|
||||
self.lang = lang
|
||||
@@ -322,34 +331,55 @@ class JCLComponent(Component, object):
|
||||
self.stream.send(info_query)
|
||||
return 1
|
||||
|
||||
def disco_get_commands_list():
|
||||
"""Return Ad-Hoc commands list"""
|
||||
return None
|
||||
|
||||
def disco_get_info(self, node, info_query):
|
||||
"""Discovery get info handler
|
||||
"""
|
||||
return self.apply_behavior(\
|
||||
info_query,
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.account_disco_get_info(),
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.account_type_disco_get_info(),
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.root_disco_get_info(\
|
||||
self.name,
|
||||
self.disco_identity.category,
|
||||
self.disco_identity.type))
|
||||
result = self.apply_behavior(\
|
||||
info_query,
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.account_disco_get_info(),
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.account_type_disco_get_info(),
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.root_disco_get_info(\
|
||||
node,
|
||||
self.name,
|
||||
self.disco_identity.category,
|
||||
self.disco_identity.type))
|
||||
if result is None:
|
||||
lang_class = self.lang.get_lang_class_from_node(info_query.get_node())
|
||||
for disco_filter in self.disco_get_info_handlers:
|
||||
data = disco_filter.filter(node, info_query)
|
||||
if data:
|
||||
result = disco_filter.handle(result, node, info_query,
|
||||
data, lang_class)
|
||||
return result
|
||||
|
||||
def disco_get_items(self, node, info_query):
|
||||
"""Discovery get nested nodes handler
|
||||
"""
|
||||
return self.apply_behavior(\
|
||||
result = self.apply_behavior(\
|
||||
info_query,
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
DiscoItems(),
|
||||
None,
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.account_type_disco_get_items(from_jid,
|
||||
account_type),
|
||||
lambda name, from_jid, account_type, lang_class: \
|
||||
self.account_manager.root_disco_get_items(from_jid,
|
||||
lang_class))
|
||||
if result is None:
|
||||
lang_class = self.lang.get_lang_class_from_node(info_query.get_node())
|
||||
for disco_filter in self.disco_get_items_handlers:
|
||||
data = disco_filter.filter(node, info_query)
|
||||
if data:
|
||||
result = disco_filter.handle(result, node, info_query,
|
||||
data, lang_class)
|
||||
return result
|
||||
|
||||
def handle_get_version(self, info_query):
|
||||
"""Get Version handler
|
||||
@@ -569,8 +599,10 @@ class AccountManager(object):
|
||||
def __init__(self, component):
|
||||
"""AccountManager constructor"""
|
||||
self.__logger = logging.getLogger("jcl.jabber.JCLComponent")
|
||||
self.regexp_type = re.compile("(.*)Account$")
|
||||
self.account_classes = (Account,)
|
||||
self.component = component
|
||||
self.account_types = []
|
||||
|
||||
def _get_account_classes(self):
|
||||
"""account_classes getter"""
|
||||
@@ -580,6 +612,16 @@ class AccountManager(object):
|
||||
"""account_classes setter"""
|
||||
self._account_classes = account_classes
|
||||
self.has_multiple_account_type = (len(self._account_classes) > 1)
|
||||
self.account_types = []
|
||||
for account_class in account_classes:
|
||||
match = self.regexp_type.search(account_class.__name__)
|
||||
if match is not None:
|
||||
account_type = match.group(1)
|
||||
self.account_types.append(account_type)
|
||||
else:
|
||||
self.__logger.error(account_class.__name__ +
|
||||
" name not well formed")
|
||||
self.account_types.append("")
|
||||
|
||||
account_classes = property(_get_account_classes, _set_account_classes)
|
||||
|
||||
@@ -596,38 +638,38 @@ class AccountManager(object):
|
||||
self.__logger.debug("account_type_disco_get_info")
|
||||
return self.account_disco_get_info()
|
||||
|
||||
def root_disco_get_info(self, name, category, type):
|
||||
def root_disco_get_info(self, node, name, category, type):
|
||||
"""Implement discovery get_info on main component JID"""
|
||||
self.__logger.debug("root_disco_get_info")
|
||||
disco_info = DiscoInfo()
|
||||
disco_info.add_feature("jabber:iq:version")
|
||||
if not self.has_multiple_account_type:
|
||||
disco_info.add_feature("jabber:iq:register")
|
||||
DiscoIdentity(disco_info, name,
|
||||
category,
|
||||
type)
|
||||
return disco_info
|
||||
if not node:
|
||||
disco_info = DiscoInfo()
|
||||
disco_info.add_feature("jabber:iq:version")
|
||||
if not self.has_multiple_account_type:
|
||||
disco_info.add_feature("jabber:iq:register")
|
||||
DiscoIdentity(disco_info, name,
|
||||
category,
|
||||
type)
|
||||
return disco_info
|
||||
else:
|
||||
return None
|
||||
|
||||
###### disco_get_items handlers ######
|
||||
def account_type_disco_get_items(self, from_jid, account_type):
|
||||
"""Discovery get_items on an account type node"""
|
||||
self.__logger.debug("Listing account for " + account_type)
|
||||
disco_items = DiscoItems()
|
||||
account_class = self._get_account_class(account_type + "Account")
|
||||
if account_class is not None:
|
||||
self._list_accounts(disco_items,
|
||||
account_class,
|
||||
from_jid.bare(),
|
||||
account_type=account_type)
|
||||
return self._list_accounts(account_class,
|
||||
from_jid.bare(),
|
||||
account_type=account_type)
|
||||
else:
|
||||
self.__logger.error("Error: " + account_class.__name__
|
||||
+ " class not in account_classes")
|
||||
return disco_items
|
||||
return None
|
||||
|
||||
def root_disco_get_items(self, from_jid, lang_class):
|
||||
"""Discovery get_items on root node"""
|
||||
disco_items = DiscoItems()
|
||||
regexp_type = re.compile("(.*)Account$")
|
||||
disco_items = None
|
||||
if self.has_multiple_account_type: # list accounts with only one type declared
|
||||
def _list_account_types(disco_items, account_class, bare_from_jid, account_type):
|
||||
type_label_attr = "type_" + account_type.lower() + "_name"
|
||||
@@ -640,20 +682,15 @@ class AccountManager(object):
|
||||
account_type),
|
||||
account_type,
|
||||
type_label)
|
||||
list_func = _list_account_types
|
||||
|
||||
disco_items = DiscoItems()
|
||||
for account_type in self.account_types:
|
||||
_list_account_types(disco_items,
|
||||
self._get_account_class(account_type
|
||||
+ "Account"),
|
||||
from_jid.bare(), account_type)
|
||||
else:
|
||||
list_func = self._list_accounts
|
||||
|
||||
for account_class in self.account_classes:
|
||||
match = regexp_type.search(account_class.__name__)
|
||||
if match is not None:
|
||||
account_type = match.group(1)
|
||||
list_func(disco_items, account_class,
|
||||
from_jid.bare(), account_type)
|
||||
else:
|
||||
self.__logger.error(account_class.__name__ +
|
||||
" name not well formed")
|
||||
disco_items = self._list_accounts(self.account_classes[0],
|
||||
from_jid.bare())
|
||||
return disco_items
|
||||
|
||||
###### get_register handlers ######
|
||||
@@ -1014,7 +1051,7 @@ class AccountManager(object):
|
||||
return result
|
||||
|
||||
|
||||
def _list_accounts(self, disco_items, _account_class, bare_from_jid,
|
||||
def _list_accounts(self, _account_class, bare_from_jid,
|
||||
account_type=""):
|
||||
"""List accounts in disco_items for given _account_class and user jid"""
|
||||
if account_type is not None and account_type != "":
|
||||
@@ -1023,14 +1060,19 @@ class AccountManager(object):
|
||||
else:
|
||||
resource = ""
|
||||
self.db_connect()
|
||||
for _account in _account_class.select(_account_class.q.user_jid == \
|
||||
unicode(bare_from_jid)):
|
||||
accounts = _account_class.select(_account_class.q.user_jid == \
|
||||
unicode(bare_from_jid))
|
||||
if accounts.count() == 0:
|
||||
return None
|
||||
disco_items = DiscoItems()
|
||||
for _account in accounts:
|
||||
self.__logger.debug(str(_account))
|
||||
DiscoItem(disco_items,
|
||||
JID(unicode(_account.jid) + resource),
|
||||
account_type + _account.name,
|
||||
_account.long_name)
|
||||
self.db_disconnect()
|
||||
return disco_items
|
||||
|
||||
def _get_account_class(self, account_class_name):
|
||||
"""Return account class definition from declared classes in
|
||||
@@ -1221,20 +1263,6 @@ class AccountManager(object):
|
||||
% (exception)))
|
||||
return result
|
||||
|
||||
class Handler(object):
|
||||
"""handling class"""
|
||||
|
||||
def filter(self, stanza, lang_class):
|
||||
"""Filter account to be processed by the handler
|
||||
return all accounts. DB connection might already be opened."""
|
||||
accounts = Account.select()
|
||||
return accounts
|
||||
|
||||
def handle(self, stanza, lang_class, accounts):
|
||||
"""Apply actions to do on given accounts
|
||||
Do nothing by default"""
|
||||
return []
|
||||
|
||||
class DefaultPresenceHandler(Handler):
|
||||
"""Handle presence"""
|
||||
|
||||
@@ -1313,4 +1341,3 @@ class PasswordMessageHandler(Handler):
|
||||
to_jid=stanza.get_from(),
|
||||
subject=lang_class.password_saved_for_session,
|
||||
body=lang_class.password_saved_for_session)]
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ __revision__ = "$Id: feeder.py,v 1.3 2005/09/18 20:24:07 dax Exp $"
|
||||
|
||||
import logging
|
||||
|
||||
from jcl.jabber.component import JCLComponent, Handler
|
||||
from jcl.jabber import Handler
|
||||
from jcl.jabber.component import JCLComponent
|
||||
from jcl.lang import Lang
|
||||
from jcl.model.account import Account
|
||||
|
||||
|
||||
@@ -533,6 +533,28 @@ class JCLComponent_TestCase(unittest.TestCase):
|
||||
info_query)
|
||||
self.assertTrue(disco_info.has_feature("jabber:iq:register"))
|
||||
|
||||
def test_disco_get_info_root_unknown_node(self):
|
||||
info_query = Iq(stanza_type="get",
|
||||
from_jid="user1@test.com",
|
||||
to_jid="jcl.test.com")
|
||||
disco_info = self.comp.disco_get_info("unknown", info_query)
|
||||
self.assertEquals(disco_info, None)
|
||||
|
||||
def test_disco_get_info_command_list(self):
|
||||
info_query = Iq(stanza_type="get",
|
||||
from_jid="user1@test.com",
|
||||
to_jid="jcl.test.com")
|
||||
disco_info = self.comp.disco_get_info("list", info_query)
|
||||
self.assertNotEquals(disco_info, None)
|
||||
self.assertTrue(disco_info.has_feature("http://jabber.org/protocol/commands"))
|
||||
self.assertEquals(len(disco_info.get_identities()), 1)
|
||||
self.assertEquals(disco_info.get_identities()[0].get_category(),
|
||||
"automation")
|
||||
self.assertEquals(disco_info.get_identities()[0].get_type(),
|
||||
"command-node")
|
||||
self.assertEquals(disco_info.get_identities()[0].get_name(),
|
||||
Lang.en.command_list)
|
||||
|
||||
###########################################################################
|
||||
# 'disco_get_items' tests
|
||||
###########################################################################
|
||||
@@ -546,25 +568,32 @@ class JCLComponent_TestCase(unittest.TestCase):
|
||||
info_query = Iq(stanza_type = "get", \
|
||||
from_jid = "user1@test.com", \
|
||||
to_jid = "jcl.test.com")
|
||||
disco_items = self.comp.disco_get_items(None, info_query)
|
||||
disco_items = self.comp.disco_get_items("unknown", info_query)
|
||||
self.assertEquals(len(disco_items.get_items()), 1)
|
||||
disco_item = disco_items.get_items()[0]
|
||||
self.assertEquals(disco_item.get_jid(), account1.jid)
|
||||
self.assertEquals(disco_item.get_node(), account1.name)
|
||||
self.assertEquals(disco_item.get_name(), account1.long_name)
|
||||
|
||||
def test_disco_get_items_unknown_node(self):
|
||||
info_query = Iq(stanza_type="get",
|
||||
from_jid="user1@test.com",
|
||||
to_jid="jcl.test.com")
|
||||
disco_items = self.comp.disco_get_items(None, info_query)
|
||||
self.assertEquals(disco_items, None)
|
||||
|
||||
def test_disco_get_items_1type_with_node(self):
|
||||
"""get_items on an account. Must return nothing"""
|
||||
account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL)
|
||||
account1 = Account(user_jid = "user1@test.com", \
|
||||
name = "account1", \
|
||||
jid = "account1@jcl.test.com")
|
||||
account1 = Account(user_jid="user1@test.com",
|
||||
name="account1",
|
||||
jid="account1@jcl.test.com")
|
||||
del account.hub.threadConnection
|
||||
info_query = Iq(stanza_type = "get", \
|
||||
from_jid = "user1@test.com", \
|
||||
to_jid = "account1@jcl.test.com")
|
||||
info_query = Iq(stanza_type="get",
|
||||
from_jid="user1@test.com",
|
||||
to_jid="account1@jcl.test.com")
|
||||
disco_items = self.comp.disco_get_items("account1", info_query)
|
||||
self.assertEquals(disco_items.get_items(), [])
|
||||
self.assertEquals(disco_items, None)
|
||||
|
||||
def test_disco_get_items_2types_no_node(self):
|
||||
"""get_items on main entity. Must account types"""
|
||||
@@ -663,7 +692,7 @@ class JCLComponent_TestCase(unittest.TestCase):
|
||||
from_jid = "user1@test.com", \
|
||||
to_jid = "account1@jcl.test.com/Example")
|
||||
disco_items = self.comp.disco_get_items("Example/account1", info_query)
|
||||
self.assertEquals(disco_items.get_items(), [])
|
||||
self.assertEquals(disco_items, None)
|
||||
|
||||
def test_disco_get_items_2types_with_long_node2(self):
|
||||
"""get_items on a second type account. Must return nothing"""
|
||||
@@ -677,7 +706,18 @@ class JCLComponent_TestCase(unittest.TestCase):
|
||||
from_jid = "user1@test.com", \
|
||||
to_jid = "account1@jcl.test.com/Example2")
|
||||
disco_items = self.comp.disco_get_items("Example2/account1", info_query)
|
||||
self.assertEquals(disco_items.get_items(), [])
|
||||
self.assertEquals(disco_items, None)
|
||||
|
||||
def test_disco_get_items_list_commands(self):
|
||||
info_query = Iq(stanza_type="get",
|
||||
from_jid="user1@test.com",
|
||||
to_jid="jcl.test.com")
|
||||
disco_items = self.comp.disco_get_items("http://jabber.org/protocol/commands",
|
||||
info_query)
|
||||
self.assertEquals(len(disco_items.get_items()), 1)
|
||||
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
|
||||
|
||||
@@ -110,6 +110,8 @@ class Lang:
|
||||
get_gateway_desc = u"Please enter the email address of your contact"
|
||||
get_gateway_prompt = u"Email address"
|
||||
|
||||
command_list = u"List accounts"
|
||||
|
||||
class fr:
|
||||
component_name = u"composant générique Jabber Component Library"
|
||||
register_title = u"Enregistrement d'une nouvelle connexion"
|
||||
@@ -151,6 +153,8 @@ class Lang:
|
||||
get_gateway_desc = u"Entrer l'adresse email de votre contact"
|
||||
get_gateway_prompt = u"Adresse email"
|
||||
|
||||
command_list = u"List les comptes"
|
||||
|
||||
class nl:
|
||||
# TODO: when finish, delete this line and uncomment in tests/lang.py the makeSuite(Language_nl_TestCase, 'test') line
|
||||
register_title = u"Registratie van verbindingen voor Jabber Mail"
|
||||
|
||||
@@ -32,7 +32,7 @@ from sqlobject.dbconnection import ConnectionHub
|
||||
from sqlobject.joins import MultipleJoin
|
||||
|
||||
from jcl.lang import Lang
|
||||
from jcl.jabber.error import FieldError
|
||||
from jcl.error import FieldError
|
||||
|
||||
OFFLINE = "offline"
|
||||
ONLINE = "online"
|
||||
|
||||
@@ -27,7 +27,7 @@ import os
|
||||
from sqlobject import *
|
||||
from sqlobject.dbconnection import TheURIOpener
|
||||
|
||||
from jcl.jabber.error import FieldError
|
||||
from jcl.error import FieldError
|
||||
from jcl.model import account
|
||||
from jcl.model.account import Account, PresenceAccount
|
||||
|
||||
|
||||
@@ -114,6 +114,8 @@ class Language_TestCase(unittest.TestCase):
|
||||
self.assertNotEquals(self.lang_class.get_gateway_desc, None)
|
||||
self.assertNotEquals(self.lang_class.get_gateway_prompt, None)
|
||||
|
||||
self.assertNotEquals(self.lang_class.command_list, None)
|
||||
|
||||
class Language_fr_TestCase(Language_TestCase):
|
||||
def setUp(self):
|
||||
self.lang_class = Lang.fr
|
||||
|
||||
Reference in New Issue
Block a user