diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py index d1972d5..d0f8216 100644 --- a/src/jcl/jabber/component.py +++ b/src/jcl/jabber/component.py @@ -52,7 +52,7 @@ from pyxmpp.jabber.dataforms import Form, Field, Option import jcl from jcl.jabber.error import FieldError from jcl.model import account -from jcl.model.account import Account +from jcl.model.account import Account, LegacyJID from jcl.lang import Lang VERSION = "0.1" @@ -894,8 +894,9 @@ class AccountManager(object): orderBy="user_jid"): if current_user_jid != _account.user_jid: current_user_jid = _account.user_jid - result.extend(getattr(self, "_send_presence_" + - presence + "_root")(_account.user_jid)) + result.extend(self._send_presence(self.component.jid, + _account.user_jid, + presence)) result.extend(getattr(self, "_send_presence_" + presence)(_account)) self.db_disconnect() @@ -917,14 +918,13 @@ class AccountManager(object): return self.root_handle_presence(\ from_jid, lambda _account: \ - self._send_presence_available(_account, - show, - lang_class), + self._send_presence_available(_account, + show, + lang_class), lambda nb_accounts: \ - self._send_presence_available_root(from_jid, - show, - str(nb_accounts) - + lang_class.message_status)) + self._send_root_presence(from_jid, show, + str(nb_accounts) + + lang_class.message_status)) ###### presence_unavailable handlers ###### def account_handle_presence_unavailable(self, name, from_jid): @@ -939,9 +939,9 @@ class AccountManager(object): return self.root_handle_presence(\ from_jid, lambda _account: \ - self._send_presence_unavailable(_account), + self._send_presence_unavailable(_account), lambda nb_accounts: \ - self._send_presence_unavailable_root(from_jid)) + self._send_root_presence(from_jid)) ###### presence_subscribe handlers ###### def account_handle_presence_subscribe(self, name, from_jid, stanza): @@ -1111,24 +1111,12 @@ class AccountManager(object): """Compose account jid from account name""" return name + u"@" + unicode(self.component.jid) - def _send_presence_probe_root(self, to_jid): - """Send presence probe to account's user from root JID""" - return [Presence(from_jid=self.component.jid, - to_jid=to_jid, - stanza_type="probe")] - def _send_presence_probe(self, _account): """Send presence probe to account's user""" return [Presence(from_jid=_account.jid, to_jid=_account.user_jid, stanza_type="probe")] - def _send_presence_unavailable_root(self, to_jid): - """Send unavailable presence to account's user from root JID""" - return [Presence(from_jid=self.component.jid, - to_jid=to_jid, - stanza_type="unavailable")] - def _send_presence_unavailable(self, _account): """Send unavailable presence to account's user""" _account.status = account.OFFLINE @@ -1136,14 +1124,24 @@ class AccountManager(object): to_jid=_account.user_jid, stanza_type="unavailable")] - def _send_presence_available_root(self, to_jid, show, status_msg): - """Send available presence to account's user from root JID""" - return [Presence(from_jid=self.component.jid, - to_jid=to_jid, - status=status_msg, - show=show, - stanza_type="available")] + def _send_root_presence(self, to_jid, show=None, status=None): + result = self._send_presence(self.component.jid, to_jid, + "unavailable", show=show, + status=status) + result.extend(self._send_root_presence_legacy(to_jid, + "unavailable", + show=show, + status=status)) + return result + def _send_presence(self, from_jid, to_jid, presence_type, status=None, show=None): + """Send presence stanza""" + return [Presence(from_jid=from_jid, + to_jid=to_jid, + status=status, + show=show, + stanza_type=presence_type)] + def _send_presence_available(self, _account, show, lang_class): """Send available presence to account's user and ask for password if necessary""" @@ -1167,6 +1165,23 @@ class AccountManager(object): result.extend(self.ask_password(_account, lang_class)) return result + def _send_root_presence_legacy(self, to_jid, presence_type, + status=None, show=None): + """Send presence from legacy JID""" + result = [] + self.db_connect() + legacy_jids = LegacyJID.select(\ + AND(LegacyJID.q.accountID == Account.q.id, + Account.q.user_jid == unicode(to_jid.bare()))) + for legacy_jid in legacy_jids: + result.append(Presence(from_jid=legacy_jid.jid, + to_jid=to_jid, + show=show, + status=status, + stanza_type=presence_type)) + self.db_disconnect() + return result + def ask_password(self, _account, lang_class): """Send a Jabber message to ask for account password """ @@ -1254,7 +1269,7 @@ class PasswordMessageHandler(Handler): """Handle password message""" def __init__(self): - """á¸Ĥandler constructor""" + """handler constructor""" self.password_regexp = re.compile("\[PASSWORD\]") def filter(self, stanza, lang_class): diff --git a/src/jcl/jabber/tests/component.py b/src/jcl/jabber/tests/component.py index 4650d94..bc5fa97 100644 --- a/src/jcl/jabber/tests/component.py +++ b/src/jcl/jabber/tests/component.py @@ -45,7 +45,7 @@ from jcl.jabber.component import JCLComponent, Handler, \ PasswordMessageHandler, DefaultSubscribeHandler, \ DefaultUnsubscribeHandler, DefaultPresenceHandler from jcl.model import account -from jcl.model.account import Account +from jcl.model.account import Account, LegacyJID from jcl.lang import Lang from jcl.model.tests.account import ExampleAccount, Example2Account @@ -174,6 +174,7 @@ class JCLComponent_TestCase(unittest.TestCase): 'sqlite://' + DB_URL) account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) Account.createTable(ifNotExists = True) + LegacyJID.createTable(ifNotExists=True) ExampleAccount.createTable(ifNotExists = True) Example2Account.createTable(ifNotExists = True) del account.hub.threadConnection @@ -184,6 +185,7 @@ class JCLComponent_TestCase(unittest.TestCase): account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) Example2Account.dropTable(ifExists = True) ExampleAccount.dropTable(ifExists = True) + LegacyJID.dropTable(ifExists=True) Account.dropTable(ifExists = True) del TheURIOpener.cachedURIs['sqlite://' + DB_URL] account.hub.threadConnection.close() @@ -1474,6 +1476,88 @@ class JCLComponent_TestCase(unittest.TestCase): and isinstance(presence, Presence)]), \ 1) + def test_handle_presence_available_to_component_legacy_users(self): + self.comp.stream = MockStream() + self.comp.stream_class = MockStream + 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") + account2 = Account(user_jid="user2@test.com", + name="account2", + jid="account2@jcl.test.com") + legacy_jid111 = LegacyJID(legacy_address="u111@test.com", + jid="u111%test.com@jcl.test.com", + account=account11) + legacy_jid112 = LegacyJID(legacy_address="u112@test.com", + jid="u112%test.com@jcl.test.com", + account=account11) + legacy_jid121 = LegacyJID(legacy_address="u121@test.com", + jid="u121%test.com@jcl.test.com", + account=account12) + legacy_jid122 = LegacyJID(legacy_address="u122@test.com", + jid="u122%test.com@jcl.test.com", + account=account12) + legacy_jid21 = LegacyJID(legacy_address="u21@test.com", + jid="u21%test.com@jcl.test.com", + account=account2) + del account.hub.threadConnection + self.comp.handle_presence_available(Presence(\ + stanza_type="available", + from_jid="user1@test.com", + to_jid="jcl.test.com")) + presence_sent = self.comp.stream.sent + self.assertEqual(len(presence_sent), 7) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_to_jid() == "user1@test.com"]), + 7) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "account11@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "account12@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u111%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u112%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u121%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u122%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + def test_handle_presence_available_to_component_unknown_user(self): self.comp.stream = MockStream() self.comp.stream_class = MockStream @@ -1705,6 +1789,88 @@ class JCLComponent_TestCase(unittest.TestCase): == "unavailable"]), \ 1) + def test_handle_presence_unavailable_to_component_legacy_users(self): + self.comp.stream = MockStream() + self.comp.stream_class = MockStream + 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") + account2 = Account(user_jid="user2@test.com", + name="account2", + jid="account2@jcl.test.com") + legacy_jid111 = LegacyJID(legacy_address="u111@test.com", + jid="u111%test.com@jcl.test.com", + account=account11) + legacy_jid112 = LegacyJID(legacy_address="u112@test.com", + jid="u112%test.com@jcl.test.com", + account=account11) + legacy_jid121 = LegacyJID(legacy_address="u121@test.com", + jid="u121%test.com@jcl.test.com", + account=account12) + legacy_jid122 = LegacyJID(legacy_address="u122@test.com", + jid="u122%test.com@jcl.test.com", + account=account12) + legacy_jid21 = LegacyJID(legacy_address="u21@test.com", + jid="u21%test.com@jcl.test.com", + account=account2) + del account.hub.threadConnection + self.comp.handle_presence_unavailable(Presence(\ + stanza_type="unavailable", + from_jid="user1@test.com", + to_jid="jcl.test.com")) + presence_sent = self.comp.stream.sent + self.assertEqual(len(presence_sent), 7) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_to_jid() == "user1@test.com"]), + 7) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "account11@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "account12@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u111%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u112%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u121%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + self.assertEqual(len([presence + for presence in presence_sent + if presence.get_from_jid() == \ + "u122%test.com@jcl.test.com" + and isinstance(presence, Presence)]), + 1) + def test_handle_presence_unavailable_to_component_unknown_user(self): self.comp.stream = MockStream() self.comp.stream_class = MockStream diff --git a/src/jcl/jabber/tests/feeder.py b/src/jcl/jabber/tests/feeder.py index a6c5da5..884d950 100644 --- a/src/jcl/jabber/tests/feeder.py +++ b/src/jcl/jabber/tests/feeder.py @@ -35,7 +35,7 @@ from pyxmpp.message import Message from jcl.jabber.component import JCLComponent from jcl.jabber.feeder import FeederComponent, Feeder, Sender, MessageSender, \ HeadlineSender, FeederHandler -from jcl.model.account import Account +from jcl.model.account import Account, LegacyJID from jcl.model import account from jcl.model.tests.account import ExampleAccount, Example2Account @@ -69,6 +69,7 @@ class FeederComponent_TestCase(JCLComponent_TestCase): 'sqlite://' + DB_URL) account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) Account.createTable(ifNotExists = True) + LegacyJID.createTable(ifNotExists=True) ExampleAccount.createTable(ifNotExists = True) Example2Account.createTable(ifNotExists = True) del account.hub.threadConnection @@ -76,6 +77,7 @@ class FeederComponent_TestCase(JCLComponent_TestCase): def tearDown(self): account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) Account.dropTable(ifExists = True) + LegacyJID.dropTable(ifExists=True) ExampleAccount.dropTable(ifExists = True) Example2Account.dropTable(ifExists = True) del TheURIOpener.cachedURIs['sqlite://' + DB_URL] diff --git a/src/jcl/model/account.py b/src/jcl/model/account.py index ee059dc..99d1937 100644 --- a/src/jcl/model/account.py +++ b/src/jcl/model/account.py @@ -27,8 +27,9 @@ __revision__ = "$Id: account.py,v 1.3 2005/09/18 20:24:07 dax Exp $" from sqlobject.inheritance import InheritableSQLObject -from sqlobject.col import StringCol, EnumCol, IntCol, BoolCol +from sqlobject.col import StringCol, EnumCol, IntCol, BoolCol, ForeignKey from sqlobject.dbconnection import ConnectionHub +from sqlobject.joins import MultipleJoin from jcl.lang import Lang from jcl.jabber.error import FieldError @@ -69,7 +70,8 @@ class Account(InheritableSQLObject): ## Not yet used first_check = BoolCol(default = True) __status = StringCol(default=OFFLINE, dbName="status") in_error = BoolCol(default=False) - + legacy_jids = MultipleJoin('LegacyJID') + ## Use these attributs to support volatile password ## login = StringCol(default = "") ## password = StringCol(default = None) @@ -265,3 +267,11 @@ class PresenceAccount(Account): return PresenceAccount.DO_NOTHING action = property(get_action) + +class LegacyJID(InheritableSQLObject): + _connection = hub + + legacy_address = StringCol() + jid = StringCol() + account = ForeignKey('Account') +