mhlib.py revision 560131328c9ddfa25555048b1bf4d760c02e1dd7
1560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# MH interface -- purely object-oriented (well, almost) 2560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 3560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Executive summary: 4560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 5560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# import mhlib 6560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 7560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh = mhlib.MH() # use default mailbox directory and profile 8560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh = mhlib.MH(mailbox) # override mailbox location (default from profile) 9560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh = mhlib.MH(mailbox, profile) # override mailbox and profile 10560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 11560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh.error(format, ...) # print error message -- can be overridden 12560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# s = mh.getprofile(key) # profile entry (None if not set) 13560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# path = mh.getpath() # mailbox pathname 14560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# name = mh.getcontext() # name of current folder 15560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 16560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# list = mh.listfolders() # names of top-level folders 17560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# list = mh.listallfolders() # names of all folders, including subfolders 18560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# list = mh.listsubfolders(name) # direct subfolders of given folder 19560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# list = mh.listallsubfolders(name) # all subfolders of given folder 20560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 21560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh.makefolder(name) # create new folder 22560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# mh.deletefolder(name) # delete folder -- must have no subfolders 23560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 24560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# f = mh.openfolder(name) # new open folder object 25560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 26560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# f.error(format, ...) # same as mh.error(format, ...) 27560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# path = f.getfullname() # folder's full pathname 28560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# path = f.getsequencesfilename() # full pathname of folder's sequences file 29560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# path = f.getmessagefilename(n) # full pathname of message n in folder 30560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 31560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# list = f.listmessages() # list of messages in folder (as numbers) 32560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# n = f.getcurrent() # get current message 33560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# f.setcurrent(n) # set current message 34560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 35560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# dict = f.getsequences() # dictionary of sequences in folder {name: list} 36560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# f.putsequences(dict) # write sequences back to folder 37560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 38560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# m = f.openmessage(n) # new open message object (costs a file descriptor) 39560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# s = m.getheadertext() # text of message's headers 40560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# s = m.getheadertext(pred) # text of message's headers, filtered by pred 41560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# s = m.getbodytext() # text of message's body, decoded 42560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# s = m.getbodytext(0) # text of message's body, not decoded 43560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 44560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# XXX To do, functionality: 45560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - remove, refile messages 46560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - annotate messages 47560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - create, send messages 48560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 49560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# XXX To do, orgaanization: 50560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - move IntSet to separate file 51560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - move most Message functionality to module mimetools 52560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 53560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 54560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Customizable defaults 55560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 56560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van RossumMH_PROFILE = '~/.mh_profile' 57560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van RossumPATH = '~/Mail' 58560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van RossumMH_SEQUENCES = '.mh_sequences' 59560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van RossumFOLDER_PROTECT = 0700 60560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 61560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 62560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Imported modules 63560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 64560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumimport os 65560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumfrom stat import ST_NLINK 66560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumimport regex 67560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumimport string 68560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumimport mimetools 69560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumimport multifile 70560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 71560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 72560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Exported constants 73560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 74560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van RossumError = 'mhlib.Error' 75560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 76560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 77560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Class representing a particular collection of folders. 78560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Optional constructor arguments are the pathname for the directory 79560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# containing the collection, and the MH profile to use. 80560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# If either is omitted or empty a default is used; the default 81560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# directory is taken from the MH profile if it is specified there. 82560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 83560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumclass MH: 84560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 85560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Constructor 86560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __init__(self, path = None, profile = None): 87560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not profile: profile = MH_PROFILE 88560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.profile = os.path.expanduser(profile) 89560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not path: path = self.getprofile('Path') 90560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not path: path = PATH 91560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not os.path.isabs(path) and path[0] != '~': 92560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = os.path.join('~', path) 93560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = os.path.expanduser(path) 94560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not os.path.isdir(path): raise Error, 'MH() path not found' 95560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.path = path 96560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 97560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # String representation 98560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __repr__(self): 99560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 'MH(%s, %s)' % (`self.path`, `self.profile`) 100560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 101560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Routine to print an error. May be overridden by a derived class 102560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def error(self, msg, *args): 103560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum sys.stderr.write('MH error: %\n' % (msg % args)) 104560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 105560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return a profile entry, None if not found 106560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getprofile(self, key): 107560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return pickline(self.profile, key) 108560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 109560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the path (the name of the collection's directory) 110560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getpath(self): 111560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.path 112560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 113560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the name of the current folder 114560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getcontext(self): 115560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum context = pickline(os.path.join(self.getpath(), 'context'), 116560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 'Current-Folder') 117560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not context: context = 'inbox' 118560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return context 119560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 120560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the names of the top-level folders 121560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listfolders(self): 122560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum folders = [] 123560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = self.getpath() 124560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for name in os.listdir(path): 125560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if name in (os.curdir, os.pardir): continue 126560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = os.path.join(path, name) 127560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if os.path.isdir(fullname): 128560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum folders.append(name) 129560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum folders.sort() 130560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return folders 131560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 132560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the names of the subfolders in a given folder 133560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # (prefixed with the given folder name) 134560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listsubfolders(self, name): 135560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = os.path.join(self.path, name) 136560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Get the link count so we can avoid listing folders 137560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # that have no subfolders. 138560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum st = os.stat(fullname) 139560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum nlinks = st[ST_NLINK] 140560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if nlinks <= 2: 141560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return [] 142560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders = [] 143560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subnames = os.listdir(fullname) 144560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for subname in subnames: 145560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if subname in (os.curdir, os.pardir): continue 146560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullsubname = os.path.join(fullname, subname) 147560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if os.path.isdir(fullsubname): 148560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum name_subname = os.path.join(name, subname) 149560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders.append(name_subname) 150560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Stop looking for subfolders when 151560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # we've seen them all 152560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum nlinks = nlinks - 1 153560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if nlinks <= 2: 154560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum break 155560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders.sort() 156560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return subfolders 157560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 158560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the names of all folders, including subfolders, recursively 159560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listallfolders(self): 160560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.listallsubfolders('') 161560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 162560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the names of subfolders in a given folder, recursively 163560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listallsubfolders(self, name): 164560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = os.path.join(self.path, name) 165560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Get the link count so we can avoid listing folders 166560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # that have no subfolders. 167560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum st = os.stat(fullname) 168560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum nlinks = st[ST_NLINK] 169560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if nlinks <= 2: 170560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return [] 171560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders = [] 172560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subnames = os.listdir(fullname) 173560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for subname in subnames: 174560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if subname in (os.curdir, os.pardir): continue 175560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if subname[0] == ',' or isnumeric(subname): continue 176560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullsubname = os.path.join(fullname, subname) 177560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if os.path.isdir(fullsubname): 178560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum name_subname = os.path.join(name, subname) 179560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders.append(name_subname) 180560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not os.path.islink(fullsubname): 181560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subsubfolders = self.listallsubfolders( 182560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum name_subname) 183560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders = subfolders + subsubfolders 184560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Stop looking for subfolders when 185560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # we've seen them all 186560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum nlinks = nlinks - 1 187560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if nlinks <= 2: 188560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum break 189560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum subfolders.sort() 190560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return subfolders 191560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 192560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return a new Folder object for the named folder 193560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def openfolder(self, name): 194560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return Folder(self, name) 195560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 196560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Create a new folder. This raises os.error if the folder 197560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # cannot be created 198560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def makefolder(self, name): 199560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum protect = pickline(self.profile, 'Folder-Protect') 200560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if protect and isnumeric(protect): 201560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mode = eval('0' + protect) 202560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 203560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mode = FOLDER_PROTECT 204560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.mkdir(os.path.join(self.getpath(), name), mode) 205560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 206560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Delete a folder. This removes files in the folder but not 207560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # subdirectories. If deleting the folder itself fails it 208560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # raises os.error 209560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def deletefolder(self, name): 210560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = os.path.join(self.getpath(), name) 211560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for subname in os.listdir(fullname): 212560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if subname in (os.curdir, os.pardir): continue 213560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullsubname = os.path.join(fullname, subname) 214560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 215560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.unlink(fullsubname) 216560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except os.error: 217560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.error('%s not deleted, continuing...' % 218560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullsubname) 219560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.rmdir(fullname) 220560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 221560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 222560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Class representing a particular folder 223560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 224560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumnumericprog = regex.compile('[1-9][0-9]*') 225560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumdef isnumeric(str): 226560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return numericprog.match(str) == len(str) 227560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 228560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumclass Folder: 229560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 230560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Constructor 231560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __init__(self, mh, name): 232560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.mh = mh 233560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.name = name 234560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not os.path.isdir(self.getfullname()): 235560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise Error, 'no folder %s' % name 236560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 237560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # String representation 238560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __repr__(self): 239560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 'Folder(%s, %s)' % (`self.mh`, `self.name`) 240560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 241560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Error message handler 242560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def error(self, *args): 243560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum apply(self.mh.error, args) 244560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 245560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the full pathname of the folder 246560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getfullname(self): 247560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return os.path.join(self.mh.path, self.name) 248560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 249560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the full pathname of the folder's sequences file 250560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getsequencesfilename(self): 251560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return os.path.join(self.getfullname(), MH_SEQUENCES) 252560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 253560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the full pathname of a message in the folder 254560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getmessagefilename(self, n): 255560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return os.path.join(self.getfullname(), str(n)) 256560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 257560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return list of direct subfolders 258560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listsubfolders(self): 259560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.mh.listsubfolders(self.name) 260560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 261560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return list of all subfolders 262560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listallsubfolders(self): 263560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.mh.listallsubfolders(self.name) 264560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 265560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the list of messages currently present in the folder. 266560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # As a side effect, set self.last to the last message (or 0) 267560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def listmessages(self): 268560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum messages = [] 269560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for name in os.listdir(self.getfullname()): 270560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if isnumeric(name): 271560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum messages.append(eval(name)) 272560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum messages.sort() 273560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if messages: 274560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.last = max(messages) 275560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 276560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.last = 0 277560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return messages 278560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 279560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the set of sequences for the folder 280560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getsequences(self): 281560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum sequences = {} 282560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = self.getsequencesfilename() 283560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 284560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = open(fullname, 'r') 285560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except IOError: 286560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return sequences 287560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum while 1: 288560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum line = f.readline() 289560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not line: break 290560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fields = string.splitfields(line, ':') 291560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if len(fields) <> 2: 292560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.error('bad sequence in %s: %s' % 293560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum (fullname, string.strip(line))) 294560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum key = string.strip(fields[0]) 295560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum value = IntSet(string.strip(fields[1]), ' ').tolist() 296560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum sequences[key] = value 297560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return sequences 298560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 299560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Write the set of sequences back to the folder 300560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def putsequences(self, sequences): 301560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fullname = self.getsequencesfilename() 302560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = open(fullname, 'w') 303560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for key in sequences.keys(): 304560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum s = IntSet('', ' ') 305560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum s.fromlist(sequences[key]) 306560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f.write('%s: %s\n' % (key, s.tostring())) 307560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 308560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the current message. Raise KeyError when there is none 309560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getcurrent(self): 310560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return min(self.getsequences()['cur']) 311560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 312560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Set the current message 313560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def setcurrent(self, n): 314560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum updateline(self.getsequencesfilename(), 'cur', str(n), 0) 315560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 316560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Open a message -- returns a mimetools.Message object 317560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def openmessage(self, n): 318560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = self.getmessagefilename(n) 319560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return Message(self, n) 320560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 321560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Remove one or more messages -- may raise os.error 322560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def removemessages(self, list): 323560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum errors = [] 324560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum deleted = [] 325560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for n in list: 326560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = self.getmessagefilename(n) 327560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum commapath = self.getmessagefilename(',' + str(n)) 328560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 329560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.unlink(commapath) 330560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except os.error: 331560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum pass 332560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 333560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.rename(path, commapath) 334560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except os.error, msg: 335560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum errors.append(msg) 336560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 337560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum deleted.append(n) 338560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if deleted: 339560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.removefromallsequences(deleted) 340560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if errors: 341560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if len(errors) == 1: 342560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise os.error, errors[0] 343560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 344560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise os.error, ('multiple errors:', errors) 345560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 346560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Refile one or more messages -- may raise os.error. 347560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # 'tofolder' is an open folder object 348560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def refilemessages(self, list, tofolder): 349560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum errors = [] 350560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum refiled = [] 351560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for n in list: 352560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum ton = tofolder.getlast() + 1 353560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = self.getmessagefilename(n) 354560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum topath = tofolder.getmessagefilename(ton) 355560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 356560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.rename(path, topath) 357560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # XXX What if it's on a different filesystem? 358560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except os.error, msg: 359560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum errors.append(msg) 360560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 361560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum tofolder.setlast(ton) 362560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum refiled.append(n) 363560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if refiled: 364560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.removefromallsequences(refiled) 365560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if errors: 366560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if len(errors) == 1: 367560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise os.error, errors[0] 368560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 369560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise os.error, ('multiple errors:', errors) 370560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 371560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Remove one or more messages from all sequeuces (including last) 372560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def removefromallsequences(self, list): 373560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if hasattr(self, 'last') and self.last in list: 374560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum del self.last 375560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum sequences = self.getsequences() 376560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum changed = 0 377560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for name, seq in sequences.items(): 378560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for n in list: 379560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if n in seq: 380560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum seq.remove(n) 381560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum changed = 1 382560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not seq: 383560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum del sequences[name] 384560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if changed: 385560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.putsequences() 386560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 387560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the last message number 388560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getlast(self): 389560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not hasattr(self, 'last'): 390560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum messages = self.listmessages() 391560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.last 392560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 393560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Set the last message number 394560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def setlast(self, last): 395560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if last is None: 396560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if hasattr(self, 'last'): 397560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum del self.last 398560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 399560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.last = last 400560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 401560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumclass Message(mimetools.Message): 402560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 403560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Constructor 404560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __init__(self, f, n, fp = None): 405560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.folder = f 406560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.number = n 407560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not fp: 408560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum path = f.getmessagefilename(n) 409560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum fp = open(path, 'r') 410560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mimetools.Message.__init__(self, fp) 411560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 412560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # String representation 413560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __repr__(self): 414560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 'Message(%s, %s)' % (repr(self.folder), self.number) 415560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 416560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the message's header text as a string. If an 417560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # argument is specified, it is used as a filter predicate to 418560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # decide which headers to return (its argument is the header 419560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # name converted to lower case). 420560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getheadertext(self, pred = None): 421560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not pred: 422560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return string.joinfields(self.headers, '') 423560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum headers = [] 424560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum hit = 0 425560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for line in self.headers: 426560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if line[0] not in string.whitespace: 427560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum i = string.find(line, ':') 428560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if i > 0: 429560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum hit = pred(string.lower(line[:i])) 430560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if hit: headers.append(line) 431560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return string.joinfields(headers, '') 432560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 433560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return the message's body text as string. This undoes a 434560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Content-Transfer-Encoding, but does not interpret other MIME 435560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # features (e.g. multipart messages). To suppress to 436560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # decoding, pass a 0 as argument 437560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbodytext(self, decode = 1): 438560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.fp.seek(self.startofbody) 439560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum encoding = self.getencoding() 440560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not decode or encoding in ('7bit', '8bit', 'binary'): 441560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.fp.read() 442560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum from StringIO import StringIO 443560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum output = StringIO() 444560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mimetools.decode(self.fp, output, encoding) 445560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return output.getvalue() 446560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 447560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Only for multipart messages: return the message's body as a 448560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # list of SubMessage objects. Each submessage object behaves 449560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # (almost) as a Message object. 450560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbodyparts(self): 451560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if self.getmaintype() != 'multipart': 452560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise Error, \ 453560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 'Content-Type is not multipart/*' 454560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum bdry = self.getparam('boundary') 455560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not bdry: 456560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise Error, 'multipart/* without boundary param' 457560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.fp.seek(self.startofbody) 458560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mf = multifile.MultiFile(self.fp) 459560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mf.push(bdry) 460560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum parts = [] 461560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum while mf.next(): 462560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum n = str(self.number) + '.' + `1 + len(parts)` 463560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum part = SubMessage(self.folder, n, mf) 464560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum parts.append(part) 465560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mf.pop() 466560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return parts 467560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 468560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Return body, either a string or a list of messages 469560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbody(self): 470560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if self.getmaintype() == 'multipart': 471560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.getbodyparts() 472560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 473560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.getbodytext() 474560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 475560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 476560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumclass SubMessage(Message): 477560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 478560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Constructor 479560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __init__(self, f, n, fp): 480560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum Message.__init__(self, f, n, fp) 481560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if self.getmaintype() == 'multipart': 482560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.body = Message.getbodyparts(self) 483560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 484560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.body = Message.getbodytext(self) 485560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # XXX If this is big, should remember file pointers 486560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 487560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # String representation 488560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __repr__(self): 489560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f, n, fp = self.folder, self.number, self.fp 490560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 'SubMessage(%s, %s, %s)' % (f, n, fp) 491560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 492560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbodytext(self): 493560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if type(self.body) == type(''): 494560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.body 495560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 496560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbodyparts(self): 497560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if type(self.body) == type([]): 498560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.body 499560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 500560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def getbody(self): 501560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.body 502560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 503560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 504560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Class implementing sets of integers. 505560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 506560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# This is an efficient representation for sets consisting of several 507560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# continuous ranges, e.g. 1-100,200-400,402-1000 is represented 508560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# internally as a list of three pairs: [(1,100), (200,400), 509560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# (402,1000)]. The internal representation is always kept normalized. 510560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 511560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# The constructor has up to three arguments: 512560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - the string used to initialize the set (default ''), 513560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - the separator between ranges (default ',') 514560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# - the separator between begin and end of a range (default '-') 515560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# The separators may be regular expressions and should be different. 516560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 517560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# The tostring() function yields a string that can be passed to another 518560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# IntSet constructor; __repr__() is a valid IntSet constructor itself. 519560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 520560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# XXX The default begin/end separator means that negative numbers are 521560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# not supported very well. 522560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# 523560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# XXX There are currently no operations to remove set elements. 524560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 525560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumclass IntSet: 526560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 527560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __init__(self, data = None, sep = ',', rng = '-'): 528560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs = [] 529560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.sep = sep 530560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.rng = rng 531560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if data: self.fromstring(data) 532560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 533560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def reset(self): 534560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs = [] 535560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 536560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __cmp__(self, other): 537560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return cmp(self.pairs, other.pairs) 538560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 539560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __hash__(self): 540560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return hash(self.pairs) 541560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 542560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def __repr__(self): 543560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 'IntSet(%s, %s, %s)' % (`self.tostring()`, 544560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum `self.sep`, `self.rng`) 545560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 546560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def normalize(self): 547560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs.sort() 548560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum i = 1 549560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum while i < len(self.pairs): 550560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum alo, ahi = self.pairs[i-1] 551560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum blo, bhi = self.pairs[i] 552560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if ahi >= blo-1: 553560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs[i-1:i+1] = [ 554560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum (alo, max(ahi, bhi))] 555560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 556560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum i = i+1 557560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 558560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def tostring(self): 559560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum s = '' 560560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for lo, hi in self.pairs: 561560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if lo == hi: t = `lo` 562560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: t = `lo` + self.rng + `hi` 563560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if s: s = s + (self.sep + t) 564560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: s = t 565560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return s 566560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 567560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def tolist(self): 568560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum l = [] 569560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for lo, hi in self.pairs: 570560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum m = range(lo, hi+1) 571560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum l = l + m 572560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return l 573560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 574560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def fromlist(self, list): 575560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for i in list: 576560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.append(i) 577560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 578560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def clone(self): 579560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum new = IntSet() 580560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum new.pairs = self.pairs[:] 581560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return new 582560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 583560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def min(self): 584560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.pairs[0][0] 585560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 586560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def max(self): 587560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return self.pairs[-1][-1] 588560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 589560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def contains(self, x): 590560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for lo, hi in self.pairs: 591560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if lo <= x <= hi: return 1 592560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 0 593560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 594560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def append(self, x): 595560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for i in range(len(self.pairs)): 596560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lo, hi = self.pairs[i] 597560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if x < lo: # Need to insert before 598560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if x+1 == lo: 599560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs[i] = (x, hi) 600560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 601560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs.insert(i, (x, x)) 602560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if i > 0 and x-1 == self.pairs[i-1][1]: 603560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum # Merge with previous 604560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs[i-1:i+1] = [ 605560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum (self.pairs[i-1][0], 606560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs[i][1]) 607560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum ] 608560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 609560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if x <= hi: # Already in set 610560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 611560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum i = len(self.pairs) - 1 612560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if i >= 0: 613560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lo, hi = self.pairs[i] 614560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if x-1 == hi: 615560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs[i] = lo, x 616560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return 617560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs.append((x, x)) 618560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 619560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def addpair(self, xlo, xhi): 620560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if xlo > xhi: return 621560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs.append((xlo, xhi)) 622560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.normalize() 623560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 624560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def fromstring(self, data): 625560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum import string, regsub 626560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum new = [] 627560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for part in regsub.split(data, self.sep): 628560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum list = [] 629560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for subp in regsub.split(part, self.rng): 630560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum s = string.strip(subp) 631560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum list.append(string.atoi(s)) 632560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if len(list) == 1: 633560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum new.append((list[0], list[0])) 634560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum elif len(list) == 2 and list[0] <= list[1]: 635560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum new.append((list[0], list[1])) 636560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 637560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum raise ValueError, 'bad data passed to IntSet' 638560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.pairs = self.pairs + new 639560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum self.normalize() 640560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 641560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 642560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Subroutines to read/write entries in .mh_profile and .mh_sequences 643560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 644560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumdef pickline(file, key, casefold = 1): 645560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 646560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = open(file, 'r') 647560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except IOError: 648560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return None 649560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum pat = key + ':' 650560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if casefold: 651560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum prog = regex.compile(pat, regex.casefold) 652560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 653560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum prog = regex.compile(pat) 654560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum while 1: 655560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum line = f.readline() 656560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not line: break 657560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if prog.match(line) == len(line): 658560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum text = line[len(key)+1:] 659560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum while 1: 660560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum line = f.readline() 661560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if not line or \ 662560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum line[0] not in string.whitespace: 663560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum break 664560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum text = text + line 665560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return string.strip(text) 666560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum return None 667560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 668560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumdef updateline(file, key, value, casefold = 1): 669560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum try: 670560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = open(file, 'r') 671560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lines = f.readlines() 672560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f.close() 673560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum except IOError: 674560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lines = [] 675560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum pat = key + ':\(.*\)\n' 676560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if casefold: 677560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum prog = regex.compile(pat, regex.casefold) 678560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 679560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum prog = regex.compile(pat) 680560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if value is None: 681560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum newline = None 682560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 683560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum newline = '%s: %s' % (key, value) 684560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for i in range(len(lines)): 685560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum line = lines[i] 686560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if prog.match(line) == len(line): 687560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if newline is None: 688560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum del lines[i] 689560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 690560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lines[i] = newline 691560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum break 692560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum else: 693560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum if newline is not None: 694560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum lines.append(newline) 695560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = open(tempfile, 'w') 696560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for line in lines: 697560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f.write(line) 698560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f.close() 699560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 700560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 701560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum# Test program 702560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 703560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumdef test(): 704560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum global mh, f 705560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum os.system('rm -rf $HOME/Mail/@test') 706560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum mh = MH() 707560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum def do(s): print s; print eval(s) 708560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('mh.listfolders()') 709560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('mh.listallfolders()') 710560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum testfolders = ['@test', '@test/test1', '@test/test2', 711560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum '@test/test1/test11', '@test/test1/test12', 712560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum '@test/test1/test11/test111'] 713560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for t in testfolders: do('mh.makefolder(%s)' % `t`) 714560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('mh.listsubfolders(\'@test\')') 715560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('mh.listallsubfolders(\'@test\')') 716560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = mh.openfolder('@test') 717560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.listsubfolders()') 718560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.listallsubfolders()') 719560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.getsequences()') 720560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum seqs = f.getsequences() 721560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum seqs['foo'] = IntSet('1-10 12-20', ' ').tolist() 722560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum print seqs 723560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f.putsequences(seqs) 724560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.getsequences()') 725560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum testfolders.reverse() 726560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum for t in testfolders: do('mh.deletefolder(%s)' % `t`) 727560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('mh.getcontext()') 728560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum context = mh.getcontext() 729560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum f = mh.openfolder(context) 730560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.listmessages()') 731560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum do('f.getcurrent()') 732560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 733560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum 734560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossumif __name__ == '__main__': 735560131328c9ddfa25555048b1bf4d760c02e1dd7Guido van Rossum test() 736