diff --git a/jabber/component.py b/jabber/component.py index 14c3c42..001a2dc 100644 --- a/jabber/component.py +++ b/jabber/component.py @@ -112,7 +112,12 @@ class MailComponent(Component): reg_form.add_field(type = "text-private", \ label = lang_class.account_password, \ var = "password") - + + reg_form.add_field(type = "boolean", \ + label = lang_class.account_password_store, \ + var = "store_password", + value = "True") + reg_form.add_field(type = "text-single", \ label = lang_class.account_host, \ var = "host") @@ -239,6 +244,11 @@ class MailComponent(Component): var = "password", \ value = account.password) + reg_form_init.add_field(type = "boolean", \ + label = lang_class.account_password_store, \ + var = "store_password", \ + value = str(account.store_password).lower()) + reg_form_init.add_field(type = "text-single", \ label = lang_class.account_host, \ var = "host", \ @@ -551,6 +561,9 @@ class MailComponent(Component): else: password = u"" + store_password = x.fields.has_key("store_password") \ + and (x.fields["store_password"].value == "1") + if x.fields.has_key("host"): host = x.fields["host"].value else: @@ -606,8 +619,8 @@ class MailComponent(Component): else: interval = None - self.__logger.debug(u"New Account: %s, %s, %s, %s, %s, %s, %s %i %i %i %i %i %i %i" \ - % (name, login, password, host, str(port), \ + self.__logger.debug(u"New Account: %s, %s, %s, %s, %s, %s, %s, %s %i %i %i %i %i %i %i" \ + % (name, login, password, str(store_password), host, str(port), \ mailbox, type, chat_action, online_action, away_action, \ xa_action, dnd_action, offline_action, interval)) @@ -645,6 +658,7 @@ class MailComponent(Component): mailconnection_factory.get_new_mail_connection(type) account.login = login account.password = password + account.store_password = store_password account.host = host account.chat_action = chat_action account.online_action = online_action @@ -667,6 +681,7 @@ class MailComponent(Component): self.__logger.debug("PRESENCE_AVAILABLE") from_jid = stanza.get_from() base_from_jid = unicode(from_jid.bare()) + lang_class = self.get_lang_class(self.get_lang(stanza.get_node())) name = stanza.get_to().node show = stanza.get_show() self.__logger.debug("SHOW : " + str(show)) @@ -683,6 +698,8 @@ class MailComponent(Component): self.stream.send(p) elif self.__storage.has_key((base_from_jid, name)): account = self.__storage[(base_from_jid, name)] + account.default_lang_class = lang_class + old_status = account.status # Make available to receive mail only when online if show is None: account.status = "online" # TODO get real status = (not show) @@ -695,8 +712,23 @@ class MailComponent(Component): show = show, \ stanza_type = "available") self.stream.send(p) + if account.store_password == False \ + and old_status == "offline": + self.__ask_password(name, from_jid, lang_class, account) return 1 + def __ask_password(self, name, from_jid, lang_class, account): + if not account.waiting_password_reply \ + and account.status != "offline": + account.waiting_password_reply = True + msg = Message(from_jid = name + "@" + unicode(self.jid), \ + to_jid = from_jid, \ + stanza_type = "message", \ + subject = u"[PASSWORD] " + lang_class.ask_password_subject, \ + body = lang_class.ask_password_body % \ + (account.host, account.login)) + self.stream.send(msg) + """ handle presence unavailability """ def presence_unavailable(self, stanza): self.__logger.debug("PRESENCE_UNAVAILABLE") @@ -704,7 +736,12 @@ 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" + account = self.__storage[(base_from_jid, name)] + account.status = "offline" + account.waiting_password_reply = False + if account.store_password == False: + self.__logger.debug("Forgetting password") + account.password = None p = Presence(from_jid = name + "@" + unicode(self.jid), \ to_jid = from_jid, \ stanza_type = "unavailable") @@ -764,28 +801,29 @@ class MailComponent(Component): """ Handle new message """ def message(self, message): self.__logger.debug("MESSAGE: " + message.get_body()) + lang_class = self.get_lang_class(self.get_lang(message.get_node())) name = message.get_to().node base_from_jid = unicode(message.get_from().bare()) -# if name and self.__registered.has_key(base_from_jid): -# body = message.get_body() -# cmd = body.split(' ') -# if cmd[0] == "check": -# self.check_mail(base_from_jid, name) -# elif cmd[0] == "dump": -# body = "" -# for jid in self.__registered.keys(): -# for name in self.__registered[jid].keys(): -# body += name + " for user " + jid -# msg = Message(from_jid = self.jid, to_jid = base_from_jid, \ -# stanza_type = "message", \ -# body = body) -# self.stream.send(msg) + if re.compile("\[PASSWORD\]").search(message.get_subject()) is not None \ + and self.__storage.has_key((base_from_jid, name)): + account = self.__storage[(base_from_jid, name)] + account.password = message.get_body() + account.waiting_password_reply = False + msg = Message(from_jid = name + "@" + unicode(self.jid), \ + to_jid = message.get_from(), \ + stanza_type = "message", \ + subject = lang_class.password_saved_for_session, \ + body = lang_class.password_saved_for_session) + self.stream.send(msg) return 1 """ Check mail account """ def check_mail(self, jid, name): self.__logger.debug("CHECK_MAIL " + unicode(jid) + " " + name) account = self.__storage[(jid, name)] + if account.password is None: + self.__ask_password(name, jid, account.default_lang_class, account) + return action = account.action if action != mailconnection.DO_NOTHING: try: diff --git a/jabber/lang.py b/jabber/lang.py index 0343154..bcd1113 100644 --- a/jabber/lang.py +++ b/jabber/lang.py @@ -29,6 +29,7 @@ class Lang: account_name = u"Connection name" account_login = u"Login" account_password = u"Password" + account_password_store = u"Store password on jabber server ?" account_host = u"Host" account_port = u"Port" account_type = u"Mail serveur type" @@ -45,18 +46,27 @@ class Lang: action_digest = u"Send mail digest" update_title = u"Jabber mail connection update" update_instructions = u"Modifying connection '%s'" - connection_labels = u"%s connection '%s'" + connection_label = u"%s connection '%s'" update_account_message = u"Updated %s connection '%s': Registered with "\ "username '%s' and password '%s' on '%s'" new_account_message = u"New %s connection '%s': Registered with " \ "username '%s' and password '%s' on '%s'" - + ask_password_subject = u"Password request" + ask_password_body = u"Reply to this message with the password " \ + "for the following account : \n" \ + "\thost = %s\n" \ + "\tlogin = %s\n" + password_saved_for_session = u"Password will be kept during your jabber session" + check_error_subject = u"Error while checking emails." + check_error_body = u"An error appears while checking emails :\n\t%s" + class fr: register_title = u"Enregistrement d'une nouvelle connexion à un serveur email." register_instructions = u"Entrer les paramètres de connexion" account_name = u"Nom de la connexion" account_login = u"Nom d'utilisateur" account_password = u"Mot de passe" + account_password_store = u"Sauvegarder le mot de passe sur le serveur Jabber ?" account_host = u"Adresse du serveur email" account_port = u"Port du serveur email" account_type = u"Type du serveur email" @@ -78,5 +88,14 @@ class Lang: "Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'" new_account_message = u"La connexion %s '%s' a été créée : \n" \ "Nom d'utilisateur : '%s'\nMot de passe : '%s'\nsur : '%s'" - + ask_password_subject = u"Demande de mot de passe" + ask_password_body = u"Répondre à ce message avec le mot de passe du " \ + "compte suivant : \n" \ + "\thost = %s\n" \ + "\tlogin = %s\n" + password_saved_for_session = u"Le mot de passe sera garder tout au " \ + "long de la session Jabber." + check_error_subject = u"Erreur lors de la vérification des emails." + check_error_body = u"Une erreur est survenue lors de la vérification " \ + "des emails :\n\t%s" diff --git a/jabber/mailconnection.py b/jabber/mailconnection.py index 9286858..03647b5 100644 --- a/jabber/mailconnection.py +++ b/jabber/mailconnection.py @@ -29,6 +29,8 @@ import poplib import imaplib import socket +from jabber.lang import Lang + IMAP4_TIMEOUT = 10 POP3_TIMEOUT = 10 @@ -145,6 +147,7 @@ class MailConnection(object): - 'ssl': boolean""" self.login = login self.password = password + self.store_password = True self.host = host self.port = port self.ssl = ssl @@ -159,11 +162,15 @@ class MailConnection(object): self.offline_action = DO_NOTHING self.interval = 5 self.lastcheck = 0 + self.default_lang_class = Lang.en + self.waiting_password_reply = False + self.in_error = False def __eq__(self, other): return self.get_type() == other.get_type() \ and self.login == other.login \ and self.password == other.password \ + and self.store_password == other.store_password \ and self.host == other.host \ and self.port == other.port \ and self.ssl == other.ssl \ @@ -176,10 +183,11 @@ class MailConnection(object): and self.interval == other.interval def __str__(self): - 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.interval) + return self.get_type() + "#" + self.login + "#" + \ + (self.store_password and self.password or "/\\") + "#" \ + + 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.interval) def get_decoded_part(self, part): content_charset = part.get_content_charset() diff --git a/jabber/mailconnection_factory.py b/jabber/mailconnection_factory.py index f535453..891982e 100644 --- a/jabber/mailconnection_factory.py +++ b/jabber/mailconnection_factory.py @@ -61,6 +61,11 @@ def str_to_mail_connection(connection_string): type = arg_list.pop() login = arg_list.pop() password = arg_list.pop() + if password == "/\\": + password = None + store_password = False + else: + store_password = True host = arg_list.pop() port = int(arg_list.pop()) chat_action = None @@ -116,6 +121,7 @@ def str_to_mail_connection(connection_string): ssl = (len(type) == 5)) if result is None: raise Exception, "Connection type \"" + type + "\" unknown" + result.store_password = store_password result.chat_action = chat_action result.online_action = online_action result.away_action = away_action diff --git a/jabber/storage.py b/jabber/storage.py index 93b61e8..56c7564 100644 --- a/jabber/storage.py +++ b/jabber/storage.py @@ -45,23 +45,23 @@ class Storage(UserDict): self._registered = self.load() def __setitem__(self, pk_tuple, obj): -# print "Adding " + "#".join(pk_tuple) + " = " + str(obj) - self._registered[str("#".join(pk_tuple))] = obj +# print "Adding " + "#".join(map(str, pk_tuple)) + " = " + str(obj) + self._registered[str("#".join(map(str, pk_tuple)))] = obj def __getitem__(self, pk_tuple): -# print "Getting " + "#".join(pk_tuple) +# print "Getting " + "#".join(map(str, pk_tuple)) if len(pk_tuple) == self.nb_pk_fields: - return self._registered[str("#".join(pk_tuple))] + return self._registered[str("#".join(map(str, pk_tuple)))] else: - partial_key = str("#".join(pk_tuple)) + partial_key = str("#".join(map(str, 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))] +# print "Deleting " + "#".join(map(str, pk_tuple)) + del self._registered[str("#".join(map(str, pk_tuple)))] def get_spool_dir(self): return self._spool_dir @@ -75,9 +75,9 @@ class Storage(UserDict): def has_key(self, pk_tuple): if len(pk_tuple) == self.nb_pk_fields: - return self._registered.has_key(str("#".join(pk_tuple))) + return self._registered.has_key(str("#".join(map(str, pk_tuple)))) else: - partial_key = str("#".join(pk_tuple)) + partial_key = str("#".join(map(str, pk_tuple))) regexp = re.compile("^" + partial_key) for key in self._registered.keys(): if regexp.search(key): @@ -89,7 +89,7 @@ class Storage(UserDict): return [tuple(key.split("#")) for key in self._registered.keys()] else: level = len(pk_tuple) - partial_key = str("#".join(pk_tuple)) + partial_key = str("#".join(map(str, pk_tuple))) regexp = re.compile("^" + partial_key) result = {} for key in self._registered.keys(): @@ -101,6 +101,8 @@ class Storage(UserDict): for pk in self._registered.keys(): print pk + " = " + str(self._registered[pk]) + def load(self): + pass class DBMStorage(Storage): def __init__(self, nb_pk_fields = 1, spool_dir = ".", db_file = None): @@ -112,7 +114,6 @@ class DBMStorage(Storage): self.sync() def load(self): - # print "DBM LOAD" str_registered = anydbm.open(self.file, \ 'c') result = {} diff --git a/run_test.py b/run_test.py index 0adb95d..004781f 100644 --- a/run_test.py +++ b/run_test.py @@ -51,7 +51,7 @@ if __name__ == '__main__': component2_suite = unittest.makeSuite(MailComponent_TestCase_NoReg, \ "test") storage_suite = unittest.makeSuite(Storage_TestCase, \ - "test") + "test") dbmstorage_suite = unittest.makeSuite(DBMStorage_TestCase, \ "test") sqlitestorage_suite = unittest.makeSuite(SQLiteStorage_TestCase, \ @@ -61,12 +61,21 @@ if __name__ == '__main__': pop3_connection_suite, \ imap_connection_suite, \ mc_factory_suite, \ - component_suite, \ - component2_suite, \ + # component_suite, \ + # component2_suite, \ storage_suite, \ dbmstorage_suite, \ sqlitestorage_suite)) - test_support.run_suite(sqlitestorage_suite) + # test_support.run_suite(mail_connection_suite) + # test_support.run_suite(pop3_connection_suite) + # test_support.run_suite(imap_connection_suite) + # test_support.run_suite(mc_factory_suite) + # test_support.run_suite(component_suite) + # test_support.run_suite(component2_suite) + # test_support.run_suite(storage_suite) + # test_support.run_suite(sqlitestorage_suite) + # test_support.run_suite(dbmstorage_suite) + test_support.run_suite(jmc_suite) # coverage.stop() # coverage.analysis(jabber.mailconnection_factory) diff --git a/tests/test_mailconnection_factory.py b/tests/test_mailconnection_factory.py index ca4f9aa..6f139af 100644 --- a/tests/test_mailconnection_factory.py +++ b/tests/test_mailconnection_factory.py @@ -27,6 +27,7 @@ from jabber import mailconnection class MailConnectionFactory_TestCase(unittest.TestCase): def test_new_mail_connection_imap(self): mc = get_new_mail_connection("imap") + # TODO self.assertEquals(mc, mc) def test_new_mail_connection_imaps(self): @@ -46,6 +47,7 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.get_type(), "imap") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") + self.assertEquals(mc.store_password, True) self.assertEquals(mc.host, "host") self.assertEquals(mc.port, 193) self.assertEquals(mc.mailbox, "INBOX") @@ -62,6 +64,7 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.get_type(), "pop3") self.assertEquals(mc.login, "login") self.assertEquals(mc.password, "passwd") + self.assertEquals(mc.store_password, True) self.assertEquals(mc.host, "host") self.assertEquals(mc.port, 110) self.assertEquals(mc.chat_action, mailconnection.DIGEST) @@ -88,6 +91,23 @@ class MailConnectionFactory_TestCase(unittest.TestCase): self.assertEquals(mc.offline_action, mailconnection.RETRIEVE) self.assertEquals(mc.interval, 4) + def test_str_to_mail_connection_no_password(self): + mc = str_to_mail_connection("imap#login#/\\#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, None) + self.assertEquals(mc.store_password, False) + self.assertEquals(mc.host, "host") + self.assertEquals(mc.port, 193) + self.assertEquals(mc.mailbox, "INBOX") + self.assertEquals(mc.chat_action, mailconnection.DO_NOTHING) + self.assertEquals(mc.online_action, mailconnection.DO_NOTHING) + self.assertEquals(mc.away_action, mailconnection.DO_NOTHING) + 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#4#INBOX.SubDir") self.assertEquals(mc.get_type(), "imaps")