diff -r 000000000000 -r ae805ac0140d python-2.5.2/win32/Lib/quopri.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python-2.5.2/win32/Lib/quopri.py Fri Apr 03 17:19:34 2009 +0100 @@ -0,0 +1,237 @@ +#! /usr/bin/env python + +"""Conversions to/from quoted-printable transport encoding as per RFC 1521.""" + +# (Dec 1991 version). + +__all__ = ["encode", "decode", "encodestring", "decodestring"] + +ESCAPE = '=' +MAXLINESIZE = 76 +HEX = '0123456789ABCDEF' +EMPTYSTRING = '' + +try: + from binascii import a2b_qp, b2a_qp +except ImportError: + a2b_qp = None + b2a_qp = None + + +def needsquoting(c, quotetabs, header): + """Decide whether a particular character needs to be quoted. + + The 'quotetabs' flag indicates whether embedded tabs and spaces should be + quoted. Note that line-ending tabs and spaces are always encoded, as per + RFC 1521. + """ + if c in ' \t': + return quotetabs + # if header, we have to escape _ because _ is used to escape space + if c == '_': + return header + return c == ESCAPE or not (' ' <= c <= '~') + +def quote(c): + """Quote a single character.""" + i = ord(c) + return ESCAPE + HEX[i//16] + HEX[i%16] + + + +def encode(input, output, quotetabs, header = 0): + """Read 'input', apply quoted-printable encoding, and write to 'output'. + + 'input' and 'output' are files with readline() and write() methods. + The 'quotetabs' flag indicates whether embedded tabs and spaces should be + quoted. Note that line-ending tabs and spaces are always encoded, as per + RFC 1521. + The 'header' flag indicates whether we are encoding spaces as _ as per + RFC 1522. + """ + + if b2a_qp is not None: + data = input.read() + odata = b2a_qp(data, quotetabs = quotetabs, header = header) + output.write(odata) + return + + def write(s, output=output, lineEnd='\n'): + # RFC 1521 requires that the line ending in a space or tab must have + # that trailing character encoded. + if s and s[-1:] in ' \t': + output.write(s[:-1] + quote(s[-1]) + lineEnd) + elif s == '.': + output.write(quote(s) + lineEnd) + else: + output.write(s + lineEnd) + + prevline = None + while 1: + line = input.readline() + if not line: + break + outline = [] + # Strip off any readline induced trailing newline + stripped = '' + if line[-1:] == '\n': + line = line[:-1] + stripped = '\n' + # Calculate the un-length-limited encoded line + for c in line: + if needsquoting(c, quotetabs, header): + c = quote(c) + if header and c == ' ': + outline.append('_') + else: + outline.append(c) + # First, write out the previous line + if prevline is not None: + write(prevline) + # Now see if we need any soft line breaks because of RFC-imposed + # length limitations. Then do the thisline->prevline dance. + thisline = EMPTYSTRING.join(outline) + while len(thisline) > MAXLINESIZE: + # Don't forget to include the soft line break `=' sign in the + # length calculation! + write(thisline[:MAXLINESIZE-1], lineEnd='=\n') + thisline = thisline[MAXLINESIZE-1:] + # Write out the current line + prevline = thisline + # Write out the last line, without a trailing newline + if prevline is not None: + write(prevline, lineEnd=stripped) + +def encodestring(s, quotetabs = 0, header = 0): + if b2a_qp is not None: + return b2a_qp(s, quotetabs = quotetabs, header = header) + from cStringIO import StringIO + infp = StringIO(s) + outfp = StringIO() + encode(infp, outfp, quotetabs, header) + return outfp.getvalue() + + + +def decode(input, output, header = 0): + """Read 'input', apply quoted-printable decoding, and write to 'output'. + 'input' and 'output' are files with readline() and write() methods. + If 'header' is true, decode underscore as space (per RFC 1522).""" + + if a2b_qp is not None: + data = input.read() + odata = a2b_qp(data, header = header) + output.write(odata) + return + + new = '' + while 1: + line = input.readline() + if not line: break + i, n = 0, len(line) + if n > 0 and line[n-1] == '\n': + partial = 0; n = n-1 + # Strip trailing whitespace + while n > 0 and line[n-1] in " \t\r": + n = n-1 + else: + partial = 1 + while i < n: + c = line[i] + if c == '_' and header: + new = new + ' '; i = i+1 + elif c != ESCAPE: + new = new + c; i = i+1 + elif i+1 == n and not partial: + partial = 1; break + elif i+1 < n and line[i+1] == ESCAPE: + new = new + ESCAPE; i = i+2 + elif i+2 < n and ishex(line[i+1]) and ishex(line[i+2]): + new = new + chr(unhex(line[i+1:i+3])); i = i+3 + else: # Bad escape sequence -- leave it in + new = new + c; i = i+1 + if not partial: + output.write(new + '\n') + new = '' + if new: + output.write(new) + +def decodestring(s, header = 0): + if a2b_qp is not None: + return a2b_qp(s, header = header) + from cStringIO import StringIO + infp = StringIO(s) + outfp = StringIO() + decode(infp, outfp, header = header) + return outfp.getvalue() + + + +# Other helper functions +def ishex(c): + """Return true if the character 'c' is a hexadecimal digit.""" + return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F' + +def unhex(s): + """Get the integer value of a hexadecimal number.""" + bits = 0 + for c in s: + if '0' <= c <= '9': + i = ord('0') + elif 'a' <= c <= 'f': + i = ord('a')-10 + elif 'A' <= c <= 'F': + i = ord('A')-10 + else: + break + bits = bits*16 + (ord(c) - i) + return bits + + + +def main(): + import sys + import getopt + try: + opts, args = getopt.getopt(sys.argv[1:], 'td') + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print "usage: quopri [-t | -d] [file] ..." + print "-t: quote tabs" + print "-d: decode; default encode" + sys.exit(2) + deco = 0 + tabs = 0 + for o, a in opts: + if o == '-t': tabs = 1 + if o == '-d': deco = 1 + if tabs and deco: + sys.stdout = sys.stderr + print "-t and -d are mutually exclusive" + sys.exit(2) + if not args: args = ['-'] + sts = 0 + for file in args: + if file == '-': + fp = sys.stdin + else: + try: + fp = open(file) + except IOError, msg: + sys.stderr.write("%s: can't open (%s)\n" % (file, msg)) + sts = 1 + continue + if deco: + decode(fp, sys.stdout) + else: + encode(fp, sys.stdout, tabs) + if fp is not sys.stdin: + fp.close() + if sts: + sys.exit(sts) + + + +if __name__ == '__main__': + main()