]> granicus.if.org Git - python/commitdiff
Reindented with 4 spaces.
authorGuido van Rossum <guido@python.org>
Wed, 16 Apr 1997 02:47:12 +0000 (02:47 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 16 Apr 1997 02:47:12 +0000 (02:47 +0000)
Lib/mhlib.py

index b7acf553999ef82f0adb159dfe183dd97f4c01f3..34fc3b0b29ff9e3cde332a7a3a95d6bba051d4de 100644 (file)
@@ -94,648 +94,646 @@ Error = 'mhlib.Error'
 
 class MH:
 
-       # Constructor
-       def __init__(self, path = None, profile = None):
-               if not profile: profile = MH_PROFILE
-               self.profile = os.path.expanduser(profile)
-               if not path: path = self.getprofile('Path')
-               if not path: path = PATH
-               if not os.path.isabs(path) and path[0] != '~':
-                       path = os.path.join('~', path)
-               path = os.path.expanduser(path)
-               if not os.path.isdir(path): raise Error, 'MH() path not found'
-               self.path = path
-
-       # String representation
-       def __repr__(self):
-               return 'MH(%s, %s)' % (`self.path`, `self.profile`)
-
-       # Routine to print an error.  May be overridden by a derived class
-       def error(self, msg, *args):
-               sys.stderr.write('MH error: %s\n' % (msg % args))
-
-       # Return a profile entry, None if not found
-       def getprofile(self, key):
-               return pickline(self.profile, key)
-
-       # Return the path (the name of the collection's directory)
-       def getpath(self):
-               return self.path
-
-       # Return the name of the current folder
-       def getcontext(self):
-               context = pickline(os.path.join(self.getpath(), 'context'),
-                         'Current-Folder')
-               if not context: context = 'inbox'
-               return context
-
-       # Set the name of the current folder
-       def setcontext(self, context):
-               fn = os.path.join(self.getpath(), 'context')
-               f = open(fn, "w")
-               f.write("Current-Folder: %s\n" % context)
-               f.close()
-
-       # Return the names of the top-level folders
-       def listfolders(self):
-               folders = []
-               path = self.getpath()
-               for name in os.listdir(path):
-                       fullname = os.path.join(path, name)
-                       if os.path.isdir(fullname):
-                               folders.append(name)
-               folders.sort()
-               return folders
-
-       # Return the names of the subfolders in a given folder
-       # (prefixed with the given folder name)
-       def listsubfolders(self, name):
-               fullname = os.path.join(self.path, name)
-               # Get the link count so we can avoid listing folders
-               # that have no subfolders.
-               st = os.stat(fullname)
-               nlinks = st[ST_NLINK]
+    # Constructor
+    def __init__(self, path = None, profile = None):
+       if not profile: profile = MH_PROFILE
+       self.profile = os.path.expanduser(profile)
+       if not path: path = self.getprofile('Path')
+       if not path: path = PATH
+       if not os.path.isabs(path) and path[0] != '~':
+           path = os.path.join('~', path)
+       path = os.path.expanduser(path)
+       if not os.path.isdir(path): raise Error, 'MH() path not found'
+       self.path = path
+
+    # String representation
+    def __repr__(self):
+       return 'MH(%s, %s)' % (`self.path`, `self.profile`)
+
+    # Routine to print an error.  May be overridden by a derived class
+    def error(self, msg, *args):
+       sys.stderr.write('MH error: %s\n' % (msg % args))
+
+    # Return a profile entry, None if not found
+    def getprofile(self, key):
+       return pickline(self.profile, key)
+
+    # Return the path (the name of the collection's directory)
+    def getpath(self):
+       return self.path
+
+    # Return the name of the current folder
+    def getcontext(self):
+       context = pickline(os.path.join(self.getpath(), 'context'),
+                 'Current-Folder')
+       if not context: context = 'inbox'
+       return context
+
+    # Set the name of the current folder
+    def setcontext(self, context):
+       fn = os.path.join(self.getpath(), 'context')
+       f = open(fn, "w")
+       f.write("Current-Folder: %s\n" % context)
+       f.close()
+
+    # Return the names of the top-level folders
+    def listfolders(self):
+       folders = []
+       path = self.getpath()
+       for name in os.listdir(path):
+           fullname = os.path.join(path, name)
+           if os.path.isdir(fullname):
+               folders.append(name)
+       folders.sort()
+       return folders
+
+    # Return the names of the subfolders in a given folder
+    # (prefixed with the given folder name)
+    def listsubfolders(self, name):
+       fullname = os.path.join(self.path, name)
+       # Get the link count so we can avoid listing folders
+       # that have no subfolders.
+       st = os.stat(fullname)
+       nlinks = st[ST_NLINK]
+       if nlinks <= 2:
+           return []
+       subfolders = []
+       subnames = os.listdir(fullname)
+       for subname in subnames:
+           fullsubname = os.path.join(fullname, subname)
+           if os.path.isdir(fullsubname):
+               name_subname = os.path.join(name, subname)
+               subfolders.append(name_subname)
+               # Stop looking for subfolders when
+               # we've seen them all
+               nlinks = nlinks - 1
                if nlinks <= 2:
-                       return []
-               subfolders = []
-               subnames = os.listdir(fullname)
-               for subname in subnames:
-                       fullsubname = os.path.join(fullname, subname)
-                       if os.path.isdir(fullsubname):
-                               name_subname = os.path.join(name, subname)
-                               subfolders.append(name_subname)
-                               # Stop looking for subfolders when
-                               # we've seen them all
-                               nlinks = nlinks - 1
-                               if nlinks <= 2:
-                                       break
-               subfolders.sort()
-               return subfolders
-
-       # Return the names of all folders, including subfolders, recursively
-       def listallfolders(self):
-               return self.listallsubfolders('')
-
-       # Return the names of subfolders in a given folder, recursively
-       def listallsubfolders(self, name):
-               fullname = os.path.join(self.path, name)
-               # Get the link count so we can avoid listing folders
-               # that have no subfolders.
-               st = os.stat(fullname)
-               nlinks = st[ST_NLINK]
+                   break
+       subfolders.sort()
+       return subfolders
+
+    # Return the names of all folders, including subfolders, recursively
+    def listallfolders(self):
+       return self.listallsubfolders('')
+
+    # Return the names of subfolders in a given folder, recursively
+    def listallsubfolders(self, name):
+       fullname = os.path.join(self.path, name)
+       # Get the link count so we can avoid listing folders
+       # that have no subfolders.
+       st = os.stat(fullname)
+       nlinks = st[ST_NLINK]
+       if nlinks <= 2:
+           return []
+       subfolders = []
+       subnames = os.listdir(fullname)
+       for subname in subnames:
+           if subname[0] == ',' or isnumeric(subname): continue
+           fullsubname = os.path.join(fullname, subname)
+           if os.path.isdir(fullsubname):
+               name_subname = os.path.join(name, subname)
+               subfolders.append(name_subname)
+               if not os.path.islink(fullsubname):
+                   subsubfolders = self.listallsubfolders(
+                             name_subname)
+                   subfolders = subfolders + subsubfolders
+               # Stop looking for subfolders when
+               # we've seen them all
+               nlinks = nlinks - 1
                if nlinks <= 2:
-                       return []
-               subfolders = []
-               subnames = os.listdir(fullname)
-               for subname in subnames:
-                       if subname[0] == ',' or isnumeric(subname): continue
-                       fullsubname = os.path.join(fullname, subname)
-                       if os.path.isdir(fullsubname):
-                               name_subname = os.path.join(name, subname)
-                               subfolders.append(name_subname)
-                               if not os.path.islink(fullsubname):
-                                       subsubfolders = self.listallsubfolders(
-                                                 name_subname)
-                                       subfolders = subfolders + subsubfolders
-                               # Stop looking for subfolders when
-                               # we've seen them all
-                               nlinks = nlinks - 1
-                               if nlinks <= 2:
-                                       break
-               subfolders.sort()
-               return subfolders
-
-       # Return a new Folder object for the named folder
-       def openfolder(self, name):
-               return Folder(self, name)
-
-       # Create a new folder.  This raises os.error if the folder
-       # cannot be created
-       def makefolder(self, name):
-               protect = pickline(self.profile, 'Folder-Protect')
-               if protect and isnumeric(protect):
-                       mode = string.atoi(protect, 8)
-               else:
-                       mode = FOLDER_PROTECT
-               os.mkdir(os.path.join(self.getpath(), name), mode)
-
-       # Delete a folder.  This removes files in the folder but not
-       # subdirectories.  If deleting the folder itself fails it
-       # raises os.error
-       def deletefolder(self, name):
-               fullname = os.path.join(self.getpath(), name)
-               for subname in os.listdir(fullname):
-                       fullsubname = os.path.join(fullname, subname)
-                       try:
-                               os.unlink(fullsubname)
-                       except os.error:
-                               self.error('%s not deleted, continuing...' %
-                                         fullsubname)
-               os.rmdir(fullname)
+                   break
+       subfolders.sort()
+       return subfolders
+
+    # Return a new Folder object for the named folder
+    def openfolder(self, name):
+       return Folder(self, name)
+
+    # Create a new folder.  This raises os.error if the folder
+    # cannot be created
+    def makefolder(self, name):
+       protect = pickline(self.profile, 'Folder-Protect')
+       if protect and isnumeric(protect):
+           mode = string.atoi(protect, 8)
+       else:
+           mode = FOLDER_PROTECT
+       os.mkdir(os.path.join(self.getpath(), name), mode)
+
+    # Delete a folder.  This removes files in the folder but not
+    # subdirectories.  If deleting the folder itself fails it
+    # raises os.error
+    def deletefolder(self, name):
+       fullname = os.path.join(self.getpath(), name)
+       for subname in os.listdir(fullname):
+           fullsubname = os.path.join(fullname, subname)
+           try:
+               os.unlink(fullsubname)
+           except os.error:
+               self.error('%s not deleted, continuing...' %
+                         fullsubname)
+       os.rmdir(fullname)
 
 
 # Class representing a particular folder
 
 numericprog = regex.compile('^[1-9][0-9]*$')
 def isnumeric(str):
-       return numericprog.match(str) >= 0
+    return numericprog.match(str) >= 0
 
 class Folder:
 
-       # Constructor
-       def __init__(self, mh, name):
-               self.mh = mh
-               self.name = name
-               if not os.path.isdir(self.getfullname()):
-                       raise Error, 'no folder %s' % name
-
-       # String representation
-       def __repr__(self):
-               return 'Folder(%s, %s)' % (`self.mh`, `self.name`)
-
-       # Error message handler
-       def error(self, *args):
-               apply(self.mh.error, args)
-
-       # Return the full pathname of the folder
-       def getfullname(self):
-               return os.path.join(self.mh.path, self.name)
-
-       # Return the full pathname of the folder's sequences file
-       def getsequencesfilename(self):
-               return os.path.join(self.getfullname(), MH_SEQUENCES)
-
-       # Return the full pathname of a message in the folder
-       def getmessagefilename(self, n):
-               return os.path.join(self.getfullname(), str(n))
-
-       # Return list of direct subfolders
-       def listsubfolders(self):
-               return self.mh.listsubfolders(self.name)
-
-       # Return list of all subfolders
-       def listallsubfolders(self):
-               return self.mh.listallsubfolders(self.name)
-
-       # Return the list of messages currently present in the folder.
-       # As a side effect, set self.last to the last message (or 0)
-       def listmessages(self):
-               messages = []
-               match = numericprog.match
-               append = messages.append
-               for name in os.listdir(self.getfullname()):
-                       if match(name) >= 0:
-                               append(name)
-               messages = map(string.atoi, messages)
-               messages.sort()
-               if messages:
-                       self.last = messages[-1]
-               else:
-                       self.last = 0
-               return messages
+    # Constructor
+    def __init__(self, mh, name):
+       self.mh = mh
+       self.name = name
+       if not os.path.isdir(self.getfullname()):
+           raise Error, 'no folder %s' % name
+
+    # String representation
+    def __repr__(self):
+       return 'Folder(%s, %s)' % (`self.mh`, `self.name`)
+
+    # Error message handler
+    def error(self, *args):
+       apply(self.mh.error, args)
+
+    # Return the full pathname of the folder
+    def getfullname(self):
+       return os.path.join(self.mh.path, self.name)
+
+    # Return the full pathname of the folder's sequences file
+    def getsequencesfilename(self):
+       return os.path.join(self.getfullname(), MH_SEQUENCES)
+
+    # Return the full pathname of a message in the folder
+    def getmessagefilename(self, n):
+       return os.path.join(self.getfullname(), str(n))
+
+    # Return list of direct subfolders
+    def listsubfolders(self):
+       return self.mh.listsubfolders(self.name)
+
+    # Return list of all subfolders
+    def listallsubfolders(self):
+       return self.mh.listallsubfolders(self.name)
+
+    # Return the list of messages currently present in the folder.
+    # As a side effect, set self.last to the last message (or 0)
+    def listmessages(self):
+       messages = []
+       match = numericprog.match
+       append = messages.append
+       for name in os.listdir(self.getfullname()):
+           if match(name) >= 0:
+               append(name)
+       messages = map(string.atoi, messages)
+       messages.sort()
+       if messages:
+           self.last = messages[-1]
+       else:
+           self.last = 0
+       return messages
 
-       # Return the set of sequences for the folder
-       def getsequences(self):
-               sequences = {}
-               fullname = self.getsequencesfilename()
-               try:
-                       f = open(fullname, 'r')
-               except IOError:
-                       return sequences
-               while 1:
-                       line = f.readline()
-                       if not line: break
-                       fields = string.splitfields(line, ':')
-                       if len(fields) <> 2:
-                               self.error('bad sequence in %s: %s' %
-                                         (fullname, string.strip(line)))
-                       key = string.strip(fields[0])
-                       value = IntSet(string.strip(fields[1]), ' ').tolist()
-                       sequences[key] = value
-               return sequences
-
-       # Write the set of sequences back to the folder
-       def putsequences(self, sequences):
-               fullname = self.getsequencesfilename()
-               f = None
-               for key in sequences.keys():
-                       s = IntSet('', ' ')
-                       s.fromlist(sequences[key])
-                       if not f: f = open(fullname, 'w')
-                       f.write('%s: %s\n' % (key, s.tostring()))
-               if not f:
-                       try:
-                               os.unlink(fullname)
-                       except os.error:
-                               pass
-               else:
-                       f.close()
+    # Return the set of sequences for the folder
+    def getsequences(self):
+       sequences = {}
+       fullname = self.getsequencesfilename()
+       try:
+           f = open(fullname, 'r')
+       except IOError:
+           return sequences
+       while 1:
+           line = f.readline()
+           if not line: break
+           fields = string.splitfields(line, ':')
+           if len(fields) <> 2:
+               self.error('bad sequence in %s: %s' %
+                         (fullname, string.strip(line)))
+           key = string.strip(fields[0])
+           value = IntSet(string.strip(fields[1]), ' ').tolist()
+           sequences[key] = value
+       return sequences
+
+    # Write the set of sequences back to the folder
+    def putsequences(self, sequences):
+       fullname = self.getsequencesfilename()
+       f = None
+       for key in sequences.keys():
+           s = IntSet('', ' ')
+           s.fromlist(sequences[key])
+           if not f: f = open(fullname, 'w')
+           f.write('%s: %s\n' % (key, s.tostring()))
+       if not f:
+           try:
+               os.unlink(fullname)
+           except os.error:
+               pass
+       else:
+           f.close()
 
-       # Return the current message.  Raise KeyError when there is none
-       def getcurrent(self):
+    # Return the current message.  Raise KeyError when there is none
+    def getcurrent(self):
+       seqs = self.getsequences()
+       try:
+           return max(seqs['cur'])
+       except (ValueError, KeyError):
+           raise Error, "no cur message"
+
+    # Set the current message
+    def setcurrent(self, n):
+       updateline(self.getsequencesfilename(), 'cur', str(n), 0)
+
+    # Parse an MH sequence specification into a message list.
+    # Attempt to mimic mh-sequence(5) as close as possible.
+    # Also attempt to mimic observed behavior regarding which
+    # conditions cause which error messages
+    def parsesequence(self, seq):
+       # XXX Still not complete (see mh-format(5)).
+       # Missing are:
+       # - 'prev', 'next' as count
+       # - Sequence-Negation option
+       all = self.listmessages()
+       # Observed behavior: test for empty folder is done first
+       if not all:
+           raise Error, "no messages in %s" % self.name
+       # Common case first: all is frequently the default
+       if seq == 'all':
+           return all
+       # Test for X:Y before X-Y because 'seq:-n' matches both
+       i = string.find(seq, ':')
+       if i >= 0:
+           head, dir, tail = seq[:i], '', seq[i+1:]
+           if tail[:1] in '-+':
+               dir, tail = tail[:1], tail[1:]
+           if not isnumeric(tail):
+               raise Error, "bad message list %s" % seq
+           try:
+               count = string.atoi(tail)
+           except (ValueError, OverflowError):
+               # Can't use sys.maxint because of i+count below
+               count = len(all)
+           try:
+               anchor = self._parseindex(head, all)
+           except Error, msg:
                seqs = self.getsequences()
-               try:
-                       return max(seqs['cur'])
-               except (ValueError, KeyError):
-                       raise Error, "no cur message"
-
-       # Set the current message
-       def setcurrent(self, n):
-               updateline(self.getsequencesfilename(), 'cur', str(n), 0)
-
-       # Parse an MH sequence specification into a message list.
-       # Attempt to mimic mh-sequence(5) as close as possible.
-       # Also attempt to mimic observed behavior regarding which
-       # conditions cause which error messages
-       def parsesequence(self, seq):
-               # XXX Still not complete (see mh-format(5)).
-               # Missing are:
-               # - 'prev', 'next' as count
-               # - Sequence-Negation option
-               all = self.listmessages()
-               # Observed behavior: test for empty folder is done first
-               if not all:
-                       raise Error, "no messages in %s" % self.name
-               # Common case first: all is frequently the default
-               if seq == 'all':
-                       return all
-               # Test for X:Y before X-Y because 'seq:-n' matches both
-               i = string.find(seq, ':')
-               if i >= 0:
-                       head, dir, tail = seq[:i], '', seq[i+1:]
-                       if tail[:1] in '-+':
-                               dir, tail = tail[:1], tail[1:]
-                       if not isnumeric(tail):
-                               raise Error, "bad message list %s" % seq
-                       try:
-                               count = string.atoi(tail)
-                       except (ValueError, OverflowError):
-                               # Can't use sys.maxint because of i+count below
-                               count = len(all)
-                       try:
-                               anchor = self._parseindex(head, all)
-                       except Error, msg:
-                               seqs = self.getsequences()
-                               if not seqs.has_key(head):
-                                       if not msg:
-                                           msg = "bad message list %s" % seq
-                                       raise Error, msg, sys.exc_traceback
-                               msgs = seqs[head]
-                               if not msgs:
-                                       raise Error, "sequence %s empty" % head
-                               if dir == '-':
-                                       return msgs[-count:]
-                               else:
-                                       return msgs[:count]
-                       else:
-                               if not dir:
-                                       if head in ('prev', 'last'):
-                                               dir = '-'
-                               if dir == '-':
-                                       i = bisect(all, anchor)
-                                       return all[max(0, i-count):i]
-                               else:
-                                       i = bisect(all, anchor-1)
-                                       return all[i:i+count]
-               # Test for X-Y next
-               i = string.find(seq, '-')
-               if i >= 0:
-                       begin = self._parseindex(seq[:i], all)
-                       end = self._parseindex(seq[i+1:], all)
-                       i = bisect(all, begin-1)
-                       j = bisect(all, end)
-                       r = all[i:j]
-                       if not r:
-                               raise Error, "bad message list %s" % seq
-                       return r
-               # Neither X:Y nor X-Y; must be a number or a (pseudo-)sequence
-               try:
-                       n = self._parseindex(seq, all)
-               except Error, msg:
-                       seqs = self.getsequences()
-                       if not seqs.has_key(seq):
-                               if not msg:
-                                       msg = "bad message list %s" % seq
-                               raise Error, msg
-                       return seqs[seq]
+               if not seqs.has_key(head):
+                   if not msg:
+                       msg = "bad message list %s" % seq
+                   raise Error, msg, sys.exc_traceback
+               msgs = seqs[head]
+               if not msgs:
+                   raise Error, "sequence %s empty" % head
+               if dir == '-':
+                   return msgs[-count:]
                else:
-                       if n not in all:
-                               if isnumeric(seq):
-                                       raise Error, \
-                                             "message %d doesn't exist" % n
-                               else:
-                                       raise Error, "no %s message" % seq
-                       else:
-                               return [n]
-
-       # Internal: parse a message number (or cur, first, etc.)
-       def _parseindex(self, seq, all):
+                   return msgs[:count]
+           else:
+               if not dir:
+                   if head in ('prev', 'last'):
+                       dir = '-'
+               if dir == '-':
+                   i = bisect(all, anchor)
+                   return all[max(0, i-count):i]
+               else:
+                   i = bisect(all, anchor-1)
+                   return all[i:i+count]
+       # Test for X-Y next
+       i = string.find(seq, '-')
+       if i >= 0:
+           begin = self._parseindex(seq[:i], all)
+           end = self._parseindex(seq[i+1:], all)
+           i = bisect(all, begin-1)
+           j = bisect(all, end)
+           r = all[i:j]
+           if not r:
+               raise Error, "bad message list %s" % seq
+           return r
+       # Neither X:Y nor X-Y; must be a number or a (pseudo-)sequence
+       try:
+           n = self._parseindex(seq, all)
+       except Error, msg:
+           seqs = self.getsequences()
+           if not seqs.has_key(seq):
+               if not msg:
+                   msg = "bad message list %s" % seq
+               raise Error, msg
+           return seqs[seq]
+       else:
+           if n not in all:
                if isnumeric(seq):
-                       try:
-                               return string.atoi(seq)
-                       except (OverflowError, ValueError):
-                               return sys.maxint
-               if seq in ('cur', '.'):
-                       return self.getcurrent()
-               if seq == 'first':
-                       return all[0]
-               if seq == 'last':
-                       return all[-1]
-               if seq == 'next':
-                       n = self.getcurrent()
-                       i = bisect(all, n)
-                       try:
-                               return all[i]
-                       except IndexError:
-                               raise Error, "no next message"
-               if seq == 'prev':
-                       n = self.getcurrent()
-                       i = bisect(all, n-1)
-                       if i == 0:
-                               raise Error, "no prev message"
-                       try:
-                               return all[i-1]
-                       except IndexError:
-                               raise Error, "no prev message"
-               raise Error, None
-
-       # Open a message -- returns a Message object
-       def openmessage(self, n):
-               return Message(self, n)
-
-       # Remove one or more messages -- may raise os.error
-       def removemessages(self, list):
-               errors = []
-               deleted = []
-               for n in list:
-                       path = self.getmessagefilename(n)
-                       commapath = self.getmessagefilename(',' + str(n))
-                       try:
-                               os.unlink(commapath)
-                       except os.error:
-                               pass
-                       try:
-                               os.rename(path, commapath)
-                       except os.error, msg:
-                               errors.append(msg)
-                       else:
-                               deleted.append(n)
-               if deleted:
-                       self.removefromallsequences(deleted)
-               if errors:
-                       if len(errors) == 1:
-                               raise os.error, errors[0]
-                       else:
-                               raise os.error, ('multiple errors:', errors)
-
-       # Refile one or more messages -- may raise os.error.
-       # 'tofolder' is an open folder object
-       def refilemessages(self, list, tofolder, keepsequences=0):
-               errors = []
-               refiled = {}
-               for n in list:
-                       ton = tofolder.getlast() + 1
-                       path = self.getmessagefilename(n)
-                       topath = tofolder.getmessagefilename(ton)
-                       try:
-                               os.rename(path, topath)
-                       except os.error:
-                               # Try copying
-                               try:
-                                       shutil.copy2(path, topath)
-                                       os.unlink(path)
-                               except (IOError, os.error), msg:
-                                       errors.append(msg)
-                                       try:
-                                               os.unlink(topath)
-                                       except os.error:
-                                               pass
-                                       continue
-                       tofolder.setlast(ton)
-                       refiled[n] = ton
-               if refiled:
-                       if keepsequences:
-                               tofolder._copysequences(self, refiled.items())
-                       self.removefromallsequences(refiled.keys())
-               if errors:
-                       if len(errors) == 1:
-                               raise os.error, errors[0]
-                       else:
-                               raise os.error, ('multiple errors:', errors)
-
-       # Helper for refilemessages() to copy sequences
-       def _copysequences(self, fromfolder, refileditems):
-               fromsequences = fromfolder.getsequences()
-               tosequences = self.getsequences()
-               changed = 0
-               for name, seq in fromsequences.items():
-                       try:
-                               toseq = tosequences[name]
-                               new = 0
-                       except:
-                               toseq = []
-                               new = 1
-                       for fromn, ton in refileditems:
-                               if fromn in seq:
-                                       toseq.append(ton)
-                                       changed = 1
-                       if new and toseq:
-                               tosequences[name] = toseq
-               if changed:
-                       self.putsequences(tosequences)
-
-       # Move one message over a specific destination message,
-       # which may or may not already exist.
-       def movemessage(self, n, tofolder, ton):
-               path = self.getmessagefilename(n)
-               # Open it to check that it exists
-               f = open(path)
-               f.close()
-               del f
-               topath = tofolder.getmessagefilename(ton)
-               backuptopath = tofolder.getmessagefilename(',%d' % ton)
+                   raise Error, "message %d doesn't exist" % n
+               else:
+                   raise Error, "no %s message" % seq
+           else:
+               return [n]
+
+    # Internal: parse a message number (or cur, first, etc.)
+    def _parseindex(self, seq, all):
+       if isnumeric(seq):
+           try:
+               return string.atoi(seq)
+           except (OverflowError, ValueError):
+               return sys.maxint
+       if seq in ('cur', '.'):
+           return self.getcurrent()
+       if seq == 'first':
+           return all[0]
+       if seq == 'last':
+           return all[-1]
+       if seq == 'next':
+           n = self.getcurrent()
+           i = bisect(all, n)
+           try:
+               return all[i]
+           except IndexError:
+               raise Error, "no next message"
+       if seq == 'prev':
+           n = self.getcurrent()
+           i = bisect(all, n-1)
+           if i == 0:
+               raise Error, "no prev message"
+           try:
+               return all[i-1]
+           except IndexError:
+               raise Error, "no prev message"
+       raise Error, None
+
+    # Open a message -- returns a Message object
+    def openmessage(self, n):
+       return Message(self, n)
+
+    # Remove one or more messages -- may raise os.error
+    def removemessages(self, list):
+       errors = []
+       deleted = []
+       for n in list:
+           path = self.getmessagefilename(n)
+           commapath = self.getmessagefilename(',' + str(n))
+           try:
+               os.unlink(commapath)
+           except os.error:
+               pass
+           try:
+               os.rename(path, commapath)
+           except os.error, msg:
+               errors.append(msg)
+           else:
+               deleted.append(n)
+       if deleted:
+           self.removefromallsequences(deleted)
+       if errors:
+           if len(errors) == 1:
+               raise os.error, errors[0]
+           else:
+               raise os.error, ('multiple errors:', errors)
+
+    # Refile one or more messages -- may raise os.error.
+    # 'tofolder' is an open folder object
+    def refilemessages(self, list, tofolder, keepsequences=0):
+       errors = []
+       refiled = {}
+       for n in list:
+           ton = tofolder.getlast() + 1
+           path = self.getmessagefilename(n)
+           topath = tofolder.getmessagefilename(ton)
+           try:
+               os.rename(path, topath)
+           except os.error:
+               # Try copying
                try:
-                       os.rename(topath, backuptopath)
-               except os.error:
+                   shutil.copy2(path, topath)
+                   os.unlink(path)
+               except (IOError, os.error), msg:
+                   errors.append(msg)
+                   try:
+                       os.unlink(topath)
+                   except os.error:
                        pass
-               try:
-                       os.rename(path, topath)
-               except os.error:
-                       # Try copying
-                       ok = 0
-                       try:
-                               tofolder.setlast(None)
-                               shutil.copy2(path, topath)
-                               ok = 1
-                       finally:
-                               if not ok:
-                                       try:
-                                               os.unlink(topath)
-                                       except os.error:
-                                               pass
-                       os.unlink(path)
-               self.removefromallsequences([n])
-
-       # Copy one message over a specific destination message,
-       # which may or may not already exist.
-       def copymessage(self, n, tofolder, ton):
-               path = self.getmessagefilename(n)
-               # Open it to check that it exists
-               f = open(path)
-               f.close()
-               del f
-               topath = tofolder.getmessagefilename(ton)
-               backuptopath = tofolder.getmessagefilename(',%d' % ton)
-               try:
-                       os.rename(topath, backuptopath)
-               except os.error:
+                   continue
+           tofolder.setlast(ton)
+           refiled[n] = ton
+       if refiled:
+           if keepsequences:
+               tofolder._copysequences(self, refiled.items())
+           self.removefromallsequences(refiled.keys())
+       if errors:
+           if len(errors) == 1:
+               raise os.error, errors[0]
+           else:
+               raise os.error, ('multiple errors:', errors)
+
+    # Helper for refilemessages() to copy sequences
+    def _copysequences(self, fromfolder, refileditems):
+       fromsequences = fromfolder.getsequences()
+       tosequences = self.getsequences()
+       changed = 0
+       for name, seq in fromsequences.items():
+           try:
+               toseq = tosequences[name]
+               new = 0
+           except:
+               toseq = []
+               new = 1
+           for fromn, ton in refileditems:
+               if fromn in seq:
+                   toseq.append(ton)
+                   changed = 1
+           if new and toseq:
+               tosequences[name] = toseq
+       if changed:
+           self.putsequences(tosequences)
+
+    # Move one message over a specific destination message,
+    # which may or may not already exist.
+    def movemessage(self, n, tofolder, ton):
+       path = self.getmessagefilename(n)
+       # Open it to check that it exists
+       f = open(path)
+       f.close()
+       del f
+       topath = tofolder.getmessagefilename(ton)
+       backuptopath = tofolder.getmessagefilename(',%d' % ton)
+       try:
+           os.rename(topath, backuptopath)
+       except os.error:
+           pass
+       try:
+           os.rename(path, topath)
+       except os.error:
+           # Try copying
+           ok = 0
+           try:
+               tofolder.setlast(None)
+               shutil.copy2(path, topath)
+               ok = 1
+           finally:
+               if not ok:
+                   try:
+                       os.unlink(topath)
+                   except os.error:
                        pass
-               ok = 0
+           os.unlink(path)
+       self.removefromallsequences([n])
+
+    # Copy one message over a specific destination message,
+    # which may or may not already exist.
+    def copymessage(self, n, tofolder, ton):
+       path = self.getmessagefilename(n)
+       # Open it to check that it exists
+       f = open(path)
+       f.close()
+       del f
+       topath = tofolder.getmessagefilename(ton)
+       backuptopath = tofolder.getmessagefilename(',%d' % ton)
+       try:
+           os.rename(topath, backuptopath)
+       except os.error:
+           pass
+       ok = 0
+       try:
+           tofolder.setlast(None)
+           shutil.copy2(path, topath)
+           ok = 1
+       finally:
+           if not ok:
                try:
-                       tofolder.setlast(None)
-                       shutil.copy2(path, topath)
-                       ok = 1
-               finally:
-                       if not ok:
-                               try:
-                                       os.unlink(topath)
-                               except os.error:
-                                       pass
-
-       # Remove one or more messages from all sequeuces (including last)
-       # -- but not from 'cur'!!!
-       def removefromallsequences(self, list):
-               if hasattr(self, 'last') and self.last in list:
-                       del self.last
-               sequences = self.getsequences()
-               changed = 0
-               for name, seq in sequences.items():
-                       if name == 'cur':
-                               continue
-                       for n in list:
-                               if n in seq:
-                                       seq.remove(n)
-                                       changed = 1
-                                       if not seq:
-                                               del sequences[name]
-               if changed:
-                       self.putsequences(sequences)
-
-       # Return the last message number
-       def getlast(self):
-               if not hasattr(self, 'last'):
-                       messages = self.listmessages()
-               return self.last
-
-       # Set the last message number
-       def setlast(self, last):
-               if last is None:
-                       if hasattr(self, 'last'):
-                               del self.last
-               else:
-                       self.last = last
+                   os.unlink(topath)
+               except os.error:
+                   pass
+
+    # Remove one or more messages from all sequeuces (including last)
+    # -- but not from 'cur'!!!
+    def removefromallsequences(self, list):
+       if hasattr(self, 'last') and self.last in list:
+           del self.last
+       sequences = self.getsequences()
+       changed = 0
+       for name, seq in sequences.items():
+           if name == 'cur':
+               continue
+           for n in list:
+               if n in seq:
+                   seq.remove(n)
+                   changed = 1
+                   if not seq:
+                       del sequences[name]
+       if changed:
+           self.putsequences(sequences)
+
+    # Return the last message number
+    def getlast(self):
+       if not hasattr(self, 'last'):
+           messages = self.listmessages()
+       return self.last
+
+    # Set the last message number
+    def setlast(self, last):
+       if last is None:
+           if hasattr(self, 'last'):
+               del self.last
+       else:
+           self.last = last
 
 class Message(mimetools.Message):
 
-       # Constructor
-       def __init__(self, f, n, fp = None):
-               self.folder = f
-               self.number = n
-               if not fp:
-                       path = f.getmessagefilename(n)
-                       fp = open(path, 'r')
-               mimetools.Message.__init__(self, fp)
-
-       # String representation
-       def __repr__(self):
-               return 'Message(%s, %s)' % (repr(self.folder), self.number)
-
-       # Return the message's header text as a string.  If an
-       # argument is specified, it is used as a filter predicate to
-       # decide which headers to return (its argument is the header
-       # name converted to lower case).
-       def getheadertext(self, pred = None):
-               if not pred:
-                       return string.joinfields(self.headers, '')
-               headers = []
-               hit = 0
-               for line in self.headers:
-                       if line[0] not in string.whitespace:
-                               i = string.find(line, ':')
-                               if i > 0:
-                                       hit = pred(string.lower(line[:i]))
-                       if hit: headers.append(line)
-               return string.joinfields(headers, '')
-
-       # Return the message's body text as string.  This undoes a
-       # Content-Transfer-Encoding, but does not interpret other MIME
-       # features (e.g. multipart messages).  To suppress to
-       # decoding, pass a 0 as argument
-       def getbodytext(self, decode = 1):
-               self.fp.seek(self.startofbody)
-               encoding = self.getencoding()
-               if not decode or encoding in ('7bit', '8bit', 'binary'):
-                       return self.fp.read()
-               from StringIO import StringIO
-               output = StringIO()
-               mimetools.decode(self.fp, output, encoding)
-               return output.getvalue()
-
-       # Only for multipart messages: return the message's body as a
-       # list of SubMessage objects.  Each submessage object behaves
-       # (almost) as a Message object.
-       def getbodyparts(self):
-               if self.getmaintype() != 'multipart':
-                       raise Error, \
-                             'Content-Type is not multipart/*'
-               bdry = self.getparam('boundary')
-               if not bdry:
-                       raise Error, 'multipart/* without boundary param'
-               self.fp.seek(self.startofbody)
-               mf = multifile.MultiFile(self.fp)
-               mf.push(bdry)
-               parts = []
-               while mf.next():
-                       n = str(self.number) + '.' + `1 + len(parts)`
-                       part = SubMessage(self.folder, n, mf)
-                       parts.append(part)
-               mf.pop()
-               return parts
-
-       # Return body, either a string or a list of messages
-       def getbody(self):
-               if self.getmaintype() == 'multipart':
-                       return self.getbodyparts()
-               else:
-                       return self.getbodytext()
+    # Constructor
+    def __init__(self, f, n, fp = None):
+       self.folder = f
+       self.number = n
+       if not fp:
+           path = f.getmessagefilename(n)
+           fp = open(path, 'r')
+       mimetools.Message.__init__(self, fp)
+
+    # String representation
+    def __repr__(self):
+       return 'Message(%s, %s)' % (repr(self.folder), self.number)
+
+    # Return the message's header text as a string.  If an
+    # argument is specified, it is used as a filter predicate to
+    # decide which headers to return (its argument is the header
+    # name converted to lower case).
+    def getheadertext(self, pred = None):
+       if not pred:
+           return string.joinfields(self.headers, '')
+       headers = []
+       hit = 0
+       for line in self.headers:
+           if line[0] not in string.whitespace:
+               i = string.find(line, ':')
+               if i > 0:
+                   hit = pred(string.lower(line[:i]))
+           if hit: headers.append(line)
+       return string.joinfields(headers, '')
+
+    # Return the message's body text as string.  This undoes a
+    # Content-Transfer-Encoding, but does not interpret other MIME
+    # features (e.g. multipart messages).  To suppress to
+    # decoding, pass a 0 as argument
+    def getbodytext(self, decode = 1):
+       self.fp.seek(self.startofbody)
+       encoding = self.getencoding()
+       if not decode or encoding in ('7bit', '8bit', 'binary'):
+           return self.fp.read()
+       from StringIO import StringIO
+       output = StringIO()
+       mimetools.decode(self.fp, output, encoding)
+       return output.getvalue()
+
+    # Only for multipart messages: return the message's body as a
+    # list of SubMessage objects.  Each submessage object behaves
+    # (almost) as a Message object.
+    def getbodyparts(self):
+       if self.getmaintype() != 'multipart':
+           raise Error, 'Content-Type is not multipart/*'
+       bdry = self.getparam('boundary')
+       if not bdry:
+           raise Error, 'multipart/* without boundary param'
+       self.fp.seek(self.startofbody)
+       mf = multifile.MultiFile(self.fp)
+       mf.push(bdry)
+       parts = []
+       while mf.next():
+           n = str(self.number) + '.' + `1 + len(parts)`
+           part = SubMessage(self.folder, n, mf)
+           parts.append(part)
+       mf.pop()
+       return parts
+
+    # Return body, either a string or a list of messages
+    def getbody(self):
+       if self.getmaintype() == 'multipart':
+           return self.getbodyparts()
+       else:
+           return self.getbodytext()
 
 
 class SubMessage(Message):
 
-       # Constructor
-       def __init__(self, f, n, fp):
-               Message.__init__(self, f, n, fp)
-               if self.getmaintype() == 'multipart':
-                       self.body = Message.getbodyparts(self)
-               else:
-                       self.body = Message.getbodytext(self)
-                       # XXX If this is big, should remember file pointers
+    # Constructor
+    def __init__(self, f, n, fp):
+       Message.__init__(self, f, n, fp)
+       if self.getmaintype() == 'multipart':
+           self.body = Message.getbodyparts(self)
+       else:
+           self.body = Message.getbodytext(self)
+           # XXX If this is big, should remember file pointers
 
-       # String representation
-       def __repr__(self):
-               f, n, fp = self.folder, self.number, self.fp
-               return 'SubMessage(%s, %s, %s)' % (f, n, fp)
+    # String representation
+    def __repr__(self):
+       f, n, fp = self.folder, self.number, self.fp
+       return 'SubMessage(%s, %s, %s)' % (f, n, fp)
 
-       def getbodytext(self):
-               if type(self.body) == type(''):
-                       return self.body
+    def getbodytext(self):
+       if type(self.body) == type(''):
+           return self.body
 
-       def getbodyparts(self):
-               if type(self.body) == type([]):
-                       return self.body
+    def getbodyparts(self):
+       if type(self.body) == type([]):
+           return self.body
 
-       def getbody(self):
-               return self.body
+    def getbody(self):
+       return self.body
 
 
 # Class implementing sets of integers.
@@ -761,225 +759,224 @@ class SubMessage(Message):
 
 class IntSet:
 
-       def __init__(self, data = None, sep = ',', rng = '-'):
-               self.pairs = []
-               self.sep = sep
-               self.rng = rng
-               if data: self.fromstring(data)
-
-       def reset(self):
-               self.pairs = []
-
-       def __cmp__(self, other):
-               return cmp(self.pairs, other.pairs)
-
-       def __hash__(self):
-               return hash(self.pairs)
-
-       def __repr__(self):
-               return 'IntSet(%s, %s, %s)' % (`self.tostring()`,
-                         `self.sep`, `self.rng`)
-
-       def normalize(self):
-               self.pairs.sort()
-               i = 1
-               while i < len(self.pairs):
-                       alo, ahi = self.pairs[i-1]
-                       blo, bhi = self.pairs[i]
-                       if ahi >= blo-1:
-                               self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
-                       else:
-                               i = i+1
-
-       def tostring(self):
-               s = ''
-               for lo, hi in self.pairs:
-                       if lo == hi: t = `lo`
-                       else: t = `lo` + self.rng + `hi`
-                       if s: s = s + (self.sep + t)
-                       else: s = t
-               return s
-
-       def tolist(self):
-               l = []
-               for lo, hi in self.pairs:
-                       m = range(lo, hi+1)
-                       l = l + m
-               return l
-
-       def fromlist(self, list):
-               for i in list:
-                       self.append(i)
-
-       def clone(self):
-               new = IntSet()
-               new.pairs = self.pairs[:]
-               return new
-
-       def min(self):
-               return self.pairs[0][0]
-
-       def max(self):
-               return self.pairs[-1][-1]
-
-       def contains(self, x):
-               for lo, hi in self.pairs:
-                       if lo <= x <= hi: return 1
-               return 0
-
-       def append(self, x):
-               for i in range(len(self.pairs)):
-                       lo, hi = self.pairs[i]
-                       if x < lo: # Need to insert before
-                               if x+1 == lo:
-                                       self.pairs[i] = (x, hi)
-                               else:
-                                       self.pairs.insert(i, (x, x))
-                               if i > 0 and x-1 == self.pairs[i-1][1]:
-                                       # Merge with previous
-                                       self.pairs[i-1:i+1] = [
-                                               (self.pairs[i-1][0],
-                                                self.pairs[i][1])
-                                             ]
-                               return
-                       if x <= hi: # Already in set
-                               return
-               i = len(self.pairs) - 1
-               if i >= 0:
-                       lo, hi = self.pairs[i]
-                       if x-1 == hi:
-                               self.pairs[i] = lo, x
-                               return
-               self.pairs.append((x, x))
-
-       def addpair(self, xlo, xhi):
-               if xlo > xhi: return
-               self.pairs.append((xlo, xhi))
-               self.normalize()
-
-       def fromstring(self, data):
-               import string, regsub
-               new = []
-               for part in regsub.split(data, self.sep):
-                       list = []
-                       for subp in regsub.split(part, self.rng):
-                               s = string.strip(subp)
-                               list.append(string.atoi(s))
-                       if len(list) == 1:
-                               new.append((list[0], list[0]))
-                       elif len(list) == 2 and list[0] <= list[1]:
-                               new.append((list[0], list[1]))
-                       else:
-                               raise ValueError, 'bad data passed to IntSet'
-               self.pairs = self.pairs + new
-               self.normalize()
+    def __init__(self, data = None, sep = ',', rng = '-'):
+       self.pairs = []
+       self.sep = sep
+       self.rng = rng
+       if data: self.fromstring(data)
+
+    def reset(self):
+       self.pairs = []
+
+    def __cmp__(self, other):
+       return cmp(self.pairs, other.pairs)
+
+    def __hash__(self):
+       return hash(self.pairs)
+
+    def __repr__(self):
+       return 'IntSet(%s, %s, %s)' % (`self.tostring()`,
+                 `self.sep`, `self.rng`)
+
+    def normalize(self):
+       self.pairs.sort()
+       i = 1
+       while i < len(self.pairs):
+           alo, ahi = self.pairs[i-1]
+           blo, bhi = self.pairs[i]
+           if ahi >= blo-1:
+               self.pairs[i-1:i+1] = [(alo, max(ahi, bhi))]
+           else:
+               i = i+1
+
+    def tostring(self):
+       s = ''
+       for lo, hi in self.pairs:
+           if lo == hi: t = `lo`
+           else: t = `lo` + self.rng + `hi`
+           if s: s = s + (self.sep + t)
+           else: s = t
+       return s
+
+    def tolist(self):
+       l = []
+       for lo, hi in self.pairs:
+           m = range(lo, hi+1)
+           l = l + m
+       return l
+
+    def fromlist(self, list):
+       for i in list:
+           self.append(i)
+
+    def clone(self):
+       new = IntSet()
+       new.pairs = self.pairs[:]
+       return new
+
+    def min(self):
+       return self.pairs[0][0]
+
+    def max(self):
+       return self.pairs[-1][-1]
+
+    def contains(self, x):
+       for lo, hi in self.pairs:
+           if lo <= x <= hi: return 1
+       return 0
+
+    def append(self, x):
+       for i in range(len(self.pairs)):
+           lo, hi = self.pairs[i]
+           if x < lo: # Need to insert before
+               if x+1 == lo:
+                   self.pairs[i] = (x, hi)
+               else:
+                   self.pairs.insert(i, (x, x))
+               if i > 0 and x-1 == self.pairs[i-1][1]:
+                   # Merge with previous
+                   self.pairs[i-1:i+1] = [
+                           (self.pairs[i-1][0],
+                            self.pairs[i][1])
+                         ]
+               return
+           if x <= hi: # Already in set
+               return
+       i = len(self.pairs) - 1
+       if i >= 0:
+           lo, hi = self.pairs[i]
+           if x-1 == hi:
+               self.pairs[i] = lo, x
+               return
+       self.pairs.append((x, x))
+
+    def addpair(self, xlo, xhi):
+       if xlo > xhi: return
+       self.pairs.append((xlo, xhi))
+       self.normalize()
+
+    def fromstring(self, data):
+       import string, regsub
+       new = []
+       for part in regsub.split(data, self.sep):
+           list = []
+           for subp in regsub.split(part, self.rng):
+               s = string.strip(subp)
+               list.append(string.atoi(s))
+           if len(list) == 1:
+               new.append((list[0], list[0]))
+           elif len(list) == 2 and list[0] <= list[1]:
+               new.append((list[0], list[1]))
+           else:
+               raise ValueError, 'bad data passed to IntSet'
+       self.pairs = self.pairs + new
+       self.normalize()
 
 
 # Subroutines to read/write entries in .mh_profile and .mh_sequences
 
 def pickline(file, key, casefold = 1):
-       try:
-               f = open(file, 'r')
-       except IOError:
-               return None
-       pat = key + ':'
-       if casefold:
-               prog = regex.compile(pat, regex.casefold)
-       else:
-               prog = regex.compile(pat)
-       while 1:
-               line = f.readline()
-               if not line: break
-               if prog.match(line) >= 0:
-                       text = line[len(key)+1:]
-                       while 1:
-                               line = f.readline()
-                               if not line or \
-                                  line[0] not in string.whitespace:
-                                       break
-                               text = text + line
-                       return string.strip(text)
+    try:
+       f = open(file, 'r')
+    except IOError:
        return None
+    pat = key + ':'
+    if casefold:
+       prog = regex.compile(pat, regex.casefold)
+    else:
+       prog = regex.compile(pat)
+    while 1:
+       line = f.readline()
+       if not line: break
+       if prog.match(line) >= 0:
+           text = line[len(key)+1:]
+           while 1:
+               line = f.readline()
+               if not line or line[0] not in string.whitespace:
+                   break
+               text = text + line
+           return string.strip(text)
+    return None
 
 def updateline(file, key, value, casefold = 1):
-       try:
-               f = open(file, 'r')
-               lines = f.readlines()
-               f.close()
-       except IOError:
-               lines = []
-       pat = key + ':\(.*\)\n'
-       if casefold:
-               prog = regex.compile(pat, regex.casefold)
-       else:
-               prog = regex.compile(pat)
-       if value is None:
-               newline = None
-       else:
-               newline = '%s: %s\n' % (key, value)
-       for i in range(len(lines)):
-               line = lines[i]
-               if prog.match(line) == len(line):
-                       if newline is None:
-                               del lines[i]
-                       else:
-                               lines[i] = newline
-                       break
-       else:
-               if newline is not None:
-                       lines.append(newline)
-       tempfile = file + "~"
-       f = open(tempfile, 'w')
-       for line in lines:
-               f.write(line)
+    try:
+       f = open(file, 'r')
+       lines = f.readlines()
        f.close()
-       os.rename(tempfile, file)
+    except IOError:
+       lines = []
+    pat = key + ':\(.*\)\n'
+    if casefold:
+       prog = regex.compile(pat, regex.casefold)
+    else:
+       prog = regex.compile(pat)
+    if value is None:
+       newline = None
+    else:
+       newline = '%s: %s\n' % (key, value)
+    for i in range(len(lines)):
+       line = lines[i]
+       if prog.match(line) == len(line):
+           if newline is None:
+               del lines[i]
+           else:
+               lines[i] = newline
+           break
+    else:
+       if newline is not None:
+           lines.append(newline)
+    tempfile = file + "~"
+    f = open(tempfile, 'w')
+    for line in lines:
+       f.write(line)
+    f.close()
+    os.rename(tempfile, file)
 
 
 # Test program
 
 def test():
-       global mh, f
-       os.system('rm -rf $HOME/Mail/@test')
-       mh = MH()
-       def do(s): print s; print eval(s)
-       do('mh.listfolders()')
-       do('mh.listallfolders()')
-       testfolders = ['@test', '@test/test1', '@test/test2',
-                      '@test/test1/test11', '@test/test1/test12',
-                      '@test/test1/test11/test111']
-       for t in testfolders: do('mh.makefolder(%s)' % `t`)
-       do('mh.listsubfolders(\'@test\')')
-       do('mh.listallsubfolders(\'@test\')')
-       f = mh.openfolder('@test')
-       do('f.listsubfolders()')
-       do('f.listallsubfolders()')
-       do('f.getsequences()')
-       seqs = f.getsequences()
-       seqs['foo'] = IntSet('1-10 12-20', ' ').tolist()
-       print seqs
-       f.putsequences(seqs)
-       do('f.getsequences()')
-       testfolders.reverse()
-       for t in testfolders: do('mh.deletefolder(%s)' % `t`)
-       do('mh.getcontext()')
-       context = mh.getcontext()
-       f = mh.openfolder(context)
-       do('f.getcurrent()')
-       for seq in ['first', 'last', 'cur', '.', 'prev', 'next',
-                   'first:3', 'last:3', 'cur:3', 'cur:-3',
-                   'prev:3', 'next:3',
-                   '1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
-                   'all']:
-               try:
-                       do('f.parsesequence(%s)' % `seq`)
-               except Error, msg:
-                       print "Error:", msg
-               stuff = os.popen("pick %s 2>/dev/null" % `seq`).read()
-               list = map(string.atoi, string.split(stuff))
-               print list, "<-- pick"
-       do('f.listmessages()')
+    global mh, f
+    os.system('rm -rf $HOME/Mail/@test')
+    mh = MH()
+    def do(s): print s; print eval(s)
+    do('mh.listfolders()')
+    do('mh.listallfolders()')
+    testfolders = ['@test', '@test/test1', '@test/test2',
+                  '@test/test1/test11', '@test/test1/test12',
+                  '@test/test1/test11/test111']
+    for t in testfolders: do('mh.makefolder(%s)' % `t`)
+    do('mh.listsubfolders(\'@test\')')
+    do('mh.listallsubfolders(\'@test\')')
+    f = mh.openfolder('@test')
+    do('f.listsubfolders()')
+    do('f.listallsubfolders()')
+    do('f.getsequences()')
+    seqs = f.getsequences()
+    seqs['foo'] = IntSet('1-10 12-20', ' ').tolist()
+    print seqs
+    f.putsequences(seqs)
+    do('f.getsequences()')
+    testfolders.reverse()
+    for t in testfolders: do('mh.deletefolder(%s)' % `t`)
+    do('mh.getcontext()')
+    context = mh.getcontext()
+    f = mh.openfolder(context)
+    do('f.getcurrent()')
+    for seq in ['first', 'last', 'cur', '.', 'prev', 'next',
+               'first:3', 'last:3', 'cur:3', 'cur:-3',
+               'prev:3', 'next:3',
+               '1:3', '1:-3', '100:3', '100:-3', '10000:3', '10000:-3',
+               'all']:
+       try:
+           do('f.parsesequence(%s)' % `seq`)
+       except Error, msg:
+           print "Error:", msg
+       stuff = os.popen("pick %s 2>/dev/null" % `seq`).read()
+       list = map(string.atoi, string.split(stuff))
+       print list, "<-- pick"
+    do('f.listmessages()')
 
 
 if __name__ == '__main__':
-       test()
+    test()