1# Copyright (C) 2001-2007 Python Software Foundation 
    2# Author: Barry Warsaw, Thomas Wouters, Anthony Baxter 
    3# Contact: email-sig@python.org 
    4 
    5"""A parser of RFC 2822 and MIME email messages.""" 
    6from __future__ import unicode_literals 
    7from __future__ import division 
    8from __future__ import absolute_import 
    9 
    10__all__ = ['Parser', 'HeaderParser', 'BytesParser', 'BytesHeaderParser'] 
    11 
    12import warnings 
    13from io import StringIO, TextIOWrapper 
    14 
    15from future.backports.email.feedparser import FeedParser, BytesFeedParser 
    16from future.backports.email.message import Message 
    17from future.backports.email._policybase import compat32 
    18 
    19 
    20class Parser(object): 
    21    def __init__(self, _class=Message, **_3to2kwargs): 
    22        """Parser of RFC 2822 and MIME email messages. 
    23 
    24        Creates an in-memory object tree representing the email message, which 
    25        can then be manipulated and turned over to a Generator to return the 
    26        textual representation of the message. 
    27 
    28        The string must be formatted as a block of RFC 2822 headers and header 
    29        continuation lines, optionally preceded by a `Unix-from' header.  The 
    30        header block is terminated either by the end of the string or by a 
    31        blank line. 
    32 
    33        _class is the class to instantiate for new message objects when they 
    34        must be created.  This class must have a constructor that can take 
    35        zero arguments.  Default is Message.Message. 
    36 
    37        The policy keyword specifies a policy object that controls a number of 
    38        aspects of the parser's operation.  The default policy maintains 
    39        backward compatibility. 
    40 
    41        """ 
    42        if 'policy' in _3to2kwargs: policy = _3to2kwargs['policy']; del _3to2kwargs['policy'] 
    43        else: policy = compat32 
    44        self._class = _class 
    45        self.policy = policy 
    46 
    47    def parse(self, fp, headersonly=False): 
    48        """Create a message structure from the data in a file. 
    49 
    50        Reads all the data from the file and returns the root of the message 
    51        structure.  Optional headersonly is a flag specifying whether to stop 
    52        parsing after reading the headers or not.  The default is False, 
    53        meaning it parses the entire contents of the file. 
    54        """ 
    55        feedparser = FeedParser(self._class, policy=self.policy) 
    56        if headersonly: 
    57            feedparser._set_headersonly() 
    58        while True: 
    59            data = fp.read(8192) 
    60            if not data: 
    61                break 
    62            feedparser.feed(data) 
    63        return feedparser.close() 
    64 
    65    def parsestr(self, text, headersonly=False): 
    66        """Create a message structure from a string. 
    67 
    68        Returns the root of the message structure.  Optional headersonly is a 
    69        flag specifying whether to stop parsing after reading the headers or 
    70        not.  The default is False, meaning it parses the entire contents of 
    71        the file. 
    72        """ 
    73        return self.parse(StringIO(text), headersonly=headersonly) 
    74 
    75 
    76 
    77class HeaderParser(Parser): 
    78    def parse(self, fp, headersonly=True): 
    79        return Parser.parse(self, fp, True) 
    80 
    81    def parsestr(self, text, headersonly=True): 
    82        return Parser.parsestr(self, text, True) 
    83 
    84 
    85class BytesParser(object): 
    86 
    87    def __init__(self, *args, **kw): 
    88        """Parser of binary RFC 2822 and MIME email messages. 
    89 
    90        Creates an in-memory object tree representing the email message, which 
    91        can then be manipulated and turned over to a Generator to return the 
    92        textual representation of the message. 
    93 
    94        The input must be formatted as a block of RFC 2822 headers and header 
    95        continuation lines, optionally preceded by a `Unix-from' header.  The 
    96        header block is terminated either by the end of the input or by a 
    97        blank line. 
    98 
    99        _class is the class to instantiate for new message objects when they 
    100        must be created.  This class must have a constructor that can take 
    101        zero arguments.  Default is Message.Message. 
    102        """ 
    103        self.parser = Parser(*args, **kw) 
    104 
    105    def parse(self, fp, headersonly=False): 
    106        """Create a message structure from the data in a binary file. 
    107 
    108        Reads all the data from the file and returns the root of the message 
    109        structure.  Optional headersonly is a flag specifying whether to stop 
    110        parsing after reading the headers or not.  The default is False, 
    111        meaning it parses the entire contents of the file. 
    112        """ 
    113        fp = TextIOWrapper(fp, encoding='ascii', errors='surrogateescape') 
    114        with fp: 
    115            return self.parser.parse(fp, headersonly) 
    116 
    117 
    118    def parsebytes(self, text, headersonly=False): 
    119        """Create a message structure from a byte string. 
    120 
    121        Returns the root of the message structure.  Optional headersonly is a 
    122        flag specifying whether to stop parsing after reading the headers or 
    123        not.  The default is False, meaning it parses the entire contents of 
    124        the file. 
    125        """ 
    126        text = text.decode('ASCII', errors='surrogateescape') 
    127        return self.parser.parsestr(text, headersonly) 
    128 
    129 
    130class BytesHeaderParser(BytesParser): 
    131    def parse(self, fp, headersonly=True): 
    132        return BytesParser.parse(self, fp, headersonly=True) 
    133 
    134    def parsebytes(self, text, headersonly=True): 
    135        return BytesParser.parsebytes(self, text, headersonly=True)