generator.py (6604B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\email\generator.py 2 __all__ = ['Generator', 'DecodedGenerator'] 3 import re 4 import sys 5 import time 6 import random 7 import warnings 8 from cStringIO import StringIO 9 from email.header import Header 10 UNDERSCORE = '_' 11 NL = '\n' 12 fcre = re.compile('^From ', re.MULTILINE) 13 14 def _is8bitstring(s): 15 if isinstance(s, str): 16 try: 17 unicode(s, 'us-ascii') 18 except UnicodeError: 19 return True 20 21 return False 22 23 24 class Generator(): 25 26 def __init__(self, outfp, mangle_from_ = True, maxheaderlen = 78): 27 self._fp = outfp 28 self._mangle_from_ = mangle_from_ 29 self._maxheaderlen = maxheaderlen 30 31 def write(self, s): 32 self._fp.write(s) 33 34 def flatten(self, msg, unixfrom = False): 35 if unixfrom: 36 ufrom = msg.get_unixfrom() 37 if not ufrom: 38 ufrom = 'From nobody ' + time.ctime(time.time()) 39 print >> self._fp, ufrom 40 self._write(msg) 41 42 def clone(self, fp): 43 return self.__class__(fp, self._mangle_from_, self._maxheaderlen) 44 45 def _write(self, msg): 46 oldfp = self._fp 47 try: 48 self._fp = sfp = StringIO() 49 self._dispatch(msg) 50 finally: 51 self._fp = oldfp 52 53 meth = getattr(msg, '_write_headers', None) 54 if meth is None: 55 self._write_headers(msg) 56 else: 57 meth(self) 58 self._fp.write(sfp.getvalue()) 59 60 def _dispatch(self, msg): 61 main = msg.get_content_maintype() 62 sub = msg.get_content_subtype() 63 specific = UNDERSCORE.join((main, sub)).replace('-', '_') 64 meth = getattr(self, '_handle_' + specific, None) 65 if meth is None: 66 generic = main.replace('-', '_') 67 meth = getattr(self, '_handle_' + generic, None) 68 if meth is None: 69 meth = self._writeBody 70 meth(msg) 71 72 def _write_headers(self, msg): 73 for h, v in msg.items(): 74 print >> self._fp, '%s:' % h, 75 if self._maxheaderlen == 0: 76 print >> self._fp, v 77 elif isinstance(v, Header): 78 print >> self._fp, v.encode() 79 elif _is8bitstring(v): 80 print >> self._fp, v 81 else: 82 print >> self._fp, Header(v, maxlinelen=self._maxheaderlen, header_name=h).encode() 83 84 print >> self._fp 85 86 def _handle_text(self, msg): 87 payload = msg.get_payload() 88 if payload is None: 89 return 90 if not isinstance(payload, basestring): 91 raise TypeError('string payload expected: %s' % type(payload)) 92 if self._mangle_from_: 93 payload = fcre.sub('>From ', payload) 94 self._fp.write(payload) 95 96 _writeBody = _handle_text 97 98 def _handle_multipart(self, msg): 99 msgtexts = [] 100 subparts = msg.get_payload() 101 if subparts is None: 102 subparts = [] 103 else: 104 if isinstance(subparts, basestring): 105 self._fp.write(subparts) 106 return 107 if not isinstance(subparts, list): 108 subparts = [subparts] 109 for part in subparts: 110 s = StringIO() 111 g = self.clone(s) 112 g.flatten(part, unixfrom=False) 113 msgtexts.append(s.getvalue()) 114 115 alltext = NL.join(msgtexts) 116 boundary = msg.get_boundary(failobj=_make_boundary(alltext)) 117 if msg.get_boundary() != boundary: 118 msg.set_boundary(boundary) 119 if msg.preamble is not None: 120 print >> self._fp, msg.preamble 121 print >> self._fp, '--' + boundary 122 if msgtexts: 123 self._fp.write(msgtexts.pop(0)) 124 for body_part in msgtexts: 125 print >> self._fp, '\n--' + boundary 126 self._fp.write(body_part) 127 128 self._fp.write('\n--' + boundary + '--') 129 if msg.epilogue is not None: 130 print >> self._fp 131 self._fp.write(msg.epilogue) 132 133 def _handle_multipart_signed(self, msg): 134 old_maxheaderlen = self._maxheaderlen 135 try: 136 self._maxheaderlen = 0 137 self._handle_multipart(msg) 138 finally: 139 self._maxheaderlen = old_maxheaderlen 140 141 def _handle_message_delivery_status(self, msg): 142 blocks = [] 143 for part in msg.get_payload(): 144 s = StringIO() 145 g = self.clone(s) 146 g.flatten(part, unixfrom=False) 147 text = s.getvalue() 148 lines = text.split('\n') 149 if lines and lines[-1] == '': 150 blocks.append(NL.join(lines[:-1])) 151 else: 152 blocks.append(text) 153 154 self._fp.write(NL.join(blocks)) 155 156 def _handle_message(self, msg): 157 s = StringIO() 158 g = self.clone(s) 159 payload = msg.get_payload() 160 if isinstance(payload, list): 161 g.flatten(msg.get_payload(0), unixfrom=False) 162 payload = s.getvalue() 163 self._fp.write(payload) 164 165 166 _FMT = '[Non-text (%(type)s) part of message omitted, filename %(filename)s]' 167 168 class DecodedGenerator(Generator): 169 170 def __init__(self, outfp, mangle_from_ = True, maxheaderlen = 78, fmt = None): 171 Generator.__init__(self, outfp, mangle_from_, maxheaderlen) 172 if fmt is None: 173 self._fmt = _FMT 174 else: 175 self._fmt = fmt 176 177 def _dispatch(self, msg): 178 for part in msg.walk(): 179 maintype = part.get_content_maintype() 180 if maintype == 'text': 181 print >> self, part.get_payload(decode=True) 182 elif maintype == 'multipart': 183 pass 184 else: 185 print >> self, self._fmt % {'type': part.get_content_type(), 186 'maintype': part.get_content_maintype(), 187 'subtype': part.get_content_subtype(), 188 'filename': part.get_filename('[no filename]'), 189 'description': part.get('Content-Description', '[no description]'), 190 'encoding': part.get('Content-Transfer-Encoding', '[no encoding]')} 191 192 193 _width = len(repr(sys.maxint - 1)) 194 _fmt = '%%0%dd' % _width 195 196 def _make_boundary(text = None): 197 token = random.randrange(sys.maxint) 198 boundary = '===============' + _fmt % token + '==' 199 if text is None: 200 return boundary 201 b = boundary 202 counter = 0 203 while True: 204 cre = re.compile('^--' + re.escape(b) + '(--)?$', re.MULTILINE) 205 if not cre.search(text): 206 break 207 b = boundary + '.' + str(counter) 208 counter += 1 209 210 return b