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