home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_python.idb / usr / freeware / lib / python1.5 / mailbox.py.z / mailbox.py
Encoding:
Python Source  |  1999-04-16  |  5.5 KB  |  263 lines

  1. #! /usr/bin/env python
  2.  
  3. """Classes to handle Unix style, MMDF style, and MH style mailboxes."""
  4.  
  5.  
  6. import rfc822
  7. import os
  8.  
  9. class _Mailbox:
  10.  
  11.     def __init__(self, fp):
  12.         self.fp = fp
  13.         self.seekp = 0
  14.  
  15.     def seek(self, pos, whence=0):
  16.         if whence==1:        # Relative to current position
  17.             self.pos = self.pos + pos
  18.         if whence==2:        # Relative to file's end
  19.             self.pos = self.stop + pos
  20.         else:            # Default - absolute position
  21.             self.pos = self.start + pos
  22.  
  23.     def next(self):
  24.         while 1:
  25.             self.fp.seek(self.seekp)
  26.             try:
  27.                 self._search_start()
  28.             except EOFError:
  29.                 self.seekp = self.fp.tell()
  30.                 return None
  31.             start = self.fp.tell()
  32.             self._search_end()
  33.             self.seekp = stop = self.fp.tell()
  34.             if start <> stop:
  35.                 break
  36.         return rfc822.Message(_Subfile(self.fp, start, stop))
  37.  
  38. class _Subfile:
  39.  
  40.     def __init__(self, fp, start, stop):
  41.         self.fp = fp
  42.         self.start = start
  43.         self.stop = stop
  44.         self.pos = self.start
  45.  
  46.     def read(self, length = None):
  47.         if self.pos >= self.stop:
  48.             return ''
  49.         remaining = self.stop - self.pos
  50.         if length is None or length < 0:
  51.             length = remaining
  52.         elif length > remaining:
  53.             length = remaining
  54.         self.fp.seek(self.pos)
  55.         data = self.fp.read(length)
  56.         self.pos = self.fp.tell()
  57.         return data
  58.  
  59.     def readline(self, length = None):
  60.         if self.pos >= self.stop:
  61.             return ''
  62.         if length is None:
  63.             length = self.stop - self.pos
  64.         self.fp.seek(self.pos)
  65.         data = self.fp.readline(length)
  66.         self.pos = self.fp.tell()
  67.         return data
  68.  
  69.     def tell(self):
  70.         return self.pos - self.start
  71.  
  72.     def seek(self, pos, whence=0):
  73.         if whence == 0:
  74.             self.pos = self.start + pos
  75.         elif whence == 1:
  76.             self.pos = self.pos + pos
  77.         elif whence == 2:
  78.             self.pos = self.stop + pos
  79.  
  80.     def close(self):
  81.         del self.fp
  82.  
  83. class UnixMailbox(_Mailbox):
  84.  
  85.     def _search_start(self):
  86.         while 1:
  87.             line = self.fp.readline()
  88.             if not line:
  89.                 raise EOFError
  90.             if line[:5] == 'From ' and self._isrealfromline(line):
  91.                 return
  92.  
  93.     def _search_end(self):
  94.         while 1:
  95.             pos = self.fp.tell()
  96.             line = self.fp.readline()
  97.             if not line:
  98.                 return
  99.             if line[:5] == 'From ' and self._isrealfromline(line):
  100.                 self.fp.seek(pos)
  101.                 return
  102.  
  103.     # An overridable mechanism to test for From-line-ness.
  104.     # You can either specify a different regular expression
  105.     # or define a whole new _isrealfromline() method.
  106.     # Note that this only gets called for lines starting with
  107.     # the 5 characters "From ".
  108.  
  109.     _fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \
  110.                r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$"
  111.     _regexp = None
  112.  
  113.     def _isrealfromline(self, line):
  114.         if not self._regexp:
  115.             import re
  116.             self._regexp = re.compile(self._fromlinepattern)
  117.         return self._regexp.match(line)
  118.  
  119. class MmdfMailbox(_Mailbox):
  120.  
  121.     def _search_start(self):
  122.         while 1:
  123.             line = self.fp.readline()
  124.             if not line:
  125.                 raise EOFError
  126.             if line[:5] == '\001\001\001\001\n':
  127.                 return
  128.  
  129.     def _search_end(self):
  130.         while 1:
  131.             pos = self.fp.tell()
  132.             line = self.fp.readline()
  133.             if not line:
  134.                 return
  135.             if line == '\001\001\001\001\n':
  136.                 self.fp.seek(pos)
  137.                 return
  138.  
  139. class MHMailbox:
  140.  
  141.     def __init__(self, dirname):
  142.         import re
  143.         pat = re.compile('^[0-9][0-9]*$')
  144.         self.dirname = dirname
  145.         files = os.listdir(self.dirname)
  146.         self.boxes = []
  147.         for f in files:
  148.             if pat.match(f):
  149.                 self.boxes.append(f)
  150.  
  151.     def next(self):
  152.         if not self.boxes:
  153.             return None
  154.         fn = self.boxes[0]
  155.         del self.boxes[0]
  156.         fp = open(os.path.join(self.dirname, fn))
  157.         return rfc822.Message(fp)
  158.  
  159. class Maildir:
  160.  
  161.     # Qmail directory mailbox
  162.  
  163.     def __init__(self, dirname):
  164.         import string
  165.         self.dirname = dirname
  166.         self.boxes = []
  167.  
  168.         # check for new mail
  169.         newdir = os.path.join(self.dirname, 'new')
  170.         for file in os.listdir(newdir):
  171.             if len(string.split(file, '.')) > 2:
  172.                 self.boxes.append(os.path.join(newdir, file))
  173.  
  174.         # Now check for current mail in this maildir
  175.         curdir = os.path.join(self.dirname, 'cur')
  176.         for file in os.listdir(curdir):
  177.             if len(string.split(file, '.')) > 2:
  178.                 self.boxes.append(os.path.join(curdir, file))
  179.  
  180.     def next(self):
  181.         if not self.boxes:
  182.             return None
  183.         fn = self.boxes[0]
  184.         del self.boxes[0]
  185.         fp = open(os.path.join(self.dirname, fn))
  186.         return rfc822.Message(fp)
  187.  
  188. class BabylMailbox(_Mailbox):
  189.  
  190.     def _search_start(self):
  191.         while 1:
  192.             line = self.fp.readline()
  193.             if not line:
  194.                 raise EOFError
  195.             if line == '*** EOOH ***\n':
  196.                 return
  197.  
  198.     def _search_end(self):
  199.         while 1:
  200.             pos = self.fp.tell()
  201.             line = self.fp.readline()
  202.             if not line:
  203.                 return
  204.             if line == '\037\014\n':
  205.                 self.fp.seek(pos)
  206.                 return
  207.  
  208.  
  209. def _test():
  210.     import time
  211.     import sys
  212.     import string
  213.     import os
  214.  
  215.     args = sys.argv[1:]
  216.     if not args:
  217.         for key in 'MAILDIR', 'MAIL', 'LOGNAME', 'USER':
  218.             if os.environ.has_key(key):
  219.                 mbox = os.environ[key]
  220.                 break
  221.         else:
  222.             print "$MAIL, $LOGNAME nor $USER set -- who are you?"
  223.             return
  224.     else:
  225.         mbox = args[0]
  226.     if mbox[:1] == '+':
  227.         mbox = os.environ['HOME'] + '/Mail/' + mbox[1:]
  228.     elif not '/' in mbox:
  229.         mbox = '/usr/mail/' + mbox
  230.     if os.path.isdir(mbox):
  231.         if os.path.isdir(os.path.join(mbox, 'cur')):
  232.             mb = Maildir(mbox)
  233.         else:
  234.             mb = MHMailbox(mbox)
  235.     else:
  236.         fp = open(mbox, 'r')
  237.         mb = UnixMailbox(fp)
  238.     
  239.     msgs = []
  240.     while 1:
  241.         msg = mb.next()
  242.         if msg is None:
  243.             break
  244.         msgs.append(msg)
  245.         msg.fp = None
  246.     if len(args) > 1:
  247.         num = string.atoi(args[1])
  248.         print 'Message %d body:'%num
  249.         msg = msgs[num-1]
  250.         msg.rewindbody()
  251.         sys.stdout.write(msg.fp.read())
  252.     else:
  253.         print 'Mailbox',mbox,'has',len(msgs),'messages:'
  254.         for msg in msgs:
  255.             f = msg.getheader('from') or ""
  256.             s = msg.getheader('subject') or ""
  257.             d = msg.getheader('date') or ""
  258.             print '%20.20s   %18.18s   %-30.30s'%(f, d[5:], s)
  259.  
  260.  
  261. if __name__ == '__main__':
  262.     _test()
  263.