Package ProcImap :: Module ImapMessage
[hide private]
[frames] | no frames]

Source Code for Module ProcImap.ImapMessage

  1  ############################################################################ 
  2  #    Copyright (C) 2008 by Michael Goerz                                   # 
  3  #    http://www.physik.fu-berlin.de/~goerz                                 # 
  4  #                                                                          # 
  5  #    This program is free software; you can redistribute it and#or modify  # 
  6  #    it under the terms of the GNU General Public License as published by  # 
  7  #    the Free Software Foundation; either version 3 of the License, or     # 
  8  #    (at your option) any later version.                                   # 
  9  #                                                                          # 
 10  #    This program is distributed in the hope that it will be useful,       # 
 11  #    but WITHOUT ANY WARRANTY; without even the implied warranty of        # 
 12  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         # 
 13  #    GNU General Public License for more details.                          # 
 14  #                                                                          # 
 15  #    You should have received a copy of the GNU General Public License     # 
 16  #    along with this program; if not, write to the                         # 
 17  #    Free Software Foundation, Inc.,                                       # 
 18  #    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             # 
 19  ############################################################################ 
 20   
 21  """ This module contains the ImapMessage class, which derives from 
 22      mailbox.Message. The full interface of mailbox.Message including 
 23      conversion to and from other subclasses of mailbox.Message is 
 24      implemented. 
 25  """ 
 26   
 27  import imaplib 
 28  import mailbox 
 29  import time 
 30   
 31  INTTIME_FROM_MESSAGE = True # Some mailboxes do not support the notion of an 
 32      # internal time (e.g. mbox). If you convert a message coming from one of  
 33      # these mailboxes into an ImapMessage, the internal time of the ImapMessage 
 34      # will be set to the time that is specified in the Date header of the 
 35      # original message, if the INTTIME_FROM_MESSAGE flag is set to True. If the 
 36      # flag is set to False, no internal time will be set for the ImapMessage, 
 37      # which usually means the internal time on the server will end up being the 
 38      # upload time. Note that his flag has no effect if the message that is 
 39      # being converted comes from a mailbox format that supports internal times 
 40   
