From ccde3a2bc9664b16212a70ee300102c1aca3193e Mon Sep 17 00:00:00 2001 From: David Rousselie Date: Sun, 22 Jan 2006 17:55:10 +0100 Subject: [PATCH] Check mail and interval storage - interval per account is stored - check mail algorithm implemented - new timer method darcs-hash:20060122165510-86b55-f432cb2c421fac7069cf45a6cd288b8a9998b924.gz --- jabber/component.py | 91 +++++++++++++++------------- jabber/mailconnection.py | 7 ++- jabber/mailconnection_factory.py | 2 + jabber/storage.py | 6 +- tests/test_mailconnection_factory.py | 12 ++-- tests/test_storage.py | 7 ++- 6 files changed, 72 insertions(+), 53 deletions(-) diff --git a/jabber/component.py b/jabber/component.py index 7b99878..dba1106 100644 --- a/jabber/component.py +++ b/jabber/component.py @@ -23,10 +23,12 @@ import re import signal import threading +import thread import logging import sys import anydbm import os +import time import mailconnection from mailconnection import * @@ -77,8 +79,9 @@ class MailComponent(Component): self.__storage.nb_pk_fields = 2 self.__reg_form = None self.__reg_form_init = None - # dump registered accounts (save) at least every hour - self.__count = 60 / self.__interval + # dump registered accounts (save) every hour + self.__count = 60 + self.running = False def __del__(self): logging.shutdown() @@ -352,8 +355,8 @@ class MailComponent(Component): """ Looping method """ def run(self, timeout): self.connect() - # Set check mail timer - threading.Timer(self.__interval * 60, self.time_handler) + self.running = True + thread.start_new_thread(self.time_handler, ()) try: while (not self.__shutdown and self.stream and not self.stream.eof and self.stream.socket is not None): @@ -367,6 +370,7 @@ class MailComponent(Component): finally: ## TODO : for jid in self.__storage.keys(()) ## for name in self.__storage.keys((jid,)) + self.running = False if self.stream: for jid in self.__storage.keys(()): p = Presence(from_jid = unicode(self.jid), to_jid = jid, \ @@ -399,30 +403,31 @@ class MailComponent(Component): self.__shutdown = 1 """ SIGALRM signal handler """ - def time_handler(self, signum, frame): - self.__logger.debug("Signal %i received, checking mail..." % (signum,)) - self.check_all_mail() - self.__logger.debug("Resetting alarm signal") - threading.Timer(self.__interval * 60, self.time_handler) - if self.__count == 0: - self.__logger.debug("Dumping registered accounts Database") - self.__storage.sync() - self.__count = 60 / self.__interval - else: - self.__count -= 1 + def time_handler(self): + self.__logger.debug("Check mail thread started...") + while self.running: + self.check_all_mail() + self.__logger.debug("Resetting alarm signal") + if self.__count == 0: + self.__logger.debug("Dumping registered accounts Database") + self.__storage.sync() + self.__count = 60 + else: + self.__count -= 1 + time.sleep(60) """ Component authentication handler """ def authenticated(self): self.__logger.debug("AUTHENTICATED") Component.authenticated(self) - for jid, name in self.__storage.keys(): - p = Presence(from_jid = name + "@" + unicode(self.jid), \ - to_jid = jid, stanza_type = "probe") - self.stream.send(p) for jid in self.__storage.keys(()): p = Presence(from_jid = unicode(self.jid), \ to_jid = jid, stanza_type = "probe") self.stream.send(p) + for jid, name in self.__storage.keys(): + p = Presence(from_jid = name + "@" + unicode(self.jid), \ + to_jid = jid, stanza_type = "probe") + self.stream.send(p) self.stream.set_iq_get_handler("query", "jabber:iq:version", \ self.get_version) @@ -473,8 +478,8 @@ class MailComponent(Component): base_from_jid = unicode(iq.get_from().bare()) di = DiscoItems() if not node: - for jid, name in self.__storage.keys(): - account = self.__storage[(jid, name)] + for name in self.__storage.keys((base_from_jid,)): + account = self.__storage[(base_from_jid, name)] str_name = account.get_type() + " connection " + name if account.get_type()[0:4] == "imap": str_name += " (" + account.mailbox + ")" @@ -687,7 +692,10 @@ class MailComponent(Component): elif self.__storage.has_key((base_from_jid, name)): account = self.__storage[(base_from_jid, name)] # Make available to receive mail only when online - account.status = "online" # TODO get real status = (not show) + if show is None: + account.status = "online" # TODO get real status = (not show) + else: + account.status = show p = Presence(from_jid = name + "@" + \ unicode(self.jid), \ to_jid = from_jid, \ @@ -704,7 +712,7 @@ class MailComponent(Component): base_from_jid = unicode(from_jid.bare()) if stanza.get_to() == unicode(self.jid): for jid, name in self.__storage.keys(): - self.__storage[(base_from_jid, name)].status = "offline" # TODO get real status + self.__storage[(base_from_jid, name)].status = "offline" p = Presence(from_jid = name + "@" + unicode(self.jid), \ to_jid = from_jid, \ stanza_type = "unavailable") @@ -784,13 +792,12 @@ class MailComponent(Component): """ Check mail account """ def check_mail(self, jid, name): - self.__logger.debug("CHECK_MAIL") + self.__logger.debug("CHECK_MAIL " + unicode(jid) + " " + name) account = self.__storage[(jid, name)] action = account.action - if action != "nothing": + if action != mailconnection.DO_NOTHING: try: - self.__logger.debug("Checking " \ - + name) + self.__logger.debug("Checking " + name) self.__logger.debug("\t" + account.login \ + "@" + account.host) account.connect() @@ -800,25 +807,26 @@ class MailComponent(Component): else: num = len(mail_list) # unseen mails checked by external client - if num < account.lastcheck: - account.lastcheck = 0 - if action == "retrieve": - while account.lastcheck < num: - body = account.get_mail(int(mail_list[account.lastcheck])) + # TODO : better test to find + if num < account.lastmail: + account.lastmail = 0 + if action == mailconnection.RETRIEVE: + while account.lastmail < num: + body = account.get_mail(int(mail_list[account.lastmail])) mesg = Message(from_jid = name + "@" + \ unicode(self.jid), \ to_jid = jid, \ stanza_type = "message", \ body = body) self.stream.send(mesg) - account.lastcheck += 1 + account.lastmail += 1 else: body = "" - while account.lastcheck < num: + while account.lastmail < num: body += \ - account.get_mail_summary(int(mail_list[account.lastcheck])) \ + account.get_mail_summary(int(mail_list[account.lastmail])) \ + "\n----------------------------------\n" - account.lastcheck += 1 + account.lastmail += 1 if body != "": mesg = Message(from_jid = name + "@" + \ unicode(self.jid), \ @@ -826,7 +834,6 @@ class MailComponent(Component): stanza_type = "headline", \ body = body) self.stream.send(mesg) - account.disconnect() except Exception,e: self.__logger.debug("Error while checking mail : %s" \ @@ -835,7 +842,9 @@ class MailComponent(Component): """ check mail handler """ def check_all_mail(self): self.__logger.debug("CHECK_ALL_MAIL") - ## TODO -# for jid in self.__registered.keys(): -# for name in self.__registered[jid].keys(): -# self.check_mail(jid, name) + for jid, name in self.__storage.keys(): + account = self.__storage[(jid, name)] + account.lastcheck += 1 + if account.lastcheck == account.interval: + account.lastcheck = 0 + self.check_mail(jid, name) diff --git a/jabber/mailconnection.py b/jabber/mailconnection.py index 89e5f08..9d7eca6 100644 --- a/jabber/mailconnection.py +++ b/jabber/mailconnection.py @@ -148,7 +148,7 @@ class MailConnection(object): self.host = host self.port = port self.ssl = ssl - self.lastcheck = 0 + self.lastmail = 0 self.status = "offline" self.connection = None self.chat_action = RETRIEVE @@ -158,6 +158,7 @@ class MailConnection(object): self.dnd_action = RETRIEVE self.offline_action = DO_NOTHING self.interval = 5 + self.lastcheck = 0 def __eq__(self, other): return self.get_type() == other.get_type() \ @@ -178,7 +179,7 @@ class MailConnection(object): return self.get_type() + "#" + self.login + "#" + self.password + "#" \ + self.host + "#" + str(self.port) + "#" + str(self.chat_action) + "#" \ + str(self.online_action) + "#" + str(self.away_action) + "#" + \ - str(self.xa_action) + "#" + str(self.dnd_action) + "#" + str(self.offline_action) + str(self.xa_action) + "#" + str(self.dnd_action) + "#" + str(self.offline_action) + "#" + str(self.interval) def get_decoded_part(self, part): content_charset = part.get_content_charset() @@ -251,7 +252,7 @@ class MailConnection(object): "offline": self.offline_action} if mapping.has_key(self.status): return mapping[self.status] - return NOTHING + return DO_NOTHING action = property(get_action) diff --git a/jabber/mailconnection_factory.py b/jabber/mailconnection_factory.py index 95eef09..1967933 100644 --- a/jabber/mailconnection_factory.py +++ b/jabber/mailconnection_factory.py @@ -68,6 +68,7 @@ def str_to_mail_connection(connection_string): xa_action = int(arg_list.pop()) dnd_action = int(arg_list.pop()) offline_action = int(arg_list.pop()) + interval = int(arg_list.pop()) result = None if type == "imap": mailbox = arg_list.pop() @@ -105,6 +106,7 @@ def str_to_mail_connection(connection_string): result.xa_action = xa_action result.dnd_action = dnd_action result.offline_action = offline_action + result.interval = interval return result diff --git a/jabber/storage.py b/jabber/storage.py index 985d8fd..b9f2d46 100644 --- a/jabber/storage.py +++ b/jabber/storage.py @@ -73,7 +73,7 @@ class DBMStorage(Storage): self.sync() def load(self): -# print "DBM LOAD" + # print "DBM LOAD" str_registered = anydbm.open(self.file, \ 'c') result = {} @@ -101,7 +101,7 @@ class DBMStorage(Storage): registered[key], key) else: self.__str_registered[pk] = str(registered) - print "STORING : " + pk + " = " + str(registered) +# print "STORING : " + pk + " = " + str(registered) def store(self): # print "DBM STORE" @@ -161,7 +161,7 @@ class DBMStorage(Storage): return result.keys() def dump(self): - print "dumping" +# print "dumping" for pk in self.__registered.keys(): print pk + " = " + str(self.__registered[pk]) diff --git a/tests/test_mailconnection_factory.py b/tests/test_mailconnection_factory.py index 30d796a..e2e7520 100644 --- a/tests/test_mailconnection_factory.py +++ b/tests/test_mailconnection_factory.py @@ -42,7 +42,7 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc, mc) def test_str_to_mail_connection_imap(self): - mc = str_to_mail_connection("imap#login#passwd#host#193#0#0#0#1#1#2#INBOX") + mc = str_to_mail_connection("imap#login#passwd#host#193#0#0#0#1#1#2#4#INBOX") self.assertEquals(mc.get_type(), "imap") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") @@ -55,9 +55,10 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.xa_action, mailconnection.DIGEST) self.assertEquals(mc.dnd_action, mailconnection.DIGEST) self.assertEquals(mc.offline_action, mailconnection.RETRIEVE) + self.assertEquals(mc.interval, 4) def test_str_to_mail_connection_imaps(self): - mc = str_to_mail_connection("imaps#login#passwd#host#993#0#0#0#1#1#2#INBOX.SubDir") + mc = str_to_mail_connection("imaps#login#passwd#host#993#0#0#0#1#1#2#4#INBOX.SubDir") self.assertEquals(mc.get_type(), "imaps") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") @@ -70,9 +71,10 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.xa_action, mailconnection.DIGEST) self.assertEquals(mc.dnd_action, mailconnection.DIGEST) self.assertEquals(mc.offline_action, mailconnection.RETRIEVE) + self.assertEquals(mc.interval, 4) def test_str_to_mail_connection_pop3(self): - mc = str_to_mail_connection("pop3#login#passwd#host#110#0#0#0#1#1#2") + mc = str_to_mail_connection("pop3#login#passwd#host#110#0#0#0#1#1#2#4") self.assertEquals(mc.get_type(), "pop3") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") @@ -84,9 +86,10 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.xa_action, mailconnection.DIGEST) self.assertEquals(mc.dnd_action, mailconnection.DIGEST) self.assertEquals(mc.offline_action, mailconnection.RETRIEVE) + self.assertEquals(mc.interval, 4) def test_str_to_mail_connection_pop3s(self): - mc = str_to_mail_connection("pop3s#login#passwd#host#995#0#0#0#1#1#2") + mc = str_to_mail_connection("pop3s#login#passwd#host#995#0#0#0#1#1#2#4") self.assertEquals(mc.get_type(), "pop3s") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") @@ -98,4 +101,5 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.xa_action, mailconnection.DIGEST) self.assertEquals(mc.dnd_action, mailconnection.DIGEST) self.assertEquals(mc.offline_action, mailconnection.RETRIEVE) + self.assertEquals(mc.interval, 4) diff --git a/tests/test_storage.py b/tests/test_storage.py index 1b213ee..382897b 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -45,7 +45,8 @@ class SQLiteStorage_TestCase(unittest.TestCase): class DBMStorage_TestCase(unittest.TestCase): def setUp(self): - self._storage = DBMStorage(nb_pk_fields = 2) + spool_dir = "./spool/test" + self._storage = DBMStorage(nb_pk_fields = 2, spool_dir = spool_dir) self._account1 = IMAPConnection(login = "login1", password = "password1", host = "host1", @@ -58,6 +59,7 @@ class DBMStorage_TestCase(unittest.TestCase): self._account1.xa_action = mailconnection.DO_NOTHING self._account1.dnd_action = mailconnection.DO_NOTHING self._account1.offline_action = mailconnection.DO_NOTHING + self._account1.interval = 4 self._account2 = IMAPConnection(login = "login2", password = "password2", host = "host2", @@ -70,6 +72,7 @@ class DBMStorage_TestCase(unittest.TestCase): self._account2.xa_action = mailconnection.DO_NOTHING self._account2.dnd_action = mailconnection.DO_NOTHING self._account2.offline_action = mailconnection.DO_NOTHING + self._account2.interval = 4 def tearDown(self): os.remove(self._storage.file) @@ -84,7 +87,7 @@ class DBMStorage_TestCase(unittest.TestCase): def test_set_sync_get(self): self._storage[("test@localhost", "account1")] = self._account1 self._storage[("test@localhost", "account2")] = self._account2 - loaded_storage = DBMStorage(nb_pk_fields = 2) + loaded_storage = DBMStorage(nb_pk_fields = 2, spool_dir = "./spool/test") self.assertEquals(loaded_storage[("test@localhost", "account1")], self._account1) self.assertEquals(loaded_storage[("test@localhost", "account2")], self._account2)