Store mailbox with "/" delimiter and discover when populating account what is the real delimiter

darcs-hash:20071031165547-86b55-50bb56e0db9ff77385656b126d7f0f2a02ff3d3a.gz
This commit is contained in:
David Rousselie
2007-10-31 17:55:47 +01:00
parent e24224c873
commit 511e4916c3
4 changed files with 150 additions and 39 deletions

View File

@@ -56,9 +56,11 @@ class MailAccountManager(AccountManager):
from_jid, from_jid,
account_type, account_type,
lang_class): lang_class):
"""Handle get_register on an IMAP account. """
Handle get_register on an IMAP account.
Return a preinitialized form. Return a preinitialized form.
account_type contains 'account_type + imap_dir'""" account_type contains 'account_type + imap_dir'
"""
splitted_node = account_type.split("/") splitted_node = account_type.split("/")
splitted_node_len = len(splitted_node) splitted_node_len = len(splitted_node)
if splitted_node_len == 1 or \ if splitted_node_len == 1 or \
@@ -71,6 +73,7 @@ class MailAccountManager(AccountManager):
else: else:
info_query = info_query.make_result_response() info_query = info_query.make_result_response()
model.db_connect() model.db_connect()
# TODO : "/" is default, "." could be
imap_dir = "/".join(splitted_node[1:]) imap_dir = "/".join(splitted_node[1:])
bare_from_jid = from_jid.bare() bare_from_jid = from_jid.bare()
_account = account.get_account_filter(\ _account = account.get_account_filter(\
@@ -80,17 +83,20 @@ class MailAccountManager(AccountManager):
account_class=IMAPAccount) account_class=IMAPAccount)
query = info_query.new_query("jabber:iq:register") query = info_query.new_query("jabber:iq:register")
if _account is not None: if _account is not None:
# update account
result = self.generate_registration_form_init(lang_class, result = self.generate_registration_form_init(lang_class,
_account) _account)
else: else:
_account = account.get_account(bare_from_jid, name, _account = account.get_account(bare_from_jid, name,
IMAPAccount) IMAPAccount)
if _account is not None: if _account is not None:
# create new account based on current one
result = self.generate_registration_form_init(lang_class, result = self.generate_registration_form_init(lang_class,
_account) _account)
result["name"].value = None result["name"].value = None
result["name"].type = "text-single" result["name"].type = "text-single"
else: else:
# create new account from scratch
result = self.generate_registration_form(\ result = self.generate_registration_form(\
lang_class, lang_class,
IMAPAccount, IMAPAccount,

View File

@@ -137,17 +137,17 @@ class Lang(jcl.lang.Lang):
send_mail_ok_body = u"Votre email a été envoyé à %s." send_mail_ok_body = u"Votre email a été envoyé à %s."
help_message_body = u"Pour envoyer un email avec JMC, vous avez le choix " \ help_message_body = u"Pour envoyer un email avec JMC, vous avez le choix " \
+ "entre :\n" \ + u"entre :\n" \
+ " - Envoyer un message à la passerelle JMC: le sujet de l'email" \ + u" - Envoyer un message à la passerelle JMC: le sujet de l'email" \
+ " sera le sujet du message Jabber ou le sujet spécifié avec la " \ + u" sera le sujet du message Jabber ou le sujet spécifié avec la " \
+ "syntaxe suivant dans le corps du message Jabber :\n" \ + u"syntaxe suivant dans le corps du message Jabber :\n" \
+ "\tSubject: votre sujet\n" \ + u"\tSubject: votre sujet\n" \
+ " Pour spécifier les destinataires de l'email, il faut ajouter une" \ + u" Pour spécifier les destinataires de l'email, il faut ajouter une" \
+ " ligne au corps du message Jabber avec la syntaxe suivante:\n" \ + u" ligne au corps du message Jabber avec la syntaxe suivante:\n" \
+ "\tTo: to_email@test.com\n\n" \ + u"\tTo: to_email@test.com\n\n" \
+ " - Ajouter un contact à votre roster, avec comme JID " \ + u" - Ajouter un contact à votre roster, avec comme JID " \
+ "to_email\%test.com@jmc.test.com, où to_email@test.com est " \ + u"to_email\%test.com@jmc.test.com, où to_email@test.com est " \
+ "l'adresse du destinataire." + u"l'adresse du destinataire."
class nl(jcl.lang.Lang.nl): class nl(jcl.lang.Lang.nl):
# TODO: when finish, delete this line and uncomment in tests/lang.py the makeSuite(Language_nl_TestCase, 'test') line # TODO: when finish, delete this line and uncomment in tests/lang.py the makeSuite(Language_nl_TestCase, 'test') line

View File

@@ -373,6 +373,7 @@ class MailAccount(PresenceAccount):
class IMAPAccount(MailAccount): class IMAPAccount(MailAccount):
mailbox = StringCol(default="INBOX") mailbox = StringCol(default="INBOX")
delimiter = StringCol(default=".")
def _get_register_fields(cls, real_class=None): def _get_register_fields(cls, real_class=None):
"""See Account._get_register_fields """See Account._get_register_fields
@@ -397,13 +398,19 @@ class IMAPAccount(MailAccount):
self.__logger = logging.getLogger("jmc.IMAPConnection") self.__logger = logging.getLogger("jmc.IMAPConnection")
self._regexp_list = re.compile("\((.*)\) \"(.)\" \"?([^\"]*)\"?$") self._regexp_list = re.compile("\((.*)\) \"(.)\" \"?([^\"]*)\"?$")
self.__cached_folders = {} self.__cached_folders = {}
self.default_delimiter = "."
def get_type(self): def get_type(self):
if self.ssl: if self.ssl:
return "imaps" return "imaps"
return "imap" return "imap"
def _get_real_mailbox(self):
"""
mailbox attribute is stored with "/" to delimit folders.
real mailbox is the folder with the delimiter used by the IMAP server
"""
return self.mailbox.replace("/", self.delimiter)
def get_status(self): def get_status(self):
return MailAccount.get_status(self) + "/" + self.mailbox return MailAccount.get_status(self) + "/" + self.mailbox
@@ -427,7 +434,7 @@ class IMAPAccount(MailAccount):
def get_mail_list(self): def get_mail_list(self):
self.__logger.debug("Getting mail list") self.__logger.debug("Getting mail list")
typ, data = self.connection.select(self.mailbox) typ, data = self.connection.select(self._get_real_mailbox())
typ, data = self.connection.search(None, 'RECENT') typ, data = self.connection.search(None, 'RECENT')
if typ == 'OK': if typ == 'OK':
return data[0].split(' ') return data[0].split(' ')
@@ -476,8 +483,8 @@ class IMAPAccount(MailAccount):
for line in data: for line in data:
match = self._regexp_list.match(line) match = self._regexp_list.match(line)
if match is not None: if match is not None:
self.default_delimiter = match.group(2) delimiter = match.group(2)
subdir = match.group(3).split(self.default_delimiter) subdir = match.group(3).split(delimiter)
self._add_full_path_to_cache(subdir) self._add_full_path_to_cache(subdir)
return self.__cached_folders return self.__cached_folders
@@ -485,7 +492,6 @@ class IMAPAccount(MailAccount):
""" """
imap_dir: IMAP directory to list. subdirs must be delimited by '/' imap_dir: IMAP directory to list. subdirs must be delimited by '/'
""" """
# TODO : implement with cache (ie. only one connection)
self.__logger.debug("Listing IMAP dir '" + str(imap_dir) + "'") self.__logger.debug("Listing IMAP dir '" + str(imap_dir) + "'")
if self.__cached_folders == {}: if self.__cached_folders == {}:
if not self.connected: if not self.connected:
@@ -504,6 +510,31 @@ class IMAPAccount(MailAccount):
current_folder = current_folder[folder] current_folder = current_folder[folder]
return current_folder.keys() return current_folder.keys()
def populate_handler(self):
"""
Handler called when populating account
"""
# Get delimiter
if not self.connected:
self.connect()
typ, data = self.connection.list(self.mailbox)
if typ == 'OK':
line = data[0]
match = self._regexp_list.match(line)
if match is not None:
self.delimiter = match.group(2)
else:
self.disconnect()
raise Exception("Cannot find mailbox " + self.mailbox)
else:
self.disconnect()
raise Exception("Cannot find mailbox " + self.mailbox)
self.disconnect()
# replace any previous delimiter in self.mailbox by "/"
if self.delimiter != "/":
self.mailbox = self.mailbox.replace(self.delimiter, "/")
class POP3Account(MailAccount): class POP3Account(MailAccount):
nb_mail = IntCol(default=0) nb_mail = IntCol(default=0)
lastmail = IntCol(default=0) lastmail = IntCol(default=0)

View File

@@ -242,8 +242,8 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
self.imap_account.ssl = False self.imap_account.ssl = False
self.account_class = IMAPAccount self.account_class = IMAPAccount
def make_test(responses=None, queries=None, core=None): def make_test(self, responses=None, queries=None, core=None):
def inner(self): def inner():
self.server = server.DummyServer("localhost", 1143) self.server = server.DummyServer("localhost", 1143)
thread.start_new_thread(self.server.serve, ()) thread.start_new_thread(self.server.serve, ())
self.server.responses = ["* OK [CAPABILITY IMAP4 LOGIN-REFERRALS " + \ self.server.responses = ["* OK [CAPABILITY IMAP4 LOGIN-REFERRALS " + \
@@ -261,6 +261,7 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
if queries: if queries:
self.server.queries += queries self.server.queries += queries
self.server.queries += ["^[^ ]* LOGOUT"] self.server.queries += ["^[^ ]* LOGOUT"]
if not self.imap_account.connected:
self.imap_account.connect() self.imap_account.connect()
self.failUnless(self.imap_account.connection, \ self.failUnless(self.imap_account.connection, \
"Cannot establish connection") "Cannot establish connection")
@@ -268,13 +269,17 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
model.db_connect() model.db_connect()
core(self) core(self)
model.db_disconnect() model.db_disconnect()
if self.imap_account.connected:
self.imap_account.disconnect() self.imap_account.disconnect()
self.failUnless(self.server.verify_queries()) self.failUnless(self.server.verify_queries())
return inner return inner
test_connection = make_test() def test_connection(self):
test_func = self.make_test()
test_func()
test_get_mail_list = make_test([lambda data: "* 42 EXISTS\n* 1 RECENT\n* OK" +\ def test_get_mail_list(self):
test_func = self.make_test([lambda data: "* 42 EXISTS\n* 1 RECENT\n* OK" +\
" [UNSEEN 9]\n* FLAGS (\Deleted \Seen\*)\n*" +\ " [UNSEEN 9]\n* FLAGS (\Deleted \Seen\*)\n*" +\
" OK [PERMANENTFLAGS (\Deleted \Seen\*)\n" + \ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\n" + \
data.split()[0] + \ data.split()[0] + \
@@ -285,22 +290,60 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
"^[^ ]* SEARCH RECENT"], \ "^[^ ]* SEARCH RECENT"], \
lambda self: \ lambda self: \
self.assertEquals(self.imap_account.get_mail_list(), ['9', '10'])) self.assertEquals(self.imap_account.get_mail_list(), ['9', '10']))
test_func()
test_get_mail_summary = make_test([lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\ def test_get_mail_list_delimiter1(self):
self.imap_account.mailbox = "INBOX/dir1/subdir2"
self.imap_account.delimiter = "."
test_func = self.make_test( \
[lambda data: "* 42 EXISTS\n* 1 RECENT\n* OK" + \
" [UNSEEN 9]\n* FLAGS (\Deleted \Seen\*)\n*" + \
" OK [PERMANENTFLAGS (\Deleted \Seen\*)\n" + \
data.split()[0] + \
" OK [READ-WRITE] SELECT completed\n", \
lambda data: "* SEARCH 9 10 \n" + \
data.split()[0] + " OK SEARCH completed\n"], \
["^[^ ]* SELECT \"?INBOX\.dir1\.subdir2\"?",
"^[^ ]* SEARCH RECENT"], \
lambda self: \
self.assertEquals(self.imap_account.get_mail_list(), ['9', '10']))
test_func()
def test_get_mail_list_delimiter2(self):
self.imap_account.mailbox = "INBOX/dir1/subdir2"
self.imap_account.delimiter = "/"
test_func = self.make_test( \
[lambda data: "* 42 EXISTS\n* 1 RECENT\n* OK" + \
" [UNSEEN 9]\n* FLAGS (\Deleted \Seen\*)\n*" + \
" OK [PERMANENTFLAGS (\Deleted \Seen\*)\n" + \
data.split()[0] + \
" OK [READ-WRITE] SELECT completed\n", \
lambda data: "* SEARCH 9 10 \n" + \
data.split()[0] + " OK SEARCH completed\n"], \
["^[^ ]* SELECT \"?INBOX/dir1/subdir2\"?",
"^[^ ]* SEARCH RECENT"], \
lambda self: \
self.assertEquals(self.imap_account.get_mail_list(), ['9', '10']))
test_func()
def test_get_mail_summary(self):
test_func = self.make_test([lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
" [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
" OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
data.split()[0] + \ data.split()[0] + \
" OK [READ-WRITE] SELECT completed\r\n", \ " OK [READ-WRITE] SELECT completed\r\n", \
lambda data: "* 1 FETCH ((RFC822) {12}\r\nbody" + \ lambda data: "* 1 FETCH ((RFC822) {12}\r\nbody" + \
" text\r\n)\r\n" + \ " text\r\n)\r\n" + \
data.split()[0] + " OK FETCH completed\r\n"], \ data.split()[0] + " OK FETCH completed\r\n"],
["^[^ ]* EXAMINE INBOX", \ ["^[^ ]* EXAMINE INBOX",
"^[^ ]* FETCH 1 \(RFC822\)"], \ "^[^ ]* FETCH 1 \(RFC822\)"],
lambda self: self.assertEquals(self.imap_account.get_mail_summary(1), \ lambda self: self.assertEquals(self.imap_account.get_mail_summary(1),
(u"From : None\nSubject : None\n\n", \ (u"From : None\nSubject : None\n\n",
u"None"))) u"None")))
test_func()
test_get_mail = make_test([lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\ def test_get_mail(self):
test_func = self.make_test([lambda data: "* 42 EXISTS\r\n* 1 RECENT\r\n* OK" +\
" [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\ " [UNSEEN 9]\r\n* FLAGS (\Deleted \Seen\*)\r\n*" +\
" OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \ " OK [PERMANENTFLAGS (\Deleted \Seen\*)\r\n" + \
data.split()[0] + \ data.split()[0] + \
@@ -313,8 +356,10 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
lambda self: self.assertEquals(self.imap_account.get_mail(1), \ lambda self: self.assertEquals(self.imap_account.get_mail(1), \
(u"From : None\nSubject : None\n\nbody text\r\n\n", \ (u"From : None\nSubject : None\n\nbody text\r\n\n", \
u"None"))) u"None")))
test_func()
test_build_folder_cache = make_test(\ def test_build_folder_cache(self):
test_func = self.make_test(\
[lambda data: '* LIST () "." "INBOX"\r\n' + \ [lambda data: '* LIST () "." "INBOX"\r\n' + \
'* LIST () "." "INBOX.dir1"\r\n' + \ '* LIST () "." "INBOX.dir1"\r\n' + \
'* LIST () "." "INBOX.dir1.subdir1"\r\n' + \ '* LIST () "." "INBOX.dir1.subdir1"\r\n' + \
@@ -328,6 +373,7 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
{"subdir1": {}, {"subdir1": {},
"subdir2": {}}, "subdir2": {}},
"dir2": {}}})) "dir2": {}}}))
test_func()
def test_ls_dir_base(self): def test_ls_dir_base(self):
self.test_build_folder_cache() self.test_build_folder_cache()
@@ -356,6 +402,34 @@ class IMAPAccount_TestCase(InheritableAccount_TestCase):
self.assertEquals(result, self.assertEquals(result,
["subdir1", "subdir2"]) ["subdir1", "subdir2"])
def test_populate_handler(self):
self.assertEquals(".", self.imap_account.delimiter)
self.imap_account.mailbox = "INBOX.dir1.subdir2"
def call_func(self):
self.imap_account.populate_handler()
self.assertEquals("INBOX/dir1/subdir2", self.imap_account.mailbox)
test_func = self.make_test(\
[lambda data: '* LIST () "." "INBOX.dir1.subdir2"\r\n' + \
data.split()[0] + ' OK LIST completed\r\n'],
["^[^ ]* LIST \"?INBOX.dir1.subdir2\"? \*"],
call_func)
test_func()
def test_populate_handler_wrong_mailbox(self):
self.assertEquals(".", self.imap_account.delimiter)
self.imap_account.mailbox = "INBOX.dir1.subdir2"
def call_func(self):
try:
self.imap_account.populate_handler()
except Exception, e:
return
self.fail("Exception should have been raised")
test_func = self.make_test(\
[lambda data: data.split()[0] + ' ERR LIST completed\r\n'],
["^[^ ]* LIST \"?INBOX.dir1.subdir2\"? \*"],
call_func)
test_func()
class SMTPAccount_TestCase(Account_TestCase): class SMTPAccount_TestCase(Account_TestCase):
def setUp(self): def setUp(self):
JCLTestCase.setUp(self, tables=[Account, ExampleAccount, User, JCLTestCase.setUp(self, tables=[Account, ExampleAccount, User,