home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_621 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  60.3 KB  |  2,393 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import sys
  5. import os
  6. import time
  7. import calendar
  8. import socket
  9. import errno
  10. import copy
  11. import email
  12. import email.message as email
  13. import email.generator as email
  14. import rfc822
  15. import StringIO
  16.  
  17. try:
  18.     if sys.platform == 'os2emx':
  19.         raise ImportError
  20.     sys.platform == 'os2emx'
  21.     import fcntl
  22. except ImportError:
  23.     fcntl = None
  24.  
  25. __all__ = [
  26.     'Mailbox',
  27.     'Maildir',
  28.     'mbox',
  29.     'MH',
  30.     'Babyl',
  31.     'MMDF',
  32.     'Message',
  33.     'MaildirMessage',
  34.     'mboxMessage',
  35.     'MHMessage',
  36.     'BabylMessage',
  37.     'MMDFMessage',
  38.     'UnixMailbox',
  39.     'PortableUnixMailbox',
  40.     'MmdfMailbox',
  41.     'MHMailbox',
  42.     'BabylMailbox']
  43.  
  44. class Mailbox:
  45.     
  46.     def __init__(self, path, factory = None, create = True):
  47.         self._path = os.path.abspath(os.path.expanduser(path))
  48.         self._factory = factory
  49.  
  50.     
  51.     def add(self, message):
  52.         raise NotImplementedError('Method must be implemented by subclass')
  53.  
  54.     
  55.     def remove(self, key):
  56.         raise NotImplementedError('Method must be implemented by subclass')
  57.  
  58.     
  59.     def __delitem__(self, key):
  60.         self.remove(key)
  61.  
  62.     
  63.     def discard(self, key):
  64.         
  65.         try:
  66.             self.remove(key)
  67.         except KeyError:
  68.             pass
  69.  
  70.  
  71.     
  72.     def __setitem__(self, key, message):
  73.         raise NotImplementedError('Method must be implemented by subclass')
  74.  
  75.     
  76.     def get(self, key, default = None):
  77.         
  78.         try:
  79.             return self.__getitem__(key)
  80.         except KeyError:
  81.             return default
  82.  
  83.  
  84.     
  85.     def __getitem__(self, key):
  86.         if not self._factory:
  87.             return self.get_message(key)
  88.         return self._factory(self.get_file(key))
  89.  
  90.     
  91.     def get_message(self, key):
  92.         raise NotImplementedError('Method must be implemented by subclass')
  93.  
  94.     
  95.     def get_string(self, key):
  96.         raise NotImplementedError('Method must be implemented by subclass')
  97.  
  98.     
  99.     def get_file(self, key):
  100.         raise NotImplementedError('Method must be implemented by subclass')
  101.  
  102.     
  103.     def iterkeys(self):
  104.         raise NotImplementedError('Method must be implemented by subclass')
  105.  
  106.     
  107.     def keys(self):
  108.         return list(self.iterkeys())
  109.  
  110.     
  111.     def itervalues(self):
  112.         for key in self.iterkeys():
  113.             
  114.             try:
  115.                 value = self[key]
  116.             except KeyError:
  117.                 continue
  118.  
  119.             yield value
  120.         
  121.  
  122.     
  123.     def __iter__(self):
  124.         return self.itervalues()
  125.  
  126.     
  127.     def values(self):
  128.         return list(self.itervalues())
  129.  
  130.     
  131.     def iteritems(self):
  132.         for key in self.iterkeys():
  133.             
  134.             try:
  135.                 value = self[key]
  136.             except KeyError:
  137.                 continue
  138.  
  139.             yield (key, value)
  140.         
  141.  
  142.     
  143.     def items(self):
  144.         return list(self.iteritems())
  145.  
  146.     
  147.     def has_key(self, key):
  148.         raise NotImplementedError('Method must be implemented by subclass')
  149.  
  150.     
  151.     def __contains__(self, key):
  152.         return self.has_key(key)
  153.  
  154.     
  155.     def __len__(self):
  156.         raise NotImplementedError('Method must be implemented by subclass')
  157.  
  158.     
  159.     def clear(self):
  160.         for key in self.iterkeys():
  161.             self.discard(key)
  162.         
  163.  
  164.     
  165.     def pop(self, key, default = None):
  166.         
  167.         try:
  168.             result = self[key]
  169.         except KeyError:
  170.             return default
  171.  
  172.         self.discard(key)
  173.         return result
  174.  
  175.     
  176.     def popitem(self):
  177.         for key in self.iterkeys():
  178.             return (key, self.pop(key))
  179.         else:
  180.             raise KeyError('No messages in mailbox')
  181.  
  182.     
  183.     def update(self, arg = None):
  184.         if hasattr(arg, 'iteritems'):
  185.             source = arg.iteritems()
  186.         elif hasattr(arg, 'items'):
  187.             source = arg.items()
  188.         else:
  189.             source = arg
  190.         bad_key = False
  191.         for key, message in source:
  192.             
  193.             try:
  194.                 self[key] = message
  195.             continue
  196.             except KeyError:
  197.                 bad_key = True
  198.                 continue
  199.             
  200.  
  201.         
  202.         if bad_key:
  203.             raise KeyError('No message with key(s)')
  204.         bad_key
  205.  
  206.     
  207.     def flush(self):
  208.         raise NotImplementedError('Method must be implemented by subclass')
  209.  
  210.     
  211.     def lock(self):
  212.         raise NotImplementedError('Method must be implemented by subclass')
  213.  
  214.     
  215.     def unlock(self):
  216.         raise NotImplementedError('Method must be implemented by subclass')
  217.  
  218.     
  219.     def close(self):
  220.         raise NotImplementedError('Method must be implemented by subclass')
  221.  
  222.     
  223.     def _dump_message(self, message, target, mangle_from_ = False):
  224.         if isinstance(message, email.message.Message):
  225.             buffer = StringIO.StringIO()
  226.             gen = email.generator.Generator(buffer, mangle_from_, 0)
  227.             gen.flatten(message)
  228.             buffer.seek(0)
  229.             target.write(buffer.read().replace('\n', os.linesep))
  230.         elif isinstance(message, str):
  231.             if mangle_from_:
  232.                 message = message.replace('\nFrom ', '\n>From ')
  233.             
  234.             message = message.replace('\n', os.linesep)
  235.             target.write(message)
  236.         elif hasattr(message, 'read'):
  237.             while True:
  238.                 line = message.readline()
  239.                 if line == '':
  240.                     break
  241.                 
  242.                 if mangle_from_ and line.startswith('From '):
  243.                     line = '>From ' + line[5:]
  244.                 
  245.                 line = line.replace('\n', os.linesep)
  246.                 target.write(line)
  247.         else:
  248.             raise TypeError('Invalid message type: %s' % type(message))
  249.         return isinstance(message, email.message.Message)
  250.  
  251.  
  252.  
  253. class Maildir(Mailbox):
  254.     colon = ':'
  255.     
  256.     def __init__(self, dirname, factory = rfc822.Message, create = True):
  257.         Mailbox.__init__(self, dirname, factory, create)
  258.         if not os.path.exists(self._path):
  259.             if create:
  260.                 os.mkdir(self._path, 448)
  261.                 os.mkdir(os.path.join(self._path, 'tmp'), 448)
  262.                 os.mkdir(os.path.join(self._path, 'new'), 448)
  263.                 os.mkdir(os.path.join(self._path, 'cur'), 448)
  264.             else:
  265.                 raise NoSuchMailboxError(self._path)
  266.         create
  267.         self._toc = { }
  268.  
  269.     
  270.     def add(self, message):
  271.         tmp_file = self._create_tmp()
  272.         
  273.         try:
  274.             self._dump_message(message, tmp_file)
  275.         finally:
  276.             _sync_close(tmp_file)
  277.  
  278.         if isinstance(message, MaildirMessage):
  279.             subdir = message.get_subdir()
  280.             suffix = self.colon + message.get_info()
  281.             if suffix == self.colon:
  282.                 suffix = ''
  283.             
  284.         else:
  285.             subdir = 'new'
  286.             suffix = ''
  287.         uniq = os.path.basename(tmp_file.name).split(self.colon)[0]
  288.         dest = os.path.join(self._path, subdir, uniq + suffix)
  289.         
  290.         try:
  291.             if hasattr(os, 'link'):
  292.                 os.link(tmp_file.name, dest)
  293.                 os.remove(tmp_file.name)
  294.             else:
  295.                 os.rename(tmp_file.name, dest)
  296.         except OSError:
  297.             e = None
  298.             os.remove(tmp_file.name)
  299.             if e.errno == errno.EEXIST:
  300.                 raise ExternalClashError('Name clash with existing message: %s' % dest)
  301.             e.errno == errno.EEXIST
  302.             raise 
  303.  
  304.         if isinstance(message, MaildirMessage):
  305.             os.utime(dest, (os.path.getatime(dest), message.get_date()))
  306.         
  307.         return uniq
  308.  
  309.     
  310.     def remove(self, key):
  311.         os.remove(os.path.join(self._path, self._lookup(key)))
  312.  
  313.     
  314.     def discard(self, key):
  315.         
  316.         try:
  317.             self.remove(key)
  318.         except KeyError:
  319.             pass
  320.         except OSError:
  321.             e = None
  322.             if e.errno != errno.ENOENT:
  323.                 raise 
  324.             e.errno != errno.ENOENT
  325.  
  326.  
  327.     
  328.     def __setitem__(self, key, message):
  329.         old_subpath = self._lookup(key)
  330.         temp_key = self.add(message)
  331.         temp_subpath = self._lookup(temp_key)
  332.         if isinstance(message, MaildirMessage):
  333.             dominant_subpath = temp_subpath
  334.         else:
  335.             dominant_subpath = old_subpath
  336.         subdir = os.path.dirname(dominant_subpath)
  337.         if self.colon in dominant_subpath:
  338.             suffix = self.colon + dominant_subpath.split(self.colon)[-1]
  339.         else:
  340.             suffix = ''
  341.         self.discard(key)
  342.         new_path = os.path.join(self._path, subdir, key + suffix)
  343.         os.rename(os.path.join(self._path, temp_subpath), new_path)
  344.         if isinstance(message, MaildirMessage):
  345.             os.utime(new_path, (os.path.getatime(new_path), message.get_date()))
  346.         
  347.  
  348.     
  349.     def get_message(self, key):
  350.         subpath = self._lookup(key)
  351.         f = open(os.path.join(self._path, subpath), 'r')
  352.         
  353.         try:
  354.             if self._factory:
  355.                 msg = self._factory(f)
  356.             else:
  357.                 msg = MaildirMessage(f)
  358.         finally:
  359.             f.close()
  360.  
  361.         (subdir, name) = os.path.split(subpath)
  362.         msg.set_subdir(subdir)
  363.         if self.colon in name:
  364.             msg.set_info(name.split(self.colon)[-1])
  365.         
  366.         msg.set_date(os.path.getmtime(os.path.join(self._path, subpath)))
  367.         return msg
  368.  
  369.     
  370.     def get_string(self, key):
  371.         f = open(os.path.join(self._path, self._lookup(key)), 'r')
  372.         
  373.         try:
  374.             return f.read()
  375.         finally:
  376.             f.close()
  377.  
  378.  
  379.     
  380.     def get_file(self, key):
  381.         f = open(os.path.join(self._path, self._lookup(key)), 'rb')
  382.         return _ProxyFile(f)
  383.  
  384.     
  385.     def iterkeys(self):
  386.         self._refresh()
  387.         for key in self._toc:
  388.             
  389.             try:
  390.                 self._lookup(key)
  391.             except KeyError:
  392.                 continue
  393.  
  394.             yield key
  395.         
  396.  
  397.     
  398.     def has_key(self, key):
  399.         self._refresh()
  400.         return key in self._toc
  401.  
  402.     
  403.     def __len__(self):
  404.         self._refresh()
  405.         return len(self._toc)
  406.  
  407.     
  408.     def flush(self):
  409.         pass
  410.  
  411.     
  412.     def lock(self):
  413.         pass
  414.  
  415.     
  416.     def unlock(self):
  417.         pass
  418.  
  419.     
  420.     def close(self):
  421.         pass
  422.  
  423.     
  424.     def list_folders(self):
  425.         result = []
  426.         for entry in os.listdir(self._path):
  427.             if len(entry) > 1 and entry[0] == '.' and os.path.isdir(os.path.join(self._path, entry)):
  428.                 result.append(entry[1:])
  429.                 continue
  430.         
  431.         return result
  432.  
  433.     
  434.     def get_folder(self, folder):
  435.         return Maildir(os.path.join(self._path, '.' + folder), factory = self._factory, create = False)
  436.  
  437.     
  438.     def add_folder(self, folder):
  439.         path = os.path.join(self._path, '.' + folder)
  440.         result = Maildir(path, factory = self._factory)
  441.         maildirfolder_path = os.path.join(path, 'maildirfolder')
  442.         if not os.path.exists(maildirfolder_path):
  443.             os.close(os.open(maildirfolder_path, os.O_CREAT | os.O_WRONLY, 438))
  444.         
  445.         return result
  446.  
  447.     
  448.     def remove_folder(self, folder):
  449.         path = os.path.join(self._path, '.' + folder)
  450.         for entry in os.listdir(os.path.join(path, 'new')) + os.listdir(os.path.join(path, 'cur')):
  451.             if len(entry) < 1 or entry[0] != '.':
  452.                 raise NotEmptyError('Folder contains message(s): %s' % folder)
  453.             entry[0] != '.'
  454.         
  455.         for entry in os.listdir(path):
  456.             if entry != 'new' and entry != 'cur' and entry != 'tmp' and os.path.isdir(os.path.join(path, entry)):
  457.                 raise NotEmptyError("Folder contains subdirectory '%s': %s" % (folder, entry))
  458.             os.path.isdir(os.path.join(path, entry))
  459.         
  460.         for root, dirs, files in os.walk(path, topdown = False):
  461.             for entry in files:
  462.                 os.remove(os.path.join(root, entry))
  463.             
  464.             for entry in dirs:
  465.                 os.rmdir(os.path.join(root, entry))
  466.             
  467.         
  468.         os.rmdir(path)
  469.  
  470.     
  471.     def clean(self):
  472.         now = time.time()
  473.         for entry in os.listdir(os.path.join(self._path, 'tmp')):
  474.             path = os.path.join(self._path, 'tmp', entry)
  475.             if now - os.path.getatime(path) > 129600:
  476.                 os.remove(path)
  477.                 continue
  478.         
  479.  
  480.     _count = 1
  481.     
  482.     def _create_tmp(self):
  483.         now = time.time()
  484.         hostname = socket.gethostname()
  485.         if '/' in hostname:
  486.             hostname = hostname.replace('/', '\\057')
  487.         
  488.         if ':' in hostname:
  489.             hostname = hostname.replace(':', '\\072')
  490.         
  491.         uniq = '%s.M%sP%sQ%s.%s' % (int(now), int((now % 1) * 1e+06), os.getpid(), Maildir._count, hostname)
  492.         path = os.path.join(self._path, 'tmp', uniq)
  493.         
  494.         try:
  495.             os.stat(path)
  496.         except OSError:
  497.             e = None
  498.             if e.errno == errno.ENOENT:
  499.                 Maildir._count += 1
  500.                 
  501.                 try:
  502.                     return _create_carefully(path)
  503.                 except OSError:
  504.                     Maildir
  505.                     e = Maildir
  506.                     if e.errno != errno.EEXIST:
  507.                         raise 
  508.                     e.errno != errno.EEXIST
  509.                 except:
  510.                     Maildir<EXCEPTION MATCH>OSError
  511.                 
  512.  
  513.             Maildir<EXCEPTION MATCH>OSError
  514.             raise 
  515.         except:
  516.             Maildir
  517.  
  518.         raise ExternalClashError('Name clash prevented file creation: %s' % path)
  519.  
  520.     
  521.     def _refresh(self):
  522.         self._toc = { }
  523.         for subdir in ('new', 'cur'):
  524.             subdir_path = os.path.join(self._path, subdir)
  525.             for entry in os.listdir(subdir_path):
  526.                 p = os.path.join(subdir_path, entry)
  527.                 if os.path.isdir(p):
  528.                     continue
  529.                 
  530.                 uniq = entry.split(self.colon)[0]
  531.                 self._toc[uniq] = os.path.join(subdir, entry)
  532.             
  533.         
  534.  
  535.     
  536.     def _lookup(self, key):
  537.         
  538.         try:
  539.             if os.path.exists(os.path.join(self._path, self._toc[key])):
  540.                 return self._toc[key]
  541.         except KeyError:
  542.             pass
  543.  
  544.         self._refresh()
  545.         
  546.         try:
  547.             return self._toc[key]
  548.         except KeyError:
  549.             raise KeyError('No message with key: %s' % key)
  550.  
  551.  
  552.     
  553.     def next(self):
  554.         if not hasattr(self, '_onetime_keys'):
  555.             self._onetime_keys = self.iterkeys()
  556.         
  557.         while True:
  558.             
  559.             try:
  560.                 return self[self._onetime_keys.next()]
  561.             continue
  562.             except StopIteration:
  563.                 return None
  564.                 except KeyError:
  565.                     continue
  566.                     continue
  567.                 
  568.                 None<EXCEPTION MATCH>KeyError
  569.             return None
  570.  
  571.  
  572.  
  573.  
  574. class _singlefileMailbox(Mailbox):
  575.     
  576.     def __init__(self, path, factory = None, create = True):
  577.         Mailbox.__init__(self, path, factory, create)
  578.         
  579.         try:
  580.             f = open(self._path, 'rb+')
  581.         except IOError:
  582.             e = None
  583.             if e.errno == errno.ENOENT:
  584.                 if create:
  585.                     f = open(self._path, 'wb+')
  586.                 else:
  587.                     raise NoSuchMailboxError(self._path)
  588.             create
  589.             if e.errno == errno.EACCES:
  590.                 f = open(self._path, 'rb')
  591.             else:
  592.                 raise 
  593.             e.errno == errno.EACCES
  594.  
  595.         self._file = f
  596.         self._toc = None
  597.         self._next_key = 0
  598.         self._pending = False
  599.         self._locked = False
  600.         self._file_length = None
  601.  
  602.     
  603.     def add(self, message):
  604.         self._lookup()
  605.         self._toc[self._next_key] = self._append_message(message)
  606.         self._next_key += 1
  607.         self._pending = True
  608.         return self._next_key - 1
  609.  
  610.     
  611.     def remove(self, key):
  612.         self._lookup(key)
  613.         del self._toc[key]
  614.         self._pending = True
  615.  
  616.     
  617.     def __setitem__(self, key, message):
  618.         self._lookup(key)
  619.         self._toc[key] = self._append_message(message)
  620.         self._pending = True
  621.  
  622.     
  623.     def iterkeys(self):
  624.         self._lookup()
  625.         for key in self._toc.keys():
  626.             yield key
  627.         
  628.  
  629.     
  630.     def has_key(self, key):
  631.         self._lookup()
  632.         return key in self._toc
  633.  
  634.     
  635.     def __len__(self):
  636.         self._lookup()
  637.         return len(self._toc)
  638.  
  639.     
  640.     def lock(self):
  641.         if not self._locked:
  642.             _lock_file(self._file)
  643.             self._locked = True
  644.         
  645.  
  646.     
  647.     def unlock(self):
  648.         if self._locked:
  649.             _unlock_file(self._file)
  650.             self._locked = False
  651.         
  652.  
  653.     
  654.     def flush(self):
  655.         if not self._pending:
  656.             return None
  657.         self._file.seek(0, 2)
  658.         cur_len = self._file.tell()
  659.         if cur_len != self._file_length:
  660.             raise ExternalClashError('Size of mailbox file changed (expected %i, found %i)' % (self._file_length, cur_len))
  661.         cur_len != self._file_length
  662.         new_file = _create_temporary(self._path)
  663.         
  664.         try:
  665.             new_toc = { }
  666.             self._pre_mailbox_hook(new_file)
  667.             for key in sorted(self._toc.keys()):
  668.                 (start, stop) = self._toc[key]
  669.                 self._file.seek(start)
  670.                 self._pre_message_hook(new_file)
  671.                 new_start = new_file.tell()
  672.                 while True:
  673.                     buffer = self._file.read(min(4096, stop - self._file.tell()))
  674.                     if buffer == '':
  675.                         break
  676.                     
  677.                     new_file.write(buffer)
  678.                 new_toc[key] = (new_start, new_file.tell())
  679.                 self._post_message_hook(new_file)
  680.         except:
  681.             self._pending
  682.             new_file.close()
  683.             os.remove(new_file.name)
  684.             raise 
  685.  
  686.         _sync_close(new_file)
  687.         self._file.close()
  688.         
  689.         try:
  690.             os.rename(new_file.name, self._path)
  691.         except OSError:
  692.             self._pending
  693.             e = self._pending
  694.             if (e.errno == errno.EEXIST or os.name == 'os2') and e.errno == errno.EACCES:
  695.                 os.remove(self._path)
  696.                 os.rename(new_file.name, self._path)
  697.             else:
  698.                 raise 
  699.             e.errno == errno.EACCES
  700.  
  701.         self._file = open(self._path, 'rb+')
  702.         self._toc = new_toc
  703.         self._pending = False
  704.         if self._locked:
  705.             _lock_file(self._file, dotlock = False)
  706.         
  707.  
  708.     
  709.     def _pre_mailbox_hook(self, f):
  710.         pass
  711.  
  712.     
  713.     def _pre_message_hook(self, f):
  714.         pass
  715.  
  716.     
  717.     def _post_message_hook(self, f):
  718.         pass
  719.  
  720.     
  721.     def close(self):
  722.         self.flush()
  723.         if self._locked:
  724.             self.unlock()
  725.         
  726.         self._file.close()
  727.  
  728.     
  729.     def _lookup(self, key = None):
  730.         if self._toc is None:
  731.             self._generate_toc()
  732.         
  733.         if key is not None:
  734.             
  735.             try:
  736.                 return self._toc[key]
  737.             except KeyError:
  738.                 raise KeyError('No message with key: %s' % key)
  739.             except:
  740.                 None<EXCEPTION MATCH>KeyError
  741.             
  742.  
  743.         None<EXCEPTION MATCH>KeyError
  744.  
  745.     
  746.     def _append_message(self, message):
  747.         self._file.seek(0, 2)
  748.         self._pre_message_hook(self._file)
  749.         offsets = self._install_message(message)
  750.         self._post_message_hook(self._file)
  751.         self._file.flush()
  752.         self._file_length = self._file.tell()
  753.         return offsets
  754.  
  755.  
  756.  
  757. class _mboxMMDF(_singlefileMailbox):
  758.     _mangle_from_ = True
  759.     
  760.     def get_message(self, key):
  761.         (start, stop) = self._lookup(key)
  762.         self._file.seek(start)
  763.         from_line = self._file.readline().replace(os.linesep, '')
  764.         string = self._file.read(stop - self._file.tell())
  765.         msg = self._message_factory(string.replace(os.linesep, '\n'))
  766.         msg.set_from(from_line[5:])
  767.         return msg
  768.  
  769.     
  770.     def get_string(self, key, from_ = False):
  771.         (start, stop) = self._lookup(key)
  772.         self._file.seek(start)
  773.         if not from_:
  774.             self._file.readline()
  775.         
  776.         string = self._file.read(stop - self._file.tell())
  777.         return string.replace(os.linesep, '\n')
  778.  
  779.     
  780.     def get_file(self, key, from_ = False):
  781.         (start, stop) = self._lookup(key)
  782.         self._file.seek(start)
  783.         if not from_:
  784.             self._file.readline()
  785.         
  786.         return _PartialFile(self._file, self._file.tell(), stop)
  787.  
  788.     
  789.     def _install_message(self, message):
  790.         from_line = None
  791.         if isinstance(message, str) and message.startswith('From '):
  792.             newline = message.find('\n')
  793.             if newline != -1:
  794.                 from_line = message[:newline]
  795.                 message = message[newline + 1:]
  796.             else:
  797.                 from_line = message
  798.                 message = ''
  799.         elif isinstance(message, _mboxMMDFMessage):
  800.             from_line = 'From ' + message.get_from()
  801.         elif isinstance(message, email.message.Message):
  802.             from_line = message.get_unixfrom()
  803.         
  804.         if from_line is None:
  805.             from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime())
  806.         
  807.         start = self._file.tell()
  808.         self._file.write(from_line + os.linesep)
  809.         self._dump_message(message, self._file, self._mangle_from_)
  810.         stop = self._file.tell()
  811.         return (start, stop)
  812.  
  813.  
  814.  
  815. class mbox(_mboxMMDF):
  816.     _mangle_from_ = True
  817.     
  818.     def __init__(self, path, factory = None, create = True):
  819.         self._message_factory = mboxMessage
  820.         _mboxMMDF.__init__(self, path, factory, create)
  821.  
  822.     
  823.     def _pre_message_hook(self, f):
  824.         if f.tell() != 0:
  825.             f.write(os.linesep)
  826.         
  827.  
  828.     
  829.     def _generate_toc(self):
  830.         starts = []
  831.         stops = []
  832.         self._file.seek(0)
  833.         while True:
  834.             line_pos = self._file.tell()
  835.             line = self._file.readline()
  836.             if line.startswith('From '):
  837.                 if len(stops) < len(starts):
  838.                     stops.append(line_pos - len(os.linesep))
  839.                 
  840.                 starts.append(line_pos)
  841.                 continue
  842.             if line == '':
  843.                 stops.append(line_pos)
  844.                 break
  845.                 continue
  846.         self._toc = dict(enumerate(zip(starts, stops)))
  847.         self._next_key = len(self._toc)
  848.         self._file_length = self._file.tell()
  849.  
  850.  
  851.  
  852. class MMDF(_mboxMMDF):
  853.     
  854.     def __init__(self, path, factory = None, create = True):
  855.         self._message_factory = MMDFMessage
  856.         _mboxMMDF.__init__(self, path, factory, create)
  857.  
  858.     
  859.     def _pre_message_hook(self, f):
  860.         f.write('\x01\x01\x01\x01' + os.linesep)
  861.  
  862.     
  863.     def _post_message_hook(self, f):
  864.         f.write(os.linesep + '\x01\x01\x01\x01' + os.linesep)
  865.  
  866.     
  867.     def _generate_toc(self):
  868.         starts = []
  869.         stops = []
  870.         self._file.seek(0)
  871.         next_pos = 0
  872.         while True:
  873.             line_pos = next_pos
  874.             line = self._file.readline()
  875.             next_pos = self._file.tell()
  876.             if line.startswith('\x01\x01\x01\x01' + os.linesep):
  877.                 starts.append(next_pos)
  878.                 while True:
  879.                     line_pos = next_pos
  880.                     line = self._file.readline()
  881.                     next_pos = self._file.tell()
  882.                     if line == '\x01\x01\x01\x01' + os.linesep:
  883.                         stops.append(line_pos - len(os.linesep))
  884.                         break
  885.                         continue
  886.                     if line == '':
  887.                         stops.append(line_pos)
  888.                         break
  889.                         continue
  890.                 continue
  891.             if line == '':
  892.                 break
  893.                 continue
  894.         self._toc = dict(enumerate(zip(starts, stops)))
  895.         self._next_key = len(self._toc)
  896.         self._file.seek(0, 2)
  897.         self._file_length = self._file.tell()
  898.  
  899.  
  900.  
  901. class MH(Mailbox):
  902.     
  903.     def __init__(self, path, factory = None, create = True):
  904.         Mailbox.__init__(self, path, factory, create)
  905.         if not os.path.exists(self._path):
  906.             if create:
  907.                 os.mkdir(self._path, 448)
  908.                 os.close(os.open(os.path.join(self._path, '.mh_sequences'), os.O_CREAT | os.O_EXCL | os.O_WRONLY, 384))
  909.             else:
  910.                 raise NoSuchMailboxError(self._path)
  911.         create
  912.         self._locked = False
  913.  
  914.     
  915.     def add(self, message):
  916.         keys = self.keys()
  917.         if len(keys) == 0:
  918.             new_key = 1
  919.         else:
  920.             new_key = max(keys) + 1
  921.         new_path = os.path.join(self._path, str(new_key))
  922.         f = _create_carefully(new_path)
  923.         
  924.         try:
  925.             if self._locked:
  926.                 _lock_file(f)
  927.             
  928.             
  929.             try:
  930.                 self._dump_message(message, f)
  931.                 if isinstance(message, MHMessage):
  932.                     self._dump_sequences(message, new_key)
  933.             finally:
  934.                 if self._locked:
  935.                     _unlock_file(f)
  936.                 
  937.  
  938.         finally:
  939.             _sync_close(f)
  940.  
  941.         return new_key
  942.  
  943.     
  944.     def remove(self, key):
  945.         path = os.path.join(self._path, str(key))
  946.         
  947.         try:
  948.             f = open(path, 'rb+')
  949.         except IOError:
  950.             e = None
  951.             if e.errno == errno.ENOENT:
  952.                 raise KeyError('No message with key: %s' % key)
  953.             e.errno == errno.ENOENT
  954.             raise 
  955.  
  956.         
  957.         try:
  958.             if self._locked:
  959.                 _lock_file(f)
  960.             
  961.             
  962.             try:
  963.                 f.close()
  964.                 os.remove(os.path.join(self._path, str(key)))
  965.             finally:
  966.                 if self._locked:
  967.                     _unlock_file(f)
  968.                 
  969.  
  970.         finally:
  971.             f.close()
  972.  
  973.  
  974.     
  975.     def __setitem__(self, key, message):
  976.         path = os.path.join(self._path, str(key))
  977.         
  978.         try:
  979.             f = open(path, 'rb+')
  980.         except IOError:
  981.             e = None
  982.             if e.errno == errno.ENOENT:
  983.                 raise KeyError('No message with key: %s' % key)
  984.             e.errno == errno.ENOENT
  985.             raise 
  986.  
  987.         
  988.         try:
  989.             if self._locked:
  990.                 _lock_file(f)
  991.             
  992.             
  993.             try:
  994.                 os.close(os.open(path, os.O_WRONLY | os.O_TRUNC))
  995.                 self._dump_message(message, f)
  996.                 if isinstance(message, MHMessage):
  997.                     self._dump_sequences(message, key)
  998.             finally:
  999.                 if self._locked:
  1000.                     _unlock_file(f)
  1001.                 
  1002.  
  1003.         finally:
  1004.             _sync_close(f)
  1005.  
  1006.  
  1007.     
  1008.     def get_message(self, key):
  1009.         
  1010.         try:
  1011.             if self._locked:
  1012.                 f = open(os.path.join(self._path, str(key)), 'r+')
  1013.             else:
  1014.                 f = open(os.path.join(self._path, str(key)), 'r')
  1015.         except IOError:
  1016.             e = None
  1017.             if e.errno == errno.ENOENT:
  1018.                 raise KeyError('No message with key: %s' % key)
  1019.             e.errno == errno.ENOENT
  1020.             raise 
  1021.  
  1022.         
  1023.         try:
  1024.             if self._locked:
  1025.                 _lock_file(f)
  1026.             
  1027.             
  1028.             try:
  1029.                 msg = MHMessage(f)
  1030.             finally:
  1031.                 if self._locked:
  1032.                     _unlock_file(f)
  1033.                 
  1034.  
  1035.         finally:
  1036.             f.close()
  1037.  
  1038.         for name, key_list in self.get_sequences().iteritems():
  1039.             if key in key_list:
  1040.                 msg.add_sequence(name)
  1041.                 continue
  1042.         
  1043.         return msg
  1044.  
  1045.     
  1046.     def get_string(self, key):
  1047.         
  1048.         try:
  1049.             if self._locked:
  1050.                 f = open(os.path.join(self._path, str(key)), 'r+')
  1051.             else:
  1052.                 f = open(os.path.join(self._path, str(key)), 'r')
  1053.         except IOError:
  1054.             e = None
  1055.             if e.errno == errno.ENOENT:
  1056.                 raise KeyError('No message with key: %s' % key)
  1057.             e.errno == errno.ENOENT
  1058.             raise 
  1059.  
  1060.         
  1061.         try:
  1062.             if self._locked:
  1063.                 _lock_file(f)
  1064.             
  1065.             
  1066.             try:
  1067.                 return f.read()
  1068.             finally:
  1069.                 if self._locked:
  1070.                     _unlock_file(f)
  1071.                 
  1072.  
  1073.         finally:
  1074.             f.close()
  1075.  
  1076.  
  1077.     
  1078.     def get_file(self, key):
  1079.         
  1080.         try:
  1081.             f = open(os.path.join(self._path, str(key)), 'rb')
  1082.         except IOError:
  1083.             e = None
  1084.             if e.errno == errno.ENOENT:
  1085.                 raise KeyError('No message with key: %s' % key)
  1086.             e.errno == errno.ENOENT
  1087.             raise 
  1088.  
  1089.         return _ProxyFile(f)
  1090.  
  1091.     
  1092.     def iterkeys(self):
  1093.         return iter(sorted((lambda .0: for entry in .0:
  1094. if entry.isdigit():
  1095. int(entry)continue)(os.listdir(self._path))))
  1096.  
  1097.     
  1098.     def has_key(self, key):
  1099.         return os.path.exists(os.path.join(self._path, str(key)))
  1100.  
  1101.     
  1102.     def __len__(self):
  1103.         return len(list(self.iterkeys()))
  1104.  
  1105.     
  1106.     def lock(self):
  1107.         if not self._locked:
  1108.             self._file = open(os.path.join(self._path, '.mh_sequences'), 'rb+')
  1109.             _lock_file(self._file)
  1110.             self._locked = True
  1111.         
  1112.  
  1113.     
  1114.     def unlock(self):
  1115.         if self._locked:
  1116.             _unlock_file(self._file)
  1117.             _sync_close(self._file)
  1118.             del self._file
  1119.             self._locked = False
  1120.         
  1121.  
  1122.     
  1123.     def flush(self):
  1124.         pass
  1125.  
  1126.     
  1127.     def close(self):
  1128.         if self._locked:
  1129.             self.unlock()
  1130.         
  1131.  
  1132.     
  1133.     def list_folders(self):
  1134.         result = []
  1135.         for entry in os.listdir(self._path):
  1136.             if os.path.isdir(os.path.join(self._path, entry)):
  1137.                 result.append(entry)
  1138.                 continue
  1139.         
  1140.         return result
  1141.  
  1142.     
  1143.     def get_folder(self, folder):
  1144.         return MH(os.path.join(self._path, folder), factory = self._factory, create = False)
  1145.  
  1146.     
  1147.     def add_folder(self, folder):
  1148.         return MH(os.path.join(self._path, folder), factory = self._factory)
  1149.  
  1150.     
  1151.     def remove_folder(self, folder):
  1152.         path = os.path.join(self._path, folder)
  1153.         entries = os.listdir(path)
  1154.         if entries == [
  1155.             '.mh_sequences']:
  1156.             os.remove(os.path.join(path, '.mh_sequences'))
  1157.         elif entries == []:
  1158.             pass
  1159.         else:
  1160.             raise NotEmptyError('Folder not empty: %s' % self._path)
  1161.         (entries == [
  1162.             '.mh_sequences']).rmdir(path)
  1163.  
  1164.     
  1165.     def get_sequences(self):
  1166.         results = { }
  1167.         f = open(os.path.join(self._path, '.mh_sequences'), 'r')
  1168.         
  1169.         try:
  1170.             all_keys = set(self.keys())
  1171.             for line in f:
  1172.                 
  1173.                 try:
  1174.                     (name, contents) = line.split(':')
  1175.                     keys = set()
  1176.                     for spec in contents.split():
  1177.                         if spec.isdigit():
  1178.                             keys.add(int(spec))
  1179.                             continue
  1180.                         (start, stop) = (lambda .0: for x in .0:
  1181. int(x))(spec.split('-'))
  1182.                         keys.update(range(start, stop + 1))
  1183.                     
  1184.                     results[name] = _[1]
  1185.                     if len(results[name]) == 0:
  1186.                         del results[name]
  1187.                 continue
  1188.                 except ValueError:
  1189.                     raise FormatError('Invalid sequence specification: %s' % line.rstrip())
  1190.                     continue
  1191.                 
  1192.  
  1193.         finally:
  1194.             f.close()
  1195.  
  1196.         return results
  1197.  
  1198.     
  1199.     def set_sequences(self, sequences):
  1200.         f = open(os.path.join(self._path, '.mh_sequences'), 'r+')
  1201.         
  1202.         try:
  1203.             os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC))
  1204.             for name, keys in sequences.iteritems():
  1205.                 if len(keys) == 0:
  1206.                     continue
  1207.                 
  1208.                 f.write('%s:' % name)
  1209.                 prev = None
  1210.                 completing = False
  1211.                 for key in sorted(set(keys)):
  1212.                     if key - 1 == prev:
  1213.                         if not completing:
  1214.                             completing = True
  1215.                             f.write('-')
  1216.                         
  1217.                     elif completing:
  1218.                         completing = False
  1219.                         f.write('%s %s' % (prev, key))
  1220.                     else:
  1221.                         f.write(' %s' % key)
  1222.                     prev = key
  1223.                 
  1224.                 if completing:
  1225.                     f.write(str(prev) + '\n')
  1226.                     continue
  1227.                 f.write('\n')
  1228.         finally:
  1229.             _sync_close(f)
  1230.  
  1231.  
  1232.     
  1233.     def pack(self):
  1234.         sequences = self.get_sequences()
  1235.         prev = 0
  1236.         changes = []
  1237.         for key in self.iterkeys():
  1238.             if key - 1 != prev:
  1239.                 changes.append((key, prev + 1))
  1240.                 if hasattr(os, 'link'):
  1241.                     os.link(os.path.join(self._path, str(key)), os.path.join(self._path, str(prev + 1)))
  1242.                     os.unlink(os.path.join(self._path, str(key)))
  1243.                 else:
  1244.                     os.rename(os.path.join(self._path, str(key)), os.path.join(self._path, str(prev + 1)))
  1245.             
  1246.             prev += 1
  1247.         
  1248.         self._next_key = prev + 1
  1249.         if len(changes) == 0:
  1250.             return None
  1251.         for name, key_list in sequences.items():
  1252.             for old, new in changes:
  1253.                 if old in key_list:
  1254.                     key_list[key_list.index(old)] = new
  1255.                     continue
  1256.                 len(changes) == 0
  1257.             
  1258.         
  1259.         self.set_sequences(sequences)
  1260.  
  1261.     
  1262.     def _dump_sequences(self, message, key):
  1263.         pending_sequences = message.get_sequences()
  1264.         all_sequences = self.get_sequences()
  1265.         for name, key_list in all_sequences.iteritems():
  1266.             if name in pending_sequences:
  1267.                 key_list.append(key)
  1268.                 continue
  1269.             if key in key_list:
  1270.                 del key_list[key_list.index(key)]
  1271.                 continue
  1272.         
  1273.         for sequence in pending_sequences:
  1274.             if sequence not in all_sequences:
  1275.                 all_sequences[sequence] = [
  1276.                     key]
  1277.                 continue
  1278.         
  1279.         self.set_sequences(all_sequences)
  1280.  
  1281.  
  1282.  
  1283. class Babyl(_singlefileMailbox):
  1284.     _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered', 'forwarded', 'edited', 'resent'))
  1285.     
  1286.     def __init__(self, path, factory = None, create = True):
  1287.         _singlefileMailbox.__init__(self, path, factory, create)
  1288.         self._labels = { }
  1289.  
  1290.     
  1291.     def add(self, message):
  1292.         key = _singlefileMailbox.add(self, message)
  1293.         if isinstance(message, BabylMessage):
  1294.             self._labels[key] = message.get_labels()
  1295.         
  1296.         return key
  1297.  
  1298.     
  1299.     def remove(self, key):
  1300.         _singlefileMailbox.remove(self, key)
  1301.         if key in self._labels:
  1302.             del self._labels[key]
  1303.         
  1304.  
  1305.     
  1306.     def __setitem__(self, key, message):
  1307.         _singlefileMailbox.__setitem__(self, key, message)
  1308.         if isinstance(message, BabylMessage):
  1309.             self._labels[key] = message.get_labels()
  1310.         
  1311.  
  1312.     
  1313.     def get_message(self, key):
  1314.         (start, stop) = self._lookup(key)
  1315.         self._file.seek(start)
  1316.         self._file.readline()
  1317.         original_headers = StringIO.StringIO()
  1318.         while True:
  1319.             line = self._file.readline()
  1320.             if line == '*** EOOH ***' + os.linesep or line == '':
  1321.                 break
  1322.             
  1323.             original_headers.write(line.replace(os.linesep, '\n'))
  1324.         visible_headers = StringIO.StringIO()
  1325.         while True:
  1326.             line = self._file.readline()
  1327.             if line == os.linesep or line == '':
  1328.                 break
  1329.             
  1330.             visible_headers.write(line.replace(os.linesep, '\n'))
  1331.         body = self._file.read(stop - self._file.tell()).replace(os.linesep, '\n')
  1332.         msg = BabylMessage(original_headers.getvalue() + body)
  1333.         msg.set_visible(visible_headers.getvalue())
  1334.         if key in self._labels:
  1335.             msg.set_labels(self._labels[key])
  1336.         
  1337.         return msg
  1338.  
  1339.     
  1340.     def get_string(self, key):
  1341.         (start, stop) = self._lookup(key)
  1342.         self._file.seek(start)
  1343.         self._file.readline()
  1344.         original_headers = StringIO.StringIO()
  1345.         while True:
  1346.             line = self._file.readline()
  1347.             if line == '*** EOOH ***' + os.linesep or line == '':
  1348.                 break
  1349.             
  1350.             original_headers.write(line.replace(os.linesep, '\n'))
  1351.         while True:
  1352.             line = self._file.readline()
  1353.             if line == os.linesep or line == '':
  1354.                 break
  1355.                 continue
  1356.         return original_headers.getvalue() + self._file.read(stop - self._file.tell()).replace(os.linesep, '\n')
  1357.  
  1358.     
  1359.     def get_file(self, key):
  1360.         return StringIO.StringIO(self.get_string(key).replace('\n', os.linesep))
  1361.  
  1362.     
  1363.     def get_labels(self):
  1364.         self._lookup()
  1365.         labels = set()
  1366.         for label_list in self._labels.values():
  1367.             labels.update(label_list)
  1368.         
  1369.         labels.difference_update(self._special_labels)
  1370.         return list(labels)
  1371.  
  1372.     
  1373.     def _generate_toc(self):
  1374.         starts = []
  1375.         stops = []
  1376.         self._file.seek(0)
  1377.         next_pos = 0
  1378.         label_lists = []
  1379.         while True:
  1380.             line_pos = next_pos
  1381.             line = self._file.readline()
  1382.             next_pos = self._file.tell()
  1383.             if line == '\x1f\x0c' + os.linesep:
  1384.                 if len(stops) < len(starts):
  1385.                     stops.append(line_pos - len(os.linesep))
  1386.                 
  1387.                 starts.append(next_pos)
  1388.                 labels = _[1]
  1389.                 label_lists.append(labels)
  1390.                 continue
  1391.             []
  1392.             if line == '\x1f' or line == '\x1f' + os.linesep:
  1393.                 if len(stops) < len(starts):
  1394.                     stops.append(line_pos - len(os.linesep))
  1395.                 
  1396.             len(stops) < len(starts)
  1397.             if line == '':
  1398.                 stops.append(line_pos - len(os.linesep))
  1399.                 break
  1400.                 continue
  1401.             []
  1402.         self._toc = dict(enumerate(zip(starts, stops)))
  1403.         self._labels = dict(enumerate(label_lists))
  1404.         self._next_key = len(self._toc)
  1405.         self._file.seek(0, 2)
  1406.         self._file_length = self._file.tell()
  1407.  
  1408.     
  1409.     def _pre_mailbox_hook(self, f):
  1410.         f.write('BABYL OPTIONS:%sVersion: 5%sLabels:%s%s\x1f' % (os.linesep, os.linesep, ','.join(self.get_labels()), os.linesep))
  1411.  
  1412.     
  1413.     def _pre_message_hook(self, f):
  1414.         f.write('\x0c' + os.linesep)
  1415.  
  1416.     
  1417.     def _post_message_hook(self, f):
  1418.         f.write(os.linesep + '\x1f')
  1419.  
  1420.     
  1421.     def _install_message(self, message):
  1422.         start = self._file.tell()
  1423.         if isinstance(message, BabylMessage):
  1424.             special_labels = []
  1425.             labels = []
  1426.             for label in message.get_labels():
  1427.                 if label in self._special_labels:
  1428.                     special_labels.append(label)
  1429.                     continue
  1430.                 labels.append(label)
  1431.             
  1432.             self._file.write('1')
  1433.             for label in special_labels:
  1434.                 self._file.write(', ' + label)
  1435.             
  1436.             self._file.write(',,')
  1437.             for label in labels:
  1438.                 self._file.write(' ' + label + ',')
  1439.             
  1440.             self._file.write(os.linesep)
  1441.         else:
  1442.             self._file.write('1,,' + os.linesep)
  1443.         if isinstance(message, email.message.Message):
  1444.             orig_buffer = StringIO.StringIO()
  1445.             orig_generator = email.generator.Generator(orig_buffer, False, 0)
  1446.             orig_generator.flatten(message)
  1447.             orig_buffer.seek(0)
  1448.             while True:
  1449.                 line = orig_buffer.readline()
  1450.                 self._file.write(line.replace('\n', os.linesep))
  1451.                 if line == '\n' or line == '':
  1452.                     break
  1453.                     continue
  1454.             self._file.write('*** EOOH ***' + os.linesep)
  1455.             if isinstance(message, BabylMessage):
  1456.                 vis_buffer = StringIO.StringIO()
  1457.                 vis_generator = email.generator.Generator(vis_buffer, False, 0)
  1458.                 vis_generator.flatten(message.get_visible())
  1459.                 while True:
  1460.                     line = vis_buffer.readline()
  1461.                     self._file.write(line.replace('\n', os.linesep))
  1462.                     if line == '\n' or line == '':
  1463.                         break
  1464.                         continue
  1465.             else:
  1466.                 orig_buffer.seek(0)
  1467.                 while True:
  1468.                     line = orig_buffer.readline()
  1469.                     self._file.write(line.replace('\n', os.linesep))
  1470.                     if line == '\n' or line == '':
  1471.                         break
  1472.                         continue
  1473.             while True:
  1474.                 buffer = orig_buffer.read(4096)
  1475.                 if buffer == '':
  1476.                     break
  1477.                 
  1478.                 self._file.write(buffer.replace('\n', os.linesep))
  1479.         elif isinstance(message, str):
  1480.             body_start = message.find('\n\n') + 2
  1481.             if body_start - 2 != -1:
  1482.                 self._file.write(message[:body_start].replace('\n', os.linesep))
  1483.                 self._file.write('*** EOOH ***' + os.linesep)
  1484.                 self._file.write(message[:body_start].replace('\n', os.linesep))
  1485.                 self._file.write(message[body_start:].replace('\n', os.linesep))
  1486.             else:
  1487.                 self._file.write('*** EOOH ***' + os.linesep + os.linesep)
  1488.                 self._file.write(message.replace('\n', os.linesep))
  1489.         elif hasattr(message, 'readline'):
  1490.             original_pos = message.tell()
  1491.             first_pass = True
  1492.             while True:
  1493.                 line = message.readline()
  1494.                 self._file.write(line.replace('\n', os.linesep))
  1495.                 if line == '\n' or line == '':
  1496.                     self._file.write('*** EOOH ***' + os.linesep)
  1497.                     if first_pass:
  1498.                         first_pass = False
  1499.                         message.seek(original_pos)
  1500.                     else:
  1501.                         break
  1502.                 first_pass
  1503.             while True:
  1504.                 buffer = message.read(4096)
  1505.                 if buffer == '':
  1506.                     break
  1507.                 
  1508.                 self._file.write(buffer.replace('\n', os.linesep))
  1509.         else:
  1510.             raise TypeError('Invalid message type: %s' % type(message))
  1511.         stop = isinstance(message, email.message.Message)._file.tell()
  1512.         return (start, stop)
  1513.  
  1514.  
  1515.  
  1516. class Message(email.message.Message):
  1517.     
  1518.     def __init__(self, message = None):
  1519.         if isinstance(message, email.message.Message):
  1520.             self._become_message(copy.deepcopy(message))
  1521.             if isinstance(message, Message):
  1522.                 message._explain_to(self)
  1523.             
  1524.         elif isinstance(message, str):
  1525.             self._become_message(email.message_from_string(message))
  1526.         elif hasattr(message, 'read'):
  1527.             self._become_message(email.message_from_file(message))
  1528.         elif message is None:
  1529.             email.message.Message.__init__(self)
  1530.         else:
  1531.             raise TypeError('Invalid message type: %s' % type(message))
  1532.         return isinstance(message, email.message.Message)
  1533.  
  1534.     
  1535.     def _become_message(self, message):
  1536.         for name in ('_headers', '_unixfrom', '_payload', '_charset', 'preamble', 'epilogue', 'defects', '_default_type'):
  1537.             self.__dict__[name] = message.__dict__[name]
  1538.         
  1539.  
  1540.     
  1541.     def _explain_to(self, message):
  1542.         if isinstance(message, Message):
  1543.             return None
  1544.         raise TypeError('Cannot convert to specified type')
  1545.  
  1546.  
  1547.  
  1548. class MaildirMessage(Message):
  1549.     
  1550.     def __init__(self, message = None):
  1551.         self._subdir = 'new'
  1552.         self._info = ''
  1553.         self._date = time.time()
  1554.         Message.__init__(self, message)
  1555.  
  1556.     
  1557.     def get_subdir(self):
  1558.         return self._subdir
  1559.  
  1560.     
  1561.     def set_subdir(self, subdir):
  1562.         if subdir == 'new' or subdir == 'cur':
  1563.             self._subdir = subdir
  1564.         else:
  1565.             raise ValueError("subdir must be 'new' or 'cur': %s" % subdir)
  1566.         return subdir == 'cur'
  1567.  
  1568.     
  1569.     def get_flags(self):
  1570.         if self._info.startswith('2,'):
  1571.             return self._info[2:]
  1572.         return ''
  1573.  
  1574.     
  1575.     def set_flags(self, flags):
  1576.         self._info = '2,' + ''.join(sorted(flags))
  1577.  
  1578.     
  1579.     def add_flag(self, flag):
  1580.         self.set_flags(''.join(set(self.get_flags()) | set(flag)))
  1581.  
  1582.     
  1583.     def remove_flag(self, flag):
  1584.         if self.get_flags() != '':
  1585.             self.set_flags(''.join(set(self.get_flags()) - set(flag)))
  1586.         
  1587.  
  1588.     
  1589.     def get_date(self):
  1590.         return self._date
  1591.  
  1592.     
  1593.     def set_date(self, date):
  1594.         
  1595.         try:
  1596.             self._date = float(date)
  1597.         except ValueError:
  1598.             raise TypeError("can't convert to float: %s" % date)
  1599.  
  1600.  
  1601.     
  1602.     def get_info(self):
  1603.         return self._info
  1604.  
  1605.     
  1606.     def set_info(self, info):
  1607.         if isinstance(info, str):
  1608.             self._info = info
  1609.         else:
  1610.             raise TypeError('info must be a string: %s' % type(info))
  1611.         return isinstance(info, str)
  1612.  
  1613.     
  1614.     def _explain_to(self, message):
  1615.         if isinstance(message, MaildirMessage):
  1616.             message.set_flags(self.get_flags())
  1617.             message.set_subdir(self.get_subdir())
  1618.             message.set_date(self.get_date())
  1619.         elif isinstance(message, _mboxMMDFMessage):
  1620.             flags = set(self.get_flags())
  1621.             if 'S' in flags:
  1622.                 message.add_flag('R')
  1623.             
  1624.             if self.get_subdir() == 'cur':
  1625.                 message.add_flag('O')
  1626.             
  1627.             if 'T' in flags:
  1628.                 message.add_flag('D')
  1629.             
  1630.             if 'F' in flags:
  1631.                 message.add_flag('F')
  1632.             
  1633.             if 'R' in flags:
  1634.                 message.add_flag('A')
  1635.             
  1636.             message.set_from('MAILER-DAEMON', time.gmtime(self.get_date()))
  1637.         elif isinstance(message, MHMessage):
  1638.             flags = set(self.get_flags())
  1639.             if 'S' not in flags:
  1640.                 message.add_sequence('unseen')
  1641.             
  1642.             if 'R' in flags:
  1643.                 message.add_sequence('replied')
  1644.             
  1645.             if 'F' in flags:
  1646.                 message.add_sequence('flagged')
  1647.             
  1648.         elif isinstance(message, BabylMessage):
  1649.             flags = set(self.get_flags())
  1650.             if 'S' not in flags:
  1651.                 message.add_label('unseen')
  1652.             
  1653.             if 'T' in flags:
  1654.                 message.add_label('deleted')
  1655.             
  1656.             if 'R' in flags:
  1657.                 message.add_label('answered')
  1658.             
  1659.             if 'P' in flags:
  1660.                 message.add_label('forwarded')
  1661.             
  1662.         elif isinstance(message, Message):
  1663.             pass
  1664.         else:
  1665.             raise TypeError('Cannot convert to specified type: %s' % type(message))
  1666.         return isinstance(message, MaildirMessage)
  1667.  
  1668.  
  1669.  
  1670. class _mboxMMDFMessage(Message):
  1671.     
  1672.     def __init__(self, message = None):
  1673.         self.set_from('MAILER-DAEMON', True)
  1674.         if isinstance(message, email.message.Message):
  1675.             unixfrom = message.get_unixfrom()
  1676.             if unixfrom is not None and unixfrom.startswith('From '):
  1677.                 self.set_from(unixfrom[5:])
  1678.             
  1679.         
  1680.         Message.__init__(self, message)
  1681.  
  1682.     
  1683.     def get_from(self):
  1684.         return self._from
  1685.  
  1686.     
  1687.     def set_from(self, from_, time_ = None):
  1688.         if time_ is not None:
  1689.             if time_ is True:
  1690.                 time_ = time.gmtime()
  1691.             
  1692.             from_ += ' ' + time.asctime(time_)
  1693.         
  1694.         self._from = from_
  1695.  
  1696.     
  1697.     def get_flags(self):
  1698.         return self.get('Status', '') + self.get('X-Status', '')
  1699.  
  1700.     
  1701.     def set_flags(self, flags):
  1702.         flags = set(flags)
  1703.         (status_flags, xstatus_flags) = ('', '')
  1704.         for flag in ('R', 'O'):
  1705.             if flag in flags:
  1706.                 status_flags += flag
  1707.                 flags.remove(flag)
  1708.                 continue
  1709.         
  1710.         for flag in ('D', 'F', 'A'):
  1711.             if flag in flags:
  1712.                 xstatus_flags += flag
  1713.                 flags.remove(flag)
  1714.                 continue
  1715.         
  1716.         xstatus_flags += ''.join(sorted(flags))
  1717.         
  1718.         try:
  1719.             self.replace_header('Status', status_flags)
  1720.         except KeyError:
  1721.             self.add_header('Status', status_flags)
  1722.  
  1723.         
  1724.         try:
  1725.             self.replace_header('X-Status', xstatus_flags)
  1726.         except KeyError:
  1727.             self.add_header('X-Status', xstatus_flags)
  1728.  
  1729.  
  1730.     
  1731.     def add_flag(self, flag):
  1732.         self.set_flags(''.join(set(self.get_flags()) | set(flag)))
  1733.  
  1734.     
  1735.     def remove_flag(self, flag):
  1736.         if 'Status' in self or 'X-Status' in self:
  1737.             self.set_flags(''.join(set(self.get_flags()) - set(flag)))
  1738.         
  1739.  
  1740.     
  1741.     def _explain_to(self, message):
  1742.         if isinstance(message, MaildirMessage):
  1743.             flags = set(self.get_flags())
  1744.             if 'O' in flags:
  1745.                 message.set_subdir('cur')
  1746.             
  1747.             if 'F' in flags:
  1748.                 message.add_flag('F')
  1749.             
  1750.             if 'A' in flags:
  1751.                 message.add_flag('R')
  1752.             
  1753.             if 'R' in flags:
  1754.                 message.add_flag('S')
  1755.             
  1756.             if 'D' in flags:
  1757.                 message.add_flag('T')
  1758.             
  1759.             del message['status']
  1760.             del message['x-status']
  1761.             maybe_date = ' '.join(self.get_from().split()[-5:])
  1762.             
  1763.             try:
  1764.                 message.set_date(calendar.timegm(time.strptime(maybe_date, '%a %b %d %H:%M:%S %Y')))
  1765.             except (ValueError, OverflowError):
  1766.                 pass
  1767.             except:
  1768.                 None<EXCEPTION MATCH>(ValueError, OverflowError)
  1769.             
  1770.  
  1771.         None<EXCEPTION MATCH>(ValueError, OverflowError)
  1772.         if isinstance(message, _mboxMMDFMessage):
  1773.             message.set_flags(self.get_flags())
  1774.             message.set_from(self.get_from())
  1775.         elif isinstance(message, MHMessage):
  1776.             flags = set(self.get_flags())
  1777.             if 'R' not in flags:
  1778.                 message.add_sequence('unseen')
  1779.             
  1780.             if 'A' in flags:
  1781.                 message.add_sequence('replied')
  1782.             
  1783.             if 'F' in flags:
  1784.                 message.add_sequence('flagged')
  1785.             
  1786.             del message['status']
  1787.             del message['x-status']
  1788.         elif isinstance(message, BabylMessage):
  1789.             flags = set(self.get_flags())
  1790.             if 'R' not in flags:
  1791.                 message.add_label('unseen')
  1792.             
  1793.             if 'D' in flags:
  1794.                 message.add_label('deleted')
  1795.             
  1796.             if 'A' in flags:
  1797.                 message.add_label('answered')
  1798.             
  1799.             del message['status']
  1800.             del message['x-status']
  1801.         elif isinstance(message, Message):
  1802.             pass
  1803.         else:
  1804.             raise TypeError('Cannot convert to specified type: %s' % type(message))
  1805.         return isinstance(message, _mboxMMDFMessage)
  1806.  
  1807.  
  1808.  
  1809. class mboxMessage(_mboxMMDFMessage):
  1810.     pass
  1811.  
  1812.  
  1813. class MHMessage(Message):
  1814.     
  1815.     def __init__(self, message = None):
  1816.         self._sequences = []
  1817.         Message.__init__(self, message)
  1818.  
  1819.     
  1820.     def get_sequences(self):
  1821.         return self._sequences[:]
  1822.  
  1823.     
  1824.     def set_sequences(self, sequences):
  1825.         self._sequences = list(sequences)
  1826.  
  1827.     
  1828.     def add_sequence(self, sequence):
  1829.         if isinstance(sequence, str):
  1830.             if sequence not in self._sequences:
  1831.                 self._sequences.append(sequence)
  1832.             
  1833.         else:
  1834.             raise TypeError('sequence must be a string: %s' % type(sequence))
  1835.         return isinstance(sequence, str)
  1836.  
  1837.     
  1838.     def remove_sequence(self, sequence):
  1839.         
  1840.         try:
  1841.             self._sequences.remove(sequence)
  1842.         except ValueError:
  1843.             pass
  1844.  
  1845.  
  1846.     
  1847.     def _explain_to(self, message):
  1848.         if isinstance(message, MaildirMessage):
  1849.             sequences = set(self.get_sequences())
  1850.             if 'unseen' in sequences:
  1851.                 message.set_subdir('cur')
  1852.             else:
  1853.                 message.set_subdir('cur')
  1854.                 message.add_flag('S')
  1855.             if 'flagged' in sequences:
  1856.                 message.add_flag('F')
  1857.             
  1858.             if 'replied' in sequences:
  1859.                 message.add_flag('R')
  1860.             
  1861.         elif isinstance(message, _mboxMMDFMessage):
  1862.             sequences = set(self.get_sequences())
  1863.             if 'unseen' not in sequences:
  1864.                 message.add_flag('RO')
  1865.             else:
  1866.                 message.add_flag('O')
  1867.             if 'flagged' in sequences:
  1868.                 message.add_flag('F')
  1869.             
  1870.             if 'replied' in sequences:
  1871.                 message.add_flag('A')
  1872.             
  1873.         elif isinstance(message, MHMessage):
  1874.             for sequence in self.get_sequences():
  1875.                 message.add_sequence(sequence)
  1876.             
  1877.         elif isinstance(message, BabylMessage):
  1878.             sequences = set(self.get_sequences())
  1879.             if 'unseen' in sequences:
  1880.                 message.add_label('unseen')
  1881.             
  1882.             if 'replied' in sequences:
  1883.                 message.add_label('answered')
  1884.             
  1885.         elif isinstance(message, Message):
  1886.             pass
  1887.         else:
  1888.             raise TypeError('Cannot convert to specified type: %s' % type(message))
  1889.         return isinstance(message, MaildirMessage)
  1890.  
  1891.  
  1892.  
  1893. class BabylMessage(Message):
  1894.     
  1895.     def __init__(self, message = None):
  1896.         self._labels = []
  1897.         self._visible = Message()
  1898.         Message.__init__(self, message)
  1899.  
  1900.     
  1901.     def get_labels(self):
  1902.         return self._labels[:]
  1903.  
  1904.     
  1905.     def set_labels(self, labels):
  1906.         self._labels = list(labels)
  1907.  
  1908.     
  1909.     def add_label(self, label):
  1910.         if isinstance(label, str):
  1911.             if label not in self._labels:
  1912.                 self._labels.append(label)
  1913.             
  1914.         else:
  1915.             raise TypeError('label must be a string: %s' % type(label))
  1916.         return isinstance(label, str)
  1917.  
  1918.     
  1919.     def remove_label(self, label):
  1920.         
  1921.         try:
  1922.             self._labels.remove(label)
  1923.         except ValueError:
  1924.             pass
  1925.  
  1926.  
  1927.     
  1928.     def get_visible(self):
  1929.         return Message(self._visible)
  1930.  
  1931.     
  1932.     def set_visible(self, visible):
  1933.         self._visible = Message(visible)
  1934.  
  1935.     
  1936.     def update_visible(self):
  1937.         for header in self._visible.keys():
  1938.             if header in self:
  1939.                 self._visible.replace_header(header, self[header])
  1940.                 continue
  1941.             del self._visible[header]
  1942.         
  1943.         for header in ('Date', 'From', 'Reply-To', 'To', 'CC', 'Subject'):
  1944.             if header in self and header not in self._visible:
  1945.                 self._visible[header] = self[header]
  1946.                 continue
  1947.         
  1948.  
  1949.     
  1950.     def _explain_to(self, message):
  1951.         if isinstance(message, MaildirMessage):
  1952.             labels = set(self.get_labels())
  1953.             if 'unseen' in labels:
  1954.                 message.set_subdir('cur')
  1955.             else:
  1956.                 message.set_subdir('cur')
  1957.                 message.add_flag('S')
  1958.             if 'forwarded' in labels or 'resent' in labels:
  1959.                 message.add_flag('P')
  1960.             
  1961.             if 'answered' in labels:
  1962.                 message.add_flag('R')
  1963.             
  1964.             if 'deleted' in labels:
  1965.                 message.add_flag('T')
  1966.             
  1967.         elif isinstance(message, _mboxMMDFMessage):
  1968.             labels = set(self.get_labels())
  1969.             if 'unseen' not in labels:
  1970.                 message.add_flag('RO')
  1971.             else:
  1972.                 message.add_flag('O')
  1973.             if 'deleted' in labels:
  1974.                 message.add_flag('D')
  1975.             
  1976.             if 'answered' in labels:
  1977.                 message.add_flag('A')
  1978.             
  1979.         elif isinstance(message, MHMessage):
  1980.             labels = set(self.get_labels())
  1981.             if 'unseen' in labels:
  1982.                 message.add_sequence('unseen')
  1983.             
  1984.             if 'answered' in labels:
  1985.                 message.add_sequence('replied')
  1986.             
  1987.         elif isinstance(message, BabylMessage):
  1988.             message.set_visible(self.get_visible())
  1989.             for label in self.get_labels():
  1990.                 message.add_label(label)
  1991.             
  1992.         elif isinstance(message, Message):
  1993.             pass
  1994.         else:
  1995.             raise TypeError('Cannot convert to specified type: %s' % type(message))
  1996.         return isinstance(message, MaildirMessage)
  1997.  
  1998.  
  1999.  
  2000. class MMDFMessage(_mboxMMDFMessage):
  2001.     pass
  2002.  
  2003.  
  2004. class _ProxyFile:
  2005.     
  2006.     def __init__(self, f, pos = None):
  2007.         self._file = f
  2008.         if pos is None:
  2009.             self._pos = f.tell()
  2010.         else:
  2011.             self._pos = pos
  2012.  
  2013.     
  2014.     def read(self, size = None):
  2015.         return self._read(size, self._file.read)
  2016.  
  2017.     
  2018.     def readline(self, size = None):
  2019.         return self._read(size, self._file.readline)
  2020.  
  2021.     
  2022.     def readlines(self, sizehint = None):
  2023.         result = []
  2024.         for line in self:
  2025.             result.append(line)
  2026.             if sizehint is not None:
  2027.                 sizehint -= len(line)
  2028.                 if sizehint <= 0:
  2029.                     break
  2030.                 
  2031.             sizehint <= 0
  2032.         
  2033.         return result
  2034.  
  2035.     
  2036.     def __iter__(self):
  2037.         return iter(self.readline, '')
  2038.  
  2039.     
  2040.     def tell(self):
  2041.         return self._pos
  2042.  
  2043.     
  2044.     def seek(self, offset, whence = 0):
  2045.         if whence == 1:
  2046.             self._file.seek(self._pos)
  2047.         
  2048.         self._file.seek(offset, whence)
  2049.         self._pos = self._file.tell()
  2050.  
  2051.     
  2052.     def close(self):
  2053.         del self._file
  2054.  
  2055.     
  2056.     def _read(self, size, read_method):
  2057.         if size is None:
  2058.             size = -1
  2059.         
  2060.         self._file.seek(self._pos)
  2061.         result = read_method(size)
  2062.         self._pos = self._file.tell()
  2063.         return result
  2064.  
  2065.  
  2066.  
  2067. class _PartialFile(_ProxyFile):
  2068.     
  2069.     def __init__(self, f, start = None, stop = None):
  2070.         _ProxyFile.__init__(self, f, start)
  2071.         self._start = start
  2072.         self._stop = stop
  2073.  
  2074.     
  2075.     def tell(self):
  2076.         return _ProxyFile.tell(self) - self._start
  2077.  
  2078.     
  2079.     def seek(self, offset, whence = 0):
  2080.         if whence == 0:
  2081.             self._pos = self._start
  2082.             whence = 1
  2083.         elif whence == 2:
  2084.             self._pos = self._stop
  2085.             whence = 1
  2086.         
  2087.         _ProxyFile.seek(self, offset, whence)
  2088.  
  2089.     
  2090.     def _read(self, size, read_method):
  2091.         remaining = self._stop - self._pos
  2092.         if remaining <= 0:
  2093.             return ''
  2094.         if size is None and size < 0 or size > remaining:
  2095.             size = remaining
  2096.         
  2097.         return _ProxyFile._read(self, size, read_method)
  2098.  
  2099.  
  2100.  
  2101. def _lock_file(f, dotlock = True):
  2102.     dotlock_done = False
  2103.     
  2104.     try:
  2105.         if fcntl:
  2106.             
  2107.             try:
  2108.                 fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
  2109.             except IOError:
  2110.                 e = None
  2111.                 if e.errno in (errno.EAGAIN, errno.EACCES):
  2112.                     raise ExternalClashError('lockf: lock unavailable: %s' % f.name)
  2113.                 e.errno in (errno.EAGAIN, errno.EACCES)
  2114.                 raise 
  2115.             except:
  2116.                 None<EXCEPTION MATCH>IOError
  2117.             
  2118.  
  2119.         None<EXCEPTION MATCH>IOError
  2120.         if dotlock:
  2121.             
  2122.             try:
  2123.                 pre_lock = _create_temporary(f.name + '.lock')
  2124.                 pre_lock.close()
  2125.             except IOError:
  2126.                 e = None
  2127.                 if e.errno == errno.EACCES:
  2128.                     return None
  2129.                 raise 
  2130.             except:
  2131.                 e.errno == errno.EACCES
  2132.  
  2133.             
  2134.             try:
  2135.                 if hasattr(os, 'link'):
  2136.                     os.link(pre_lock.name, f.name + '.lock')
  2137.                     dotlock_done = True
  2138.                     os.unlink(pre_lock.name)
  2139.                 else:
  2140.                     os.rename(pre_lock.name, f.name + '.lock')
  2141.                     dotlock_done = True
  2142.             except OSError:
  2143.                 e.errno == errno.EACCES
  2144.                 e = e.errno == errno.EACCES
  2145.                 if (e.errno == errno.EEXIST or os.name == 'os2') and e.errno == errno.EACCES:
  2146.                     os.remove(pre_lock.name)
  2147.                     raise ExternalClashError('dot lock unavailable: %s' % f.name)
  2148.                 e.errno == errno.EACCES
  2149.                 raise 
  2150.             except:
  2151.                 e.errno == errno.EACCES<EXCEPTION MATCH>OSError
  2152.             
  2153.  
  2154.         e.errno == errno.EACCES
  2155.     except:
  2156.         if fcntl:
  2157.             fcntl.lockf(f, fcntl.LOCK_UN)
  2158.         
  2159.         if dotlock_done:
  2160.             os.remove(f.name + '.lock')
  2161.         
  2162.         raise 
  2163.  
  2164.  
  2165.  
  2166. def _unlock_file(f):
  2167.     if fcntl:
  2168.         fcntl.lockf(f, fcntl.LOCK_UN)
  2169.     
  2170.     if os.path.exists(f.name + '.lock'):
  2171.         os.remove(f.name + '.lock')
  2172.     
  2173.  
  2174.  
  2175. def _create_carefully(path):
  2176.     fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR, 438)
  2177.     
  2178.     try:
  2179.         return open(path, 'rb+')
  2180.     finally:
  2181.         os.close(fd)
  2182.  
  2183.  
  2184.  
  2185. def _create_temporary(path):
  2186.     return _create_carefully('%s.%s.%s.%s' % (path, int(time.time()), socket.gethostname(), os.getpid()))
  2187.  
  2188.  
  2189. def _sync_flush(f):
  2190.     f.flush()
  2191.     if hasattr(os, 'fsync'):
  2192.         os.fsync(f.fileno())
  2193.     
  2194.  
  2195.  
  2196. def _sync_close(f):
  2197.     _sync_flush(f)
  2198.     f.close()
  2199.  
  2200.  
  2201. class _Mailbox:
  2202.     
  2203.     def __init__(self, fp, factory = rfc822.Message):
  2204.         self.fp = fp
  2205.         self.seekp = 0
  2206.         self.factory = factory
  2207.  
  2208.     
  2209.     def __iter__(self):
  2210.         return iter(self.next, None)
  2211.  
  2212.     
  2213.     def next(self):
  2214.         while None:
  2215.             
  2216.             try:
  2217.                 self._search_start()
  2218.             except EOFError:
  2219.                 self.seekp = self.fp.tell()
  2220.                 return None
  2221.  
  2222.             start = self.fp.tell()
  2223.             self._search_end()
  2224.             self.seekp = stop = self.fp.tell()
  2225.             if start != stop:
  2226.                 break
  2227.                 continue
  2228.             continue
  2229.             return self.factory(_PartialFile(self.fp, start, stop))
  2230.  
  2231.  
  2232.  
  2233. class UnixMailbox(_Mailbox):
  2234.     
  2235.     def _search_start(self):
  2236.         while None:
  2237.             pos = self.fp.tell()
  2238.             line = self.fp.readline()
  2239.             if not line:
  2240.                 raise EOFError
  2241.             if line[:5] == 'From ' and self._isrealfromline(line):
  2242.                 self.fp.seek(pos)
  2243.                 return None
  2244.             continue
  2245.             return None
  2246.  
  2247.     
  2248.     def _search_end(self):
  2249.         self.fp.readline()
  2250.         while None:
  2251.             pos = self.fp.tell()
  2252.             line = self.fp.readline()
  2253.             if not line:
  2254.                 return None
  2255.             if line[:5] == 'From ' and self._isrealfromline(line):
  2256.                 self.fp.seek(pos)
  2257.                 return None
  2258.             continue
  2259.             return None
  2260.  
  2261.     _fromlinepattern = 'From \\s*[^\\s]+\\s+\\w\\w\\w\\s+\\w\\w\\w\\s+\\d?\\d\\s+\\d?\\d:\\d\\d(:\\d\\d)?(\\s+[^\\s]+)?\\s+\\d\\d\\d\\d\\s*[^\\s]*\\s*$'
  2262.     _regexp = None
  2263.     
  2264.     def _strict_isrealfromline(self, line):
  2265.         if not self._regexp:
  2266.             import re
  2267.             self._regexp = re.compile(self._fromlinepattern)
  2268.         
  2269.         return self._regexp.match(line)
  2270.  
  2271.     
  2272.     def _portable_isrealfromline(self, line):
  2273.         return True
  2274.  
  2275.     _isrealfromline = _strict_isrealfromline
  2276.  
  2277.  
  2278. class PortableUnixMailbox(UnixMailbox):
  2279.     _isrealfromline = UnixMailbox._portable_isrealfromline
  2280.  
  2281.  
  2282. class MmdfMailbox(_Mailbox):
  2283.     
  2284.     def _search_start(self):
  2285.         while None:
  2286.             line = self.fp.readline()
  2287.             if not line:
  2288.                 raise EOFError
  2289.             if line[:5] == '\x01\x01\x01\x01\n':
  2290.                 return None
  2291.             continue
  2292.             return None
  2293.  
  2294.     
  2295.     def _search_end(self):
  2296.         while None:
  2297.             pos = self.fp.tell()
  2298.             line = self.fp.readline()
  2299.             if not line:
  2300.                 return None
  2301.             if line == '\x01\x01\x01\x01\n':
  2302.                 self.fp.seek(pos)
  2303.                 return None
  2304.             continue
  2305.             return None
  2306.  
  2307.  
  2308.  
  2309. class MHMailbox:
  2310.     
  2311.     def __init__(self, dirname, factory = rfc822.Message):
  2312.         import re
  2313.         pat = re.compile('^[1-9][0-9]*$')
  2314.         self.dirname = dirname
  2315.         list = os.listdir(self.dirname)
  2316.         list = filter(pat.match, list)
  2317.         list = map(long, list)
  2318.         list.sort()
  2319.         self.boxes = map(str, list)
  2320.         self.boxes.reverse()
  2321.         self.factory = factory
  2322.  
  2323.     
  2324.     def __iter__(self):
  2325.         return iter(self.next, None)
  2326.  
  2327.     
  2328.     def next(self):
  2329.         if not self.boxes:
  2330.             return None
  2331.         fn = self.boxes.pop()
  2332.         fp = open(os.path.join(self.dirname, fn))
  2333.         msg = self.factory(fp)
  2334.         
  2335.         try:
  2336.             msg._mh_msgno = fn
  2337.         except (AttributeError, TypeError):
  2338.             self.boxes
  2339.             self.boxes
  2340.         except:
  2341.             self.boxes
  2342.  
  2343.         return msg
  2344.  
  2345.  
  2346.  
  2347. class BabylMailbox(_Mailbox):
  2348.     
  2349.     def _search_start(self):
  2350.         while None:
  2351.             line = self.fp.readline()
  2352.             if not line:
  2353.                 raise EOFError
  2354.             if line == '*** EOOH ***\n':
  2355.                 return None
  2356.             continue
  2357.             return None
  2358.  
  2359.     
  2360.     def _search_end(self):
  2361.         while None:
  2362.             pos = self.fp.tell()
  2363.             line = self.fp.readline()
  2364.             if not line:
  2365.                 return None
  2366.             if line == '\x1f\x0c\n' or line == '\x1f':
  2367.                 self.fp.seek(pos)
  2368.                 return None
  2369.             continue
  2370.             return None
  2371.  
  2372.  
  2373.  
  2374. class Error(Exception):
  2375.     pass
  2376.  
  2377.  
  2378. class NoSuchMailboxError(Error):
  2379.     pass
  2380.  
  2381.  
  2382. class NotEmptyError(Error):
  2383.     pass
  2384.  
  2385.  
  2386. class ExternalClashError(Error):
  2387.     pass
  2388.  
  2389.  
  2390. class FormatError(Error):
  2391.     pass
  2392.  
  2393.