Plugin IMAP, plugin MAILDIR: added IMAP's UID management, mailbox data persistence
This commit is contained in:
parent
5d051810cf
commit
e14f357b95
1 changed files with 171 additions and 10 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue