| 
									
										
										
										
											1997-07-11 18:39:03 +00:00
										 |  |  | #! /usr/bin/env python | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-04 15:28:42 +00:00
										 |  |  | """Conversions to/from quoted-printable transport encoding as per RFC-1521.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | # (Dec 1991 version). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-02-12 02:00:42 +00:00
										 |  |  | __all__ = ["encode","decode"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | ESCAPE = '=' | 
					
						
							|  |  |  | MAXLINESIZE = 76 | 
					
						
							|  |  |  | HEX = '0123456789ABCDEF' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def needsquoting(c, quotetabs): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """Decide whether a particular character needs to be quoted.
 | 
					
						
							| 
									
										
										
										
											2000-02-04 15:28:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     The 'quotetabs' flag indicates whether tabs should be quoted."""
 | 
					
						
							|  |  |  |     if c == '\t': | 
					
						
							|  |  |  |         return not quotetabs | 
					
						
							|  |  |  |     return c == ESCAPE or not(' ' <= c <= '~') | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def quote(c): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """Quote a single character.""" | 
					
						
							|  |  |  |     i = ord(c) | 
					
						
							|  |  |  |     return ESCAPE + HEX[i/16] + HEX[i%16] | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def encode(input, output, quotetabs): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """Read 'input', apply quoted-printable encoding, and write to 'output'.
 | 
					
						
							| 
									
										
										
										
											2000-02-04 15:28:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     'input' and 'output' are files with readline() and write() methods. | 
					
						
							|  |  |  |     The 'quotetabs' flag indicates whether tabs should be quoted. | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     while 1: | 
					
						
							|  |  |  |         line = input.readline() | 
					
						
							|  |  |  |         if not line: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         new = '' | 
					
						
							|  |  |  |         last = line[-1:] | 
					
						
							|  |  |  |         if last == '\n': | 
					
						
							|  |  |  |             line = line[:-1] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             last = '' | 
					
						
							|  |  |  |         prev = '' | 
					
						
							|  |  |  |         for c in line: | 
					
						
							|  |  |  |             if needsquoting(c, quotetabs): | 
					
						
							|  |  |  |                 c = quote(c) | 
					
						
							|  |  |  |             if len(new) + len(c) >= MAXLINESIZE: | 
					
						
							|  |  |  |                 output.write(new + ESCAPE + '\n') | 
					
						
							|  |  |  |                 new = '' | 
					
						
							|  |  |  |             new = new + c | 
					
						
							|  |  |  |             prev = c | 
					
						
							|  |  |  |         if prev in (' ', '\t'): | 
					
						
							|  |  |  |             output.write(new + ESCAPE + '\n\n') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             output.write(new + '\n') | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def decode(input, output): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """Read 'input', apply quoted-printable decoding, and write to 'output'.
 | 
					
						
							| 
									
										
										
										
											2000-02-04 15:28:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     'input' and 'output' are files with readline() and write() methods."""
 | 
					
						
							|  |  |  |     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'): | 
					
						
							|  |  |  |                 n = n-1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             partial = 1 | 
					
						
							|  |  |  |         while i < n: | 
					
						
							|  |  |  |             c = line[i] | 
					
						
							| 
									
										
										
										
											2000-12-12 23:20:45 +00:00
										 |  |  |             if c != ESCAPE: | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |                 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) | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def ishex(c): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """Return true if the character 'c' is a hexadecimal digit.""" | 
					
						
							|  |  |  |     return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F' | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def unhex(s): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     """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 | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def test(): | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											1995-06-14 23:43:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2000-10-05 17:24:33 +00:00
										 |  |  |     test() |