• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Policy framework for the email package.
2
3Allows fine grained feature control of how the package parses and emits data.
4"""
5
6import abc
7from email import header
8from email import charset as _charset
9from email.utils import _has_surrogates
10
11__all__ = [
12    'Policy',
13    'Compat32',
14    'compat32',
15    ]
16
17
18class _PolicyBase:
19
20    """Policy Object basic framework.
21
22    This class is useless unless subclassed.  A subclass should define
23    class attributes with defaults for any values that are to be
24    managed by the Policy object.  The constructor will then allow
25    non-default values to be set for these attributes at instance
26    creation time.  The instance will be callable, taking these same
27    attributes keyword arguments, and returning a new instance
28    identical to the called instance except for those values changed
29    by the keyword arguments.  Instances may be added, yielding new
30    instances with any non-default values from the right hand
31    operand overriding those in the left hand operand.  That is,
32
33        A + B == A(<non-default values of B>)
34
35    The repr of an instance can be used to reconstruct the object
36    if and only if the repr of the values can be used to reconstruct
37    those values.
38
39    """
40
41    def __init__(self, **kw):
42        """Create new Policy, possibly overriding some defaults.
43
44        See class docstring for a list of overridable attributes.
45
46        """
47        for name, value in kw.items():
48            if hasattr(self, name):
49                super(_PolicyBase,self).__setattr__(name, value)
50            else:
51                raise TypeError(
52                    "{!r} is an invalid keyword argument for {}".format(
53                        name, self.__class__.__name__))
54
55    def __repr__(self):
56        args = [ "{}={!r}".format(name, value)
57                 for name, value in self.__dict__.items() ]
58        return "{}({})".format(self.__class__.__name__, ', '.join(args))
59
60    def clone(self, **kw):
61        """Return a new instance with specified attributes changed.
62
63        The new instance has the same attribute values as the current object,
64        except for the changes passed in as keyword arguments.
65
66        """
67        newpolicy = self.__class__.__new__(self.__class__)
68        for attr, value in self.__dict__.items():
69            object.__setattr__(newpolicy, attr, value)
70        for attr, value in kw.items():
71            if not hasattr(self, attr):
72                raise TypeError(
73                    "{!r} is an invalid keyword argument for {}".format(
74                        attr, self.__class__.__name__))
75            object.__setattr__(newpolicy, attr, value)
76        return newpolicy
77
78    def __setattr__(self, name, value):
79        if hasattr(self, name):
80            msg = "{!r} object attribute {!r} is read-only"
81        else:
82            msg = "{!r} object has no attribute {!r}"
83        raise AttributeError(msg.format(self.__class__.__name__, name))
84
85    def __add__(self, other):
86        """Non-default values from right operand override those from left.
87
88        The object returned is a new instance of the subclass.
89
90        """
91        return self.clone(**other.__dict__)
92
93
94def _append_doc(doc, added_doc):
95    doc = doc.rsplit('\n', 1)[0]
96    added_doc = added_doc.split('\n', 1)[1]
97    return doc + '\n' + added_doc
98
99def _extend_docstrings(cls):
100    if cls.__doc__ and cls.__doc__.startswith('+'):
101        cls.__doc__ = _append_doc(cls.__bases__[0].__doc__, cls.__doc__)
102    for name, attr in cls.__dict__.items():
103        if attr.__doc__ and attr.__doc__.startswith('+'):
104            for c in (c for base in cls.__bases__ for c in base.mro()):
105                doc = getattr(getattr(c, name), '__doc__')
106                if doc:
107                    attr.__doc__ = _append_doc(doc, attr.__doc__)
108                    break
109    return cls
110
111
112class Policy(_PolicyBase, metaclass=abc.ABCMeta):
113
114    r"""Controls for how messages are interpreted and formatted.
115
116    Most of the classes and many of the methods in the email package accept
117    Policy objects as parameters.  A Policy object contains a set of values and
118    functions that control how input is interpreted and how output is rendered.
119    For example, the parameter 'raise_on_defect' controls whether or not an RFC
120    violation results in an error being raised or not, while 'max_line_length'
121    controls the maximum length of output lines when a Message is serialized.
122
123    Any valid attribute may be overridden when a Policy is created by passing
124    it as a keyword argument to the constructor.  Policy objects are immutable,
125    but a new Policy object can be created with only certain values changed by
126    calling the Policy instance with keyword arguments.  Policy objects can
127    also be added, producing a new Policy object in which the non-default
128    attributes set in the right hand operand overwrite those specified in the
129    left operand.
130
131    Settable attributes:
132
133    raise_on_defect     -- If true, then defects should be raised as errors.
134                           Default: False.
135
136    linesep             -- string containing the value to use as separation
137                           between output lines.  Default '\n'.
138
139    cte_type            -- Type of allowed content transfer encodings
140
141                           7bit  -- ASCII only
142                           8bit  -- Content-Transfer-Encoding: 8bit is allowed
143
144                           Default: 8bit.  Also controls the disposition of
145                           (RFC invalid) binary data in headers; see the
146                           documentation of the binary_fold method.
147
148    max_line_length     -- maximum length of lines, excluding 'linesep',
149                           during serialization.  None or 0 means no line
150                           wrapping is done.  Default is 78.
151
152    mangle_from_        -- a flag that, when True escapes From_ lines in the
153                           body of the message by putting a `>' in front of
154                           them. This is used when the message is being
155                           serialized by a generator. Default: False.
156
157    message_factory     -- the class to use to create new message objects.
158                           If the value is None, the default is Message.
159
160    verify_generated_headers
161                        -- if true, the generator verifies that each header
162                           they are properly folded, so that a parser won't
163                           treat it as multiple headers, start-of-body, or
164                           part of another header.
165                           This is a check against custom Header & fold()
166                           implementations.
167    """
168
169    raise_on_defect = False
170    linesep = '\n'
171    cte_type = '8bit'
172    max_line_length = 78
173    mangle_from_ = False
174    message_factory = None
175    verify_generated_headers = True
176
177    def handle_defect(self, obj, defect):
178        """Based on policy, either raise defect or call register_defect.
179
180            handle_defect(obj, defect)
181
182        defect should be a Defect subclass, but in any case must be an
183        Exception subclass.  obj is the object on which the defect should be
184        registered if it is not raised.  If the raise_on_defect is True, the
185        defect is raised as an error, otherwise the object and the defect are
186        passed to register_defect.
187
188        This method is intended to be called by parsers that discover defects.
189        The email package parsers always call it with Defect instances.
190
191        """
192        if self.raise_on_defect:
193            raise defect
194        self.register_defect(obj, defect)
195
196    def register_defect(self, obj, defect):
197        """Record 'defect' on 'obj'.
198
199        Called by handle_defect if raise_on_defect is False.  This method is
200        part of the Policy API so that Policy subclasses can implement custom
201        defect handling.  The default implementation calls the append method of
202        the defects attribute of obj.  The objects used by the email package by
203        default that get passed to this method will always have a defects
204        attribute with an append method.
205
206        """
207        obj.defects.append(defect)
208
209    def header_max_count(self, name):
210        """Return the maximum allowed number of headers named 'name'.
211
212        Called when a header is added to a Message object.  If the returned
213        value is not 0 or None, and there are already a number of headers with
214        the name 'name' equal to the value returned, a ValueError is raised.
215
216        Because the default behavior of Message's __setitem__ is to append the
217        value to the list of headers, it is easy to create duplicate headers
218        without realizing it.  This method allows certain headers to be limited
219        in the number of instances of that header that may be added to a
220        Message programmatically.  (The limit is not observed by the parser,
221        which will faithfully produce as many headers as exist in the message
222        being parsed.)
223
224        The default implementation returns None for all header names.
225        """
226        return None
227
228    @abc.abstractmethod
229    def header_source_parse(self, sourcelines):
230        """Given a list of linesep terminated strings constituting the lines of
231        a single header, return the (name, value) tuple that should be stored
232        in the model.  The input lines should retain their terminating linesep
233        characters.  The lines passed in by the email package may contain
234        surrogateescaped binary data.
235        """
236        raise NotImplementedError
237
238    @abc.abstractmethod
239    def header_store_parse(self, name, value):
240        """Given the header name and the value provided by the application
241        program, return the (name, value) that should be stored in the model.
242        """
243        raise NotImplementedError
244
245    @abc.abstractmethod
246    def header_fetch_parse(self, name, value):
247        """Given the header name and the value from the model, return the value
248        to be returned to the application program that is requesting that
249        header.  The value passed in by the email package may contain
250        surrogateescaped binary data if the lines were parsed by a BytesParser.
251        The returned value should not contain any surrogateescaped data.
252
253        """
254        raise NotImplementedError
255
256    @abc.abstractmethod
257    def fold(self, name, value):
258        """Given the header name and the value from the model, return a string
259        containing linesep characters that implement the folding of the header
260        according to the policy controls.  The value passed in by the email
261        package may contain surrogateescaped binary data if the lines were
262        parsed by a BytesParser.  The returned value should not contain any
263        surrogateescaped data.
264
265        """
266        raise NotImplementedError
267
268    @abc.abstractmethod
269    def fold_binary(self, name, value):
270        """Given the header name and the value from the model, return binary
271        data containing linesep characters that implement the folding of the
272        header according to the policy controls.  The value passed in by the
273        email package may contain surrogateescaped binary data.
274
275        """
276        raise NotImplementedError
277
278
279@_extend_docstrings
280class Compat32(Policy):
281
282    """+
283    This particular policy is the backward compatibility Policy.  It
284    replicates the behavior of the email package version 5.1.
285    """
286
287    mangle_from_ = True
288
289    def _sanitize_header(self, name, value):
290        # If the header value contains surrogates, return a Header using
291        # the unknown-8bit charset to encode the bytes as encoded words.
292        if not isinstance(value, str):
293            # Assume it is already a header object
294            return value
295        if _has_surrogates(value):
296            return header.Header(value, charset=_charset.UNKNOWN8BIT,
297                                 header_name=name)
298        else:
299            return value
300
301    def header_source_parse(self, sourcelines):
302        """+
303        The name is parsed as everything up to the ':' and returned unmodified.
304        The value is determined by stripping leading whitespace off the
305        remainder of the first line joined with all subsequent lines, and
306        stripping any trailing carriage return or linefeed characters.
307
308        """
309        name, value = sourcelines[0].split(':', 1)
310        value = ''.join((value, *sourcelines[1:])).lstrip(' \t\r\n')
311        return (name, value.rstrip('\r\n'))
312
313    def header_store_parse(self, name, value):
314        """+
315        The name and value are returned unmodified.
316        """
317        return (name, value)
318
319    def header_fetch_parse(self, name, value):
320        """+
321        If the value contains binary data, it is converted into a Header object
322        using the unknown-8bit charset.  Otherwise it is returned unmodified.
323        """
324        return self._sanitize_header(name, value)
325
326    def fold(self, name, value):
327        """+
328        Headers are folded using the Header folding algorithm, which preserves
329        existing line breaks in the value, and wraps each resulting line to the
330        max_line_length.  Non-ASCII binary data are CTE encoded using the
331        unknown-8bit charset.
332
333        """
334        return self._fold(name, value, sanitize=True)
335
336    def fold_binary(self, name, value):
337        """+
338        Headers are folded using the Header folding algorithm, which preserves
339        existing line breaks in the value, and wraps each resulting line to the
340        max_line_length.  If cte_type is 7bit, non-ascii binary data is CTE
341        encoded using the unknown-8bit charset.  Otherwise the original source
342        header is used, with its existing line breaks and/or binary data.
343
344        """
345        folded = self._fold(name, value, sanitize=self.cte_type=='7bit')
346        return folded.encode('ascii', 'surrogateescape')
347
348    def _fold(self, name, value, sanitize):
349        parts = []
350        parts.append('%s: ' % name)
351        if isinstance(value, str):
352            if _has_surrogates(value):
353                if sanitize:
354                    h = header.Header(value,
355                                      charset=_charset.UNKNOWN8BIT,
356                                      header_name=name)
357                else:
358                    # If we have raw 8bit data in a byte string, we have no idea
359                    # what the encoding is.  There is no safe way to split this
360                    # string.  If it's ascii-subset, then we could do a normal
361                    # ascii split, but if it's multibyte then we could break the
362                    # string.  There's no way to know so the least harm seems to
363                    # be to not split the string and risk it being too long.
364                    parts.append(value)
365                    h = None
366            else:
367                h = header.Header(value, header_name=name)
368        else:
369            # Assume it is a Header-like object.
370            h = value
371        if h is not None:
372            # The Header class interprets a value of None for maxlinelen as the
373            # default value of 78, as recommended by RFC 2822.
374            maxlinelen = 0
375            if self.max_line_length is not None:
376                maxlinelen = self.max_line_length
377            parts.append(h.encode(linesep=self.linesep, maxlinelen=maxlinelen))
378        parts.append(self.linesep)
379        return ''.join(parts)
380
381
382compat32 = Compat32()
383