home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pytho152.zip / emx / lib / python1.5 / mimetools.py < prev    next >
Text File  |  2000-08-10  |  5KB  |  225 lines

  1. # Various tools used by MIME-reading or MIME-writing programs.
  2.  
  3.  
  4. import os
  5. import rfc822
  6. import string
  7. import tempfile
  8.  
  9.  
  10. # A derived class of rfc822.Message that knows about MIME headers and
  11. # contains some hooks for decoding encoded and multipart messages.
  12.  
  13. class Message(rfc822.Message):
  14.  
  15.     def __init__(self, fp, seekable = 1):
  16.         rfc822.Message.__init__(self, fp, seekable)
  17.         self.encodingheader = \
  18.             self.getheader('content-transfer-encoding')
  19.         self.typeheader = \
  20.             self.getheader('content-type')
  21.         self.parsetype()
  22.         self.parseplist()
  23.  
  24.     def parsetype(self):
  25.         str = self.typeheader
  26.         if str == None:
  27.             str = 'text/plain'
  28.         if ';' in str:
  29.             i = string.index(str, ';')
  30.             self.plisttext = str[i:]
  31.             str = str[:i]
  32.         else:
  33.             self.plisttext = ''
  34.         fields = string.splitfields(str, '/')
  35.         for i in range(len(fields)):
  36.             fields[i] = string.lower(string.strip(fields[i]))
  37.         self.type = string.joinfields(fields, '/')
  38.         self.maintype = fields[0]
  39.         self.subtype = string.joinfields(fields[1:], '/')
  40.  
  41.     def parseplist(self):
  42.         str = self.plisttext
  43.         self.plist = []
  44.         while str[:1] == ';':
  45.             str = str[1:]
  46.             if ';' in str:
  47.                 # XXX Should parse quotes!
  48.                 end = string.index(str, ';')
  49.             else:
  50.                 end = len(str)
  51.             f = str[:end]
  52.             if '=' in f:
  53.                 i = string.index(f, '=')
  54.                 f = string.lower(string.strip(f[:i])) + \
  55.                     '=' + string.strip(f[i+1:])
  56.             self.plist.append(string.strip(f))
  57.             str = str[end:]
  58.  
  59.     def getplist(self):
  60.         return self.plist
  61.  
  62.     def getparam(self, name):
  63.         name = string.lower(name) + '='
  64.         n = len(name)
  65.         for p in self.plist:
  66.             if p[:n] == name:
  67.                 return rfc822.unquote(p[n:])
  68.         return None
  69.  
  70.     def getparamnames(self):
  71.         result = []
  72.         for p in self.plist:
  73.             i = string.find(p, '=')
  74.             if i >= 0:
  75.                 result.append(string.lower(p[:i]))
  76.         return result
  77.  
  78.     def getencoding(self):
  79.         if self.encodingheader == None:
  80.             return '7bit'
  81.         return string.lower(self.encodingheader)
  82.  
  83.     def gettype(self):
  84.         return self.type
  85.  
  86.     def getmaintype(self):
  87.         return self.maintype
  88.  
  89.     def getsubtype(self):
  90.         return self.subtype
  91.  
  92.  
  93.  
  94.  
  95. # Utility functions
  96. # -----------------
  97.  
  98.  
  99. # Return a random string usable as a multipart boundary.
  100. # The method used is so that it is *very* unlikely that the same
  101. # string of characters will every occur again in the Universe,
  102. # so the caller needn't check the data it is packing for the
  103. # occurrence of the boundary.
  104. #
  105. # The boundary contains dots so you have to quote it in the header.
  106.  
  107. _prefix = None
  108.  
  109. def choose_boundary():
  110.     global _prefix
  111.     import time
  112.     import random
  113.     if _prefix == None:
  114.         import socket
  115.         import os
  116.         hostid = socket.gethostbyname(socket.gethostname())
  117.         try:
  118.             uid = `os.getuid()`
  119.         except:
  120.             uid = '1'
  121.         try:
  122.             pid = `os.getpid()`
  123.         except:
  124.             pid = '1'
  125.         _prefix = hostid + '.' + uid + '.' + pid
  126.     timestamp = '%.3f' % time.time()
  127.     seed = `random.randint(0, 32767)`
  128.     return _prefix + '.' + timestamp + '.' + seed
  129.  
  130.  
  131. # Subroutines for decoding some common content-transfer-types
  132.  
  133. def decode(input, output, encoding):
  134.     if encoding == 'base64':
  135.         import base64
  136.         return base64.decode(input, output)
  137.     if encoding == 'quoted-printable':
  138.         import quopri
  139.         return quopri.decode(input, output)
  140.     if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
  141.         import uu
  142.         return uu.decode(input, output)
  143.     if decodetab.has_key(encoding):
  144.         pipethrough(input, decodetab[encoding], output)
  145.     else:
  146.         raise ValueError, \
  147.               'unknown Content-Transfer-Encoding: %s' % encoding
  148.  
  149. def encode(input, output, encoding):
  150.     if encoding == 'base64':
  151.         import base64
  152.         return base64.encode(input, output)
  153.     if encoding == 'quoted-printable':
  154.         import quopri
  155.         return quopri.encode(input, output, 0)
  156.     if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
  157.         import uu
  158.         return uu.encode(input, output)
  159.     if encodetab.has_key(encoding):
  160.         pipethrough(input, encodetab[encoding], output)
  161.     else:
  162.         raise ValueError, \
  163.               'unknown Content-Transfer-Encoding: %s' % encoding
  164.  
  165. # The following is no longer used for standard encodings
  166.  
  167. # XXX This requires that uudecode and mmencode are in $PATH
  168.  
  169. uudecode_pipe = '''(
  170. TEMP=/tmp/@uu.$$
  171. sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
  172. cat $TEMP
  173. rm $TEMP
  174. )'''
  175.  
  176. decodetab = {
  177.     'uuencode':        uudecode_pipe,
  178.     'x-uuencode':        uudecode_pipe,
  179.     'uue':            uudecode_pipe,
  180.     'x-uue':        uudecode_pipe,
  181.     'quoted-printable':    'mmencode -u -q',
  182.     'base64':        'mmencode -u -b',
  183. }
  184.  
  185. encodetab = {
  186.     'x-uuencode':        'uuencode tempfile',
  187.     'uuencode':        'uuencode tempfile',
  188.     'x-uue':        'uuencode tempfile',
  189.     'uue':            'uuencode tempfile',
  190.     'quoted-printable':    'mmencode -q',
  191.     'base64':        'mmencode -b',
  192. }
  193.  
  194. def pipeto(input, command):
  195.     pipe = os.popen(command, 'w')
  196.     copyliteral(input, pipe)
  197.     pipe.close()
  198.  
  199. def pipethrough(input, command, output):
  200.     tempname = tempfile.mktemp()
  201.     try:
  202.         temp = open(tempname, 'w')
  203.     except IOError:
  204.         print '*** Cannot create temp file', `tempname`
  205.         return
  206.     copyliteral(input, temp)
  207.     temp.close()
  208.     pipe = os.popen(command + ' <' + tempname, 'r')
  209.     copybinary(pipe, output)
  210.     pipe.close()
  211.     os.unlink(tempname)
  212.  
  213. def copyliteral(input, output):
  214.     while 1:
  215.         line = input.readline()
  216.         if not line: break
  217.         output.write(line)
  218.  
  219. def copybinary(input, output):
  220.     BUFSIZE = 8192
  221.     while 1:
  222.         line = input.read(BUFSIZE)
  223.         if not line: break
  224.         output.write(line)
  225.