diff --git a/TODO b/TODO index 67e90cd..f9a4fa3 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,3 @@ -* i18n support in the same way as ejabberd and - PyMSNt, PyICQ-t and PyAIM-t: using xml:lang, but have an option in - the config to set the default language to show, when the client do - not support xml:lang.i18n support (use xml:lang + default) - * Database backend (default SQLLite) * Support for attachements with size limit and file format limit diff --git a/jabber/mailconnection.py b/jabber/mailconnection.py index d463ef0..9286858 100644 --- a/jabber/mailconnection.py +++ b/jabber/mailconnection.py @@ -221,9 +221,6 @@ class MailConnection(object): def format_message_summary(self, email_msg): return self.format_message(email_msg, False) - def get_type(self): - return "UNKNOWN" - def get_status_msg(self): return self.get_type() + "://" + self.login + "@" + self.host + ":" + \ unicode(self.port) @@ -324,6 +321,8 @@ class IMAPConnection(MailConnection): return self.format_message_summary(email.message_from_string(data[0][1])) return u"Error while fetching mail " + str(index) + type = property(get_type) + class POP3Connection(MailConnection): def __init__(self, login = "", password = "", host = "", \ port = None, ssl = False): @@ -377,3 +376,5 @@ class POP3Connection(MailConnection): if ret[0:3] == '+OK': return self.format_message_summary(email.message_from_string('\n'.join(data))) return u"Error while fetching mail " + str(index) + + type = property(get_type) diff --git a/jabber/storage.py b/jabber/storage.py index f29a5ea..89e97d5 100644 --- a/jabber/storage.py +++ b/jabber/storage.py @@ -27,6 +27,8 @@ import sys import anydbm import mailconnection_factory from UserDict import UserDict +from pysqlite2 import dbapi2 as sqlite + class Storage(UserDict): def __init__(self, nb_pk_fields = 1, spool_dir = "."): @@ -35,39 +37,70 @@ class Storage(UserDict): self.set_spool_dir(spool_dir) self.nb_pk_fields = nb_pk_fields self.file = self._spool_dir + "/registered.db" + self._registered = self.load() - # return hash of hash (jid and name) - def load(self): - pass + def __setitem__(self, pk_tuple, obj): +# print "Adding " + "#".join(pk_tuple) + " = " + str(obj) + self._registered[str("#".join(pk_tuple))] = obj - def sync(self): - pass - - def store(self, nb_pk_fields, registered, pk): - pass - - def add(self, key_list, obj): - pass + def __getitem__(self, pk_tuple): +# print "Getting " + "#".join(pk_tuple) + if len(pk_tuple) == self.nb_pk_fields: + return self._registered[str("#".join(pk_tuple))] + else: + partial_key = str("#".join(pk_tuple)) + regexp = re.compile(partial_key) + return [self._registered[key] + for key in self._registered.keys() + if regexp.search(key)] + + def __delitem__(self, pk_tuple): +# print "Deleting " + "#".join(pk_tuple) + del self._registered[str("#".join(pk_tuple))] - def remove(self, key_list): - pass - def get_spool_dir(self): return self._spool_dir def set_spool_dir(self, spool_dir): - print "setting spool dir to " + spool_dir self._spool_dir = spool_dir if not os.path.isdir(self._spool_dir): os.makedirs(self._spool_dir) spool_dir = property(get_spool_dir, set_spool_dir) - + + def has_key(self, pk_tuple): + if len(pk_tuple) == self.nb_pk_fields: + return self._registered.has_key(str("#".join(pk_tuple))) + else: + partial_key = str("#".join(pk_tuple)) + regexp = re.compile("^" + partial_key) + for key in self._registered.keys(): + if regexp.search(key): + return True + return False + + def keys(self, pk_tuple = None): + if pk_tuple is None: + return [tuple(key.split("#")) for key in self._registered.keys()] + else: + level = len(pk_tuple) + partial_key = str("#".join(pk_tuple)) + regexp = re.compile("^" + partial_key) + result = {} + for key in self._registered.keys(): + if regexp.search(key): + result[key.split("#")[level]] = None + return result.keys() + + def dump(self): + for pk in self._registered.keys(): + print pk + " = " + str(self._registered[pk]) + + class DBMStorage(Storage): def __init__(self, nb_pk_fields = 1, spool_dir = "."): # print "DBM INIT" Storage.__init__(self, nb_pk_fields, spool_dir) - self.__registered = self.load() def __del__(self): # print "DBM STOP" @@ -109,80 +142,105 @@ class DBMStorage(Storage): try: str_registered = anydbm.open(self.file, \ 'c') - for pk in self.__registered.keys(): - str_registered[pk] = str(self.__registered[pk]) + for pk in self._registered.keys(): + str_registered[pk] = str(self._registered[pk]) except Exception, e: print >>sys.stderr, "Cannot save to registered.db : " print >>sys.stderr, e str_registered.close() - - def __setitem__(self, pk_tuple, obj): -# print "Adding " + "#".join(pk_tuple) + " = " + str(obj) - self.__registered[str("#".join(pk_tuple))] = obj - self.sync() - def __getitem__(self, pk_tuple): -# print "Getting " + "#".join(pk_tuple) - if len(pk_tuple) == self.nb_pk_fields: - return self.__registered[str("#".join(pk_tuple))] - else: - partial_key = str("#".join(pk_tuple)) - regexp = re.compile(partial_key) - return [self.__registered[key] - for key in self.__registered.keys() - if regexp.search(key)] + def __setitem__(self, pk_tuple, obj): + Storage.__setitem__(self, pk_tuple, obj) + self.sync() def __delitem__(self, pk_tuple): -# print "Deleting " + "#".join(pk_tuple) - del self.__registered[str("#".join(pk_tuple))] + Storage.__delitem__(self, pk_tuple) self.sync() - - def has_key(self, pk_tuple): - if len(pk_tuple) == self.nb_pk_fields: - return self.__registered.has_key(str("#".join(pk_tuple))) - else: - partial_key = str("#".join(pk_tuple)) - regexp = re.compile("^" + partial_key) - for key in self.__registered.keys(): - if regexp.search(key): - return True - return False - - def keys(self, pk_tuple = None): - if pk_tuple is None: - return [tuple(key.split("#")) for key in self.__registered.keys()] - else: - level = len(pk_tuple) - partial_key = str("#".join(pk_tuple)) - regexp = re.compile("^" + partial_key) - result = {} - for key in self.__registered.keys(): - if regexp.search(key): - result[key.split("#")[level]] = None - return result.keys() - - def dump(self): -# print "dumping" - for pk in self.__registered.keys(): - print pk + " = " + str(self.__registered[pk]) class SQLiteStorage(Storage): def __init__(self, nb_pk_fields = 1, spool_dir = "."): - pass + self.__connection = None + Storage.__init__(self, nb_pk_fields, spool_dir) - def load(self): - pass + def create(self): +# print "creating new Table" + cursor = self.__connection.cursor() + cursor.execute(""" + create table account( + jid STRING, + name STRING, + type STRING, + login STRING, + password STRING, + host STRING, + port INTEGER, + chat_action INTEGER, + online_action INTEGER, + away_action INTEGER, + xa_action INTEGER, + dnd_action INTEGER, + offline_action INTEGER, + interval INTEGER, + mailbox STRING, + PRIMARY KEY(jid, name) + ) + """) + self.__connection.commit() + cursor.close() + + def __del__(self): + self.__connection.close() def sync(self): pass - - def store(self, nb_pk_fields, registered, pk): - pass - - def add(self, key_list, obj): - pass - def remove(self, key_list): - pass + def load(self): + if not os.path.exists(self.file): + self.__connection = sqlite.connect(self.file) + self.create() + else: + self.__connection = sqlite.connect(self.file) + cursor = self.__connection.cursor() + cursor.execute("""select * from account""") + result = {} + for row in cursor.fetchall(): +# print "Creating new " + row[self.nb_pk_fields] + " connection." + account = result["#".join(row[0:self.nb_pk_fields])] = mailconnection_factory.get_new_mail_connection(row[self.nb_pk_fields]) + for field_index in range(self.nb_pk_fields + 1, len(row)): +# print "\tSetting " + str(cursor.description[field_index][0]) + \ +# " to " + str(row[field_index]) + setattr(account, + cursor.description[field_index][0], + row[field_index]) + cursor.close() + return result + def __setitem__(self, pk_tuple, obj): + Storage.__setitem__(self, pk_tuple, obj) + cursor = self.__connection.cursor() + cursor.execute(""" + insert or replace into account values + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + (pk_tuple[0], + pk_tuple[1], + obj.type, + obj.login, + obj.password, + obj.host, + obj.port, + obj.chat_action, + obj.online_action, + obj.away_action, + obj.xa_action, + obj.dnd_action, + obj.offline_action, + obj.interval, + obj.mailbox)) + self.__connection.commit() + cursor.close() + + def __delitem__(self, pk_tuple): + Storage.__delitem__(self, pk_tuple) + diff --git a/run_test.py b/run_test.py index 4ffb5ad..0adb95d 100644 --- a/run_test.py +++ b/run_test.py @@ -54,6 +54,8 @@ if __name__ == '__main__': "test") dbmstorage_suite = unittest.makeSuite(DBMStorage_TestCase, \ "test") + sqlitestorage_suite = unittest.makeSuite(SQLiteStorage_TestCase, \ + "test") jmc_suite = unittest.TestSuite((mail_connection_suite, \ pop3_connection_suite, \ @@ -62,8 +64,9 @@ if __name__ == '__main__': component_suite, \ component2_suite, \ storage_suite, \ - dbmstorage_suite)) - test_support.run_suite(mc_factory_suite) + dbmstorage_suite, \ + sqlitestorage_suite)) + test_support.run_suite(sqlitestorage_suite) # coverage.stop() # coverage.analysis(jabber.mailconnection_factory) diff --git a/tests/test_storage.py b/tests/test_storage.py index 700c9de..ce026f2 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -54,7 +54,7 @@ class DBMStorage_TestCase(unittest.TestCase): ssl = True, mailbox = "INBOX.box1") self._account1.chat_action = mailconnection.DO_NOTHING - self._account1.onlline_action = mailconnection.DO_NOTHING + self._account1.online_action = mailconnection.DO_NOTHING self._account1.away_action = mailconnection.DO_NOTHING self._account1.xa_action = mailconnection.DO_NOTHING self._account1.dnd_action = mailconnection.DO_NOTHING @@ -67,7 +67,7 @@ class DBMStorage_TestCase(unittest.TestCase): ssl = False, mailbox = "INBOX.box2") self._account2.chat_action = mailconnection.DO_NOTHING - self._account2.onlline_action = mailconnection.DO_NOTHING + self._account2.online_action = mailconnection.DO_NOTHING self._account2.away_action = mailconnection.DO_NOTHING self._account2.xa_action = mailconnection.DO_NOTHING self._account2.dnd_action = mailconnection.DO_NOTHING @@ -156,3 +156,46 @@ class DBMStorage_TestCase(unittest.TestCase): self.assertEquals(len(result), 2) self.assertEquals(result[0], "account2") self.assertEquals(result[1], "account1") + +class SQLiteStorage_TestCase(DBMStorage_TestCase): + def setUp(self): + spool_dir = "./spool/test" + self._storage = SQLiteStorage(nb_pk_fields = 2, spool_dir = spool_dir) + self._account1 = IMAPConnection(login = "login1", + password = "password1", + host = "host1", + port = 993, + ssl = True, + mailbox = "INBOX.box1") + self._account1.chat_action = mailconnection.DIGEST + self._account1.online_action = mailconnection.DIGEST + self._account1.away_action = mailconnection.DO_NOTHING + 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", + port = 1993, + ssl = False, + mailbox = "INBOX.box2") + self._account2.chat_action = mailconnection.DO_NOTHING + self._account2.online_action = mailconnection.DO_NOTHING + self._account2.away_action = mailconnection.DO_NOTHING + 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) +# self._storage = None + + + def test_set_sync_get(self): + self._storage[("test@localhost", "account1")] = self._account1 + self._storage[("test@localhost", "account2")] = self._account2 + loaded_storage = SQLiteStorage(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)