xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/email/headerregistry.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Representing and manipulating email headers via custom objects.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerThis module provides an implementation of the HeaderRegistry API.
4*cda5da8dSAndroid Build Coastguard WorkerThe implementation is designed to flexibly follow RFC5322 rules.
5*cda5da8dSAndroid Build Coastguard Worker"""
6*cda5da8dSAndroid Build Coastguard Workerfrom types import MappingProxyType
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Workerfrom email import utils
9*cda5da8dSAndroid Build Coastguard Workerfrom email import errors
10*cda5da8dSAndroid Build Coastguard Workerfrom email import _header_value_parser as parser
11*cda5da8dSAndroid Build Coastguard Worker
12*cda5da8dSAndroid Build Coastguard Workerclass Address:
13*cda5da8dSAndroid Build Coastguard Worker
14*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, display_name='', username='', domain='', addr_spec=None):
15*cda5da8dSAndroid Build Coastguard Worker        """Create an object representing a full email address.
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker        An address can have a 'display_name', a 'username', and a 'domain'.  In
18*cda5da8dSAndroid Build Coastguard Worker        addition to specifying the username and domain separately, they may be
19*cda5da8dSAndroid Build Coastguard Worker        specified together by using the addr_spec keyword *instead of* the
20*cda5da8dSAndroid Build Coastguard Worker        username and domain keywords.  If an addr_spec string is specified it
21*cda5da8dSAndroid Build Coastguard Worker        must be properly quoted according to RFC 5322 rules; an error will be
22*cda5da8dSAndroid Build Coastguard Worker        raised if it is not.
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Worker        An Address object has display_name, username, domain, and addr_spec
25*cda5da8dSAndroid Build Coastguard Worker        attributes, all of which are read-only.  The addr_spec and the string
26*cda5da8dSAndroid Build Coastguard Worker        value of the object are both quoted according to RFC5322 rules, but
27*cda5da8dSAndroid Build Coastguard Worker        without any Content Transfer Encoding.
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker        """
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker        inputs = ''.join(filter(None, (display_name, username, domain, addr_spec)))
32*cda5da8dSAndroid Build Coastguard Worker        if '\r' in inputs or '\n' in inputs:
33*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("invalid arguments; address parts cannot contain CR or LF")
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker        # This clause with its potential 'raise' may only happen when an
36*cda5da8dSAndroid Build Coastguard Worker        # application program creates an Address object using an addr_spec
37*cda5da8dSAndroid Build Coastguard Worker        # keyword.  The email library code itself must always supply username
38*cda5da8dSAndroid Build Coastguard Worker        # and domain.
39*cda5da8dSAndroid Build Coastguard Worker        if addr_spec is not None:
40*cda5da8dSAndroid Build Coastguard Worker            if username or domain:
41*cda5da8dSAndroid Build Coastguard Worker                raise TypeError("addrspec specified when username and/or "
42*cda5da8dSAndroid Build Coastguard Worker                                "domain also specified")
43*cda5da8dSAndroid Build Coastguard Worker            a_s, rest = parser.get_addr_spec(addr_spec)
44*cda5da8dSAndroid Build Coastguard Worker            if rest:
45*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("Invalid addr_spec; only '{}' "
46*cda5da8dSAndroid Build Coastguard Worker                                 "could be parsed from '{}'".format(
47*cda5da8dSAndroid Build Coastguard Worker                                    a_s, addr_spec))
48*cda5da8dSAndroid Build Coastguard Worker            if a_s.all_defects:
49*cda5da8dSAndroid Build Coastguard Worker                raise a_s.all_defects[0]
50*cda5da8dSAndroid Build Coastguard Worker            username = a_s.local_part
51*cda5da8dSAndroid Build Coastguard Worker            domain = a_s.domain
52*cda5da8dSAndroid Build Coastguard Worker        self._display_name = display_name
53*cda5da8dSAndroid Build Coastguard Worker        self._username = username
54*cda5da8dSAndroid Build Coastguard Worker        self._domain = domain
55*cda5da8dSAndroid Build Coastguard Worker
56*cda5da8dSAndroid Build Coastguard Worker    @property
57*cda5da8dSAndroid Build Coastguard Worker    def display_name(self):
58*cda5da8dSAndroid Build Coastguard Worker        return self._display_name
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Worker    @property
61*cda5da8dSAndroid Build Coastguard Worker    def username(self):
62*cda5da8dSAndroid Build Coastguard Worker        return self._username
63*cda5da8dSAndroid Build Coastguard Worker
64*cda5da8dSAndroid Build Coastguard Worker    @property
65*cda5da8dSAndroid Build Coastguard Worker    def domain(self):
66*cda5da8dSAndroid Build Coastguard Worker        return self._domain
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker    @property
69*cda5da8dSAndroid Build Coastguard Worker    def addr_spec(self):
70*cda5da8dSAndroid Build Coastguard Worker        """The addr_spec (username@domain) portion of the address, quoted
71*cda5da8dSAndroid Build Coastguard Worker        according to RFC 5322 rules, but with no Content Transfer Encoding.
72*cda5da8dSAndroid Build Coastguard Worker        """
73*cda5da8dSAndroid Build Coastguard Worker        lp = self.username
74*cda5da8dSAndroid Build Coastguard Worker        if not parser.DOT_ATOM_ENDS.isdisjoint(lp):
75*cda5da8dSAndroid Build Coastguard Worker            lp = parser.quote_string(lp)
76*cda5da8dSAndroid Build Coastguard Worker        if self.domain:
77*cda5da8dSAndroid Build Coastguard Worker            return lp + '@' + self.domain
78*cda5da8dSAndroid Build Coastguard Worker        if not lp:
79*cda5da8dSAndroid Build Coastguard Worker            return '<>'
80*cda5da8dSAndroid Build Coastguard Worker        return lp
81*cda5da8dSAndroid Build Coastguard Worker
82*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
83*cda5da8dSAndroid Build Coastguard Worker        return "{}(display_name={!r}, username={!r}, domain={!r})".format(
84*cda5da8dSAndroid Build Coastguard Worker                        self.__class__.__name__,
85*cda5da8dSAndroid Build Coastguard Worker                        self.display_name, self.username, self.domain)
86*cda5da8dSAndroid Build Coastguard Worker
87*cda5da8dSAndroid Build Coastguard Worker    def __str__(self):
88*cda5da8dSAndroid Build Coastguard Worker        disp = self.display_name
89*cda5da8dSAndroid Build Coastguard Worker        if not parser.SPECIALS.isdisjoint(disp):
90*cda5da8dSAndroid Build Coastguard Worker            disp = parser.quote_string(disp)
91*cda5da8dSAndroid Build Coastguard Worker        if disp:
92*cda5da8dSAndroid Build Coastguard Worker            addr_spec = '' if self.addr_spec=='<>' else self.addr_spec
93*cda5da8dSAndroid Build Coastguard Worker            return "{} <{}>".format(disp, addr_spec)
94*cda5da8dSAndroid Build Coastguard Worker        return self.addr_spec
95*cda5da8dSAndroid Build Coastguard Worker
96*cda5da8dSAndroid Build Coastguard Worker    def __eq__(self, other):
97*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(other, Address):
98*cda5da8dSAndroid Build Coastguard Worker            return NotImplemented
99*cda5da8dSAndroid Build Coastguard Worker        return (self.display_name == other.display_name and
100*cda5da8dSAndroid Build Coastguard Worker                self.username == other.username and
101*cda5da8dSAndroid Build Coastguard Worker                self.domain == other.domain)
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Worker
104*cda5da8dSAndroid Build Coastguard Workerclass Group:
105*cda5da8dSAndroid Build Coastguard Worker
106*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, display_name=None, addresses=None):
107*cda5da8dSAndroid Build Coastguard Worker        """Create an object representing an address group.
108*cda5da8dSAndroid Build Coastguard Worker
109*cda5da8dSAndroid Build Coastguard Worker        An address group consists of a display_name followed by colon and a
110*cda5da8dSAndroid Build Coastguard Worker        list of addresses (see Address) terminated by a semi-colon.  The Group
111*cda5da8dSAndroid Build Coastguard Worker        is created by specifying a display_name and a possibly empty list of
112*cda5da8dSAndroid Build Coastguard Worker        Address objects.  A Group can also be used to represent a single
113*cda5da8dSAndroid Build Coastguard Worker        address that is not in a group, which is convenient when manipulating
114*cda5da8dSAndroid Build Coastguard Worker        lists that are a combination of Groups and individual Addresses.  In
115*cda5da8dSAndroid Build Coastguard Worker        this case the display_name should be set to None.  In particular, the
116*cda5da8dSAndroid Build Coastguard Worker        string representation of a Group whose display_name is None is the same
117*cda5da8dSAndroid Build Coastguard Worker        as the Address object, if there is one and only one Address object in
118*cda5da8dSAndroid Build Coastguard Worker        the addresses list.
119*cda5da8dSAndroid Build Coastguard Worker
120*cda5da8dSAndroid Build Coastguard Worker        """
121*cda5da8dSAndroid Build Coastguard Worker        self._display_name = display_name
122*cda5da8dSAndroid Build Coastguard Worker        self._addresses = tuple(addresses) if addresses else tuple()
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker    @property
125*cda5da8dSAndroid Build Coastguard Worker    def display_name(self):
126*cda5da8dSAndroid Build Coastguard Worker        return self._display_name
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker    @property
129*cda5da8dSAndroid Build Coastguard Worker    def addresses(self):
130*cda5da8dSAndroid Build Coastguard Worker        return self._addresses
131*cda5da8dSAndroid Build Coastguard Worker
132*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
133*cda5da8dSAndroid Build Coastguard Worker        return "{}(display_name={!r}, addresses={!r}".format(
134*cda5da8dSAndroid Build Coastguard Worker                 self.__class__.__name__,
135*cda5da8dSAndroid Build Coastguard Worker                 self.display_name, self.addresses)
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker    def __str__(self):
138*cda5da8dSAndroid Build Coastguard Worker        if self.display_name is None and len(self.addresses)==1:
139*cda5da8dSAndroid Build Coastguard Worker            return str(self.addresses[0])
140*cda5da8dSAndroid Build Coastguard Worker        disp = self.display_name
141*cda5da8dSAndroid Build Coastguard Worker        if disp is not None and not parser.SPECIALS.isdisjoint(disp):
142*cda5da8dSAndroid Build Coastguard Worker            disp = parser.quote_string(disp)
143*cda5da8dSAndroid Build Coastguard Worker        adrstr = ", ".join(str(x) for x in self.addresses)
144*cda5da8dSAndroid Build Coastguard Worker        adrstr = ' ' + adrstr if adrstr else adrstr
145*cda5da8dSAndroid Build Coastguard Worker        return "{}:{};".format(disp, adrstr)
146*cda5da8dSAndroid Build Coastguard Worker
147*cda5da8dSAndroid Build Coastguard Worker    def __eq__(self, other):
148*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(other, Group):
149*cda5da8dSAndroid Build Coastguard Worker            return NotImplemented
150*cda5da8dSAndroid Build Coastguard Worker        return (self.display_name == other.display_name and
151*cda5da8dSAndroid Build Coastguard Worker                self.addresses == other.addresses)
152*cda5da8dSAndroid Build Coastguard Worker
153*cda5da8dSAndroid Build Coastguard Worker
154*cda5da8dSAndroid Build Coastguard Worker# Header Classes #
155*cda5da8dSAndroid Build Coastguard Worker
156*cda5da8dSAndroid Build Coastguard Workerclass BaseHeader(str):
157*cda5da8dSAndroid Build Coastguard Worker
158*cda5da8dSAndroid Build Coastguard Worker    """Base class for message headers.
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker    Implements generic behavior and provides tools for subclasses.
161*cda5da8dSAndroid Build Coastguard Worker
162*cda5da8dSAndroid Build Coastguard Worker    A subclass must define a classmethod named 'parse' that takes an unfolded
163*cda5da8dSAndroid Build Coastguard Worker    value string and a dictionary as its arguments.  The dictionary will
164*cda5da8dSAndroid Build Coastguard Worker    contain one key, 'defects', initialized to an empty list.  After the call
165*cda5da8dSAndroid Build Coastguard Worker    the dictionary must contain two additional keys: parse_tree, set to the
166*cda5da8dSAndroid Build Coastguard Worker    parse tree obtained from parsing the header, and 'decoded', set to the
167*cda5da8dSAndroid Build Coastguard Worker    string value of the idealized representation of the data from the value.
168*cda5da8dSAndroid Build Coastguard Worker    (That is, encoded words are decoded, and values that have canonical
169*cda5da8dSAndroid Build Coastguard Worker    representations are so represented.)
170*cda5da8dSAndroid Build Coastguard Worker
171*cda5da8dSAndroid Build Coastguard Worker    The defects key is intended to collect parsing defects, which the message
172*cda5da8dSAndroid Build Coastguard Worker    parser will subsequently dispose of as appropriate.  The parser should not,
173*cda5da8dSAndroid Build Coastguard Worker    insofar as practical, raise any errors.  Defects should be added to the
174*cda5da8dSAndroid Build Coastguard Worker    list instead.  The standard header parsers register defects for RFC
175*cda5da8dSAndroid Build Coastguard Worker    compliance issues, for obsolete RFC syntax, and for unrecoverable parsing
176*cda5da8dSAndroid Build Coastguard Worker    errors.
177*cda5da8dSAndroid Build Coastguard Worker
178*cda5da8dSAndroid Build Coastguard Worker    The parse method may add additional keys to the dictionary.  In this case
179*cda5da8dSAndroid Build Coastguard Worker    the subclass must define an 'init' method, which will be passed the
180*cda5da8dSAndroid Build Coastguard Worker    dictionary as its keyword arguments.  The method should use (usually by
181*cda5da8dSAndroid Build Coastguard Worker    setting them as the value of similarly named attributes) and remove all the
182*cda5da8dSAndroid Build Coastguard Worker    extra keys added by its parse method, and then use super to call its parent
183*cda5da8dSAndroid Build Coastguard Worker    class with the remaining arguments and keywords.
184*cda5da8dSAndroid Build Coastguard Worker
185*cda5da8dSAndroid Build Coastguard Worker    The subclass should also make sure that a 'max_count' attribute is defined
186*cda5da8dSAndroid Build Coastguard Worker    that is either None or 1. XXX: need to better define this API.
187*cda5da8dSAndroid Build Coastguard Worker
188*cda5da8dSAndroid Build Coastguard Worker    """
189*cda5da8dSAndroid Build Coastguard Worker
190*cda5da8dSAndroid Build Coastguard Worker    def __new__(cls, name, value):
191*cda5da8dSAndroid Build Coastguard Worker        kwds = {'defects': []}
192*cda5da8dSAndroid Build Coastguard Worker        cls.parse(value, kwds)
193*cda5da8dSAndroid Build Coastguard Worker        if utils._has_surrogates(kwds['decoded']):
194*cda5da8dSAndroid Build Coastguard Worker            kwds['decoded'] = utils._sanitize(kwds['decoded'])
195*cda5da8dSAndroid Build Coastguard Worker        self = str.__new__(cls, kwds['decoded'])
196*cda5da8dSAndroid Build Coastguard Worker        del kwds['decoded']
197*cda5da8dSAndroid Build Coastguard Worker        self.init(name, **kwds)
198*cda5da8dSAndroid Build Coastguard Worker        return self
199*cda5da8dSAndroid Build Coastguard Worker
200*cda5da8dSAndroid Build Coastguard Worker    def init(self, name, *, parse_tree, defects):
201*cda5da8dSAndroid Build Coastguard Worker        self._name = name
202*cda5da8dSAndroid Build Coastguard Worker        self._parse_tree = parse_tree
203*cda5da8dSAndroid Build Coastguard Worker        self._defects = defects
204*cda5da8dSAndroid Build Coastguard Worker
205*cda5da8dSAndroid Build Coastguard Worker    @property
206*cda5da8dSAndroid Build Coastguard Worker    def name(self):
207*cda5da8dSAndroid Build Coastguard Worker        return self._name
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Worker    @property
210*cda5da8dSAndroid Build Coastguard Worker    def defects(self):
211*cda5da8dSAndroid Build Coastguard Worker        return tuple(self._defects)
212*cda5da8dSAndroid Build Coastguard Worker
213*cda5da8dSAndroid Build Coastguard Worker    def __reduce__(self):
214*cda5da8dSAndroid Build Coastguard Worker        return (
215*cda5da8dSAndroid Build Coastguard Worker            _reconstruct_header,
216*cda5da8dSAndroid Build Coastguard Worker            (
217*cda5da8dSAndroid Build Coastguard Worker                self.__class__.__name__,
218*cda5da8dSAndroid Build Coastguard Worker                self.__class__.__bases__,
219*cda5da8dSAndroid Build Coastguard Worker                str(self),
220*cda5da8dSAndroid Build Coastguard Worker            ),
221*cda5da8dSAndroid Build Coastguard Worker            self.__getstate__())
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker    @classmethod
224*cda5da8dSAndroid Build Coastguard Worker    def _reconstruct(cls, value):
225*cda5da8dSAndroid Build Coastguard Worker        return str.__new__(cls, value)
226*cda5da8dSAndroid Build Coastguard Worker
227*cda5da8dSAndroid Build Coastguard Worker    def fold(self, *, policy):
228*cda5da8dSAndroid Build Coastguard Worker        """Fold header according to policy.
229*cda5da8dSAndroid Build Coastguard Worker
230*cda5da8dSAndroid Build Coastguard Worker        The parsed representation of the header is folded according to
231*cda5da8dSAndroid Build Coastguard Worker        RFC5322 rules, as modified by the policy.  If the parse tree
232*cda5da8dSAndroid Build Coastguard Worker        contains surrogateescaped bytes, the bytes are CTE encoded using
233*cda5da8dSAndroid Build Coastguard Worker        the charset 'unknown-8bit".
234*cda5da8dSAndroid Build Coastguard Worker
235*cda5da8dSAndroid Build Coastguard Worker        Any non-ASCII characters in the parse tree are CTE encoded using
236*cda5da8dSAndroid Build Coastguard Worker        charset utf-8. XXX: make this a policy setting.
237*cda5da8dSAndroid Build Coastguard Worker
238*cda5da8dSAndroid Build Coastguard Worker        The returned value is an ASCII-only string possibly containing linesep
239*cda5da8dSAndroid Build Coastguard Worker        characters, and ending with a linesep character.  The string includes
240*cda5da8dSAndroid Build Coastguard Worker        the header name and the ': ' separator.
241*cda5da8dSAndroid Build Coastguard Worker
242*cda5da8dSAndroid Build Coastguard Worker        """
243*cda5da8dSAndroid Build Coastguard Worker        # At some point we need to put fws here if it was in the source.
244*cda5da8dSAndroid Build Coastguard Worker        header = parser.Header([
245*cda5da8dSAndroid Build Coastguard Worker            parser.HeaderLabel([
246*cda5da8dSAndroid Build Coastguard Worker                parser.ValueTerminal(self.name, 'header-name'),
247*cda5da8dSAndroid Build Coastguard Worker                parser.ValueTerminal(':', 'header-sep')]),
248*cda5da8dSAndroid Build Coastguard Worker            ])
249*cda5da8dSAndroid Build Coastguard Worker        if self._parse_tree:
250*cda5da8dSAndroid Build Coastguard Worker            header.append(
251*cda5da8dSAndroid Build Coastguard Worker                parser.CFWSList([parser.WhiteSpaceTerminal(' ', 'fws')]))
252*cda5da8dSAndroid Build Coastguard Worker        header.append(self._parse_tree)
253*cda5da8dSAndroid Build Coastguard Worker        return header.fold(policy=policy)
254*cda5da8dSAndroid Build Coastguard Worker
255*cda5da8dSAndroid Build Coastguard Worker
256*cda5da8dSAndroid Build Coastguard Workerdef _reconstruct_header(cls_name, bases, value):
257*cda5da8dSAndroid Build Coastguard Worker    return type(cls_name, bases, {})._reconstruct(value)
258*cda5da8dSAndroid Build Coastguard Worker
259*cda5da8dSAndroid Build Coastguard Worker
260*cda5da8dSAndroid Build Coastguard Workerclass UnstructuredHeader:
261*cda5da8dSAndroid Build Coastguard Worker
262*cda5da8dSAndroid Build Coastguard Worker    max_count = None
263*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.get_unstructured)
264*cda5da8dSAndroid Build Coastguard Worker
265*cda5da8dSAndroid Build Coastguard Worker    @classmethod
266*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
267*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = cls.value_parser(value)
268*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = str(kwds['parse_tree'])
269*cda5da8dSAndroid Build Coastguard Worker
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Workerclass UniqueUnstructuredHeader(UnstructuredHeader):
272*cda5da8dSAndroid Build Coastguard Worker
273*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
274*cda5da8dSAndroid Build Coastguard Worker
275*cda5da8dSAndroid Build Coastguard Worker
276*cda5da8dSAndroid Build Coastguard Workerclass DateHeader:
277*cda5da8dSAndroid Build Coastguard Worker
278*cda5da8dSAndroid Build Coastguard Worker    """Header whose value consists of a single timestamp.
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker    Provides an additional attribute, datetime, which is either an aware
281*cda5da8dSAndroid Build Coastguard Worker    datetime using a timezone, or a naive datetime if the timezone
282*cda5da8dSAndroid Build Coastguard Worker    in the input string is -0000.  Also accepts a datetime as input.
283*cda5da8dSAndroid Build Coastguard Worker    The 'value' attribute is the normalized form of the timestamp,
284*cda5da8dSAndroid Build Coastguard Worker    which means it is the output of format_datetime on the datetime.
285*cda5da8dSAndroid Build Coastguard Worker    """
286*cda5da8dSAndroid Build Coastguard Worker
287*cda5da8dSAndroid Build Coastguard Worker    max_count = None
288*cda5da8dSAndroid Build Coastguard Worker
289*cda5da8dSAndroid Build Coastguard Worker    # This is used only for folding, not for creating 'decoded'.
290*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.get_unstructured)
291*cda5da8dSAndroid Build Coastguard Worker
292*cda5da8dSAndroid Build Coastguard Worker    @classmethod
293*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
294*cda5da8dSAndroid Build Coastguard Worker        if not value:
295*cda5da8dSAndroid Build Coastguard Worker            kwds['defects'].append(errors.HeaderMissingRequiredValue())
296*cda5da8dSAndroid Build Coastguard Worker            kwds['datetime'] = None
297*cda5da8dSAndroid Build Coastguard Worker            kwds['decoded'] = ''
298*cda5da8dSAndroid Build Coastguard Worker            kwds['parse_tree'] = parser.TokenList()
299*cda5da8dSAndroid Build Coastguard Worker            return
300*cda5da8dSAndroid Build Coastguard Worker        if isinstance(value, str):
301*cda5da8dSAndroid Build Coastguard Worker            kwds['decoded'] = value
302*cda5da8dSAndroid Build Coastguard Worker            try:
303*cda5da8dSAndroid Build Coastguard Worker                value = utils.parsedate_to_datetime(value)
304*cda5da8dSAndroid Build Coastguard Worker            except ValueError:
305*cda5da8dSAndroid Build Coastguard Worker                kwds['defects'].append(errors.InvalidDateDefect('Invalid date value or format'))
306*cda5da8dSAndroid Build Coastguard Worker                kwds['datetime'] = None
307*cda5da8dSAndroid Build Coastguard Worker                kwds['parse_tree'] = parser.TokenList()
308*cda5da8dSAndroid Build Coastguard Worker                return
309*cda5da8dSAndroid Build Coastguard Worker        kwds['datetime'] = value
310*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = utils.format_datetime(kwds['datetime'])
311*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = cls.value_parser(kwds['decoded'])
312*cda5da8dSAndroid Build Coastguard Worker
313*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
314*cda5da8dSAndroid Build Coastguard Worker        self._datetime = kw.pop('datetime')
315*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
316*cda5da8dSAndroid Build Coastguard Worker
317*cda5da8dSAndroid Build Coastguard Worker    @property
318*cda5da8dSAndroid Build Coastguard Worker    def datetime(self):
319*cda5da8dSAndroid Build Coastguard Worker        return self._datetime
320*cda5da8dSAndroid Build Coastguard Worker
321*cda5da8dSAndroid Build Coastguard Worker
322*cda5da8dSAndroid Build Coastguard Workerclass UniqueDateHeader(DateHeader):
323*cda5da8dSAndroid Build Coastguard Worker
324*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
325*cda5da8dSAndroid Build Coastguard Worker
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Workerclass AddressHeader:
328*cda5da8dSAndroid Build Coastguard Worker
329*cda5da8dSAndroid Build Coastguard Worker    max_count = None
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker    @staticmethod
332*cda5da8dSAndroid Build Coastguard Worker    def value_parser(value):
333*cda5da8dSAndroid Build Coastguard Worker        address_list, value = parser.get_address_list(value)
334*cda5da8dSAndroid Build Coastguard Worker        assert not value, 'this should not happen'
335*cda5da8dSAndroid Build Coastguard Worker        return address_list
336*cda5da8dSAndroid Build Coastguard Worker
337*cda5da8dSAndroid Build Coastguard Worker    @classmethod
338*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
339*cda5da8dSAndroid Build Coastguard Worker        if isinstance(value, str):
340*cda5da8dSAndroid Build Coastguard Worker            # We are translating here from the RFC language (address/mailbox)
341*cda5da8dSAndroid Build Coastguard Worker            # to our API language (group/address).
342*cda5da8dSAndroid Build Coastguard Worker            kwds['parse_tree'] = address_list = cls.value_parser(value)
343*cda5da8dSAndroid Build Coastguard Worker            groups = []
344*cda5da8dSAndroid Build Coastguard Worker            for addr in address_list.addresses:
345*cda5da8dSAndroid Build Coastguard Worker                groups.append(Group(addr.display_name,
346*cda5da8dSAndroid Build Coastguard Worker                                    [Address(mb.display_name or '',
347*cda5da8dSAndroid Build Coastguard Worker                                             mb.local_part or '',
348*cda5da8dSAndroid Build Coastguard Worker                                             mb.domain or '')
349*cda5da8dSAndroid Build Coastguard Worker                                     for mb in addr.all_mailboxes]))
350*cda5da8dSAndroid Build Coastguard Worker            defects = list(address_list.all_defects)
351*cda5da8dSAndroid Build Coastguard Worker        else:
352*cda5da8dSAndroid Build Coastguard Worker            # Assume it is Address/Group stuff
353*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(value, '__iter__'):
354*cda5da8dSAndroid Build Coastguard Worker                value = [value]
355*cda5da8dSAndroid Build Coastguard Worker            groups = [Group(None, [item]) if not hasattr(item, 'addresses')
356*cda5da8dSAndroid Build Coastguard Worker                                          else item
357*cda5da8dSAndroid Build Coastguard Worker                                    for item in value]
358*cda5da8dSAndroid Build Coastguard Worker            defects = []
359*cda5da8dSAndroid Build Coastguard Worker        kwds['groups'] = groups
360*cda5da8dSAndroid Build Coastguard Worker        kwds['defects'] = defects
361*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = ', '.join([str(item) for item in groups])
362*cda5da8dSAndroid Build Coastguard Worker        if 'parse_tree' not in kwds:
363*cda5da8dSAndroid Build Coastguard Worker            kwds['parse_tree'] = cls.value_parser(kwds['decoded'])
364*cda5da8dSAndroid Build Coastguard Worker
365*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
366*cda5da8dSAndroid Build Coastguard Worker        self._groups = tuple(kw.pop('groups'))
367*cda5da8dSAndroid Build Coastguard Worker        self._addresses = None
368*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
369*cda5da8dSAndroid Build Coastguard Worker
370*cda5da8dSAndroid Build Coastguard Worker    @property
371*cda5da8dSAndroid Build Coastguard Worker    def groups(self):
372*cda5da8dSAndroid Build Coastguard Worker        return self._groups
373*cda5da8dSAndroid Build Coastguard Worker
374*cda5da8dSAndroid Build Coastguard Worker    @property
375*cda5da8dSAndroid Build Coastguard Worker    def addresses(self):
376*cda5da8dSAndroid Build Coastguard Worker        if self._addresses is None:
377*cda5da8dSAndroid Build Coastguard Worker            self._addresses = tuple(address for group in self._groups
378*cda5da8dSAndroid Build Coastguard Worker                                            for address in group.addresses)
379*cda5da8dSAndroid Build Coastguard Worker        return self._addresses
380*cda5da8dSAndroid Build Coastguard Worker
381*cda5da8dSAndroid Build Coastguard Worker
382*cda5da8dSAndroid Build Coastguard Workerclass UniqueAddressHeader(AddressHeader):
383*cda5da8dSAndroid Build Coastguard Worker
384*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
385*cda5da8dSAndroid Build Coastguard Worker
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Workerclass SingleAddressHeader(AddressHeader):
388*cda5da8dSAndroid Build Coastguard Worker
389*cda5da8dSAndroid Build Coastguard Worker    @property
390*cda5da8dSAndroid Build Coastguard Worker    def address(self):
391*cda5da8dSAndroid Build Coastguard Worker        if len(self.addresses)!=1:
392*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(("value of single address header {} is not "
393*cda5da8dSAndroid Build Coastguard Worker                "a single address").format(self.name))
394*cda5da8dSAndroid Build Coastguard Worker        return self.addresses[0]
395*cda5da8dSAndroid Build Coastguard Worker
396*cda5da8dSAndroid Build Coastguard Worker
397*cda5da8dSAndroid Build Coastguard Workerclass UniqueSingleAddressHeader(SingleAddressHeader):
398*cda5da8dSAndroid Build Coastguard Worker
399*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
400*cda5da8dSAndroid Build Coastguard Worker
401*cda5da8dSAndroid Build Coastguard Worker
402*cda5da8dSAndroid Build Coastguard Workerclass MIMEVersionHeader:
403*cda5da8dSAndroid Build Coastguard Worker
404*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
405*cda5da8dSAndroid Build Coastguard Worker
406*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.parse_mime_version)
407*cda5da8dSAndroid Build Coastguard Worker
408*cda5da8dSAndroid Build Coastguard Worker    @classmethod
409*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
410*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = parse_tree = cls.value_parser(value)
411*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = str(parse_tree)
412*cda5da8dSAndroid Build Coastguard Worker        kwds['defects'].extend(parse_tree.all_defects)
413*cda5da8dSAndroid Build Coastguard Worker        kwds['major'] = None if parse_tree.minor is None else parse_tree.major
414*cda5da8dSAndroid Build Coastguard Worker        kwds['minor'] = parse_tree.minor
415*cda5da8dSAndroid Build Coastguard Worker        if parse_tree.minor is not None:
416*cda5da8dSAndroid Build Coastguard Worker            kwds['version'] = '{}.{}'.format(kwds['major'], kwds['minor'])
417*cda5da8dSAndroid Build Coastguard Worker        else:
418*cda5da8dSAndroid Build Coastguard Worker            kwds['version'] = None
419*cda5da8dSAndroid Build Coastguard Worker
420*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
421*cda5da8dSAndroid Build Coastguard Worker        self._version = kw.pop('version')
422*cda5da8dSAndroid Build Coastguard Worker        self._major = kw.pop('major')
423*cda5da8dSAndroid Build Coastguard Worker        self._minor = kw.pop('minor')
424*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
425*cda5da8dSAndroid Build Coastguard Worker
426*cda5da8dSAndroid Build Coastguard Worker    @property
427*cda5da8dSAndroid Build Coastguard Worker    def major(self):
428*cda5da8dSAndroid Build Coastguard Worker        return self._major
429*cda5da8dSAndroid Build Coastguard Worker
430*cda5da8dSAndroid Build Coastguard Worker    @property
431*cda5da8dSAndroid Build Coastguard Worker    def minor(self):
432*cda5da8dSAndroid Build Coastguard Worker        return self._minor
433*cda5da8dSAndroid Build Coastguard Worker
434*cda5da8dSAndroid Build Coastguard Worker    @property
435*cda5da8dSAndroid Build Coastguard Worker    def version(self):
436*cda5da8dSAndroid Build Coastguard Worker        return self._version
437*cda5da8dSAndroid Build Coastguard Worker
438*cda5da8dSAndroid Build Coastguard Worker
439*cda5da8dSAndroid Build Coastguard Workerclass ParameterizedMIMEHeader:
440*cda5da8dSAndroid Build Coastguard Worker
441*cda5da8dSAndroid Build Coastguard Worker    # Mixin that handles the params dict.  Must be subclassed and
442*cda5da8dSAndroid Build Coastguard Worker    # a property value_parser for the specific header provided.
443*cda5da8dSAndroid Build Coastguard Worker
444*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
445*cda5da8dSAndroid Build Coastguard Worker
446*cda5da8dSAndroid Build Coastguard Worker    @classmethod
447*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
448*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = parse_tree = cls.value_parser(value)
449*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = str(parse_tree)
450*cda5da8dSAndroid Build Coastguard Worker        kwds['defects'].extend(parse_tree.all_defects)
451*cda5da8dSAndroid Build Coastguard Worker        if parse_tree.params is None:
452*cda5da8dSAndroid Build Coastguard Worker            kwds['params'] = {}
453*cda5da8dSAndroid Build Coastguard Worker        else:
454*cda5da8dSAndroid Build Coastguard Worker            # The MIME RFCs specify that parameter ordering is arbitrary.
455*cda5da8dSAndroid Build Coastguard Worker            kwds['params'] = {utils._sanitize(name).lower():
456*cda5da8dSAndroid Build Coastguard Worker                                    utils._sanitize(value)
457*cda5da8dSAndroid Build Coastguard Worker                               for name, value in parse_tree.params}
458*cda5da8dSAndroid Build Coastguard Worker
459*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
460*cda5da8dSAndroid Build Coastguard Worker        self._params = kw.pop('params')
461*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
462*cda5da8dSAndroid Build Coastguard Worker
463*cda5da8dSAndroid Build Coastguard Worker    @property
464*cda5da8dSAndroid Build Coastguard Worker    def params(self):
465*cda5da8dSAndroid Build Coastguard Worker        return MappingProxyType(self._params)
466*cda5da8dSAndroid Build Coastguard Worker
467*cda5da8dSAndroid Build Coastguard Worker
468*cda5da8dSAndroid Build Coastguard Workerclass ContentTypeHeader(ParameterizedMIMEHeader):
469*cda5da8dSAndroid Build Coastguard Worker
470*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.parse_content_type_header)
471*cda5da8dSAndroid Build Coastguard Worker
472*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
473*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
474*cda5da8dSAndroid Build Coastguard Worker        self._maintype = utils._sanitize(self._parse_tree.maintype)
475*cda5da8dSAndroid Build Coastguard Worker        self._subtype = utils._sanitize(self._parse_tree.subtype)
476*cda5da8dSAndroid Build Coastguard Worker
477*cda5da8dSAndroid Build Coastguard Worker    @property
478*cda5da8dSAndroid Build Coastguard Worker    def maintype(self):
479*cda5da8dSAndroid Build Coastguard Worker        return self._maintype
480*cda5da8dSAndroid Build Coastguard Worker
481*cda5da8dSAndroid Build Coastguard Worker    @property
482*cda5da8dSAndroid Build Coastguard Worker    def subtype(self):
483*cda5da8dSAndroid Build Coastguard Worker        return self._subtype
484*cda5da8dSAndroid Build Coastguard Worker
485*cda5da8dSAndroid Build Coastguard Worker    @property
486*cda5da8dSAndroid Build Coastguard Worker    def content_type(self):
487*cda5da8dSAndroid Build Coastguard Worker        return self.maintype + '/' + self.subtype
488*cda5da8dSAndroid Build Coastguard Worker
489*cda5da8dSAndroid Build Coastguard Worker
490*cda5da8dSAndroid Build Coastguard Workerclass ContentDispositionHeader(ParameterizedMIMEHeader):
491*cda5da8dSAndroid Build Coastguard Worker
492*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.parse_content_disposition_header)
493*cda5da8dSAndroid Build Coastguard Worker
494*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
495*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
496*cda5da8dSAndroid Build Coastguard Worker        cd = self._parse_tree.content_disposition
497*cda5da8dSAndroid Build Coastguard Worker        self._content_disposition = cd if cd is None else utils._sanitize(cd)
498*cda5da8dSAndroid Build Coastguard Worker
499*cda5da8dSAndroid Build Coastguard Worker    @property
500*cda5da8dSAndroid Build Coastguard Worker    def content_disposition(self):
501*cda5da8dSAndroid Build Coastguard Worker        return self._content_disposition
502*cda5da8dSAndroid Build Coastguard Worker
503*cda5da8dSAndroid Build Coastguard Worker
504*cda5da8dSAndroid Build Coastguard Workerclass ContentTransferEncodingHeader:
505*cda5da8dSAndroid Build Coastguard Worker
506*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
507*cda5da8dSAndroid Build Coastguard Worker
508*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.parse_content_transfer_encoding_header)
509*cda5da8dSAndroid Build Coastguard Worker
510*cda5da8dSAndroid Build Coastguard Worker    @classmethod
511*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
512*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = parse_tree = cls.value_parser(value)
513*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = str(parse_tree)
514*cda5da8dSAndroid Build Coastguard Worker        kwds['defects'].extend(parse_tree.all_defects)
515*cda5da8dSAndroid Build Coastguard Worker
516*cda5da8dSAndroid Build Coastguard Worker    def init(self, *args, **kw):
517*cda5da8dSAndroid Build Coastguard Worker        super().init(*args, **kw)
518*cda5da8dSAndroid Build Coastguard Worker        self._cte = utils._sanitize(self._parse_tree.cte)
519*cda5da8dSAndroid Build Coastguard Worker
520*cda5da8dSAndroid Build Coastguard Worker    @property
521*cda5da8dSAndroid Build Coastguard Worker    def cte(self):
522*cda5da8dSAndroid Build Coastguard Worker        return self._cte
523*cda5da8dSAndroid Build Coastguard Worker
524*cda5da8dSAndroid Build Coastguard Worker
525*cda5da8dSAndroid Build Coastguard Workerclass MessageIDHeader:
526*cda5da8dSAndroid Build Coastguard Worker
527*cda5da8dSAndroid Build Coastguard Worker    max_count = 1
528*cda5da8dSAndroid Build Coastguard Worker    value_parser = staticmethod(parser.parse_message_id)
529*cda5da8dSAndroid Build Coastguard Worker
530*cda5da8dSAndroid Build Coastguard Worker    @classmethod
531*cda5da8dSAndroid Build Coastguard Worker    def parse(cls, value, kwds):
532*cda5da8dSAndroid Build Coastguard Worker        kwds['parse_tree'] = parse_tree = cls.value_parser(value)
533*cda5da8dSAndroid Build Coastguard Worker        kwds['decoded'] = str(parse_tree)
534*cda5da8dSAndroid Build Coastguard Worker        kwds['defects'].extend(parse_tree.all_defects)
535*cda5da8dSAndroid Build Coastguard Worker
536*cda5da8dSAndroid Build Coastguard Worker
537*cda5da8dSAndroid Build Coastguard Worker# The header factory #
538*cda5da8dSAndroid Build Coastguard Worker
539*cda5da8dSAndroid Build Coastguard Worker_default_header_map = {
540*cda5da8dSAndroid Build Coastguard Worker    'subject':                      UniqueUnstructuredHeader,
541*cda5da8dSAndroid Build Coastguard Worker    'date':                         UniqueDateHeader,
542*cda5da8dSAndroid Build Coastguard Worker    'resent-date':                  DateHeader,
543*cda5da8dSAndroid Build Coastguard Worker    'orig-date':                    UniqueDateHeader,
544*cda5da8dSAndroid Build Coastguard Worker    'sender':                       UniqueSingleAddressHeader,
545*cda5da8dSAndroid Build Coastguard Worker    'resent-sender':                SingleAddressHeader,
546*cda5da8dSAndroid Build Coastguard Worker    'to':                           UniqueAddressHeader,
547*cda5da8dSAndroid Build Coastguard Worker    'resent-to':                    AddressHeader,
548*cda5da8dSAndroid Build Coastguard Worker    'cc':                           UniqueAddressHeader,
549*cda5da8dSAndroid Build Coastguard Worker    'resent-cc':                    AddressHeader,
550*cda5da8dSAndroid Build Coastguard Worker    'bcc':                          UniqueAddressHeader,
551*cda5da8dSAndroid Build Coastguard Worker    'resent-bcc':                   AddressHeader,
552*cda5da8dSAndroid Build Coastguard Worker    'from':                         UniqueAddressHeader,
553*cda5da8dSAndroid Build Coastguard Worker    'resent-from':                  AddressHeader,
554*cda5da8dSAndroid Build Coastguard Worker    'reply-to':                     UniqueAddressHeader,
555*cda5da8dSAndroid Build Coastguard Worker    'mime-version':                 MIMEVersionHeader,
556*cda5da8dSAndroid Build Coastguard Worker    'content-type':                 ContentTypeHeader,
557*cda5da8dSAndroid Build Coastguard Worker    'content-disposition':          ContentDispositionHeader,
558*cda5da8dSAndroid Build Coastguard Worker    'content-transfer-encoding':    ContentTransferEncodingHeader,
559*cda5da8dSAndroid Build Coastguard Worker    'message-id':                   MessageIDHeader,
560*cda5da8dSAndroid Build Coastguard Worker    }
561*cda5da8dSAndroid Build Coastguard Worker
562*cda5da8dSAndroid Build Coastguard Workerclass HeaderRegistry:
563*cda5da8dSAndroid Build Coastguard Worker
564*cda5da8dSAndroid Build Coastguard Worker    """A header_factory and header registry."""
565*cda5da8dSAndroid Build Coastguard Worker
566*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, base_class=BaseHeader, default_class=UnstructuredHeader,
567*cda5da8dSAndroid Build Coastguard Worker                       use_default_map=True):
568*cda5da8dSAndroid Build Coastguard Worker        """Create a header_factory that works with the Policy API.
569*cda5da8dSAndroid Build Coastguard Worker
570*cda5da8dSAndroid Build Coastguard Worker        base_class is the class that will be the last class in the created
571*cda5da8dSAndroid Build Coastguard Worker        header class's __bases__ list.  default_class is the class that will be
572*cda5da8dSAndroid Build Coastguard Worker        used if "name" (see __call__) does not appear in the registry.
573*cda5da8dSAndroid Build Coastguard Worker        use_default_map controls whether or not the default mapping of names to
574*cda5da8dSAndroid Build Coastguard Worker        specialized classes is copied in to the registry when the factory is
575*cda5da8dSAndroid Build Coastguard Worker        created.  The default is True.
576*cda5da8dSAndroid Build Coastguard Worker
577*cda5da8dSAndroid Build Coastguard Worker        """
578*cda5da8dSAndroid Build Coastguard Worker        self.registry = {}
579*cda5da8dSAndroid Build Coastguard Worker        self.base_class = base_class
580*cda5da8dSAndroid Build Coastguard Worker        self.default_class = default_class
581*cda5da8dSAndroid Build Coastguard Worker        if use_default_map:
582*cda5da8dSAndroid Build Coastguard Worker            self.registry.update(_default_header_map)
583*cda5da8dSAndroid Build Coastguard Worker
584*cda5da8dSAndroid Build Coastguard Worker    def map_to_type(self, name, cls):
585*cda5da8dSAndroid Build Coastguard Worker        """Register cls as the specialized class for handling "name" headers.
586*cda5da8dSAndroid Build Coastguard Worker
587*cda5da8dSAndroid Build Coastguard Worker        """
588*cda5da8dSAndroid Build Coastguard Worker        self.registry[name.lower()] = cls
589*cda5da8dSAndroid Build Coastguard Worker
590*cda5da8dSAndroid Build Coastguard Worker    def __getitem__(self, name):
591*cda5da8dSAndroid Build Coastguard Worker        cls = self.registry.get(name.lower(), self.default_class)
592*cda5da8dSAndroid Build Coastguard Worker        return type('_'+cls.__name__, (cls, self.base_class), {})
593*cda5da8dSAndroid Build Coastguard Worker
594*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, name, value):
595*cda5da8dSAndroid Build Coastguard Worker        """Create a header instance for header 'name' from 'value'.
596*cda5da8dSAndroid Build Coastguard Worker
597*cda5da8dSAndroid Build Coastguard Worker        Creates a header instance by creating a specialized class for parsing
598*cda5da8dSAndroid Build Coastguard Worker        and representing the specified header by combining the factory
599*cda5da8dSAndroid Build Coastguard Worker        base_class with a specialized class from the registry or the
600*cda5da8dSAndroid Build Coastguard Worker        default_class, and passing the name and value to the constructed
601*cda5da8dSAndroid Build Coastguard Worker        class's constructor.
602*cda5da8dSAndroid Build Coastguard Worker
603*cda5da8dSAndroid Build Coastguard Worker        """
604*cda5da8dSAndroid Build Coastguard Worker        return self[name](name, value)
605