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