PyXR

c:\python24\lib \ quopri.py



0001 #! /usr/bin/env python
0002 
0003 """Conversions to/from quoted-printable transport encoding as per RFC 1521."""
0004 
0005 # (Dec 1991 version).
0006 
0007 __all__ = ["encode", "decode", "encodestring", "decodestring"]
0008 
0009 ESCAPE = '='
0010 MAXLINESIZE = 76
0011 HEX = '0123456789ABCDEF'
0012 EMPTYSTRING = ''
0013 
0014 try:
0015     from binascii import a2b_qp, b2a_qp
0016 except ImportError:
0017     a2b_qp = None
0018     b2a_qp = None
0019 
0020 
0021 def needsquoting(c, quotetabs, header):
0022     """Decide whether a particular character needs to be quoted.
0023 
0024     The 'quotetabs' flag indicates whether embedded tabs and spaces should be
0025     quoted.  Note that line-ending tabs and spaces are always encoded, as per
0026     RFC 1521.
0027     """
0028     if c in ' \t':
0029         return quotetabs
0030     # if header, we have to escape _ because _ is used to escape space
0031     if c == '_':
0032         return header
0033     return c == ESCAPE or not (' ' <= c <= '~')
0034 
0035 def quote(c):
0036     """Quote a single character."""
0037     i = ord(c)
0038     return ESCAPE + HEX[i//16] + HEX[i%16]
0039 
0040 
0041 
0042 def encode(input, output, quotetabs, header = 0):
0043     """Read 'input', apply quoted-printable encoding, and write to 'output'.
0044 
0045     'input' and 'output' are files with readline() and write() methods.
0046     The 'quotetabs' flag indicates whether embedded tabs and spaces should be
0047     quoted.  Note that line-ending tabs and spaces are always encoded, as per
0048     RFC 1521.
0049     The 'header' flag indicates whether we are encoding spaces as _ as per
0050     RFC 1522.
0051     """
0052 
0053     if b2a_qp is not None:
0054         data = input.read()
0055         odata = b2a_qp(data, quotetabs = quotetabs, header = header)
0056         output.write(odata)
0057         return
0058 
0059     def write(s, output=output, lineEnd='\n'):
0060         # RFC 1521 requires that the line ending in a space or tab must have
0061         # that trailing character encoded.
0062         if s and s[-1:] in ' \t':
0063             output.write(s[:-1] + quote(s[-1]) + lineEnd)
0064         elif s == '.':
0065             output.write(quote(s) + lineEnd)
0066         else:
0067             output.write(s + lineEnd)
0068 
0069     prevline = None
0070     while 1:
0071         line = input.readline()
0072         if not line:
0073             break
0074         outline = []
0075         # Strip off any readline induced trailing newline
0076         stripped = ''
0077         if line[-1:] == '\n':
0078             line = line[:-1]
0079             stripped = '\n'
0080         # Calculate the un-length-limited encoded line
0081         for c in line:
0082             if needsquoting(c, quotetabs, header):
0083                 c = quote(c)
0084             if header and c == ' ':
0085                 outline.append('_')
0086             else:
0087                 outline.append(c)
0088         # First, write out the previous line
0089         if prevline is not None:
0090             write(prevline)
0091         # Now see if we need any soft line breaks because of RFC-imposed
0092         # length limitations.  Then do the thisline->prevline dance.
0093         thisline = EMPTYSTRING.join(outline)
0094         while len(thisline) > MAXLINESIZE:
0095             # Don't forget to include the soft line break `=' sign in the
0096             # length calculation!
0097             write(thisline[:MAXLINESIZE-1], lineEnd='=\n')
0098             thisline = thisline[MAXLINESIZE-1:]
0099         # Write out the current line
0100         prevline = thisline
0101     # Write out the last line, without a trailing newline
0102     if prevline is not None:
0103         write(prevline, lineEnd=stripped)
0104 
0105 def encodestring(s, quotetabs = 0, header = 0):
0106     if b2a_qp is not None:
0107         return b2a_qp(s, quotetabs = quotetabs, header = header)
0108     from cStringIO import StringIO
0109     infp = StringIO(s)
0110     outfp = StringIO()
0111     encode(infp, outfp, quotetabs, header)
0112     return outfp.getvalue()
0113 
0114 
0115 
0116 def decode(input, output, header = 0):
0117     """Read 'input', apply quoted-printable decoding, and write to 'output'.
0118     'input' and 'output' are files with readline() and write() methods.
0119     If 'header' is true, decode underscore as space (per RFC 1522)."""
0120 
0121     if a2b_qp is not None:
0122         data = input.read()
0123         odata = a2b_qp(data, header = header)
0124         output.write(odata)
0125         return
0126 
0127     new = ''
0128     while 1:
0129         line = input.readline()
0130         if not line: break
0131         i, n = 0, len(line)
0132         if n > 0 and line[n-1] == '\n':
0133             partial = 0; n = n-1
0134             # Strip trailing whitespace
0135             while n > 0 and line[n-1] in " \t\r":
0136                 n = n-1
0137         else:
0138             partial = 1
0139         while i < n:
0140             c = line[i]
0141             if c == '_' and header:
0142                 new = new + ' '; i = i+1
0143             elif c != ESCAPE:
0144                 new = new + c; i = i+1
0145             elif i+1 == n and not partial:
0146                 partial = 1; break
0147             elif i+1 < n and line[i+1] == ESCAPE:
0148                 new = new + ESCAPE; i = i+2
0149             elif i+2 < n and ishex(line[i+1]) and ishex(line[i+2]):
0150                 new = new + chr(unhex(line[i+1:i+3])); i = i+3
0151             else: # Bad escape sequence -- leave it in
0152                 new = new + c; i = i+1
0153         if not partial:
0154             output.write(new + '\n')
0155             new = ''
0156     if new:
0157         output.write(new)
0158 
0159 def decodestring(s, header = 0):
0160     if a2b_qp is not None:
0161         return a2b_qp(s, header = header)
0162     from cStringIO import StringIO
0163     infp = StringIO(s)
0164     outfp = StringIO()
0165     decode(infp, outfp, header = header)
0166     return outfp.getvalue()
0167 
0168 
0169 
0170 # Other helper functions
0171 def ishex(c):
0172     """Return true if the character 'c' is a hexadecimal digit."""
0173     return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F'
0174 
0175 def unhex(s):
0176     """Get the integer value of a hexadecimal number."""
0177     bits = 0
0178     for c in s:
0179         if '0' <= c <= '9':
0180             i = ord('0')
0181         elif 'a' <= c <= 'f':
0182             i = ord('a')-10
0183         elif 'A' <= c <= 'F':
0184             i = ord('A')-10
0185         else:
0186             break
0187         bits = bits*16 + (ord(c) - i)
0188     return bits
0189 
0190 
0191 
0192 def main():
0193     import sys
0194     import getopt
0195     try:
0196         opts, args = getopt.getopt(sys.argv[1:], 'td')
0197     except getopt.error, msg:
0198         sys.stdout = sys.stderr
0199         print msg
0200         print "usage: quopri [-t | -d] [file] ..."
0201         print "-t: quote tabs"
0202         print "-d: decode; default encode"
0203         sys.exit(2)
0204     deco = 0
0205     tabs = 0
0206     for o, a in opts:
0207         if o == '-t': tabs = 1
0208         if o == '-d': deco = 1
0209     if tabs and deco:
0210         sys.stdout = sys.stderr
0211         print "-t and -d are mutually exclusive"
0212         sys.exit(2)
0213     if not args: args = ['-']
0214     sts = 0
0215     for file in args:
0216         if file == '-':
0217             fp = sys.stdin
0218         else:
0219             try:
0220                 fp = open(file)
0221             except IOError, msg:
0222                 sys.stderr.write("%s: can't open (%s)\n" % (file, msg))
0223                 sts = 1
0224                 continue
0225         if deco:
0226             decode(fp, sys.stdout)
0227         else:
0228             encode(fp, sys.stdout, tabs)
0229         if fp is not sys.stdin:
0230             fp.close()
0231     if sts:
0232         sys.exit(sts)
0233 
0234 
0235 
0236 if __name__ == '__main__':
0237     main()
0238 

Generated by PyXR 0.9.4
SourceForge.net Logo