3 """Conversions to/from quoted-printable transport encoding as per RFC 1521."""
7 __all__ = [
"encode",
"decode",
"encodestring",
"decodestring"]
11 HEX =
'0123456789ABCDEF'
15 from binascii
import a2b_qp, b2a_qp
22 """Decide whether a particular character needs to be quoted.
24 The 'quotetabs' flag indicates whether embedded tabs and spaces should be
25 quoted. Note that line-ending tabs and spaces are always encoded, as per
33 return c == ESCAPE
or not (
' ' <= c <=
'~')
36 """Quote a single character."""
38 return ESCAPE + HEX[i//16] + HEX[i%16]
42 def encode(input, output, quotetabs, header = 0):
43 """Read 'input', apply quoted-printable encoding, and write to 'output'.
45 'input' and 'output' are files with readline() and write() methods.
46 The 'quotetabs' flag indicates whether embedded tabs and spaces should be
47 quoted. Note that line-ending tabs and spaces are always encoded, as per
49 The 'header' flag indicates whether we are encoding spaces as _ as per
53 if b2a_qp
is not None:
55 odata =
b2a_qp(data, quotetabs = quotetabs, header = header)
59 def write(s, output=output, lineEnd='\n'):
62 if s
and s[-1:]
in ' \t':
63 output.write(s[:-1] +
quote(s[-1]) + lineEnd)
65 output.write(
quote(s) + lineEnd)
67 output.write(s + lineEnd)
71 line = input.readline()
84 if header
and c ==
' ':
89 if prevline
is not None:
93 thisline = EMPTYSTRING.join(outline)
94 while len(thisline) > MAXLINESIZE:
97 write(thisline[:MAXLINESIZE-1], lineEnd=
'=\n')
98 thisline = thisline[MAXLINESIZE-1:]
102 if prevline
is not None:
103 write(prevline, lineEnd=stripped)
106 if b2a_qp
is not None:
107 return b2a_qp(s, quotetabs = quotetabs, header = header)
108 from cStringIO
import StringIO
111 encode(infp, outfp, quotetabs, header)
112 return outfp.getvalue()
117 """Read 'input', apply quoted-printable decoding, and write to 'output'.
118 'input' and 'output' are files with readline() and write() methods.
119 If 'header' is true, decode underscore as space (per RFC 1522)."""
121 if a2b_qp
is not None:
123 odata =
a2b_qp(data, header = header)
129 line = input.readline()
132 if n > 0
and line[n-1] ==
'\n':
135 while n > 0
and line[n-1]
in " \t\r":
141 if c ==
'_' and header:
142 new = new +
' '; i = i+1
144 new = new + c; i = i+1
145 elif i+1 == n
and not partial:
147 elif i+1 < n
and line[i+1] == ESCAPE:
148 new = new + ESCAPE; i = i+2
149 elif i+2 < n
and ishex(line[i+1])
and ishex(line[i+2]):
150 new = new + chr(
unhex(line[i+1:i+3])); i = i+3
152 new = new + c; i = i+1
154 output.write(new +
'\n')
160 if a2b_qp
is not None:
161 return a2b_qp(s, header = header)
162 from cStringIO
import StringIO
165 decode(infp, outfp, header = header)
166 return outfp.getvalue()
172 """Return true if the character 'c' is a hexadecimal digit."""
173 return '0' <= c <=
'9' or 'a' <= c <=
'f' or 'A' <= c <=
'F'
176 """Get the integer value of a hexadecimal number."""
181 elif 'a' <= c <=
'f':
183 elif 'A' <= c <=
'F':
187 bits = bits*16 + (ord(c) - i)
197 except getopt.error, msg:
198 sys.stdout = sys.stderr
200 print "usage: quopri [-t | -d] [file] ..."
201 print "-t: quote tabs"
202 print "-d: decode; default encode"
207 if o ==
'-t': tabs = 1
208 if o ==
'-d': deco = 1
210 sys.stdout = sys.stderr
211 print "-t and -d are mutually exclusive"
213 if not args: args = [
'-']
222 sys.stderr.write(
"%s: can't open (%s)\n" % (file, msg))
228 encode(fp, sys.stdout, tabs)
229 if fp
is not sys.stdin:
236 if __name__ ==
'__main__':