Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
quopri.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 """Conversions to/from quoted-printable transport encoding as per RFC 1521."""
4 
5 # (Dec 1991 version).
6 
7 __all__ = ["encode", "decode", "encodestring", "decodestring"]
8 
9 ESCAPE = '='
10 MAXLINESIZE = 76
11 HEX = '0123456789ABCDEF'
12 EMPTYSTRING = ''
13 
14 try:
15  from binascii import a2b_qp, b2a_qp
16 except:
17  a2b_qp = None
18  b2a_qp = None
19 
20 
21 def needsquoting(c, quotetabs, header):
22  """Decide whether a particular character needs to be quoted.
23 
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
26  RFC 1521.
27  """
28  if c in ' \t':
29  return quotetabs
30  # if header, we have to escape _ because _ is used to escape space
31  if c == '_':
32  return header
33  return c == ESCAPE or not (' ' <= c <= '~')
34 
35 def quote(c):
36  """Quote a single character."""
37  i = ord(c)
38  return ESCAPE + HEX[i//16] + HEX[i%16]
39 
40 
41 
42 def encode(input, output, quotetabs, header = 0):
43  """Read 'input', apply quoted-printable encoding, and write to 'output'.
44 
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
48  RFC 1521.
49  The 'header' flag indicates whether we are encoding spaces as _ as per
50  RFC 1522.
51  """
52 
53  if b2a_qp is not None:
54  data = input.read()
55  odata = b2a_qp(data, quotetabs = quotetabs, header = header)
56  output.write(odata)
57  return
58 
59  def write(s, output=output, lineEnd='\n'):
60  # RFC 1521 requires that the line ending in a space or tab must have
61  # that trailing character encoded.
62  if s and s[-1:] in ' \t':
63  output.write(s[:-1] + quote(s[-1]) + lineEnd)
64  elif s == '.':
65  output.write(quote(s) + lineEnd)
66  else:
67  output.write(s + lineEnd)
68 
69  prevline = None
70  while 1:
71  line = input.readline()
72  if not line:
73  break
74  outline = []
75  # Strip off any readline induced trailing newline
76  stripped = ''
77  if line[-1:] == '\n':
78  line = line[:-1]
79  stripped = '\n'
80  # Calculate the un-length-limited encoded line
81  for c in line:
82  if needsquoting(c, quotetabs, header):
83  c = quote(c)
84  if header and c == ' ':
85  outline.append('_')
86  else:
87  outline.append(c)
88  # First, write out the previous line
89  if prevline is not None:
90  write(prevline)
91  # Now see if we need any soft line breaks because of RFC-imposed
92  # length limitations. Then do the thisline->prevline dance.
93  thisline = EMPTYSTRING.join(outline)
94  while len(thisline) > MAXLINESIZE:
95  # Don't forget to include the soft line break `=' sign in the
96  # length calculation!
97  write(thisline[:MAXLINESIZE-1], lineEnd='=\n')
98  thisline = thisline[MAXLINESIZE-1:]
99  # Write out the current line
100  prevline = thisline
101  # Write out the last line, without a trailing newline
102  if prevline is not None:
103  write(prevline, lineEnd=stripped)
104 
105 def encodestring(s, quotetabs = 0, header = 0):
106  if b2a_qp is not None:
107  return b2a_qp(s, quotetabs = quotetabs, header = header)
108  from cStringIO import StringIO
109  infp = StringIO(s)
110  outfp = StringIO()
111  encode(infp, outfp, quotetabs, header)
112  return outfp.getvalue()
113 
114 
115 
116 def decode(input, output, header = 0):
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)."""
120 
121  if a2b_qp is not None:
122  data = input.read()
123  odata = a2b_qp(data, header = header)
124  output.write(odata)
125  return
126 
127  new = ''
128  while 1:
129  line = input.readline()
130  if not line: break
131  i, n = 0, len(line)
132  if n > 0 and line[n-1] == '\n':
133  partial = 0; n = n-1
134  # Strip trailing whitespace
135  while n > 0 and line[n-1] in " \t\r":
136  n = n-1
137  else:
138  partial = 1
139  while i < n:
140  c = line[i]
141  if c == '_' and header:
142  new = new + ' '; i = i+1
143  elif c != ESCAPE:
144  new = new + c; i = i+1
145  elif i+1 == n and not partial:
146  partial = 1; break
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
151  else: # Bad escape sequence -- leave it in
152  new = new + c; i = i+1
153  if not partial:
154  output.write(new + '\n')
155  new = ''
156  if new:
157  output.write(new)
158 
159 def decodestring(s, header = 0):
160  if a2b_qp is not None:
161  return a2b_qp(s, header = header)
162  from cStringIO import StringIO
163  infp = StringIO(s)
164  outfp = StringIO()
165  decode(infp, outfp, header = header)
166  return outfp.getvalue()
167 
168 
169 
170 # Other helper functions
171 def ishex(c):
172  """Return true if the character 'c' is a hexadecimal digit."""
173  return '0' <= c <= '9' or 'a' <= c <= 'f' or 'A' <= c <= 'F'
174 
175 def unhex(s):
176  """Get the integer value of a hexadecimal number."""
177  bits = 0
178  for c in s:
179  if '0' <= c <= '9':
180  i = ord('0')
181  elif 'a' <= c <= 'f':
182  i = ord('a')-10
183  elif 'A' <= c <= 'F':
184  i = ord('A')-10
185  else:
186  break
187  bits = bits*16 + (ord(c) - i)
188  return bits
189 
190 
191 
192 def main():
193  import sys
194  import getopt
195  try:
196  opts, args = getopt.getopt(sys.argv[1:], 'td')
197  except getopt.error, msg:
198  sys.stdout = sys.stderr
199  print msg
200  print "usage: quopri [-t | -d] [file] ..."
201  print "-t: quote tabs"
202  print "-d: decode; default encode"
203  sys.exit(2)
204  deco = 0
205  tabs = 0
206  for o, a in opts:
207  if o == '-t': tabs = 1
208  if o == '-d': deco = 1
209  if tabs and deco:
210  sys.stdout = sys.stderr
211  print "-t and -d are mutually exclusive"
212  sys.exit(2)
213  if not args: args = ['-']
214  sts = 0
215  for file in args:
216  if file == '-':
217  fp = sys.stdin
218  else:
219  try:
220  fp = open(file)
221  except IOError, msg:
222  sys.stderr.write("%s: can't open (%s)\n" % (file, msg))
223  sts = 1
224  continue
225  if deco:
226  decode(fp, sys.stdout)
227  else:
228  encode(fp, sys.stdout, tabs)
229  if fp is not sys.stdin:
230  fp.close()
231  if sts:
232  sys.exit(sts)
233 
234 
235 
236 if __name__ == '__main__':
237  main()