github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/mimetools.py (about)

     1  """Various tools used by MIME-reading or MIME-writing programs."""
     2  
     3  
     4  import os
     5  import sys
     6  import tempfile
     7  from warnings import filterwarnings, catch_warnings
     8  with catch_warnings():
     9      if sys.py3kwarning:
    10          filterwarnings("ignore", ".*rfc822 has been removed", DeprecationWarning)
    11      import rfc822
    12  
    13  from warnings import warnpy3k
    14  warnpy3k("in 3.x, mimetools has been removed in favor of the email package",
    15           stacklevel=2)
    16  
    17  __all__ = ["Message","choose_boundary","encode","decode","copyliteral",
    18             "copybinary"]
    19  
    20  class Message(rfc822.Message):
    21      """A derived class of rfc822.Message that knows about MIME headers and
    22      contains some hooks for decoding encoded and multipart messages."""
    23  
    24      def __init__(self, fp, seekable = 1):
    25          rfc822.Message.__init__(self, fp, seekable)
    26          self.encodingheader = \
    27                  self.getheader('content-transfer-encoding')
    28          self.typeheader = \
    29                  self.getheader('content-type')
    30          self.parsetype()
    31          self.parseplist()
    32  
    33      def parsetype(self):
    34          str = self.typeheader
    35          if str is None:
    36              str = 'text/plain'
    37          if ';' in str:
    38              i = str.index(';')
    39              self.plisttext = str[i:]
    40              str = str[:i]
    41          else:
    42              self.plisttext = ''
    43          fields = str.split('/')
    44          for i in range(len(fields)):
    45              fields[i] = fields[i].strip().lower()
    46          self.type = '/'.join(fields)
    47          self.maintype = fields[0]
    48          self.subtype = '/'.join(fields[1:])
    49  
    50      def parseplist(self):
    51          str = self.plisttext
    52          self.plist = []
    53          while str[:1] == ';':
    54              str = str[1:]
    55              if ';' in str:
    56                  # XXX Should parse quotes!
    57                  end = str.index(';')
    58              else:
    59                  end = len(str)
    60              f = str[:end]
    61              if '=' in f:
    62                  i = f.index('=')
    63                  f = f[:i].strip().lower() + \
    64                          '=' + f[i+1:].strip()
    65              self.plist.append(f.strip())
    66              str = str[end:]
    67  
    68      def getplist(self):
    69          return self.plist
    70  
    71      def getparam(self, name):
    72          name = name.lower() + '='
    73          n = len(name)
    74          for p in self.plist:
    75              if p[:n] == name:
    76                  return rfc822.unquote(p[n:])
    77          return None
    78  
    79      def getparamnames(self):
    80          result = []
    81          for p in self.plist:
    82              i = p.find('=')
    83              if i >= 0:
    84                  result.append(p[:i].lower())
    85          return result
    86  
    87      def getencoding(self):
    88          if self.encodingheader is None:
    89              return '7bit'
    90          return self.encodingheader.lower()
    91  
    92      def gettype(self):
    93          return self.type
    94  
    95      def getmaintype(self):
    96          return self.maintype
    97  
    98      def getsubtype(self):
    99          return self.subtype
   100  
   101  
   102  
   103  
   104  # Utility functions
   105  # -----------------
   106  
   107  #try:
   108  import thread
   109  #except ImportError:
   110  #    import dummy_thread as thread
   111  _counter_lock = thread.allocate_lock()
   112  del thread
   113  
   114  _counter = 0
   115  def _get_next_counter():
   116      global _counter
   117      _counter_lock.acquire()
   118      _counter += 1
   119      result = _counter
   120      _counter_lock.release()
   121      return result
   122  
   123  _prefix = None
   124  
   125  #def choose_boundary():
   126  #    """Return a string usable as a multipart boundary.
   127  #
   128  #    The string chosen is unique within a single program run, and
   129  #    incorporates the user id (if available), process id (if available),
   130  #    and current time.  So it's very unlikely the returned string appears
   131  #    in message text, but there's no guarantee.
   132  #
   133  #    The boundary contains dots so you have to quote it in the header."""
   134  #
   135  #    global _prefix
   136  #    import time
   137  #    if _prefix is None:
   138  #        import socket
   139  #        try:
   140  #            hostid = socket.gethostbyname(socket.gethostname())
   141  #        except socket.gaierror:
   142  #            hostid = '127.0.0.1'
   143  #        try:
   144  #            uid = repr(os.getuid())
   145  #        except AttributeError:
   146  #            uid = '1'
   147  #        try:
   148  #            pid = repr(os.getpid())
   149  #        except AttributeError:
   150  #            pid = '1'
   151  #        _prefix = hostid + '.' + uid + '.' + pid
   152  #    return "%s.%.3f.%d" % (_prefix, time.time(), _get_next_counter())
   153  
   154  
   155  # Subroutines for decoding some common content-transfer-types
   156  
   157  def decode(input, output, encoding):
   158      """Decode common content-transfer-encodings (base64, quopri, uuencode)."""
   159      if encoding == 'base64':
   160          import base64
   161          return base64.decode(input, output)
   162      if encoding == 'quoted-printable':
   163          import quopri
   164          return quopri.decode(input, output)
   165      if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
   166          import uu
   167          return uu.decode(input, output)
   168      if encoding in ('7bit', '8bit'):
   169          return output.write(input.read())
   170      if encoding in decodetab:
   171          pipethrough(input, decodetab[encoding], output)
   172      else:
   173          raise ValueError, \
   174                'unknown Content-Transfer-Encoding: %s' % encoding
   175  
   176  def encode(input, output, encoding):
   177      """Encode common content-transfer-encodings (base64, quopri, uuencode)."""
   178      if encoding == 'base64':
   179          import base64
   180          return base64.encode(input, output)
   181      if encoding == 'quoted-printable':
   182          import quopri
   183          return quopri.encode(input, output, 0)
   184      if encoding in ('uuencode', 'x-uuencode', 'uue', 'x-uue'):
   185          import uu
   186          return uu.encode(input, output)
   187      if encoding in ('7bit', '8bit'):
   188          return output.write(input.read())
   189      if encoding in encodetab:
   190          pipethrough(input, encodetab[encoding], output)
   191      else:
   192          raise ValueError, \
   193                'unknown Content-Transfer-Encoding: %s' % encoding
   194  
   195  # The following is no longer used for standard encodings
   196  
   197  # XXX This requires that uudecode and mmencode are in $PATH
   198  
   199  uudecode_pipe = '''(
   200  TEMP=/tmp/@uu.$$
   201  sed "s%^begin [0-7][0-7]* .*%begin 600 $TEMP%" | uudecode
   202  cat $TEMP
   203  rm $TEMP
   204  )'''
   205  
   206  decodetab = {
   207          'uuencode':             uudecode_pipe,
   208          'x-uuencode':           uudecode_pipe,
   209          'uue':                  uudecode_pipe,
   210          'x-uue':                uudecode_pipe,
   211          'quoted-printable':     'mmencode -u -q',
   212          'base64':               'mmencode -u -b',
   213  }
   214  
   215  encodetab = {
   216          'x-uuencode':           'uuencode tempfile',
   217          'uuencode':             'uuencode tempfile',
   218          'x-uue':                'uuencode tempfile',
   219          'uue':                  'uuencode tempfile',
   220          'quoted-printable':     'mmencode -q',
   221          'base64':               'mmencode -b',
   222  }
   223  
   224  def pipeto(input, command):
   225      pipe = os.popen(command, 'w')
   226      copyliteral(input, pipe)
   227      pipe.close()
   228  
   229  def pipethrough(input, command, output):
   230      (fd, tempname) = tempfile.mkstemp()
   231      temp = os.fdopen(fd, 'w')
   232      copyliteral(input, temp)
   233      temp.close()
   234      pipe = os.popen(command + ' <' + tempname, 'r')
   235      copybinary(pipe, output)
   236      pipe.close()
   237      os.unlink(tempname)
   238  
   239  def copyliteral(input, output):
   240      while 1:
   241          line = input.readline()
   242          if not line: break
   243          output.write(line)
   244  
   245  def copybinary(input, output):
   246      BUFSIZE = 8192
   247      while 1:
   248          line = input.read(BUFSIZE)
   249          if not line: break
   250          output.write(line)