home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_Lib_quopri.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  4.3 KB  |  153 lines

  1. #! /usr/bin/env python
  2.  
  3. """Conversions to/from quoted-printable transport encoding as per RFC-1521."""
  4.  
  5. # (Dec 1991 version).
  6.  
  7. __all__ = ["encode","decode"]
  8.  
  9. ESCAPE = '='
  10. MAXLINESIZE = 76
  11. HEX = '0123456789ABCDEF'
  12.  
  13. def needsquoting(c, quotetabs):
  14.     """Decide whether a particular character needs to be quoted.
  15.  
  16.     The 'quotetabs' flag indicates whether tabs should be quoted."""
  17.     if c == '\t':
  18.         return not quotetabs
  19.     return c == ESCAPE or not(' ' <= c <= '~')
  20.  
  21. def quote(c):
  22.     """Quote a single character."""
  23.     i = ord(c)
  24.     return ESCAPE + HEX[i/16] + HEX[i%16]
  25.  
  26. def encode(input, output, quotetabs):
  27.     """Read 'input', apply quoted-printable encoding, and write to 'output'.
  28.  
  29.     'input' and 'output' are files with readline() and write() methods.
  30.     The 'quotetabs' flag indicates whether tabs should be quoted.
  31.         """
  32.     while 1:
  33.         line = input.readline()
  34.         if not line:
  35.             break
  36.         new = ''
  37.         last = line[-1:]
  38.         if last == '\n':
  39.             line = line[:-1]
  40.         else:
  41.             last = ''
  42.         prev = ''
  43.         for c in line:
  44.             if needsquoting(c, quotetabs):
  45.                 c = quote(c)
  46.             if len(new) + len(c) >= MAXLINESIZE:
  47.                 output.write(new + ESCAPE + '\n')
  48.                 new = ''
  49.             new = new + c
  50.             prev = c
  51.         if prev in (' ', '\t'):
  52.             output.write(new + ESCAPE + '\n\n')
  53.         else:
  54.             output.write(new + '\n')
  55.  
  56. def decode(input, output):
  57.     """Read 'input', apply quoted-printable decoding, and write to 'output'.
  58.  
  59.     'input' and 'output' are files with readline() and write() methods."""
  60.     new = ''
  61.     while 1:
  62.         line = input.readline()
  63.         if not line: break
  64.         i, n = 0, len(line)
  65.         if n > 0 and line[n-1] == '\n':
  66.             partial = 0; n = n-1
  67.             # Strip trailing whitespace
  68.             while n > 0 and line[n-1] in " \t\r":
  69.                 n = n-1
  70.         else:
  71.             partial = 1
  72.         while i < n:
  73.             c = line[i]
  74.             if c != ESCAPE:
  75.                 new = new + c; i = i+1
  76.             elif i+1 == n and not partial:
  77.                 partial = 1; break
  78.             elif i+1 < n and line[i+1] == ESCAPE:
  79.                 new = new + ESCAPE; i = i+2
  80.             elif i+2 < n and ishex(line[i+1]) and ishex(line[i+2]):
  81.                 new = new + chr(unhex(line[i+1:i+3])); i = i+3
  82.             else: # Bad escape sequence -- leave it in
  83.                 new = new + c; i = i+1
  84.         if not partial:
  85.             output.write(new + '\n')
  86.             new = ''
  87.     if new:
  88.         output.write(new)
  89.  
  90. def ishex(c):
  91.     """Return true if the character 'c' is a hexadecimal digit."""
  92.     return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F'
  93.  
  94. def unhex(s):
  95.     """Get the integer value of a hexadecimal number."""
  96.     bits = 0
  97.     for c in s:
  98.         if '0' <= c <= '9':
  99.             i = ord('0')
  100.         elif 'a' <= c <= 'f':
  101.             i = ord('a')-10
  102.         elif 'A' <= c <= 'F':
  103.             i = ord('A')-10
  104.         else:
  105.             break
  106.         bits = bits*16 + (ord(c) - i)
  107.     return bits
  108.  
  109. def test():
  110.     import sys
  111.     import getopt
  112.     try:
  113.         opts, args = getopt.getopt(sys.argv[1:], 'td')
  114.     except getopt.error, msg:
  115.         sys.stdout = sys.stderr
  116.         print msg
  117.         print "usage: quopri [-t | -d] [file] ..."
  118.         print "-t: quote tabs"
  119.         print "-d: decode; default encode"
  120.         sys.exit(2)
  121.     deco = 0
  122.     tabs = 0
  123.     for o, a in opts:
  124.         if o == '-t': tabs = 1
  125.         if o == '-d': deco = 1
  126.     if tabs and deco:
  127.         sys.stdout = sys.stderr
  128.         print "-t and -d are mutually exclusive"
  129.         sys.exit(2)
  130.     if not args: args = ['-']
  131.     sts = 0
  132.     for file in args:
  133.         if file == '-':
  134.             fp = sys.stdin
  135.         else:
  136.             try:
  137.                 fp = open(file)
  138.             except IOError, msg:
  139.                 sys.stderr.write("%s: can't open (%s)\n" % (file, msg))
  140.                 sts = 1
  141.                 continue
  142.         if deco:
  143.             decode(fp, sys.stdout)
  144.         else:
  145.             encode(fp, sys.stdout, tabs)
  146.         if fp is not sys.stdin:
  147.             fp.close()
  148.     if sts:
  149.         sys.exit(sts)
  150.  
  151. if __name__ == '__main__':
  152.     test()
  153.