41 -class ImapMessage(mailbox.Message):
42 """ Message with IMAP-specific properties. This class holds information 43 about an IMAP email message that. 44 IMAP specific properties consist of IMAP flags, the internal 45 date (date when received by the server), and possibly the message 46 size. 47 48 Class specific attributes are: 49 50 internaldate the date and time when the IMAP server received 51 the message (time tuple) 52 size number of bytes of the message, 0 if unknown 53 """
54 - def __init__(self, message=None):
55 """ If message is omitted, create new instance in a default, empty 56 state. If message is an email.Message.Message instance, its 57 contents are copied; furthermore, any format-specific information 58 is converted insofar as possible if message is a Message instance. 59 If message is a string or a file, it should contain an 60 RFC 2822-compliant message, which is read and parsed. 61 When a MaildirMessage instance is created based upon an 62 mailbox.mboxMessage or mailbox.MMDFMessage instance, the 63 Status: and X-Status: headers are omitted. 64 """ 65 self._imapflags = [] 66 self.internaldate = time.localtime() 67 self.size = 0 68 mailbox.Message.__init__(self, message) 69 self._get_explanation_from(message) 70 if isinstance(message, (mailbox.mboxMessage, mailbox.MMDFMessage)): 71 del self['status'] 72 del self['x-status']
73
74 - def _get_explanation_from(self, message):
75 """Copy specific state from message to self insofar as possible.""" 76 if isinstance(message, mailbox.Message): 77 if isinstance(message, mailbox.MaildirMessage): 78 self._imapflags = imapflags_from_maildir_message(message) 79 self.internaldate = time.localtime(message.get_date()) 80 elif isinstance(message, mailbox.mboxMessage): 81 self._imapflags = imapflags_from_mbox_message(message) 82 if INTTIME_FROM_MESSAGE: 83 try: 84 date = message['Date'] 85 internaldate = seconds_from_date(date) # FIXME: what's this? 86 if internaldate is not None: 87 self.internaldate = internaldate 88 except KeyError: 89 pass 90 elif isinstance(message, mailbox.MHMessage): 91 self._imapflags = imapflags_from_mh_message(message) 92 if INTTIME_FROM_MESSAGE: 93 try: 94 self.internaldate_from_string(message['Date']) 95 except KeyError: 96 pass 97 elif isinstance(message, mailbox.BabylMessage): 98 self._imapflags = imapflags_from_babyl_message(message) 99 if INTTIME_FROM_MESSAGE: 100 try: 101 self.internaldate_from_string(message['Date']) 102 except KeyError: 103 pass 104 elif isinstance(message, mailbox.MMDFMessage): 105 self._imapflags = imapflags_from_mmdf_message(message) 106 if INTTIME_FROM_MESSAGE: 107 try: 108 self.internaldate_from_string(message['Date']) 109 except KeyError: 110 pass
111
112 - def _explain_to(self, message):
113 """Copy IMAP-specific state to message insofar as possible.""" 114 if isinstance(message, ImapMessage): 115 message._imapflags = self._imapflags 116 message.internaldate = self.internaldate 117 message.size = self.size 118 elif isinstance(message, mailbox.MaildirMessage): 119 for flag in maildirflags_from_imap_message(self): 120 message.add_flag(flag) 121 message.set_date(time.mktime(self.internaldate)) 122 elif isinstance(message, (mailbox.mboxMessage, mailbox.MMDFMessage)): 123 for flag in mboxflags_from_imap_message(self): 124 message.add_flag(flag) 125 message.set_from('MAILER-DAEMON', time.mktime(self.internaldate)) 126 elif isinstance(message, mailbox.MHMessage): 127 for sequence in mhsequences_from_imap_message(self): 128 message.add_sequence(sequence) 129 elif isinstance(message, mailbox.BabylMessage): 130 for label in babyllabels_from_imap_message(self): 131 message.add_label(label) 132 elif isinstance(message, mailbox.Message): 133 pass 134 else: 135 raise TypeError('Cannot convert to specified type: %s' % 136 type(message))
137 138
139 - def flagstring(self):
140 """ Return string for imap flags """ 141 return "(%s)" % ' '.join(self._imapflags)
142 143
144 - def flags_from_string(self, flagstring):
145 """ Set the flags from a string as returned by 146 self.flagstring() 147 """ 148 self.set_imapflags(flagstring[1:-1].split())
149
150 - def delete(self):
151 """ Add the \Deleted flag to the list of imap flags """ 152 if not "\\Deleted" in self._imapflags: 153 self._imapflags.append("\\Deleted")
154
155 - def remove_imapflag(self, *flags):
156 """ Remove flags from the list of imap flags. Do nothing if the 157 flag does not exist. Remember that this is a local modification. 158 """ 159 new_imapflags = [] 160 flags = [flag.upper() for flag in flags] 161 for flagname in self._imapflags: 162 if not flagname.upper() in flags: 163 new_imapflags.append(flagname) 164 self._imapflags = new_imapflags
165
166 - def add_imapflag(self, *flags):
167 """ Add a flag to the list of imap flags. 168 You cannot add "\RECENT" as a flag. 169 """ 170 for flag in flags: 171 if (flag.upper() != "\\RECENT"): 172 if flag not in self._imapflags: 173 self._imapflags.append(flag)
174
175 - def set_imapflags(self, flags):
176 """ Set imap flags to flags """ 177 if isinstance(flags, str): 178 flags = [flags] 179 self._imapflags = [] 180 for flag in flags: 181 if (flag.upper() != "\\RECENT"): 182 if flag not in self._imapflags: 183 self._imapflags.append(flag)
184
185 - def get_imapflags(self):
186 """ Return a list of imap flags """ 187 return self._imapflags
188
189 - def internaldatestring(self):
190 """ Return string for internaldate. 191 Return None if internaldate is None. 192 """ 193 if self.internaldate is None: 194 return None 195 return imaplib.Time2Internaldate(self.internaldate)
196
197 - def internaldate_from_string(self, internaldatestring):
198 """ Set the internaldate from a string as it is returned 199 by self.internaldatestring() 200 """ 201 self.internaldate = imaplib.Internaldate2tuple(internaldatestring)
202 203 204 205 # Helper functions for conversion to/from other mailbox.Message instances 206
207 -def _reverse_mappings(mappings):
208 """ Switch key and value in the mappings dict 209 Make new keys upper case 210 """ 211 result = {} 212 for (key, value) in mappings.items(): 213 value = value.upper() 214 result[value] = key 215 return result
216
217 -def imapflags_from_maildir_message(message):
218 """ Return a list of IMAP flags from an MaildirMessage""" 219 flagstring = message.get_flags() 220 flags = [] 221 mappings = { 222 'D' : '\\Draft', 223 'F' : '\\Flagged', 224 'P' : '$Forwarded', 225 'R' : '\\Answered', 226 'S' : '\\Seen', 227 'T' : '\\Deleted' 228 } 229 for (letter, imapflag) in mappings.items(): 230 if letter in flagstring: 231 flags.append(imapflag) 232 return flags
233 234
235 -def maildirflags_from_imap_message(message):
236 """ Return a string of maildir flags from an ImapMessage""" 237 result = "" 238 imapflags = message.imapflags() 239 mappings = { 240 'D' : '\\Draft', 241 'F' : '\\Flagged', 242 'P' : '$Forwarded', 243 'R' : '\\Answered', 244 'S' : '\\Seen', 245 'T' : '\\Deleted' 246 } 247 mappings = _reverse_mappings(mappings) 248 for imapflag in imapflags: 249 if mappings.has_key(imapflag): 250 result += mappings[imapflag] 251 return result
252
253 -def imapflags_from_mbox_message(message):
254 """ Return a list of IMAP flags from an mboxMessage""" 255 flagstring = message.get_flags() 256 flags = [] 257 mappings = { 258 'F' : '\\Flagged', 259 'A' : '\\Answered', 260 'R' : '\\Seen', 261 'D' : '\\Deleted' 262 } 263 for (letter, imapflag) in mappings.items(): 264 if letter in flagstring: 265 flags.append(imapflag) 266 return flags
267
268 -def mboxflags_from_imap_message(message):
269 """ Return a string of mbox flags from an ImapMessage""" 270 result = "" 271 imapflags = message.imapflags() 272 mappings = { 273 'F' : '\\Flagged', 274 'A' : '\\Answered', 275 'R' : '\\Seen', 276 'D' : '\\Deleted' 277 } 278 mappings = _reverse_mappings(mappings) 279 for imapflag in imapflags: 280 if mappings.has_key(imapflag): 281 result += mappings[imapflag] 282 return result
283
284 -def imapflags_from_mh_message(message):
285 """ Return a list of IMAP flags from an MHMessage""" 286 sequences = message.get_sequences() 287 flags = [] 288 mappings = { 289 'flagged' : '\\Flagged', 290 'replied' : '\\Answered' 291 } 292 for (sequence, imapflag) in mappings.items(): 293 if sequence in sequences: 294 flags.append(imapflag) 295 return flags
296
297 -def mhsequences_from_imap_message(message):
298 """ Return a list of MH sequences from an ImapMessage""" 299 result = [] 300 imapflags = message.imapflags() 301 mappings = { 302 'flagged' : '\\Flagged', 303 'replied' : '\\Answered' 304 } 305 mappings = _reverse_mappings(mappings) 306 for imapflag in imapflags: 307 if mappings.has_key(imapflag): 308 result.append(mappings[imapflag]) 309 return result
310
311 -def imapflags_from_babyl_message(message):
312 """ Return a list of IMAP flags from an BabylMessage""" 313 labels = message.get_labels() 314 flags = [] 315 mappings = { 316 'forwarded' : '$Forwarded', 317 'answered' : '\\Answered', 318 'deleted' : '\\Deleted' 319 } 320 for (label, imapflag) in mappings.items(): 321 if label in labels: 322 flags.append(imapflag) 323 return flags
324
325 -def babyllabels_from_imap_message(message):
326 """ Return a list of Babyl lables from an ImapMessage""" 327 result = [] 328 imapflags = message.imapflags() 329 mappings = { 330 'forwarded' : '$Forwarded', 331 'answered' : '\\Answered', 332 'deleted' : '\\Deleted' 333 } 334 mappings = _reverse_mappings(mappings) 335 for imapflag in imapflags: 336 if mappings.has_key(imapflag): 337 result.append(mappings[imapflag]) 338 return result
339
340 -def imapflags_from_mmdf_message(message):
341 """ Return a list of IMAP flags from an MMDFMessage""" 342 return imapflags_from_mbox_message(message)
343
344 -def mmdfflags_from_imap_message(message):
345 """ Return a string of MMDF flags from an ImapMessage""" 346 return mboxflags_from_imap_message(message)
347