Edit File by line
/home/barbar84/www/wp-conte.../plugins/sujqvwi/AnonR/anonr.TX.../usr/lib64/python3..../email
File: generator.py
# Copyright (C) 2001-2010 Python Software Foundation
[0] Fix | Delete
# Author: Barry Warsaw
[1] Fix | Delete
# Contact: email-sig@python.org
[2] Fix | Delete
[3] Fix | Delete
"""Classes to generate plain text from a message object tree."""
[4] Fix | Delete
[5] Fix | Delete
__all__ = ['Generator', 'DecodedGenerator', 'BytesGenerator']
[6] Fix | Delete
[7] Fix | Delete
import re
[8] Fix | Delete
import sys
[9] Fix | Delete
import time
[10] Fix | Delete
import random
[11] Fix | Delete
[12] Fix | Delete
from copy import deepcopy
[13] Fix | Delete
from io import StringIO, BytesIO
[14] Fix | Delete
from email.utils import _has_surrogates
[15] Fix | Delete
[16] Fix | Delete
UNDERSCORE = '_'
[17] Fix | Delete
NL = '\n' # XXX: no longer used by the code below.
[18] Fix | Delete
[19] Fix | Delete
NLCRE = re.compile(r'\r\n|\r|\n')
[20] Fix | Delete
fcre = re.compile(r'^From ', re.MULTILINE)
[21] Fix | Delete
[22] Fix | Delete
[23] Fix | Delete
[24] Fix | Delete
class Generator:
[25] Fix | Delete
"""Generates output from a Message object tree.
[26] Fix | Delete
[27] Fix | Delete
This basic generator writes the message to the given file object as plain
[28] Fix | Delete
text.
[29] Fix | Delete
"""
[30] Fix | Delete
#
[31] Fix | Delete
# Public interface
[32] Fix | Delete
#
[33] Fix | Delete
[34] Fix | Delete
def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, *,
[35] Fix | Delete
policy=None):
[36] Fix | Delete
"""Create the generator for message flattening.
[37] Fix | Delete
[38] Fix | Delete
outfp is the output file-like object for writing the message to. It
[39] Fix | Delete
must have a write() method.
[40] Fix | Delete
[41] Fix | Delete
Optional mangle_from_ is a flag that, when True (the default if policy
[42] Fix | Delete
is not set), escapes From_ lines in the body of the message by putting
[43] Fix | Delete
a `>' in front of them.
[44] Fix | Delete
[45] Fix | Delete
Optional maxheaderlen specifies the longest length for a non-continued
[46] Fix | Delete
header. When a header line is longer (in characters, with tabs
[47] Fix | Delete
expanded to 8 spaces) than maxheaderlen, the header will split as
[48] Fix | Delete
defined in the Header class. Set maxheaderlen to zero to disable
[49] Fix | Delete
header wrapping. The default is 78, as recommended (but not required)
[50] Fix | Delete
by RFC 2822.
[51] Fix | Delete
[52] Fix | Delete
The policy keyword specifies a policy object that controls a number of
[53] Fix | Delete
aspects of the generator's operation. If no policy is specified,
[54] Fix | Delete
the policy associated with the Message object passed to the
[55] Fix | Delete
flatten method is used.
[56] Fix | Delete
[57] Fix | Delete
"""
[58] Fix | Delete
[59] Fix | Delete
if mangle_from_ is None:
[60] Fix | Delete
mangle_from_ = True if policy is None else policy.mangle_from_
[61] Fix | Delete
self._fp = outfp
[62] Fix | Delete
self._mangle_from_ = mangle_from_
[63] Fix | Delete
self.maxheaderlen = maxheaderlen
[64] Fix | Delete
self.policy = policy
[65] Fix | Delete
[66] Fix | Delete
def write(self, s):
[67] Fix | Delete
# Just delegate to the file object
[68] Fix | Delete
self._fp.write(s)
[69] Fix | Delete
[70] Fix | Delete
def flatten(self, msg, unixfrom=False, linesep=None):
[71] Fix | Delete
r"""Print the message object tree rooted at msg to the output file
[72] Fix | Delete
specified when the Generator instance was created.
[73] Fix | Delete
[74] Fix | Delete
unixfrom is a flag that forces the printing of a Unix From_ delimiter
[75] Fix | Delete
before the first object in the message tree. If the original message
[76] Fix | Delete
has no From_ delimiter, a `standard' one is crafted. By default, this
[77] Fix | Delete
is False to inhibit the printing of any From_ delimiter.
[78] Fix | Delete
[79] Fix | Delete
Note that for subobjects, no From_ line is printed.
[80] Fix | Delete
[81] Fix | Delete
linesep specifies the characters used to indicate a new line in
[82] Fix | Delete
the output. The default value is determined by the policy specified
[83] Fix | Delete
when the Generator instance was created or, if none was specified,
[84] Fix | Delete
from the policy associated with the msg.
[85] Fix | Delete
[86] Fix | Delete
"""
[87] Fix | Delete
# We use the _XXX constants for operating on data that comes directly
[88] Fix | Delete
# from the msg, and _encoded_XXX constants for operating on data that
[89] Fix | Delete
# has already been converted (to bytes in the BytesGenerator) and
[90] Fix | Delete
# inserted into a temporary buffer.
[91] Fix | Delete
policy = msg.policy if self.policy is None else self.policy
[92] Fix | Delete
if linesep is not None:
[93] Fix | Delete
policy = policy.clone(linesep=linesep)
[94] Fix | Delete
if self.maxheaderlen is not None:
[95] Fix | Delete
policy = policy.clone(max_line_length=self.maxheaderlen)
[96] Fix | Delete
self._NL = policy.linesep
[97] Fix | Delete
self._encoded_NL = self._encode(self._NL)
[98] Fix | Delete
self._EMPTY = ''
[99] Fix | Delete
self._encoded_EMPTY = self._encode(self._EMPTY)
[100] Fix | Delete
# Because we use clone (below) when we recursively process message
[101] Fix | Delete
# subparts, and because clone uses the computed policy (not None),
[102] Fix | Delete
# submessages will automatically get set to the computed policy when
[103] Fix | Delete
# they are processed by this code.
[104] Fix | Delete
old_gen_policy = self.policy
[105] Fix | Delete
old_msg_policy = msg.policy
[106] Fix | Delete
try:
[107] Fix | Delete
self.policy = policy
[108] Fix | Delete
msg.policy = policy
[109] Fix | Delete
if unixfrom:
[110] Fix | Delete
ufrom = msg.get_unixfrom()
[111] Fix | Delete
if not ufrom:
[112] Fix | Delete
ufrom = 'From nobody ' + time.ctime(time.time())
[113] Fix | Delete
self.write(ufrom + self._NL)
[114] Fix | Delete
self._write(msg)
[115] Fix | Delete
finally:
[116] Fix | Delete
self.policy = old_gen_policy
[117] Fix | Delete
msg.policy = old_msg_policy
[118] Fix | Delete
[119] Fix | Delete
def clone(self, fp):
[120] Fix | Delete
"""Clone this generator with the exact same options."""
[121] Fix | Delete
return self.__class__(fp,
[122] Fix | Delete
self._mangle_from_,
[123] Fix | Delete
None, # Use policy setting, which we've adjusted
[124] Fix | Delete
policy=self.policy)
[125] Fix | Delete
[126] Fix | Delete
#
[127] Fix | Delete
# Protected interface - undocumented ;/
[128] Fix | Delete
#
[129] Fix | Delete
[130] Fix | Delete
# Note that we use 'self.write' when what we are writing is coming from
[131] Fix | Delete
# the source, and self._fp.write when what we are writing is coming from a
[132] Fix | Delete
# buffer (because the Bytes subclass has already had a chance to transform
[133] Fix | Delete
# the data in its write method in that case). This is an entirely
[134] Fix | Delete
# pragmatic split determined by experiment; we could be more general by
[135] Fix | Delete
# always using write and having the Bytes subclass write method detect when
[136] Fix | Delete
# it has already transformed the input; but, since this whole thing is a
[137] Fix | Delete
# hack anyway this seems good enough.
[138] Fix | Delete
[139] Fix | Delete
def _new_buffer(self):
[140] Fix | Delete
# BytesGenerator overrides this to return BytesIO.
[141] Fix | Delete
return StringIO()
[142] Fix | Delete
[143] Fix | Delete
def _encode(self, s):
[144] Fix | Delete
# BytesGenerator overrides this to encode strings to bytes.
[145] Fix | Delete
return s
[146] Fix | Delete
[147] Fix | Delete
def _write_lines(self, lines):
[148] Fix | Delete
# We have to transform the line endings.
[149] Fix | Delete
if not lines:
[150] Fix | Delete
return
[151] Fix | Delete
lines = NLCRE.split(lines)
[152] Fix | Delete
for line in lines[:-1]:
[153] Fix | Delete
self.write(line)
[154] Fix | Delete
self.write(self._NL)
[155] Fix | Delete
if lines[-1]:
[156] Fix | Delete
self.write(lines[-1])
[157] Fix | Delete
# XXX logic tells me this else should be needed, but the tests fail
[158] Fix | Delete
# with it and pass without it. (NLCRE.split ends with a blank element
[159] Fix | Delete
# if and only if there was a trailing newline.)
[160] Fix | Delete
#else:
[161] Fix | Delete
# self.write(self._NL)
[162] Fix | Delete
[163] Fix | Delete
def _write(self, msg):
[164] Fix | Delete
# We can't write the headers yet because of the following scenario:
[165] Fix | Delete
# say a multipart message includes the boundary string somewhere in
[166] Fix | Delete
# its body. We'd have to calculate the new boundary /before/ we write
[167] Fix | Delete
# the headers so that we can write the correct Content-Type:
[168] Fix | Delete
# parameter.
[169] Fix | Delete
#
[170] Fix | Delete
# The way we do this, so as to make the _handle_*() methods simpler,
[171] Fix | Delete
# is to cache any subpart writes into a buffer. The we write the
[172] Fix | Delete
# headers and the buffer contents. That way, subpart handlers can
[173] Fix | Delete
# Do The Right Thing, and can still modify the Content-Type: header if
[174] Fix | Delete
# necessary.
[175] Fix | Delete
oldfp = self._fp
[176] Fix | Delete
try:
[177] Fix | Delete
self._munge_cte = None
[178] Fix | Delete
self._fp = sfp = self._new_buffer()
[179] Fix | Delete
self._dispatch(msg)
[180] Fix | Delete
finally:
[181] Fix | Delete
self._fp = oldfp
[182] Fix | Delete
munge_cte = self._munge_cte
[183] Fix | Delete
del self._munge_cte
[184] Fix | Delete
# If we munged the cte, copy the message again and re-fix the CTE.
[185] Fix | Delete
if munge_cte:
[186] Fix | Delete
msg = deepcopy(msg)
[187] Fix | Delete
# Preserve the header order if the CTE header already exists.
[188] Fix | Delete
if msg.get('content-transfer-encoding') is None:
[189] Fix | Delete
msg['Content-Transfer-Encoding'] = munge_cte[0]
[190] Fix | Delete
else:
[191] Fix | Delete
msg.replace_header('content-transfer-encoding', munge_cte[0])
[192] Fix | Delete
msg.replace_header('content-type', munge_cte[1])
[193] Fix | Delete
# Write the headers. First we see if the message object wants to
[194] Fix | Delete
# handle that itself. If not, we'll do it generically.
[195] Fix | Delete
meth = getattr(msg, '_write_headers', None)
[196] Fix | Delete
if meth is None:
[197] Fix | Delete
self._write_headers(msg)
[198] Fix | Delete
else:
[199] Fix | Delete
meth(self)
[200] Fix | Delete
self._fp.write(sfp.getvalue())
[201] Fix | Delete
[202] Fix | Delete
def _dispatch(self, msg):
[203] Fix | Delete
# Get the Content-Type: for the message, then try to dispatch to
[204] Fix | Delete
# self._handle_<maintype>_<subtype>(). If there's no handler for the
[205] Fix | Delete
# full MIME type, then dispatch to self._handle_<maintype>(). If
[206] Fix | Delete
# that's missing too, then dispatch to self._writeBody().
[207] Fix | Delete
main = msg.get_content_maintype()
[208] Fix | Delete
sub = msg.get_content_subtype()
[209] Fix | Delete
specific = UNDERSCORE.join((main, sub)).replace('-', '_')
[210] Fix | Delete
meth = getattr(self, '_handle_' + specific, None)
[211] Fix | Delete
if meth is None:
[212] Fix | Delete
generic = main.replace('-', '_')
[213] Fix | Delete
meth = getattr(self, '_handle_' + generic, None)
[214] Fix | Delete
if meth is None:
[215] Fix | Delete
meth = self._writeBody
[216] Fix | Delete
meth(msg)
[217] Fix | Delete
[218] Fix | Delete
#
[219] Fix | Delete
# Default handlers
[220] Fix | Delete
#
[221] Fix | Delete
[222] Fix | Delete
def _write_headers(self, msg):
[223] Fix | Delete
for h, v in msg.raw_items():
[224] Fix | Delete
self.write(self.policy.fold(h, v))
[225] Fix | Delete
# A blank line always separates headers from body
[226] Fix | Delete
self.write(self._NL)
[227] Fix | Delete
[228] Fix | Delete
#
[229] Fix | Delete
# Handlers for writing types and subtypes
[230] Fix | Delete
#
[231] Fix | Delete
[232] Fix | Delete
def _handle_text(self, msg):
[233] Fix | Delete
payload = msg.get_payload()
[234] Fix | Delete
if payload is None:
[235] Fix | Delete
return
[236] Fix | Delete
if not isinstance(payload, str):
[237] Fix | Delete
raise TypeError('string payload expected: %s' % type(payload))
[238] Fix | Delete
if _has_surrogates(msg._payload):
[239] Fix | Delete
charset = msg.get_param('charset')
[240] Fix | Delete
if charset is not None:
[241] Fix | Delete
# XXX: This copy stuff is an ugly hack to avoid modifying the
[242] Fix | Delete
# existing message.
[243] Fix | Delete
msg = deepcopy(msg)
[244] Fix | Delete
del msg['content-transfer-encoding']
[245] Fix | Delete
msg.set_payload(payload, charset)
[246] Fix | Delete
payload = msg.get_payload()
[247] Fix | Delete
self._munge_cte = (msg['content-transfer-encoding'],
[248] Fix | Delete
msg['content-type'])
[249] Fix | Delete
if self._mangle_from_:
[250] Fix | Delete
payload = fcre.sub('>From ', payload)
[251] Fix | Delete
self._write_lines(payload)
[252] Fix | Delete
[253] Fix | Delete
# Default body handler
[254] Fix | Delete
_writeBody = _handle_text
[255] Fix | Delete
[256] Fix | Delete
def _handle_multipart(self, msg):
[257] Fix | Delete
# The trick here is to write out each part separately, merge them all
[258] Fix | Delete
# together, and then make sure that the boundary we've chosen isn't
[259] Fix | Delete
# present in the payload.
[260] Fix | Delete
msgtexts = []
[261] Fix | Delete
subparts = msg.get_payload()
[262] Fix | Delete
if subparts is None:
[263] Fix | Delete
subparts = []
[264] Fix | Delete
elif isinstance(subparts, str):
[265] Fix | Delete
# e.g. a non-strict parse of a message with no starting boundary.
[266] Fix | Delete
self.write(subparts)
[267] Fix | Delete
return
[268] Fix | Delete
elif not isinstance(subparts, list):
[269] Fix | Delete
# Scalar payload
[270] Fix | Delete
subparts = [subparts]
[271] Fix | Delete
for part in subparts:
[272] Fix | Delete
s = self._new_buffer()
[273] Fix | Delete
g = self.clone(s)
[274] Fix | Delete
g.flatten(part, unixfrom=False, linesep=self._NL)
[275] Fix | Delete
msgtexts.append(s.getvalue())
[276] Fix | Delete
# BAW: What about boundaries that are wrapped in double-quotes?
[277] Fix | Delete
boundary = msg.get_boundary()
[278] Fix | Delete
if not boundary:
[279] Fix | Delete
# Create a boundary that doesn't appear in any of the
[280] Fix | Delete
# message texts.
[281] Fix | Delete
alltext = self._encoded_NL.join(msgtexts)
[282] Fix | Delete
boundary = self._make_boundary(alltext)
[283] Fix | Delete
msg.set_boundary(boundary)
[284] Fix | Delete
# If there's a preamble, write it out, with a trailing CRLF
[285] Fix | Delete
if msg.preamble is not None:
[286] Fix | Delete
if self._mangle_from_:
[287] Fix | Delete
preamble = fcre.sub('>From ', msg.preamble)
[288] Fix | Delete
else:
[289] Fix | Delete
preamble = msg.preamble
[290] Fix | Delete
self._write_lines(preamble)
[291] Fix | Delete
self.write(self._NL)
[292] Fix | Delete
# dash-boundary transport-padding CRLF
[293] Fix | Delete
self.write('--' + boundary + self._NL)
[294] Fix | Delete
# body-part
[295] Fix | Delete
if msgtexts:
[296] Fix | Delete
self._fp.write(msgtexts.pop(0))
[297] Fix | Delete
# *encapsulation
[298] Fix | Delete
# --> delimiter transport-padding
[299] Fix | Delete
# --> CRLF body-part
[300] Fix | Delete
for body_part in msgtexts:
[301] Fix | Delete
# delimiter transport-padding CRLF
[302] Fix | Delete
self.write(self._NL + '--' + boundary + self._NL)
[303] Fix | Delete
# body-part
[304] Fix | Delete
self._fp.write(body_part)
[305] Fix | Delete
# close-delimiter transport-padding
[306] Fix | Delete
self.write(self._NL + '--' + boundary + '--' + self._NL)
[307] Fix | Delete
if msg.epilogue is not None:
[308] Fix | Delete
if self._mangle_from_:
[309] Fix | Delete
epilogue = fcre.sub('>From ', msg.epilogue)
[310] Fix | Delete
else:
[311] Fix | Delete
epilogue = msg.epilogue
[312] Fix | Delete
self._write_lines(epilogue)
[313] Fix | Delete
[314] Fix | Delete
def _handle_multipart_signed(self, msg):
[315] Fix | Delete
# The contents of signed parts has to stay unmodified in order to keep
[316] Fix | Delete
# the signature intact per RFC1847 2.1, so we disable header wrapping.
[317] Fix | Delete
# RDM: This isn't enough to completely preserve the part, but it helps.
[318] Fix | Delete
p = self.policy
[319] Fix | Delete
self.policy = p.clone(max_line_length=0)
[320] Fix | Delete
try:
[321] Fix | Delete
self._handle_multipart(msg)
[322] Fix | Delete
finally:
[323] Fix | Delete
self.policy = p
[324] Fix | Delete
[325] Fix | Delete
def _handle_message_delivery_status(self, msg):
[326] Fix | Delete
# We can't just write the headers directly to self's file object
[327] Fix | Delete
# because this will leave an extra newline between the last header
[328] Fix | Delete
# block and the boundary. Sigh.
[329] Fix | Delete
blocks = []
[330] Fix | Delete
for part in msg.get_payload():
[331] Fix | Delete
s = self._new_buffer()
[332] Fix | Delete
g = self.clone(s)
[333] Fix | Delete
g.flatten(part, unixfrom=False, linesep=self._NL)
[334] Fix | Delete
text = s.getvalue()
[335] Fix | Delete
lines = text.split(self._encoded_NL)
[336] Fix | Delete
# Strip off the unnecessary trailing empty line
[337] Fix | Delete
if lines and lines[-1] == self._encoded_EMPTY:
[338] Fix | Delete
blocks.append(self._encoded_NL.join(lines[:-1]))
[339] Fix | Delete
else:
[340] Fix | Delete
blocks.append(text)
[341] Fix | Delete
# Now join all the blocks with an empty line. This has the lovely
[342] Fix | Delete
# effect of separating each block with an empty line, but not adding
[343] Fix | Delete
# an extra one after the last one.
[344] Fix | Delete
self._fp.write(self._encoded_NL.join(blocks))
[345] Fix | Delete
[346] Fix | Delete
def _handle_message(self, msg):
[347] Fix | Delete
s = self._new_buffer()
[348] Fix | Delete
g = self.clone(s)
[349] Fix | Delete
# The payload of a message/rfc822 part should be a multipart sequence
[350] Fix | Delete
# of length 1. The zeroth element of the list should be the Message
[351] Fix | Delete
# object for the subpart. Extract that object, stringify it, and
[352] Fix | Delete
# write it out.
[353] Fix | Delete
# Except, it turns out, when it's a string instead, which happens when
[354] Fix | Delete
# and only when HeaderParser is used on a message of mime type
[355] Fix | Delete
# message/rfc822. Such messages are generated by, for example,
[356] Fix | Delete
# Groupwise when forwarding unadorned messages. (Issue 7970.) So
[357] Fix | Delete
# in that case we just emit the string body.
[358] Fix | Delete
payload = msg._payload
[359] Fix | Delete
if isinstance(payload, list):
[360] Fix | Delete
g.flatten(msg.get_payload(0), unixfrom=False, linesep=self._NL)
[361] Fix | Delete
payload = s.getvalue()
[362] Fix | Delete
else:
[363] Fix | Delete
payload = self._encode(payload)
[364] Fix | Delete
self._fp.write(payload)
[365] Fix | Delete
[366] Fix | Delete
# This used to be a module level function; we use a classmethod for this
[367] Fix | Delete
# and _compile_re so we can continue to provide the module level function
[368] Fix | Delete
# for backward compatibility by doing
[369] Fix | Delete
# _make_boundary = Generator._make_boundary
[370] Fix | Delete
# at the end of the module. It *is* internal, so we could drop that...
[371] Fix | Delete
@classmethod
[372] Fix | Delete
def _make_boundary(cls, text=None):
[373] Fix | Delete
# Craft a random boundary. If text is given, ensure that the chosen
[374] Fix | Delete
# boundary doesn't appear in the text.
[375] Fix | Delete
token = random.randrange(sys.maxsize)
[376] Fix | Delete
boundary = ('=' * 15) + (_fmt % token) + '=='
[377] Fix | Delete
if text is None:
[378] Fix | Delete
return boundary
[379] Fix | Delete
b = boundary
[380] Fix | Delete
counter = 0
[381] Fix | Delete
while True:
[382] Fix | Delete
cre = cls._compile_re('^--' + re.escape(b) + '(--)?$', re.MULTILINE)
[383] Fix | Delete
if not cre.search(text):
[384] Fix | Delete
break
[385] Fix | Delete
b = boundary + '.' + str(counter)
[386] Fix | Delete
counter += 1
[387] Fix | Delete
return b
[388] Fix | Delete
[389] Fix | Delete
@classmethod
[390] Fix | Delete
def _compile_re(cls, s, flags):
[391] Fix | Delete
return re.compile(s, flags)
[392] Fix | Delete
[393] Fix | Delete
[394] Fix | Delete
class BytesGenerator(Generator):
[395] Fix | Delete
"""Generates a bytes version of a Message object tree.
[396] Fix | Delete
[397] Fix | Delete
Functionally identical to the base Generator except that the output is
[398] Fix | Delete
bytes and not string. When surrogates were used in the input to encode
[399] Fix | Delete
bytes, these are decoded back to bytes for output. If the policy has
[400] Fix | Delete
cte_type set to 7bit, then the message is transformed such that the
[401] Fix | Delete
non-ASCII bytes are properly content transfer encoded, using the charset
[402] Fix | Delete
unknown-8bit.
[403] Fix | Delete
[404] Fix | Delete
The outfp object must accept bytes in its write method.
[405] Fix | Delete
"""
[406] Fix | Delete
[407] Fix | Delete
def write(self, s):
[408] Fix | Delete
self._fp.write(s.encode('ascii', 'surrogateescape'))
[409] Fix | Delete
[410] Fix | Delete
def _new_buffer(self):
[411] Fix | Delete
return BytesIO()
[412] Fix | Delete
[413] Fix | Delete
def _encode(self, s):
[414] Fix | Delete
return s.encode('ascii')
[415] Fix | Delete
[416] Fix | Delete
def _write_headers(self, msg):
[417] Fix | Delete
# This is almost the same as the string version, except for handling
[418] Fix | Delete
# strings with 8bit bytes.
[419] Fix | Delete
for h, v in msg.raw_items():
[420] Fix | Delete
self._fp.write(self.policy.fold_binary(h, v))
[421] Fix | Delete
# A blank line always separates headers from body
[422] Fix | Delete
self.write(self._NL)
[423] Fix | Delete
[424] Fix | Delete
def _handle_text(self, msg):
[425] Fix | Delete
# If the string has surrogates the original source was bytes, so
[426] Fix | Delete
# just write it back out.
[427] Fix | Delete
if msg._payload is None:
[428] Fix | Delete
return
[429] Fix | Delete
if _has_surrogates(msg._payload) and not self.policy.cte_type=='7bit':
[430] Fix | Delete
if self._mangle_from_:
[431] Fix | Delete
msg._payload = fcre.sub(">From ", msg._payload)
[432] Fix | Delete
self._write_lines(msg._payload)
[433] Fix | Delete
else:
[434] Fix | Delete
super(BytesGenerator,self)._handle_text(msg)
[435] Fix | Delete
[436] Fix | Delete
# Default body handler
[437] Fix | Delete
_writeBody = _handle_text
[438] Fix | Delete
[439] Fix | Delete
@classmethod
[440] Fix | Delete
def _compile_re(cls, s, flags):
[441] Fix | Delete
return re.compile(s.encode('ascii'), flags)
[442] Fix | Delete
[443] Fix | Delete
[444] Fix | Delete
[445] Fix | Delete
_FMT = '[Non-text (%(type)s) part of message omitted, filename %(filename)s]'
[446] Fix | Delete
[447] Fix | Delete
class DecodedGenerator(Generator):
[448] Fix | Delete
"""Generates a text representation of a message.
[449] Fix | Delete
[450] Fix | Delete
Like the Generator base class, except that non-text parts are substituted
[451] Fix | Delete
with a format string representing the part.
[452] Fix | Delete
"""
[453] Fix | Delete
def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, fmt=None, *,
[454] Fix | Delete
policy=None):
[455] Fix | Delete
"""Like Generator.__init__() except that an additional optional
[456] Fix | Delete
argument is allowed.
[457] Fix | Delete
[458] Fix | Delete
Walks through all subparts of a message. If the subpart is of main
[459] Fix | Delete
type `text', then it prints the decoded payload of the subpart.
[460] Fix | Delete
[461] Fix | Delete
Otherwise, fmt is a format string that is used instead of the message
[462] Fix | Delete
payload. fmt is expanded with the following keywords (in
[463] Fix | Delete
%(keyword)s format):
[464] Fix | Delete
[465] Fix | Delete
type : Full MIME type of the non-text part
[466] Fix | Delete
maintype : Main MIME type of the non-text part
[467] Fix | Delete
subtype : Sub-MIME type of the non-text part
[468] Fix | Delete
filename : Filename of the non-text part
[469] Fix | Delete
description: Description associated with the non-text part
[470] Fix | Delete
encoding : Content transfer encoding of the non-text part
[471] Fix | Delete
[472] Fix | Delete
The default value for fmt is None, meaning
[473] Fix | Delete
[474] Fix | Delete
[Non-text (%(type)s) part of message omitted, filename %(filename)s]
[475] Fix | Delete
"""
[476] Fix | Delete
Generator.__init__(self, outfp, mangle_from_, maxheaderlen,
[477] Fix | Delete
policy=policy)
[478] Fix | Delete
if fmt is None:
[479] Fix | Delete
self._fmt = _FMT
[480] Fix | Delete
else:
[481] Fix | Delete
self._fmt = fmt
[482] Fix | Delete
[483] Fix | Delete
def _dispatch(self, msg):
[484] Fix | Delete
for part in msg.walk():
[485] Fix | Delete
maintype = part.get_content_maintype()
[486] Fix | Delete
if maintype == 'text':
[487] Fix | Delete
print(part.get_payload(decode=False), file=self)
[488] Fix | Delete
elif maintype == 'multipart':
[489] Fix | Delete
# Just skip this
[490] Fix | Delete
pass
[491] Fix | Delete
else:
[492] Fix | Delete
print(self._fmt % {
[493] Fix | Delete
'type' : part.get_content_type(),
[494] Fix | Delete
'maintype' : part.get_content_maintype(),
[495] Fix | Delete
'subtype' : part.get_content_subtype(),
[496] Fix | Delete
'filename' : part.get_filename('[no filename]'),
[497] Fix | Delete
'description': part.get('Content-Description',
[498] Fix | Delete
'[no description]'),
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function