Apparently the code to forestall Tk eating events was too aggressive (Tk user input...
[python/dscho.git] / Lib / quopri.py
blobe7e4beccda2558d37dafdd0eca88c8f12f1495a6
1 #! /usr/bin/env python
3 """Conversions to/from quoted-printable transport encoding as per RFC-1521."""
5 # (Dec 1991 version).
7 __all__ = ["encode","decode"]
9 ESCAPE = '='
10 MAXLINESIZE = 76
11 HEX = '0123456789ABCDEF'
13 def needsquoting(c, quotetabs):
14 """Decide whether a particular character needs to be quoted.
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 <= '~')
21 def quote(c):
22 """Quote a single character."""
23 i = ord(c)
24 return ESCAPE + HEX[i/16] + HEX[i%16]
26 def encode(input, output, quotetabs):
27 """Read 'input', apply quoted-printable encoding, and write to 'output'.
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')
56 def decode(input, output):
57 """Read 'input', apply quoted-printable decoding, and write to 'output'.
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)
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'
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
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)
151 if __name__ == '__main__':
152 test()