Plugin IMAP, plugin MAILDIR: added IMAP's UID management, mailbox data persistence

This commit is contained in:
Goffi 2011-01-17 04:23:31 +01:00
commit e14f357b95

View file

@ -62,10 +62,18 @@ class MaildirBox():
self.__observed={}
self.__mailboxes={}
self.data=host.memory.getPrivate("MAILDIR_data") or {"INBOX":{"cur_idx":0}}
#a value in the dictionnary for a mailbox is a dictionnary with the following value
# - cur_idx: value of the current unique integer increment (UID)
# - message_id (as returned by MaildirMailbox): a tuple of (UID, [flag1, flag2, ...])
#the trigger
host.trigger.add("MessageReceived", self.MessageReceivedTrigger)
def __destroy__(self):
debug('Destroying MaildirBox')
self.host.memory.setPrivate('MAILDIR_data',self.data)
def accessMessageBox(self, boxname, observer=None):
"""Create and return a MailboxUser instance
@param boxname: name of the box
@ -95,8 +103,109 @@ class MaildirBox():
if self.__mailboxes.has_key(boxname):
return self.__mailboxes[boxname]
def getUid(self, boxname, message_id):
"""Return an unique integer, always ascending, for a message
This is mainly needed for the IMAP protocol
@param boxname: name of the box where the message is
@param message_id: unique id of the message as given by MaildirMailbox
@return: Integer UID"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
if box_data.has_key(message_id):
ret = box_data[message_id][0]
else:
box_data['cur_idx']+=1
box_data[message_id]=(box_data['cur_idx'],[])
ret = box_data[message_id]
self.host.memory.setPrivate('MAILDIR_data',self.data)
return ret
def getNextUid(self, boxname):
"""Return next unique integer that will generated
This is mainly needed for the IMAP protocol
@param boxname: name of the box where the message is
@return: Integer UID"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
return box_data['cur_idx']+1
def getNextExistingUid(self, boxname, uid):
"""Give the next uid of existing message
@param boxname: name of the box where the message is
@param uid: uid to start from
@return: uid or None if the is no more message"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
idx=uid+1
while self.getIdfromUid(boxname, idx) == None: #TODO: this is highly inefficient because getIdfromUid is inefficient, fix this
idx+=1
if idx>box_data['cur_idx']:
return None
return idx
def getMaxUid(self, boxname):
"""Give the max existing uid
@param boxname: name of the box where the message is
@return: uid"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
return box_data['cur_idx']
def getIdfromUid(self, boxname, message_uid):
"""Return the message unique id from it's integer UID
@param boxname: name of the box where the message is
@param message_uid: unique integer identifier
@return: unique id of the message as given by MaildirMailbox or None if not found"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
for message_id in box_data.keys(): #TODO: this is highly inefficient on big mailbox, must be replaced in the future
if message_id == 'cur_idx':
continue
if box_data[message_id][0] == message_uid:
return message_id
return None
def cleanTable(self, boxname, existant_id):
"""Remove mails which no longuer exist from the table
@param boxname: name of the box to clean
@param existant_id: list of id which actually exist"""
try:
box_data = self.data[boxname] #the boxname MUST exist in the data
except KeyError:
err_msg=_("Boxname doesn't exist in internal data")
error(_("INTERNAL ERROR: ") + err_msg)
raise MaildirError(err_msg)
to_remove=[]
for key in box_data:
if key not in existant_id and key!="cur_idx":
to_remove.append(key)
for key in to_remove:
del box_data[key]
def MessageReceivedTrigger(self, message):
"""This trigger catch normal message and put the in the Maildir box.
If the message is not of "normal" type, do nothing
@ -187,10 +296,22 @@ class MailboxUser:
self.mailbox_path=mailbox_path
self.mailbox = maildir.MaildirMailbox(mailbox_path)
self.observer=observer
self.__uid_table_update()
if observer:
debug("adding observer for %s" % name)
self.maildir.addObserver(observer, name, "NEW_MESSAGE")
def __uid_table_update(self):
existant_id=[]
for mess_idx in range (self.getMessageCount()):
#we update the uid table
existant_id.append(self.getId(mess_idx))
self.getUid(mess_idx)
self.maildir.cleanTable(self.name, existant_id)
def __destroy__(self):
if observer:
debug("removing observer for %s" % self.name)
@ -204,7 +325,7 @@ class MailboxUser:
def emitSignal(self, ignore, signal):
"""Emit the signal to the observers"""
print ('self: %s, mailbox: %s, count: %i' % (self, self.mailbox, self.getMessageCount()))
self.getUid(self.getMessageCount()-1) #we make an uid for the last message added
self.maildir.emitSignal(self.name, signal)
def getId(self, mess_idx):
@ -212,12 +333,38 @@ class MailboxUser:
@mess_idx: message index"""
return self.mailbox.getUidl(mess_idx)
def getUid(self, mess_idx):
"""Return a unique interger id for the message, always ascending"""
mess_id=self.getId(mess_idx)
return self.maildir.getUid(self.name,mess_id)
def getNextUid(self):
return self.maildir.getNextUid(self.name)
def getNextExistingUid(self, uid):
return self.maildir.getNextExistingUid(self.name, uid)
def getMaxUid(self):
return self.maildir.getMaxUid(self.name)
def getMessageCount(self):
"""Return number of mails present in this box"""
print "count: %i" % len(self.mailbox.listMessages())
return len(self.mailbox.listMessages())
return len(self.mailbox.list)
def getMessageIdx(self, mess_idx):
"""Return the full message
@mess_idx: message index"""
return self.mailbox.getMessage(mess_idx)
def getMessage(self, mess_idx):
"""Return the full message
@mess_idx: message index"""
return self.mailbox.getMessage(mess_idx)
def getMessageUid(self, mess_uid):
"""Return the full message
@mess_idx: message unique identifier"""
for mess_idx in range (self.getMessageCount()):
if self.getUid(mess_idx) == mess_uid:
return self.mailbox.getMessage(mess_idx)
raise IndexError