diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py index 378c579..d584eda 100644 --- a/src/jcl/jabber/component.py +++ b/src/jcl/jabber/component.py @@ -205,35 +205,7 @@ class JCLComponent(Component, object): self.handle_message) self.send_stanzas(self.account_manager.probe_all_accounts_presence()) - def password_msg_handler_filter(message): - name = message.get_to().node - bare_from_jid = unicode(message.get_from().bare()) - accounts = Account.select(\ - AND(Account.q.name == name, \ - Account.q.user_jid == bare_from_jid)) - if accounts.count() != 1: - print >>sys.stderr, "Account " + name + " for user " + bare_from_jid + " must be uniq" - _account = accounts[0] - if hasattr(_account, 'password') \ - and hasattr(_account, 'waiting_password_reply') \ - and re.compile("\[PASSWORD\]").search(message.get_subject()) \ - is not None: - return accounts - else: - return None - - def password_msg_handler(message, accounts): - _account = accounts[0] - lang_class = self.lang.get_lang_class_from_node(message.get_node()) - _account.password = message.get_body() - _account.waiting_password_reply = False - msg = Message(from_jid = _account.jid, \ - to_jid = message.get_from(), \ - stanza_type = "normal", \ - subject = lang_class.password_saved_for_session, \ - body = lang_class.password_saved_for_session) - self.stream.send(msg) - self.msg_handlers += [(password_msg_handler, password_msg_handler_filter)] + self.msg_handlers += [PasswordMessageHandler()] def signal_handler(self, signum, frame): """Stop method handler @@ -472,12 +444,14 @@ class JCLComponent(Component, object): Handle password response message """ self.__logger.debug("MESSAGE: " + message.get_body()) + result = [] self.db_connect() - for (msg_handler, filter_func) in self.msg_handlers: - accounts = filter_func(message) + for msg_handler in self.msg_handlers: + accounts = msg_handler.filter(message) if accounts is not None: - msg_handler(message, accounts) + result += msg_handler.handle(message, self.lang, accounts) self.db_disconnect() + self.send_stanzas(result) return 1 ########################################################################### @@ -1118,3 +1092,57 @@ class AccountManager(object): body = _account.default_lang_class.check_error_body \ % (exception))) return result + +class MessageHandler(object): + """Message handling class""" + + def filter(self, message): + """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, message, lang, accounts): + """Apply actions to do on given accounts + Do nothing by default""" + return [] + +class PasswordMessageHandler(MessageHandler): + """Handle password message""" + + def __init__(self): + """á¸Ĥandler constructor""" + self.password_regexp = re.compile("\[PASSWORD\]") + + def filter(self, message): + """Return the uniq account associated with a name and user JID. + DB connection might already be opened.""" + name = message.get_to().node + bare_from_jid = unicode(message.get_from().bare()) + accounts = Account.select(\ + AND(Account.q.name == name, \ + Account.q.user_jid == bare_from_jid)) + if accounts.count() != 1: + print >>sys.stderr, "Account " + name + " for user " + bare_from_jid + " must be uniq" + _account = accounts[0] + if hasattr(_account, 'password') \ + and hasattr(_account, 'waiting_password_reply') \ + and (getattr(_account, 'waiting_password_reply') == True) \ + and self.password_regexp.search(message.get_subject()) \ + is not None: + return accounts + else: + return None + + def handle(self, message, lang, accounts): + """Receive password for given account""" + _account = accounts[0] + lang_class = lang.get_lang_class_from_node(message.get_node()) + _account.password = message.get_body() + _account.waiting_password_reply = False + return [Message(from_jid = _account.jid, \ + to_jid = message.get_from(), \ + stanza_type = "normal", \ + subject = lang_class.password_saved_for_session, \ + body = lang_class.password_saved_for_session)] + diff --git a/src/jcl/jabber/tests/component.py b/src/jcl/jabber/tests/component.py index 576339a..8fa0bb8 100644 --- a/src/jcl/jabber/tests/component.py +++ b/src/jcl/jabber/tests/component.py @@ -40,7 +40,7 @@ from pyxmpp.presence import Presence from pyxmpp.message import Message from pyxmpp.jabber.dataforms import Form, Field, Option -from jcl.jabber.component import JCLComponent +from jcl.jabber.component import JCLComponent, MessageHandler, PasswordMessageHandler from jcl.model import account from jcl.model.account import Account from jcl.lang import Lang @@ -1983,8 +1983,155 @@ class JCLComponent_TestCase(unittest.TestCase): self.comp.send_stanzas(None) self.assertEquals(len(self.comp.stream.sent), 0) +class MessageHandler_TestCase(unittest.TestCase): + def setUp(self): + self.handler = MessageHandler() + if os.path.exists(DB_PATH): + os.unlink(DB_PATH) + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + Account.createTable(ifNotExists = True) + del account.hub.threadConnection + + def tearDown(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + Account.dropTable(ifExists = True) + del TheURIOpener.cachedURIs['sqlite://' + DB_URL] + account.hub.threadConnection.close() + del account.hub.threadConnection + if os.path.exists(DB_PATH): + os.unlink(DB_PATH) + + def test_filter(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = Account(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account12 = Account(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + accounts = self.handler.filter(None) + self.assertEquals(accounts.count(), 2) + del account.hub.threadConnection + + def test_handle(self): + self.assertEquals(self.handler.handle(None, None, None), []) + +class PasswordMessageHandler_TestCase(unittest.TestCase): + def setUp(self): + self.handler = PasswordMessageHandler() + if os.path.exists(DB_PATH): + os.unlink(DB_PATH) + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + Account.createTable(ifNotExists = True) + ExampleAccount.createTable(ifNotExists = True) + del account.hub.threadConnection + + def tearDown(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + ExampleAccount.dropTable(ifExists = True) + Account.dropTable(ifExists = True) + del TheURIOpener.cachedURIs['sqlite://' + DB_URL] + account.hub.threadConnection.close() + del account.hub.threadConnection + if os.path.exists(DB_PATH): + os.unlink(DB_PATH) + + def test_filter_waiting_password(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account11.waiting_password_reply = True + account12 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + message = Message(from_jid = "user1@test.com", \ + to_jid = "account11@jcl.test.com", \ + stanza_type = "normal", \ + subject = "[PASSWORD]", \ + body = "secret") + accounts = self.handler.filter(message) + self.assertEquals(accounts.count(), 1) + self.assertEquals(accounts[0].name, "account11") + del account.hub.threadConnection + + def test_filter_not_waiting_password(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account11.waiting_password_reply = False + account12 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + message = Message(from_jid = "user1@test.com", \ + to_jid = "account11@jcl.test.com", \ + stanza_type = "normal", \ + subject = "[PASSWORD]", \ + body = "secret") + accounts = self.handler.filter(message) + self.assertEquals(accounts, None) + del account.hub.threadConnection + + def test_filter_not_good_message(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account11.waiting_password_reply = True + account12 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + message = Message(from_jid = "user1@test.com", \ + to_jid = "account11@jcl.test.com", \ + stanza_type = "normal", \ + subject = "[NOT GOOD MESSAGE]", \ + body = "secret") + accounts = self.handler.filter(message) + self.assertEquals(accounts, None) + del account.hub.threadConnection + + def test_filter_not_password_account(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = Account(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account12 = Account(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + message = Message(from_jid = "user1@test.com", \ + to_jid = "account11@jcl.test.com", \ + stanza_type = "normal", \ + subject = "[PASSWORD]", \ + body = "secret") + accounts = self.handler.filter(message) + self.assertEquals(accounts, None) + del account.hub.threadConnection + + def test_handle(self): + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + account11 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account11", \ + jid = "account11@jcl.test.com") + account12 = ExampleAccount(user_jid = "user1@test.com", \ + name = "account12", \ + jid = "account12@jcl.test.com") + message = Message(from_jid = "user1@test.com", \ + to_jid = "account11@jcl.test.com", \ + stanza_type = "normal", \ + subject = "[PASSWORD]", \ + body = "secret") + messages = self.handler.handle(message, Lang(), [account11]) + self.assertEquals(len(messages), 1) + self.assertEquals(account11.password, "secret") + del account.hub.threadConnection + def suite(): - return unittest.makeSuite(JCLComponent_TestCase, 'test') + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(JCLComponent_TestCase, 'test')) + suite.addTest(unittest.makeSuite(MessageHandler_TestCase, 'test')) + suite.addTest(unittest.makeSuite(PasswordMessageHandler_TestCase, 'test')) + return suite if __name__ == '__main__': unittest.main(defaultTest='suite')