comparison src/plugins/plugin_misc_maildir.py @ 255:55b750017b71

plugin IMAP, plugin Maildir: added flag, IMAP's uid management
author Goffi <goffi@goffi.org>
date Mon, 17 Jan 2011 21:26:16 +0100
parents 9fc32d1d9046
children 012c38b56cdd
comparison
equal deleted inserted replaced
254:9fc32d1d9046 255:55b750017b71
68 # - message_id (as returned by MaildirMailbox): a tuple of (UID, [flag1, flag2, ...]) 68 # - message_id (as returned by MaildirMailbox): a tuple of (UID, [flag1, flag2, ...])
69 69
70 #the trigger 70 #the trigger
71 host.trigger.add("MessageReceived", self.MessageReceivedTrigger) 71 host.trigger.add("MessageReceived", self.MessageReceivedTrigger)
72 72
73 def __destroy__(self): 73 def __del__(self):
74 debug('Destroying MaildirBox') 74 debug('Destroying MaildirBox')
75 self.host.memory.setPrivate('MAILDIR_data',self.data) 75 self.host.memory.setPrivate('MAILDIR_data',self.data)
76 76
77 def accessMessageBox(self, boxname, observer=None): 77 def accessMessageBox(self, boxname, observer=None):
78 """Create and return a MailboxUser instance 78 """Create and return a MailboxUser instance
101 @param boxname: name of the box to check 101 @param boxname: name of the box to check
102 @return: MailboxUser instance or None""" 102 @return: MailboxUser instance or None"""
103 if self.__mailboxes.has_key(boxname): 103 if self.__mailboxes.has_key(boxname):
104 return self.__mailboxes[boxname] 104 return self.__mailboxes[boxname]
105 105
106 def getUid(self, boxname, message_id): 106 def __getBoxData(self, boxname):
107 """Return an unique integer, always ascending, for a message 107 """Return the date of a box"""
108 This is mainly needed for the IMAP protocol
109 @param boxname: name of the box where the message is
110 @param message_id: unique id of the message as given by MaildirMailbox
111 @return: Integer UID"""
112 try: 108 try:
113 box_data = self.data[boxname] #the boxname MUST exist in the data 109 return self.data[boxname] #the boxname MUST exist in the data
114 except KeyError: 110 except KeyError:
115 err_msg=_("Boxname doesn't exist in internal data") 111 err_msg=_("Boxname doesn't exist in internal data")
116 error(_("INTERNAL ERROR: ") + err_msg) 112 error(_("INTERNAL ERROR: ") + err_msg)
117 raise MaildirError(err_msg) 113 raise MaildirError(err_msg)
114
115 def getUid(self, boxname, message_id):
116 """Return an unique integer, always ascending, for a message
117 This is mainly needed for the IMAP protocol
118 @param boxname: name of the box where the message is
119 @param message_id: unique id of the message as given by MaildirMailbox
120 @return: Integer UID"""
121 box_data = self.__getBoxData(boxname)
118 if box_data.has_key(message_id): 122 if box_data.has_key(message_id):
119 ret = box_data[message_id][0] 123 ret = box_data[message_id][0]
120 else: 124 else:
121 box_data['cur_idx']+=1 125 box_data['cur_idx']+=1
122 box_data[message_id]=(box_data['cur_idx'],[]) 126 box_data[message_id]=[box_data['cur_idx'],[]]
123 ret = box_data[message_id] 127 ret = box_data[message_id]
124 self.host.memory.setPrivate('MAILDIR_data',self.data) 128 self.host.memory.setPrivate('MAILDIR_data',self.data)
125 return ret 129 return ret
126 130
127
128 def getNextUid(self, boxname): 131 def getNextUid(self, boxname):
129 """Return next unique integer that will generated 132 """Return next unique integer that will generated
130 This is mainly needed for the IMAP protocol 133 This is mainly needed for the IMAP protocol
131 @param boxname: name of the box where the message is 134 @param boxname: name of the box where the message is
132 @return: Integer UID""" 135 @return: Integer UID"""
133 try: 136 box_data = self.__getBoxData(boxname)
134 box_data = self.data[boxname] #the boxname MUST exist in the data
135 except KeyError:
136 err_msg=_("Boxname doesn't exist in internal data")
137 error(_("INTERNAL ERROR: ") + err_msg)
138 raise MaildirError(err_msg)
139 return box_data['cur_idx']+1 137 return box_data['cur_idx']+1
140 138
141 def getNextExistingUid(self, boxname, uid): 139 def getNextExistingUid(self, boxname, uid):
142 """Give the next uid of existing message 140 """Give the next uid of existing message
143 @param boxname: name of the box where the message is 141 @param boxname: name of the box where the message is
144 @param uid: uid to start from 142 @param uid: uid to start from
145 @return: uid or None if the is no more message""" 143 @return: uid or None if the is no more message"""
146 try: 144 box_data = self.__getBoxData(boxname)
147 box_data = self.data[boxname] #the boxname MUST exist in the data
148 except KeyError:
149 err_msg=_("Boxname doesn't exist in internal data")
150 error(_("INTERNAL ERROR: ") + err_msg)
151 raise MaildirError(err_msg)
152 idx=uid+1 145 idx=uid+1
153 while self.getIdfromUid(boxname, idx) == None: #TODO: this is highly inefficient because getIdfromUid is inefficient, fix this 146 while self.getIdFromUid(boxname, idx) == None: #TODO: this is highly inefficient because getIdfromUid is inefficient, fix this
154 idx+=1 147 idx+=1
155 if idx>box_data['cur_idx']: 148 if idx>box_data['cur_idx']:
156 return None 149 return None
157 return idx 150 return idx
158 151
159 def getMaxUid(self, boxname): 152 def getMaxUid(self, boxname):
160 """Give the max existing uid 153 """Give the max existing uid
161 @param boxname: name of the box where the message is 154 @param boxname: name of the box where the message is
162 @return: uid""" 155 @return: uid"""
163 try: 156 box_data = self.__getBoxData(boxname)
164 box_data = self.data[boxname] #the boxname MUST exist in the data
165 except KeyError:
166 err_msg=_("Boxname doesn't exist in internal data")
167 error(_("INTERNAL ERROR: ") + err_msg)
168 raise MaildirError(err_msg)
169 return box_data['cur_idx'] 157 return box_data['cur_idx']
170 158
171 159 def getIdFromUid(self, boxname, message_uid):
172 def getIdfromUid(self, boxname, message_uid):
173 """Return the message unique id from it's integer UID 160 """Return the message unique id from it's integer UID
174 @param boxname: name of the box where the message is 161 @param boxname: name of the box where the message is
175 @param message_uid: unique integer identifier 162 @param message_uid: unique integer identifier
176 @return: unique id of the message as given by MaildirMailbox or None if not found""" 163 @return: unique id of the message as given by MaildirMailbox or None if not found"""
177 try: 164 box_data = self.__getBoxData(boxname)
178 box_data = self.data[boxname] #the boxname MUST exist in the data
179 except KeyError:
180 err_msg=_("Boxname doesn't exist in internal data")
181 error(_("INTERNAL ERROR: ") + err_msg)
182 raise MaildirError(err_msg)
183
184 for message_id in box_data.keys(): #TODO: this is highly inefficient on big mailbox, must be replaced in the future 165 for message_id in box_data.keys(): #TODO: this is highly inefficient on big mailbox, must be replaced in the future
185 if message_id == 'cur_idx': 166 if message_id == 'cur_idx':
186 continue 167 continue
187 if box_data[message_id][0] == message_uid: 168 if box_data[message_id][0] == message_uid:
188 return message_id 169 return message_id
189 return None 170 return None
190 171
172 def getFlags(self, boxname, mess_id):
173 """Return the messages flags
174 @param boxname: name of the box where the message is
175 @param message_idx: message id as given by MaildirMailbox
176 @return: list of strings"""
177 box_data = self.__getBoxData(boxname)
178 if not box_data.has_key(mess_id):
179 raise MailboxException("Trying to get flags from an unexisting message")
180 return box_data[mess_id][1]
181
182 def setFlags(self, boxname, mess_id, flags):
183 """Change the flags of the message
184 @param boxname: name of the box where the message is
185 @param message_idx: message id as given by MaildirMailbox
186 @param flags: list of strings
187 """
188 box_data = self.__getBoxData(boxname)
189 assert(type(flags)==list)
190 if not box_data.has_key(mess_id):
191 raise MailboxException("Trying to set flags for an unexisting message")
192 box_data[mess_id][1]=flags
193 self.host.memory.setPrivate('MAILDIR_data',self.data)
194
195 def getMessageIdsWithFlag(self, boxname, flag):
196 """Return ids of messages where a flag is set
197 @param boxname: name of the box where the message is
198 @param flag: flag to check
199 @return: list of id (as given by MaildirMailbox)"""
200 box_data = self.__getBoxData(boxname)
201 assert(isinstance(flag,basestring))
202 result = []
203 for key in box_data:
204 if key=='cur_idx':
205 continue
206 if flag in box_data[key][1]:
207 result.append(key)
208 return result
209
210 def purgeDeleted(self, boxname):
211 """Remove data for messages with flag "\\Deleted"
212 @param boxname: name of the box where the message is
213 """
214 box_data = self.__getBoxData(boxname)
215 for mess_id in self.getMessageIdsWithFlag(boxname,"\\Deleted"):
216 del(box_data[mess_id])
217 self.host.memory.setPrivate('MAILDIR_data',self.data)
218
191 def cleanTable(self, boxname, existant_id): 219 def cleanTable(self, boxname, existant_id):
192 """Remove mails which no longuer exist from the table 220 """Remove mails which no longuer exist from the table
193 @param boxname: name of the box to clean 221 @param boxname: name of the box to clean
194 @param existant_id: list of id which actually exist""" 222 @param existant_id: list of id which actually exist"""
195 try: 223 box_data = self.__getBoxData(boxname)
196 box_data = self.data[boxname] #the boxname MUST exist in the data
197 except KeyError:
198 err_msg=_("Boxname doesn't exist in internal data")
199 error(_("INTERNAL ERROR: ") + err_msg)
200 raise MaildirError(err_msg)
201 to_remove=[] 224 to_remove=[]
202 for key in box_data: 225 for key in box_data:
203 if key not in existant_id and key!="cur_idx": 226 if key not in existant_id and key!="cur_idx":
204 to_remove.append(key) 227 to_remove.append(key)
205 for key in to_remove: 228 for key in to_remove:
310 existant_id.append(self.getId(mess_idx)) 333 existant_id.append(self.getId(mess_idx))
311 self.getUid(mess_idx) 334 self.getUid(mess_idx)
312 self.maildir.cleanTable(self.name, existant_id) 335 self.maildir.cleanTable(self.name, existant_id)
313 336
314 337
315 def __destroy__(self): 338 def __del__(self):
316 if observer: 339 if observer:
317 debug("removing observer for %s" % self.name) 340 debug("removing observer for %s" % self.name)
318 self._maildir.removeObserver(observer, self.name, "NEW_MESSAGE") 341 self._maildir.removeObserver(observer, self.name, "NEW_MESSAGE")
319 self._maildir._removeBoxAccess(self.name, self) 342 self._maildir._removeBoxAccess(self.name, self)
320 343
353 376
354 def getMessageIdx(self, mess_idx): 377 def getMessageIdx(self, mess_idx):
355 """Return the full message 378 """Return the full message
356 @mess_idx: message index""" 379 @mess_idx: message index"""
357 return self.mailbox.getMessage(mess_idx) 380 return self.mailbox.getMessage(mess_idx)
381
382 def getIdxFromUid(self, mess_uid):
383 """Return the message index from the uid
384 @param mess_uid: message unique identifier
385 @return: message index, as managed by MaildirMailbox"""
386 for mess_idx in range (self.getMessageCount()):
387 if self.getUid(mess_idx) == mess_uid:
388 return mess_idx
389 raise IndexError
390
391 def getIdxFromId(self, mess_id):
392 """Return the message index from the unique index
393 @param mess_id: message unique index as given by MaildirMailbox
394 @return: message sequence index"""
395 for mess_idx in range (self.getMessageCount()):
396 if self.mailbox.getUidl(mess_idx) == mess_id:
397 return mess_idx
398 raise IndexError
358 399
359 def getMessage(self, mess_idx): 400 def getMessage(self, mess_idx):
360 """Return the full message 401 """Return the full message
361 @mess_idx: message index""" 402 @param mess_idx: message index"""
362 return self.mailbox.getMessage(mess_idx) 403 return self.mailbox.getMessage(mess_idx)
363 404
364 def getMessageUid(self, mess_uid): 405 def getMessageUid(self, mess_uid):
365 """Return the full message 406 """Return the full message
366 @mess_idx: message unique identifier""" 407 @param mess_idx: message unique identifier"""
367 for mess_idx in range (self.getMessageCount()): 408 return self.mailbox.getMessage(self.getIdxFromUid(mess_uid))
368 if self.getUid(mess_idx) == mess_uid: 409
369 return self.mailbox.getMessage(mess_idx) 410 def getFlags(self, mess_idx):
370 raise IndexError 411 """Return the flags of the message
412 @param mess_idx: message index
413 @return: list of strings"""
414 id = self.getId(mess_idx)
415 return self.maildir.getFlags(self.name, id)
416
417 def getFlagsUid(self, mess_uid):
418 """Return the flags of the message
419 @param mess_uid: message unique identifier
420 @return: list of strings"""
421 id = self.maildir.getIdFromUid(self.name,mess_uid)
422 return self.maildir.getFlags(self.name, id)
423
424 def setFlags(self, mess_idx, flags):
425 """Change the flags of the message
426 @param mess_idx: message index
427 @param flags: list of strings
428 """
429 id = self.getId(mess_idx)
430 return self.maildir.setFlags(self.name, id, flags)
431
432 def setFlagsUid(self, mess_uid, flags):
433 """Change the flags of the message
434 @param mess_uid: message unique identifier
435 @param flags: list of strings
436 """
437 id = self.maildir.getIdFromUid(self.name,mess_uid)
438 return self.maildir.setFlags(self.name, id, flags)
439
440 def getMessageIdsWithFlag(self, flag):
441 """Return ids of messages where a flag is set
442 @param flag: flag to check
443 @return: list of id (as given by MaildirMailbox)"""
444 return self.maildir.getMessageIdsWithFlag(self.name,flag)
445
446 def removeDeleted(self):
447 """Actually delete message flagged "\\Deleted"
448 Also purge the internal data of these messages
449 """
450 for mess_id in self.getMessageIdsWithFlag("\\Deleted"):
451 print ("Deleting %s", mess_id)
452 self.mailbox.deleteMessage(self.getIdxFromId(mess_id))
453 self.mailbox = maildir.MaildirMailbox(self.mailbox_path) #We need to reparse the dir to have coherent indexing
454 self.maildir.purgeDeleted(self.name)
455
456 def emptyTrash(self):
457 """Delete everything in the .Trash dir"""
458 import shutils
459 pdb.set_trace()
460