10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Copyright (C) 2001-2010 Python Software Foundation
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Contact: email-sig@python.org
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# email package unit tests
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport os
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport sys
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport time
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport base64
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport difflib
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport unittest
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport warnings
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport textwrap
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom cStringIO import StringIO
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport email
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.Charset import Charset
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.Header import Header, decode_header, make_header
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.Parser import Parser, HeaderParser
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.Generator import Generator, DecodedGenerator
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.Message import Message
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEAudio import MIMEAudio
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEText import MIMEText
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEImage import MIMEImage
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEBase import MIMEBase
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEMessage import MIMEMessage
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.MIMEMultipart import MIMEMultipart
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import Utils
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import Errors
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import Encoders
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import Iterators
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import base64MIME
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email import quopriMIME
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom test.test_support import findfile, run_unittest
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom email.test import __file__ as landmark
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiNL = '\n'
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiEMPTYSTRING = ''
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSPACE = ' '
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef openfile(filename, mode='r'):
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    path = os.path.join(os.path.dirname(landmark), 'data', filename)
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return open(path, mode)
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Base test class
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestEmailBase(unittest.TestCase):
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def ndiffAssertEqual(self, first, second):
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """Like assertEqual except use ndiff for readable output."""
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if first != second:
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sfirst = str(first)
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ssecond = str(second)
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines())
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp = StringIO()
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print >> fp, NL, NL.join(diff)
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise self.failureException, fp.getvalue()
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _msgobj(self, filename):
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile(findfile(filename))
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp)
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return msg
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test various aspects of the Message class's API
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMessageAPI(TestEmailBase):
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_all(self):
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_20.txt')
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_all('cc'), ['ccc@zzz.org', 'ddd@zzz.org', 'eee@zzz.org'])
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_all('xx', 'n/a'), 'n/a')
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_getset_charset(self):
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset(), None)
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset('iso-8859-1')
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset(charset)
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['mime-version'], '1.0')
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="iso-8859-1"')
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('charset'), 'iso-8859-1')
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], 'quoted-printable')
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset().input_charset, 'iso-8859-1')
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Remove the charset
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset(None)
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset(), None)
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain')
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try adding a charset when there's already MIME headers present
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['MIME-Version'] = '2.0'
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'text/x-weird'
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Transfer-Encoding'] = 'quinted-puntable'
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset(charset)
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['mime-version'], '2.0')
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/x-weird; charset="iso-8859-1"')
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], 'quinted-puntable')
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_charset_from_string(self):
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset('us-ascii')
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset().input_charset, 'us-ascii')
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_payload_with_charset(self):
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset('iso-8859-1')
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('This is a string payload', charset)
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_charset().input_charset, 'iso-8859-1')
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_charsets(self):
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_08.txt')
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charsets = msg.get_charsets()
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charsets, [None, 'us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r'])
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_09.txt')
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charsets = msg.get_charsets('dingbat')
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charsets, ['dingbat', 'us-ascii', 'iso-8859-1', 'dingbat',
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                      'koi8-r'])
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_12.txt')
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charsets = msg.get_charsets()
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charsets, [None, 'us-ascii', 'iso-8859-1', None, 'iso-8859-2',
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                      'iso-8859-3', 'us-ascii', 'koi8-r'])
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_filename(self):
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_04.txt')
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        filenames = [p.get_filename() for p in msg.get_payload()]
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(filenames, ['msg.txt', 'msg.txt'])
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_07.txt')
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart = msg.get_payload(1)
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart.get_filename(), 'dingusfish.gif')
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_filename_with_name_parameter(self):
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_44.txt')
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        filenames = [p.get_filename() for p in msg.get_payload()]
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(filenames, ['msg.txt', 'msg.txt'])
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_boundary(self):
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_07.txt')
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # No quotes!
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_boundary(), 'BOUNDARY')
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_boundary(self):
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This one has no existing boundary parameter, but the Content-Type:
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # header appears fifth.
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_boundary('BOUNDARY')
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        header, value = msg.items()[4]
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(header.lower(), 'content-type')
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(value, 'text/plain; charset="us-ascii"; boundary="BOUNDARY"')
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This one has a Content-Type: header, with a boundary, stuck in the
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # middle of its headers.  Make sure the order is preserved; it should
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # be fifth.
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_04.txt')
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_boundary('BOUNDARY')
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        header, value = msg.items()[4]
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(header.lower(), 'content-type')
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(value, 'multipart/mixed; boundary="BOUNDARY"')
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # And this one has no Content-Type: header at all.
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_03.txt')
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(Errors.HeaderParseError,
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                          msg.set_boundary, 'BOUNDARY')
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_make_boundary(self):
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEMultipart('form-data')
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Note that when the boundary gets created is an implementation
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # detail and might change.
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.items()[0][1], 'multipart/form-data')
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Trigger creation of boundary
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.as_string()
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.items()[0][1][:33],
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        'multipart/form-data; boundary="==')
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # XXX: there ought to be tests of the uniqueness of the boundary, too.
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_rfc822_only(self):
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Issue 7970: message/rfc822 not in multipart parsed by
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # HeaderParser caused an exception when flattened.
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile(findfile('msg_46.txt'))
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msgdata = fp.read()
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        parser = email.Parser.HeaderParser()
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = parser.parsestr(msgdata)
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out = StringIO()
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gen = email.Generator.Generator(out, True, 0)
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gen.flatten(msg, False)
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(out.getvalue(), msgdata)
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_decoded_payload(self):
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_10.txt')
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # The outer message is a multipart
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(decode=True), None)
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 1 is 7bit encoded
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(0).get_payload(decode=True),
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'This is a 7bit encoded message.\n')
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 2 is quopri
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(1).get_payload(decode=True),
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xa1This is a Quoted Printable encoded message!\n')
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 3 is base64
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(2).get_payload(decode=True),
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'This is a Base64 encoded message.')
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 4 is base64 with a trailing newline, which
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # used to be stripped (issue 7143).
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(3).get_payload(decode=True),
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'This is a Base64 encoded message.\n')
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 5 has no Content-Transfer-Encoding: header.
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(4).get_payload(decode=True),
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'This has no Content-Transfer-Encoding: header.\n')
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_decoded_uu_payload(self):
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('begin 666 -\n+:&5L;&\\@=V]R;&0 \n \nend\n')
2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg['content-transfer-encoding'] = cte
2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(msg.get_payload(decode=True), 'hello world')
2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Now try some bogus data
2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('foo')
2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(decode=True), 'foo')
2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_decode_bogus_uu_payload_quietly(self):
2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('begin 664 foo.txt\n%<W1F=0000H \n \nend\n')
2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Transfer-Encoding'] = 'x-uuencode'
2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        old_stderr = sys.stderr
2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sys.stderr = sfp = StringIO()
2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # We don't care about the payload
2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg.get_payload(decode=True)
2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sys.stderr = old_stderr
2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(sfp.getvalue(), '')
2510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_decoded_generator(self):
2530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
2540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_07.txt')
2550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_17.txt')
2560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
2580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
2590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
2600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
2610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = DecodedGenerator(s)
2620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
2630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s.getvalue(), text)
2640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test__contains__(self):
2660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
2670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['From'] = 'Me'
2680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['to'] = 'You'
2690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check for case insensitivity
2700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('from' in msg)
2710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('From' in msg)
2720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('FROM' in msg)
2730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('to' in msg)
2740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('To' in msg)
2750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('TO' in msg)
2760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_as_string(self):
2780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
2790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
2800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_01.txt')
2810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
2820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # BAW 30-Mar-2009 Evil be here.  So, the generator is broken with
2830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # respect to long line breaking.  It's also not idempotent when a
2840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # header from a parsed message is continued with tabs rather than
2850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # spaces.  Before we fixed bug 1974 it was reversedly broken,
2860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # i.e. headers that were continued with spaces got continued with
2870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # tabs.  For Python 2.x there's really no good fix and in Python
2880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # 3.x all this stuff is re-written to be right(er).  Chris Withers
2890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # convinced me that using space as the default continuation
2900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # character is less bad for more applications.
2910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read().replace('\t', ' ')
2920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
2930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
2940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(text, msg.as_string())
2950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fullrepr = str(msg)
2960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = fullrepr.split('\n')
2970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(lines[0].startswith('From '))
2980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(text, NL.join(lines[1:]))
2990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bad_param(self):
3010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("Content-Type: blarg; baz; boo\n")
3020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('baz'), '')
3030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_missing_filename(self):
3050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("From: foo\n")
3060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(), None)
3070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bogus_filename(self):
3090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        "Content-Disposition: blarg; filename\n")
3110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(), '')
3120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_missing_boundary(self):
3140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("From: foo\n")
3150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_boundary(), None)
3160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_params(self):
3180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
3190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'X-Header: foo=one; bar=two; baz=three\n')
3210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(header='x-header'),
3220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('foo', 'one'), ('bar', 'two'), ('baz', 'three')])
3230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'X-Header: foo; bar=one; baz=two\n')
3250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(header='x-header'),
3260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('foo', ''), ('bar', 'one'), ('baz', 'two')])
3270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(), None)
3280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'X-Header: foo; bar="one"; baz=two\n')
3300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(header='x-header'),
3310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('foo', ''), ('bar', 'one'), ('baz', 'two')])
3320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param_liberal(self):
3340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
3350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'Content-Type: Multipart/mixed; boundary = "CPIMSSMTPC06p5f3tG"'
3360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('boundary'), 'CPIMSSMTPC06p5f3tG')
3370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param(self):
3390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
3400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "X-Header: foo=one; bar=two; baz=three\n")
3420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('bar', header='x-header'), 'two')
3430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('quuz', header='x-header'), None)
3440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('quuz'), None)
3450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'X-Header: foo; bar="one"; baz=two\n')
3470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('foo', header='x-header'), '')
3480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('bar', header='x-header'), 'one')
3490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('baz', header='x-header'), 'two')
3500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # XXX: We are not RFC-2045 compliant!  We cannot parse:
3510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg["Content-Type"] = 'text/plain; weird="hey; dolly? [you] @ <\\"home\\">?"'
3520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg.get_param("weird")
3530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # yet.
3540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param_funky_continuation_lines(self):
3560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_22.txt')
3570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(1).get_param('name'), 'wibble.JPG')
3580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param_with_semis_in_quotes(self):
3600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'Content-Type: image/pjpeg; name="Jim&amp;&amp;Jill"\n')
3620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('name'), 'Jim&amp;&amp;Jill')
3630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('name', unquote=False),
3640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         '"Jim&amp;&amp;Jill"')
3650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param_with_quotes(self):
3670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'Content-Type: foo; bar*0="baz\\"foobar"; bar*1="\\"baz"')
3690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz')
3700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(
3710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "Content-Type: foo; bar*0=\"baz\\\"foobar\"; bar*1=\"\\\"baz\"")
3720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz')
3730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_has_key(self):
3750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string('Header: exists')
3760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.has_key('header'))
3770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.has_key('Header'))
3780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.has_key('HEADER'))
3790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(msg.has_key('headeri'))
3800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_param(self):
3820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
3830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
3840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('charset', 'iso-2022-jp')
3850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('charset'), 'iso-2022-jp')
3860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('importance', 'high value')
3870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('importance'), 'high value')
3880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('importance', unquote=False), '"high value"')
3890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(), [('text/plain', ''),
3900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                              ('charset', 'iso-2022-jp'),
3910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                              ('importance', 'high value')])
3920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(unquote=False), [('text/plain', ''),
3930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                       ('charset', '"iso-2022-jp"'),
3940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                       ('importance', '"high value"')])
3950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('charset', 'iso-9999-xx', header='X-Jimmy')
3960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('charset', header='X-Jimmy'), 'iso-9999-xx')
3970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_del_param(self):
3990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
4000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_05.txt')
4010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(),
4020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('multipart/report', ''), ('report-type', 'delivery-status'),
4030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
4040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        old_val = msg.get_param("report-type")
4050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.del_param("report-type")
4060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(),
4070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('multipart/report', ''),
4080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
4090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param("report-type", old_val)
4100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(),
4110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('multipart/report', ''),
4120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('boundary', 'D1690A7AC1.996856090/mail.example.com'),
4130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('report-type', old_val)])
4140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_del_param_on_other_header(self):
4160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')
4180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.del_param('filename', 'content-disposition')
4190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg['content-disposition'], 'attachment')
4200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_type(self):
4220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
4230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(ValueError, msg.set_type, 'text')
4250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_type('text/plain')
4260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain')
4270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('charset', 'us-ascii')
4280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
4290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_type('text/html')
4300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/html; charset="us-ascii"')
4310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_type_on_other_header(self):
4330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['X-Content-Type'] = 'text/plain'
4350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_type('application/octet-stream', 'X-Content-Type')
4360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg['x-content-type'], 'application/octet-stream')
4370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_missing(self):
4390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_type(), 'text/plain')
4410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_missing_with_default_type(self):
4430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_default_type('message/rfc822')
4450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_type(), 'message/rfc822')
4460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_from_message_implicit(self):
4480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_30.txt')
4490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_type(),
4500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'message/rfc822')
4510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_from_message_explicit(self):
4530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_28.txt')
4540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_type(),
4550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'message/rfc822')
4560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_from_message_text_plain_implicit(self):
4580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_03.txt')
4590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_type(), 'text/plain')
4600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_type_from_message_text_plain_explicit(self):
4620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
4630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_type(), 'text/plain')
4640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_missing(self):
4660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_maintype(), 'text')
4680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_missing_with_default_type(self):
4700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_default_type('message/rfc822')
4720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_maintype(), 'message')
4730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_from_message_implicit(self):
4750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_30.txt')
4760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
4770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_from_message_explicit(self):
4790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_28.txt')
4800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
4810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_from_message_text_plain_implicit(self):
4830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_03.txt')
4840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_maintype(), 'text')
4850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_from_message_text_plain_explicit(self):
4870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
4880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_maintype(), 'text')
4890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_missing(self):
4910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_subtype(), 'plain')
4930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_missing_with_default_type(self):
4950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
4960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_default_type('message/rfc822')
4970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_subtype(), 'rfc822')
4980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_from_message_implicit(self):
5000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_30.txt')
5010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
5020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_from_message_explicit(self):
5040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_28.txt')
5050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
5060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_from_message_text_plain_implicit(self):
5080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_03.txt')
5090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_subtype(), 'plain')
5100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_from_message_text_plain_explicit(self):
5120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
5130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_subtype(), 'plain')
5140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_maintype_error(self):
5160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'no-slash-in-this-string'
5180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_maintype(), 'text')
5190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_subtype_error(self):
5210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'no-slash-in-this-string'
5230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_subtype(), 'plain')
5240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_replace_header(self):
5260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
5270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('First', 'One')
5290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Second', 'Two')
5300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Third', 'Three')
5310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.keys(), ['First', 'Second', 'Third'])
5320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.values(), ['One', 'Two', 'Three'])
5330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.replace_header('Second', 'Twenty')
5340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.keys(), ['First', 'Second', 'Third'])
5350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.values(), ['One', 'Twenty', 'Three'])
5360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('First', 'Eleven')
5370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.replace_header('First', 'One Hundred')
5380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.keys(), ['First', 'Second', 'Third', 'First'])
5390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.values(), ['One Hundred', 'Twenty', 'Three', 'Eleven'])
5400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(KeyError, msg.replace_header, 'Fourth', 'Missing')
5410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_broken_base64_payload(self):
5430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x = 'AwDp0P7//y6LwKEAcPa/6Q=9'
5440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['content-type'] = 'audio/x-midi'
5460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['content-transfer-encoding'] = 'base64'
5470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload(x)
5480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_payload(decode=True), x)
5490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_content_charset(self):
5510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset('us-ascii')
5530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual('us-ascii', msg.get_content_charset())
5540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset(u'us-ascii')
5550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual('us-ascii', msg.get_content_charset())
5560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Issue 5871: reject an attempt to embed a header inside a header value
5580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # (header injection attack).
5590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_embeded_header_via_Header_rejected(self):
5600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Dummy'] = Header('dummy\nX-Injected-Header: test')
5620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(Errors.HeaderParseError, msg.as_string)
5630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_embeded_header_via_string_rejected(self):
5650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Dummy'] = 'dummy\nX-Injected-Header: test'
5670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(Errors.HeaderParseError, msg.as_string)
5680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the email.Encoders module
5710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestEncoders(unittest.TestCase):
5720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encode_empty_payload(self):
5730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
5740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
5750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_charset('us-ascii')
5760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], '7bit')
5770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_default_cte(self):
5790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
5800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # 7bit data and the default us-ascii _charset
5810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
5820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], '7bit')
5830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Similar, but with 8bit data
5840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello \xf8 world')
5850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], '8bit')
5860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # And now with a different charset
5870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello \xf8 world', _charset='iso-8859-1')
5880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], 'quoted-printable')
5890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encode7or8bit(self):
5910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make sure a charset whose input character set is 8bit but
5920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # whose output character set is 7bit gets a transfer-encoding
5930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # of 7bit.
5940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
5950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.MIMEText.MIMEText('\xca\xb8', _charset='euc-jp')
5960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], '7bit')
5970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test long header wrapping
6000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestLongHeaders(TestEmailBase):
6010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_split_long_continuation(self):
6020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
6030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("""\
6040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: bug demonstration
6050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
6060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tmore text
6070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitest
6090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
6100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
6110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(sfp)
6120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
6130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
6140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: bug demonstration
6150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
6160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi more text
6170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitest
6190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
6200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_another_long_almost_unsplittable_header(self):
6220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
6230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hstr = """\
6240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yibug demonstration
6250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
6260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tmore text"""
6270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, continuation_ws='\t')
6280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
6290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yibug demonstration
6300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
6310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tmore text""")
6320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr)
6330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
6340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yibug demonstration
6350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
6360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi more text""")
6370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_nonstring(self):
6390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
6400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Charset("iso-8859-1")
6410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cz = Charset("iso-8859-2")
6420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        utf8 = Charset("utf-8")
6430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g_head = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
6440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
6450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        utf8_head = u"\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066\u3044\u307e\u3059\u3002".encode("utf-8")
6460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(g_head, g, header_name='Subject')
6470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(cz_head, cz)
6480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(utf8_head, utf8)
6490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
6500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Subject'] = h
6510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
6520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(sfp)
6530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
6540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
6550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
6560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
6570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
6580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
6590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
6600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
6610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
6620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
6630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
6640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
6650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44Gm44GE44G+44GZ44CC?=
6660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
6680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
6690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
6700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
6710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
6720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
6730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
6740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
6750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
6760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
6770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
6780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
6790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44Gm44GE44G+44GZ44CC?=""")
6800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_header_encode(self):
6820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
6830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
6840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
6850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   header_name='X-Foobar-Spoink-Defrobnit')
6860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '''\
6870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwasnipoop; giraffes="very-long-necked-animals";
6880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
6890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_header_encode_with_tab_continuation(self):
6910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
6920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
6930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
6940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   header_name='X-Foobar-Spoink-Defrobnit',
6950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   continuation_ws='\t')
6960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '''\
6970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiwasnipoop; giraffes="very-long-necked-animals";
6980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tspooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
6990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_splitter(self):
7010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('')
7030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # It'd be great if we could use add_header() here, but that doesn't
7040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # guarantee an order of the parameters.
7050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['X-Foobar-Spoink-Defrobnit'] = (
7060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'wasnipoop; giraffes="very-long-necked-animals"; '
7070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"')
7080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
7090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(sfp)
7100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
7110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), '''\
7120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
7130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
7140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
7150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiX-Foobar-Spoink-Defrobnit: wasnipoop; giraffes="very-long-necked-animals";
7160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"
7170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
7190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_semis_header_splitter(self):
7210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
7230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['From'] = 'test@dom.ain'
7240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['References'] = SPACE.join(['<%d@dom.ain>' % i for i in range(10)])
7250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('Test')
7260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
7270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(sfp)
7280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
7290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
7300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: test@dom.ain
7310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReferences: <0@dom.ain> <1@dom.ain> <2@dom.ain> <3@dom.ain> <4@dom.ain>
7320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi <5@dom.ain> <6@dom.ain> <7@dom.ain> <8@dom.ain> <9@dom.ain>
7330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTest""")
7350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_split_long_header(self):
7370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hstr = 'References: ' + 'x' * 80
7390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, continuation_ws='\t')
7400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
7410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReferences: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""")
7420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_splitting_multiple_long_lines(self):
7440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hstr = """\
7460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
7470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfrom babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
7480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfrom babylon.socal-raves.org (localhost [127.0.0.1]); by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; for <mailman-admin@babylon.socal-raves.org>; Sat, 2 Feb 2002 17:00:06 -0800 (PST)
7490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
7500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, continuation_ws='\t')
7510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
7520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom babylon.socal-raves.org (localhost [127.0.0.1]);
7530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
7540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfor <mailman-admin@babylon.socal-raves.org>;
7550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tSat, 2 Feb 2002 17:00:06 -0800 (PST)
7560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
7570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
7580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfor <mailman-admin@babylon.socal-raves.org>;
7590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tSat, 2 Feb 2002 17:00:06 -0800 (PST)
7600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
7610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
7620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfor <mailman-admin@babylon.socal-raves.org>;
7630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tSat, 2 Feb 2002 17:00:06 -0800 (PST)""")
7640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_splitting_first_line_only_is_long(self):
7660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hstr = """\
7680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93] helo=cthulhu.gerg.ca)
7690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tby kronos.mems-exchange.org with esmtp (Exim 4.05)
7700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tid 17k4h5-00034i-00
7710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400"""
7720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, maxlinelen=78, header_name='Received',
7730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   continuation_ws='\t')
7740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
7750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93]
7760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\thelo=cthulhu.gerg.ca)
7770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tby kronos.mems-exchange.org with esmtp (Exim 4.05)
7780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tid 17k4h5-00034i-00
7790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400""")
7800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_8bit_header(self):
7820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
7840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header('Britische Regierung gibt', 'iso-8859-1',
7850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    header_name='Subject')
7860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte')
7870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Subject'] = h
7880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
7890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: =?iso-8859-1?q?Britische_Regierung_gibt?= =?iso-8859-1?q?gr=FCnes?=
7900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?_Licht_f=FCr_Offshore-Windkraftprojekte?=
7910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
7930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_8bit_header_no_charset(self):
7950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
7960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
7970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Reply-To'] = 'Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>'
7980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
7990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReply-To: Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>
8000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
8020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_to_header(self):
8040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        to = '"Someone Test #A" <someone@eecs.umich.edu>,<someone@eecs.umich.edu>,"Someone Test #B" <someone@umich.edu>, "Someone Test #C" <someone@eecs.umich.edu>, "Someone Test #D" <someone@eecs.umich.edu>'
8060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
8070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['To'] = to
8080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(0), '''\
8090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: "Someone Test #A" <someone@eecs.umich.edu>, <someone@eecs.umich.edu>,
8100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi "Someone Test #B" <someone@umich.edu>,
8110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi "Someone Test #C" <someone@eecs.umich.edu>,
8120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi "Someone Test #D" <someone@eecs.umich.edu>
8130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
8150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_line_after_append(self):
8170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'This is an example of string which has almost the limit of header length.'
8190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(s)
8200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('Add another line.')
8210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
8220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThis is an example of string which has almost the limit of header length.
8230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi Add another line.""")
8240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_shorter_line_with_append(self):
8260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'This is a shorter line.'
8280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(s)
8290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('Add another sentence. (Surprise?)')
8300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(),
8310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'This is a shorter line. Add another sentence. (Surprise?)')
8320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_field_name(self):
8340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fn = 'X-Very-Very-Very-Long-Header-Name'
8360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gs = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
8370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(gs, 'iso-8859-1', header_name=fn)
8380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # BAW: this seems broken because the first line is too long
8390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), """\
8400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?q?Die_Mieter_treten_hier_?=
8410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?ein_werden_mit_einem_Foerderband_komfortabel_den_Korridor_?=
8420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?entlang=2C_an_s=FCdl=FCndischen_Wandgem=E4lden_vorbei=2C_g?=
8430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?egen_die_rotierenden_Klingen_bef=F6rdert=2E_?=""")
8440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_received_header(self):
8460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = 'from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; Wed, 05 Mar 2003 18:10:18 -0700'
8470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
8480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Received-1'] = Header(h, continuation_ws='\t')
8490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Received-2'] = h
8500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.as_string(), """\
8510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
8520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\throthgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
8530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tWed, 05 Mar 2003 18:10:18 -0700
8540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
8550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
8560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi Wed, 05 Mar 2003 18:10:18 -0700
8570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
8590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_string_headerinst_eq(self):
8610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = '<15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner\'s message of "Thu, 6 Mar 2003 13:58:21 +0100")'
8620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
8630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Received'] = Header(h, header_name='Received',
8640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                 continuation_ws='\t')
8650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Received'] = h
8660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.ndiffAssertEqual(msg.as_string(), """\
8670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
8680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\t(David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
8690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
8700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi (David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
8710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
8730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_unbreakable_lines_with_continuation(self):
8750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
8770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t = """\
8780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
8790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp"""
8800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Face-1'] = t
8810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Face-2'] = Header(t, header_name='Face-2')
8820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
8830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFace-1: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
8840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
8850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFace-2: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
8860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
8870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
8890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_another_long_multiline_header(self):
8910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
8920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
8930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with Microsoft SMTPSVC(5.0.2195.4905);
8940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi Wed, 16 Oct 2002 07:41:11 -0700'''
8950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
8960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), '''\
8970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with
8980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi Microsoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700
8990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
9010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_lines_with_different_header(self):
9030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
9040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = """\
9050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiList-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
9060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>"""
9070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
9080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['List'] = h
9090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['List'] = Header(h, header_name='List')
9100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
9110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiList: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
9120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
9130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiList: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
9140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
9150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
9170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test mangling of "From " lines in the body of a message
9210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestFromMangling(unittest.TestCase):
9220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
9230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.msg = Message()
9240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.msg['From'] = 'aaa@bbb.org'
9250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.msg.set_payload("""\
9260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom the desk of A.A.A.:
9270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiBlah blah blah
9280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
9290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_mangled_from(self):
9310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
9320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s, mangle_from_=True)
9330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(self.msg)
9340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.getvalue(), """\
9350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aaa@bbb.org
9360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi>From the desk of A.A.A.:
9380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiBlah blah blah
9390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
9400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_dont_mangle_from(self):
9420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
9430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s, mangle_from_=False)
9440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(self.msg)
9450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.getvalue(), """\
9460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aaa@bbb.org
9470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom the desk of A.A.A.:
9490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiBlah blah blah
9500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
9510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_mangle_from_in_preamble_and_epilog(self):
9530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
9540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s, mangle_from_=True)
9550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(textwrap.dedent("""\
9560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            From: foo@bar.com
9570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Mime-Version: 1.0
9580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Content-Type: multipart/mixed; boundary=XXX
9590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            From somewhere unknown
9610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            --XXX
9630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Content-Type: text/plain
9640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            foo
9660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            --XXX--
9680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            From somewhere unknowable
9700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            """))
9710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
9720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len([1 for x in s.getvalue().split('\n')
9730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                  if x.startswith('>From ')]), 2)
9740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the basic MIMEAudio class
9770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMIMEAudio(unittest.TestCase):
9780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
9790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make sure we pick up the audiotest.au that lives in email/test/data.
9800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # In Python, there's an audiotest.au living in Lib/test but that isn't
9810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # included in some binary distros that don't include the test
9820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # package.  The trailing empty string on the .join() is significant
9830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # since findfile() will do a dirname().
9840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        datadir = os.path.join(os.path.dirname(landmark), 'data', '')
9850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = open(findfile('audiotest.au', datadir), 'rb')
9860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
9870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._audiodata = fp.read()
9880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
9890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
9900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._au = MIMEAudio(self._audiodata)
9910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_guess_minor_type(self):
9930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(self._au.get_content_type(), 'audio/basic')
9940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encoding(self):
9960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = self._au.get_payload()
9970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(base64.decodestring(payload), self._audiodata)
9980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_checkSetMinor(self):
10000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        au = MIMEAudio(self._audiodata, 'fish')
10010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(au.get_content_type(), 'audio/fish')
10020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_add_header(self):
10040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
10050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
10060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._au.add_header('Content-Disposition', 'attachment',
10070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                            filename='audiotest.au')
10080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._au['content-disposition'],
10090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'attachment; filename="audiotest.au"')
10100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._au.get_params(header='content-disposition'),
10110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('attachment', ''), ('filename', 'audiotest.au')])
10120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._au.get_param('filename', header='content-disposition'),
10130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'audiotest.au')
10140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        missing = []
10150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._au.get_param('attachment', header='content-disposition'), '')
10160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._au.get_param('foo', failobj=missing,
10170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                  header='content-disposition') is missing)
10180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try some missing stuff
10190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._au.get_param('foobar', missing) is missing)
10200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._au.get_param('attachment', missing,
10210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                  header='foobar') is missing)
10220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the basic MIMEImage class
10260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMIMEImage(unittest.TestCase):
10270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
10280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('PyBanner048.gif')
10290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
10300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._imgdata = fp.read()
10310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
10320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
10330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._im = MIMEImage(self._imgdata)
10340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_guess_minor_type(self):
10360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(self._im.get_content_type(), 'image/gif')
10370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encoding(self):
10390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = self._im.get_payload()
10400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(base64.decodestring(payload), self._imgdata)
10410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_checkSetMinor(self):
10430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        im = MIMEImage(self._imgdata, 'fish')
10440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(im.get_content_type(), 'image/fish')
10450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_add_header(self):
10470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
10480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
10490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._im.add_header('Content-Disposition', 'attachment',
10500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                            filename='dingusfish.gif')
10510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._im['content-disposition'],
10520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'attachment; filename="dingusfish.gif"')
10530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._im.get_params(header='content-disposition'),
10540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('attachment', ''), ('filename', 'dingusfish.gif')])
10550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._im.get_param('filename', header='content-disposition'),
10560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'dingusfish.gif')
10570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        missing = []
10580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._im.get_param('attachment', header='content-disposition'), '')
10590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._im.get_param('foo', failobj=missing,
10600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                  header='content-disposition') is missing)
10610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try some missing stuff
10620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._im.get_param('foobar', missing) is missing)
10630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._im.get_param('attachment', missing,
10640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                  header='foobar') is missing)
10650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the basic MIMEText class
10690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMIMEText(unittest.TestCase):
10700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
10710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._msg = MIMEText('hello there')
10720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_types(self):
10740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
10750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
10760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._msg.get_content_type(), 'text/plain')
10770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(self._msg.get_param('charset'), 'us-ascii')
10780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        missing = []
10790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._msg.get_param('foobar', missing) is missing)
10800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(self._msg.get_param('charset', missing, header='foobar')
10810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               is missing)
10820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_payload(self):
10840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(self._msg.get_payload(), 'hello there')
10850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(not self._msg.is_multipart())
10860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_charset(self):
10880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
10890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello there', _charset='us-ascii')
10900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset().input_charset, 'us-ascii')
10910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
10920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_7bit_unicode_input(self):
10940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
10950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText(u'hello there', _charset='us-ascii')
10960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset().input_charset, 'us-ascii')
10970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
10980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_7bit_unicode_input_no_charset(self):
11000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
11010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText(u'hello there')
11020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset(), 'us-ascii')
11030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
11040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue('hello there' in msg.as_string())
11050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_8bit_unicode_input(self):
11070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        teststr = u'\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430'
11080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
11090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText(teststr, _charset='utf-8')
11100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_charset().output_charset, 'utf-8')
11110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset="utf-8"')
11120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(decode=True), teststr.encode('utf-8'))
11130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_8bit_unicode_input_no_charset(self):
11150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        teststr = u'\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430'
11160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(UnicodeEncodeError, MIMEText, teststr)
11170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test complicated multipart/* messages
11210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMultipart(TestEmailBase):
11220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
11230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('PyBanner048.gif')
11240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
11250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data = fp.read()
11260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
11270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
11280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY')
11300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        image = MIMEImage(data, name='dingusfish.gif')
11310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        image.add_header('content-disposition', 'attachment',
11320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         filename='dingusfish.gif')
11330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        intro = MIMEText('''\
11340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHi there,
11350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThis is the dingus fish.
11370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
11380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container.attach(intro)
11390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container.attach(image)
11400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container['From'] = 'Barry <barry@digicool.com>'
11410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>'
11420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container['Subject'] = 'Here is your dingus fish'
11430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        now = 987809702.54848599
11450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        timetuple = time.localtime(now)
11460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if timetuple[-1] == 0:
11470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            tzsecs = time.timezone
11480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
11490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            tzsecs = time.altzone
11500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if tzsecs > 0:
11510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sign = '-'
11520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
11530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sign = '+'
11540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        tzoffset = ' %s%04d' % (sign, tzsecs // 36)
11550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container['Date'] = time.strftime(
11560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            '%a, %d %b %Y %H:%M:%S',
11570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            time.localtime(now)) + tzoffset
11580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._msg = container
11590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._im = image
11600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._txt = intro
11610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_hierarchy(self):
11630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # convenience
11640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
11650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
11660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises = self.assertRaises
11670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # tests
11680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = self._msg
11690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(m.is_multipart())
11700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(m.get_content_type(), 'multipart/mixed')
11710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(m.get_payload()), 2)
11720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises(IndexError, m.get_payload, 2)
11730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m0 = m.get_payload(0)
11740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m1 = m.get_payload(1)
11750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(m0 is self._txt)
11760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(m1 is self._im)
11770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(m.get_payload(), [m0, m1])
11780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(not m0.is_multipart())
11790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(not m1.is_multipart())
11800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_empty_multipart_idempotent(self):
11820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text = """\
11830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
11840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
11850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
11860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
11870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
11880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
11910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
11940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
11950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Parser().parsestr(text)
11960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.ndiffAssertEqual(text, msg.as_string())
11970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_parts_in_a_multipart_with_none_epilogue(self):
11990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
12000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
12010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
12020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
12030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
12040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.ndiffAssertEqual(outer.as_string(), '''\
12050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
12060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
12080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
12090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
12100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
12120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--''')
12140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_parts_in_a_multipart_with_empty_epilogue(self):
12160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
12170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
12180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
12190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
12200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.preamble = ''
12210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.epilogue = ''
12220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
12230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.ndiffAssertEqual(outer.as_string(), '''\
12240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
12250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
12270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
12280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
12290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
12320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
12340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
12350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_one_part_in_a_multipart(self):
12370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
12380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
12390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
12400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
12410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
12420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
12430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
12440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
12450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
12460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
12470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
12490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
12500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
12510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
12530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
12540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
12560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
12580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--''')
12590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_seq_parts_in_a_multipart_with_empty_preamble(self):
12610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
12620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
12630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
12640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
12650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
12660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.preamble = ''
12670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
12680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
12690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
12700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
12710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
12720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
12740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
12750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
12760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
12790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
12800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
12810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
12820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
12840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--''')
12850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_seq_parts_in_a_multipart_with_none_preamble(self):
12880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
12890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
12900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
12910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
12920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
12930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.preamble = None
12940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
12950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
12960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
12970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
12980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
12990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
13010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
13020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
13030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
13050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
13060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
13080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
13100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--''')
13110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_seq_parts_in_a_multipart_with_none_epilogue(self):
13140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
13150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
13160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
13170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
13180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
13190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.epilogue = None
13200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
13210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
13220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
13230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
13240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
13250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
13270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
13280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
13290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
13310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
13320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
13340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
13360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--''')
13370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_seq_parts_in_a_multipart_with_empty_epilogue(self):
13400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
13410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
13420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
13430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
13440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
13450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.epilogue = ''
13460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
13470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
13480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
13490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
13500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
13510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
13530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
13540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
13550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
13570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
13580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
13600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
13620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
13630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
13640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_seq_parts_in_a_multipart_with_nl_epilogue(self):
13670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
13680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = MIMEBase('multipart', 'mixed')
13690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['Subject'] = 'A subject'
13700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['To'] = 'aperson@dom.ain'
13710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer['From'] = 'bperson@dom.ain'
13720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.epilogue = '\n'
13730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEText('hello world')
13740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.attach(msg)
13750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer.set_boundary('BOUNDARY')
13760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(outer.as_string(), '''\
13770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
13780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: A subject
13800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: aperson@dom.ain
13810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bperson@dom.ain
13820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
13840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
13850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
13860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
13870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yihello world
13890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
13900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
13920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_external_body(self):
13940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
13950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_36.txt')
13960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 2)
13970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = msg.get_payload(1)
13980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg1.get_content_type(), 'multipart/alternative')
13990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg1.get_payload()), 2)
14000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for subpart in msg1.get_payload():
14010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(subpart.get_content_type(), 'message/external-body')
14020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(len(subpart.get_payload()), 1)
14030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            subsubpart = subpart.get_payload(0)
14040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(subsubpart.get_content_type(), 'text/plain')
14050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_double_boundary(self):
14070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg_37.txt is a multipart that contains two dash-boundary's in a
14080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # row.  Our interpretation of RFC 2046 calls for ignoring the second
14090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # and subsequent boundaries.
14100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_37.txt')
14110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(msg.get_payload()), 3)
14120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_nested_inner_contains_outer_boundary(self):
14140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
14150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg_38.txt has an inner part that contains outer boundaries.  My
14160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # interpretation of RFC 2046 (based on sections 5.1 and 5.1.2) say
14170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # these are illegal and should be interpreted as unterminated inner
14180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # parts.
14190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_38.txt')
14200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
14210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Iterators._structure(msg, sfp)
14220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
14230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimultipart/mixed
14240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multipart/mixed
14250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        multipart/alternative
14260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text/plain
14270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
14280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    text/plain
14290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    text/plain
14300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
14310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_nested_with_same_boundary(self):
14330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
14340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg 39.txt is similarly evil in that it's got inner parts that use
14350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # the same boundary as outer parts.  Again, I believe the way this is
14360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # parsed is closest to the spirit of RFC 2046
14370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_39.txt')
14380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
14390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Iterators._structure(msg, sfp)
14400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
14410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimultipart/mixed
14420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multipart/mixed
14430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        multipart/alternative
14440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        application/octet-stream
14450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        application/octet-stream
14460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    text/plain
14470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
14480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boundary_in_non_multipart(self):
14500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_40.txt')
14510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.as_string(), '''\
14520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
14530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/html; boundary="--961284236552522269"
14540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi----961284236552522269
14560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/html;
14570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7Bit
14580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi<html></html>
14600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi----961284236552522269--
14620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
14630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boundary_with_leading_space(self):
14650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
14660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string('''\
14670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
14680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="    XXXX"
14690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--    XXXX
14710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain
14720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--    XXXX
14750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain
14760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--    XXXX--
14780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
14790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.is_multipart())
14800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_boundary(), '    XXXX')
14810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 2)
14820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boundary_without_trailing_newline(self):
14840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = Parser().parsestr("""\
14850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="===============0012394164=="
14860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
14870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--===============0012394164==
14890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: image/file1.jpg
14900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
14910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: base64
14920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiYXNkZg==
14940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--===============0012394164==--""")
14950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(m.get_payload(0).get_payload(), 'YXNkZg==')
14960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test some badly formatted messages
15000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestNonConformant(TestEmailBase):
15010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parse_missing_minor_type(self):
15020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
15030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_14.txt')
15040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
15050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_maintype(), 'text')
15060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_subtype(), 'plain')
15070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_same_boundary_inner_outer(self):
15090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
15100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_15.txt')
15110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # XXX We can probably eventually do better
15120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        inner = msg.get_payload(0)
15130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(hasattr(inner, 'defects'))
15140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(inner.defects), 1)
15150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(inner.defects[0],
15160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                          Errors.StartBoundaryNotFoundDefect))
15170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multipart_no_boundary(self):
15190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
15200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_25.txt')
15210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg.get_payload(), str))
15220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(msg.defects), 2)
15230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect))
15240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg.defects[1],
15250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                          Errors.MultipartInvariantViolationDefect))
15260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_invalid_content_type(self):
15280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
15290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq = self.ndiffAssertEqual
15300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
15310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # RFC 2045, $5.2 says invalid yields text/plain
15320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'text'
15330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_maintype(), 'text')
15340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_subtype(), 'plain')
15350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
15360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Clear the old value and try something /really/ invalid
15370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del msg['content-type']
15380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'foo'
15390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_maintype(), 'text')
15400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_subtype(), 'plain')
15410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
15420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Still, make sure that the message is idempotently generated
15430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
15440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s)
15450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
15460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(s.getvalue(), 'Content-Type: foo\n\n')
15470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_start_boundary(self):
15490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
15500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_31.txt')
15510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), """\
15520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
15530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain
15540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 1
15560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
15580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain
15590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 2
15610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
15630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
15640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_separating_blank_line(self):
15660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
15670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_35.txt')
15680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
15690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aperson@dom.ain
15700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bperson@dom.ain
15710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: here's something interesting
15720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yicounter to RFC 2822, there's no separating newline here
15740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
15750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_lying_multipart(self):
15770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
15780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_41.txt')
15790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(hasattr(msg, 'defects'))
15800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(msg.defects), 2)
15810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect))
15820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg.defects[1],
15830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                          Errors.MultipartInvariantViolationDefect))
15840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_missing_start_boundary(self):
15860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outer = self._msgobj('msg_42.txt')
15870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # The message structure is:
15880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
15890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # multipart/mixed
15900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #    text/plain
15910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #    message/rfc822
15920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #        multipart/mixed [*]
15930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
15940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # [*] This message is missing its start boundary
15950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        bad = outer.get_payload(1).get_payload(0)
15960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(bad.defects), 1)
15970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(bad.defects[0],
15980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                   Errors.StartBoundaryNotFoundDefect))
15990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_first_line_is_continuation_header(self):
16010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
16020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = ' Line 1\nLine 2\nLine 3'
16030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
16040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.keys(), [])
16050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), 'Line 2\nLine 3')
16060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.defects), 1)
16070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(msg.defects[0],
16080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                   Errors.FirstHeaderLineIsContinuationDefect))
16090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.defects[0].line, ' Line 1\n')
16100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test RFC 2047 header encoding and decoding
16150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestRFC2047(unittest.TestCase):
16160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2047_multiline(self):
16170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
16180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz
16190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi foo bar =?mac-iceland?q?r=8Aksm=9Arg=8Cs?="""
16200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dh = decode_header(s)
16210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dh, [
16220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('Re:', None),
16230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('r\x8aksm\x9arg\x8cs', 'mac-iceland'),
16240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('baz foo bar', None),
16250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('r\x8aksm\x9arg\x8cs', 'mac-iceland')])
16260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(str(make_header(dh)),
16270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz foo bar
16280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?mac-iceland?q?r=8Aksm=9Arg=8Cs?=""")
16290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_whitespace_eater_unicode(self):
16310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
16320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = '=?ISO-8859-1?Q?Andr=E9?= Pirard <pirard@dom.ain>'
16330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dh = decode_header(s)
16340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dh, [('Andr\xe9', 'iso-8859-1'), ('Pirard <pirard@dom.ain>', None)])
16350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hu = unicode(make_header(dh)).encode('latin-1')
16360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(hu, 'Andr\xe9 Pirard <pirard@dom.ain>')
16370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_whitespace_eater_unicode_2(self):
16390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
16400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'The =?iso-8859-1?b?cXVpY2sgYnJvd24gZm94?= jumped over the =?iso-8859-1?b?bGF6eSBkb2c=?='
16410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dh = decode_header(s)
16420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dh, [('The', None), ('quick brown fox', 'iso-8859-1'),
16430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ('jumped over the', None), ('lazy dog', 'iso-8859-1')])
16440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hu = make_header(dh).__unicode__()
16450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(hu, u'The quick brown fox jumped over the lazy dog')
16460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2047_without_whitespace(self):
16480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'Sm=?ISO-8859-1?B?9g==?=rg=?ISO-8859-1?B?5Q==?=sbord'
16490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dh = decode_header(s)
16500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(dh, [(s, None)])
16510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2047_with_whitespace(self):
16530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'Sm =?ISO-8859-1?B?9g==?= rg =?ISO-8859-1?B?5Q==?= sbord'
16540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dh = decode_header(s)
16550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(dh, [('Sm', None), ('\xf6', 'iso-8859-1'),
16560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                              ('rg', None), ('\xe5', 'iso-8859-1'),
16570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                              ('sbord', None)])
16580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2047_B_bad_padding(self):
16600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = '=?iso-8859-1?B?%s?='
16610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        data = [                                # only test complete bytes
16620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('dm==', 'v'), ('dm=', 'v'), ('dm', 'v'),
16630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('dmk=', 'vi'), ('dmk', 'vi')
16640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          ]
16650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for q, a in data:
16660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dh = decode_header(s % q)
16670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(dh, [(a, 'iso-8859-1')])
16680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2047_Q_invalid_digits(self):
16700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # issue 10004.
16710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = '=?iso-8659-1?Q?andr=e9=zz?='
16720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(decode_header(s),
16730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        [(b'andr\xe9=zz', 'iso-8659-1')])
16740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the MIMEMessage class
16770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMIMEMessage(TestEmailBase):
16780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
16790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_11.txt')
16800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
16810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._text = fp.read()
16820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
16830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
16840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_type_error(self):
16860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(TypeError, MIMEMessage, 'a plain string')
16870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_valid_argument(self):
16890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
16900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
16910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subject = 'A sub-message'
16920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = Message()
16930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m['Subject'] = subject
16940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        r = MIMEMessage(m)
16950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(r.get_content_type(), 'message/rfc822')
16960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = r.get_payload()
16970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(payload, list))
16980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(payload), 1)
16990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart = payload[0]
17000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(subpart is m)
17010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart['subject'], subject)
17020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bad_multipart(self):
17040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
17050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = Message()
17060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1['Subject'] = 'subpart 1'
17070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg2 = Message()
17080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg2['Subject'] = 'subpart 2'
17090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        r = MIMEMessage(msg1)
17100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(Errors.MultipartConversionError, r.attach, msg2)
17110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_generate(self):
17130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # First craft the message to be encapsulated
17140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = Message()
17150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m['Subject'] = 'An enclosed message'
17160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m.set_payload('Here is the body of the message.\n')
17170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        r = MIMEMessage(m)
17180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        r['Subject'] = 'The enclosing message'
17190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
17200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s)
17210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(r)
17220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(s.getvalue(), """\
17230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: message/rfc822
17240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
17250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: The enclosing message
17260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: An enclosed message
17280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHere is the body of the message.
17300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
17310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parse_message_rfc822(self):
17330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
17340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
17350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_11.txt')
17360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'message/rfc822')
17370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = msg.get_payload()
17380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(payload, list))
17390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(payload), 1)
17400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        submsg = payload[0]
17410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(submsg, Message))
17420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(submsg['subject'], 'An enclosed message')
17430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(submsg.get_payload(), 'Here is the body of the message.\n')
17440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_dsn(self):
17460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
17470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
17480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # msg 16 is a Delivery Status Notification, see RFC 1894
17490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_16.txt')
17500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'multipart/report')
17510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(msg.is_multipart())
17520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 3)
17530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 1 is a text/plain, human readable section
17540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart = msg.get_payload(0)
17550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart.get_content_type(), 'text/plain')
17560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart.get_payload(), """\
17570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThis report relates to a message you sent with the following header fields:
17580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Message-id: <002001c144a6$8752e060$56104586@oxy.edu>
17600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Date: Sun, 23 Sep 2001 20:10:55 -0700
17610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  From: "Ian T. Henry" <henryi@oxy.edu>
17620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  To: SoCal Raves <scr@socal-raves.org>
17630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Subject: [scr] yeah for Ians!!
17640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiYour message cannot be delivered to the following recipients:
17660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Recipient address: jangel1@cougar.noc.ucla.edu
17680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Reason: recipient reached disk quota
17690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
17700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
17710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 2 contains the machine parsable DSN information.  It
17720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # consists of two blocks of headers, represented by two nested Message
17730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # objects.
17740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart = msg.get_payload(1)
17750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart.get_content_type(), 'message/delivery-status')
17760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(subpart.get_payload()), 2)
17770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # message/delivery-status should treat each block as a bunch of
17780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # headers, i.e. a bunch of Message objects.
17790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dsn1 = subpart.get_payload(0)
17800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(dsn1, Message))
17810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn1['original-envelope-id'], '0GK500B4HD0888@cougar.noc.ucla.edu')
17820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn1.get_param('dns', header='reporting-mta'), '')
17830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try a missing one <wink>
17840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn1.get_param('nsd', header='reporting-mta'), None)
17850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dsn2 = subpart.get_payload(1)
17860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(dsn2, Message))
17870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn2['action'], 'failed')
17880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn2.get_params(header='original-recipient'),
17890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('rfc822', ''), ('jangel1@cougar.noc.ucla.edu', '')])
17900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(dsn2.get_param('rfc822', header='final-recipient'), '')
17910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Subpart 3 is the original message
17920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart = msg.get_payload(2)
17930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart.get_content_type(), 'message/rfc822')
17940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = subpart.get_payload()
17950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(payload, list))
17960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(payload), 1)
17970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subsubpart = payload[0]
17980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(subsubpart, Message))
17990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subsubpart.get_content_type(), 'text/plain')
18000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subsubpart['message-id'],
18010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '<002001c144a6$8752e060$56104586@oxy.edu>')
18020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_epilogue(self):
18040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
18050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_21.txt')
18060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
18070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
18080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
18090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
18100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
18110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['From'] = 'aperson@dom.ain'
18120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['To'] = 'bperson@dom.ain'
18130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Subject'] = 'Test'
18140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.preamble = 'MIME message'
18150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.epilogue = 'End of MIME message\n'
18160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = MIMEText('One')
18170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg2 = MIMEText('Two')
18180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
18190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.attach(msg1)
18200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.attach(msg2)
18210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
18220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(sfp)
18230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
18240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), text)
18250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_nl_preamble(self):
18270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
18280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
18290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['From'] = 'aperson@dom.ain'
18300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['To'] = 'bperson@dom.ain'
18310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Subject'] = 'Test'
18320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.preamble = 'MIME message'
18330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.epilogue = ''
18340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = MIMEText('One')
18350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg2 = MIMEText('Two')
18360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
18370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.attach(msg1)
18380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.attach(msg2)
18390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
18400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aperson@dom.ain
18410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bperson@dom.ain
18420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: Test
18430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/mixed; boundary="BOUNDARY"
18440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME message
18460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
18470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
18480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
18490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
18500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiOne
18520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
18530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
18540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
18550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
18560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTwo
18580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
18590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
18600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_default_type(self):
18620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
18630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_30.txt')
18640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
18650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp)
18660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
18670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
18680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container1 = msg.get_payload(0)
18690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1.get_default_type(), 'message/rfc822')
18700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1.get_content_type(), 'message/rfc822')
18710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container2 = msg.get_payload(1)
18720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2.get_default_type(), 'message/rfc822')
18730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2.get_content_type(), 'message/rfc822')
18740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container1a = container1.get_payload(0)
18750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1a.get_default_type(), 'text/plain')
18760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1a.get_content_type(), 'text/plain')
18770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container2a = container2.get_payload(0)
18780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2a.get_default_type(), 'text/plain')
18790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2a.get_content_type(), 'text/plain')
18800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
18810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_default_type_with_explicit_container_type(self):
18820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
18830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_28.txt')
18840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
18850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp)
18860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
18870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
18880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container1 = msg.get_payload(0)
18890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1.get_default_type(), 'message/rfc822')
18900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1.get_content_type(), 'message/rfc822')
18910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container2 = msg.get_payload(1)
18920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2.get_default_type(), 'message/rfc822')
18930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2.get_content_type(), 'message/rfc822')
18940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container1a = container1.get_payload(0)
18950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1a.get_default_type(), 'text/plain')
18960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container1a.get_content_type(), 'text/plain')
18970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container2a = container2.get_payload(0)
18980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2a.get_default_type(), 'text/plain')
18990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(container2a.get_content_type(), 'text/plain')
19000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_default_type_non_parsed(self):
19020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
19030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq = self.ndiffAssertEqual
19040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Set up container
19050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container = MIMEMultipart('digest', 'BOUNDARY')
19060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container.epilogue = ''
19070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Set up subparts
19080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart1a = MIMEText('message 1\n')
19090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart2a = MIMEText('message 2\n')
19100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart1 = MIMEMessage(subpart1a)
19110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subpart2 = MIMEMessage(subpart2a)
19120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container.attach(subpart1)
19130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        container.attach(subpart2)
19140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart1.get_content_type(), 'message/rfc822')
19150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart1.get_default_type(), 'message/rfc822')
19160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart2.get_content_type(), 'message/rfc822')
19170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart2.get_default_type(), 'message/rfc822')
19180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(container.as_string(0), '''\
19190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/digest; boundary="BOUNDARY"
19200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
19230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: message/rfc822
19240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
19270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
19290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 1
19310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
19330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: message/rfc822
19340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
19370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
19390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 2
19410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
19430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
19440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del subpart1['content-type']
19450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del subpart1['mime-version']
19460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del subpart2['content-type']
19470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del subpart2['mime-version']
19480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart1.get_content_type(), 'message/rfc822')
19490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart1.get_default_type(), 'message/rfc822')
19500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart2.get_content_type(), 'message/rfc822')
19510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subpart2.get_default_type(), 'message/rfc822')
19520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(container.as_string(0), '''\
19530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/digest; boundary="BOUNDARY"
19540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
19570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
19590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
19610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 1
19630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY
19650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii"
19670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
19680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
19690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimessage 2
19710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi--BOUNDARY--
19730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi''')
19740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_mime_attachments_in_constructor(self):
19760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
19770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text1 = MIMEText('')
19780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text2 = MIMEText('')
19790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEMultipart(_subparts=(text1, text2))
19800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 2)
19810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(0), text1)
19820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(1), text2)
19830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_default_multipart_constructor(self):
19850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = MIMEMultipart()
19860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.is_multipart())
19870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
19890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# A general test of parser->model->generator idempotency.  IOW, read a message
19900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# in, parse it into a message object tree, then without touching the tree,
19910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# regenerate the plain text.  The original text and the transformed text
19920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# should be identical.  Note: that we ignore the Unix-From since that may
19930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# contain a changed date.
19940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestIdempotent(TestEmailBase):
19950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _msgobj(self, filename):
19960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile(filename)
19970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
19980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data = fp.read()
19990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
20000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
20010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(data)
20020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return msg, data
20030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _idempotent(self, msg, text):
20050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
20060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
20070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s, maxheaderlen=0)
20080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
20090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(text, s.getvalue())
20100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parse_text_message(self):
20120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
20130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_01.txt')
20140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
20150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_maintype(), 'text')
20160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_subtype(), 'plain')
20170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params()[1], ('charset', 'us-ascii'))
20180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('charset'), 'us-ascii')
20190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.preamble, None)
20200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.epilogue, None)
20210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parse_untyped_message(self):
20240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
20250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_03.txt')
20260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'text/plain')
20270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_params(), None)
20280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('charset'), None)
20290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_simple_multipart(self):
20320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_04.txt')
20330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_MIME_digest(self):
20360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_02.txt')
20370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_header(self):
20400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_27.txt')
20410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_MIME_digest_with_part_headers(self):
20440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_28.txt')
20450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_mixed_with_image(self):
20480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_06.txt')
20490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multipart_report(self):
20520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_05.txt')
20530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_dsn(self):
20560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_16.txt')
20570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_preamble_epilogue(self):
20600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_21.txt')
20610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multipart_one_part(self):
20640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_23.txt')
20650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multipart_no_parts(self):
20680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_24.txt')
20690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_no_start_boundary(self):
20720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_31.txt')
20730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_charset(self):
20760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_32.txt')
20770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_more_rfc2231_parameters(self):
20800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_33.txt')
20810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_text_plain_in_a_multipart_digest(self):
20840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_34.txt')
20850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_nested_multipart_mixeds(self):
20880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_12a.txt')
20890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_external_body_idempotent(self):
20920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_36.txt')
20930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._idempotent(msg, text)
20940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
20950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_content_type(self):
20960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
20970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
20980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Get a message object and reset the seek pointer for other tests
20990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_05.txt')
21000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'multipart/report')
21010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the Content-Type: parameters
21020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        params = {}
21030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for pk, pv in msg.get_params():
21040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            params[pk] = pv
21050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(params['report-type'], 'delivery-status')
21060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(params['boundary'], 'D1690A7AC1.996856090/mail.example.com')
21070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.preamble, 'This is a MIME-encapsulated message.\n')
21080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.epilogue, '\n')
21090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 3)
21100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make sure the subparts are what we expect
21110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = msg.get_payload(0)
21120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg1.get_content_type(), 'text/plain')
21130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg1.get_payload(), 'Yadda yadda yadda\n')
21140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg2 = msg.get_payload(1)
21150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg2.get_content_type(), 'text/plain')
21160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg2.get_payload(), 'Yadda yadda yadda\n')
21170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg3 = msg.get_payload(2)
21180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg3.get_content_type(), 'message/rfc822')
21190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(msg3, Message))
21200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = msg3.get_payload()
21210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(payload, list))
21220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(payload), 1)
21230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg4 = payload[0]
21240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg4, Message))
21250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg4.get_payload(), 'Yadda yadda yadda\n')
21260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parser(self):
21280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
21290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
21300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg, text = self._msgobj('msg_06.txt')
21310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check some of the outer headers
21320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'message/rfc822')
21330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make sure the payload is a list of exactly one sub-Message, and that
21340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # that submessage has a type of text/plain
21350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        payload = msg.get_payload()
21360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(payload, list))
21370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(payload), 1)
21380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg1 = payload[0]
21390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(msg1, Message))
21400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg1.get_content_type(), 'text/plain')
21410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(msg1.get_payload(), str))
21420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg1.get_payload(), '\n')
21430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test various other bits of the package's functionality
21470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestMiscellaneous(TestEmailBase):
21480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_from_string(self):
21490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_01.txt')
21500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
21510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
21520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
21530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
21540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(text)
21550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = StringIO()
21560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Don't wrap/continue long headers since we're trying to test
21570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # idempotency.
21580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Generator(s, maxheaderlen=0)
21590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g.flatten(msg)
21600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(text, s.getvalue())
21610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_from_file(self):
21630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_01.txt')
21640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
21650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
21660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.seek(0)
21670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp)
21680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            s = StringIO()
21690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # Don't wrap/continue long headers since we're trying to test
21700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # idempotency.
21710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            g = Generator(s, maxheaderlen=0)
21720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            g.flatten(msg)
21730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(text, s.getvalue())
21740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
21750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
21760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_from_string_with_class(self):
21780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
21790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_01.txt')
21800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
21810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
21820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
21830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
21840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Create a subclass
21850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class MyMessage(Message):
21860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
21870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
21880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(text, MyMessage)
21890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg, MyMessage))
21900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try something more complicated
21910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_02.txt')
21920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
21930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            text = fp.read()
21940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
21950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
21960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(text, MyMessage)
21970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for subpart in msg.walk():
21980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            unless(isinstance(subpart, MyMessage))
21990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_message_from_file_with_class(self):
22010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless = self.assertTrue
22020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Create a subclass
22030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class MyMessage(Message):
22040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
22050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_01.txt')
22070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
22080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp, MyMessage)
22090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
22100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
22110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        unless(isinstance(msg, MyMessage))
22120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try something more complicated
22130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_02.txt')
22140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
22150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp, MyMessage)
22160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
22170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
22180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for subpart in msg.walk():
22190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            unless(isinstance(subpart, MyMessage))
22200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test__all__(self):
22220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        module = __import__('email')
22230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        all = module.__all__
22240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        all.sort()
22250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(all, [
22260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # Old names
22270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'Charset', 'Encoders', 'Errors', 'Generator',
22280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'Header', 'Iterators', 'MIMEAudio', 'MIMEBase',
22290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'MIMEImage', 'MIMEMessage', 'MIMEMultipart',
22300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'MIMENonMultipart', 'MIMEText', 'Message',
22310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'Parser', 'Utils', 'base64MIME',
22320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # new names
22330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'base64mime', 'charset', 'encoders', 'errors', 'generator',
22340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'header', 'iterators', 'message', 'message_from_file',
22350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'message_from_string', 'mime', 'parser',
22360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'quopriMIME', 'quoprimime', 'utils',
22370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ])
22380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_formatdate(self):
22400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        now = time.time()
22410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parsedate(Utils.formatdate(now))[:6],
22420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         time.gmtime(now)[:6])
22430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_formatdate_localtime(self):
22450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        now = time.time()
22460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
22470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.parsedate(Utils.formatdate(now, localtime=True))[:6],
22480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            time.localtime(now)[:6])
22490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_formatdate_usegmt(self):
22510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        now = time.time()
22520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
22530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formatdate(now, localtime=False),
22540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            time.strftime('%a, %d %b %Y %H:%M:%S -0000', time.gmtime(now)))
22550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
22560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formatdate(now, localtime=False, usegmt=True),
22570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(now)))
22580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_none(self):
22600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parsedate(''), None)
22610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_compact(self):
22630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # The FWS after the comma is optional
22640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
22650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         Utils.parsedate('Wed, 3 Apr 2002 14:58:26 +0800'))
22660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_no_dayofweek(self):
22680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
22690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'),
22700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           (2003, 2, 25, 13, 47, 26, 0, 1, -1, -28800))
22710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_compact_no_dayofweek(self):
22730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
22740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
22750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
22760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_acceptable_to_time_functions(self):
22780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
22790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        timetup = Utils.parsedate('5 Feb 2003 13:47:26 -0800')
22800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t = int(time.mktime(timetup))
22810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(time.localtime(t)[:6], timetup[:6])
22820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(int(time.strftime('%Y', timetup)), 2003)
22830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        timetup = Utils.parsedate_tz('5 Feb 2003 13:47:26 -0800')
22840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t = int(time.mktime(timetup[:9]))
22850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(time.localtime(t)[:6], timetup[:6])
22860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(int(time.strftime('%Y', timetup[:9])), 2003)
22870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_mktime_tz(self):
22890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
22900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                          -1, -1, -1, 0)), 0)
22910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
22920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                                          -1, -1, -1, 1234)), -1234)
22930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parsedate_y2k(self):
22950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """Test for parsing a date with a two-digit year.
22960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
22970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Parsing a date with a two-digit year should return the correct
22980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        four-digit year. RFC822 allows two-digit years, but RFC2822 (which
22990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        obsoletes RFC822) requires four-digit years.
23000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """
23020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parsedate_tz('25 Feb 03 13:47:26 -0800'),
23030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         Utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'))
23040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parsedate_tz('25 Feb 71 13:47:26 -0800'),
23050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         Utils.parsedate_tz('25 Feb 1971 13:47:26 -0800'))
23060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parseaddr_empty(self):
23080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr('<>'), ('', ''))
23090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.formataddr(Utils.parseaddr('<>')), '')
23100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_noquote_dump(self):
23120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
23130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formataddr(('A Silly Person', 'person@dom.ain')),
23140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'A Silly Person <person@dom.ain>')
23150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_escape_dump(self):
23170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
23180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formataddr(('A (Very) Silly Person', 'person@dom.ain')),
23190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            r'"A \(Very\) Silly Person" <person@dom.ain>')
23200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = r'A \(Special\) Person'
23210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = 'person@dom.ain'
23220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
23230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_escape_backslashes(self):
23250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
23260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formataddr(('Arthur \Backslash\ Foobar', 'person@dom.ain')),
23270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>')
23280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = r'Arthur \Backslash\ Foobar'
23290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = 'person@dom.ain'
23300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
23310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_name_with_dot(self):
23330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x = 'John X. Doe <jxd@example.com>'
23340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        y = '"John X. Doe" <jxd@example.com>'
23350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a, b = ('John X. Doe', 'jxd@example.com')
23360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr(x), (a, b))
23370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr(y), (a, b))
23380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # formataddr() quotes the name if there's a dot in it
23390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.formataddr((a, b)), y)
23400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_parseaddr_preserves_quoted_pairs_in_addresses(self):
23420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # issue 10005.  Note that in the third test the second pair of
23430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # backslashes is not actually a quoted pair because it is not inside a
23440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # comment or quoted string: the address being parsed has a quoted
23450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # string containing a quoted backslash, followed by 'example' and two
23460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # backslashes, followed by another quoted string containing a space and
23470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # the word 'example'.  parseaddr copies those two backslashes
23480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # literally.  Per rfc5322 this is not technically correct since a \ may
23490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # not appear in an address outside of a quoted string.  It is probably
23500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a sensible Postel interpretation, though.
23510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
23520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.parseaddr('""example" example"@example.com'),
23530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          ('', '""example" example"@example.com'))
23540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.parseaddr('"\\"example\\" example"@example.com'),
23550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          ('', '"\\"example\\" example"@example.com'))
23560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.parseaddr('"\\\\"example\\\\" example"@example.com'),
23570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          ('', '"\\\\"example\\\\" example"@example.com'))
23580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multiline_from_comment(self):
23600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x = """\
23610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFoo
23620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tBar <foo@example.com>"""
23630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(Utils.parseaddr(x), ('Foo Bar', 'foo@example.com'))
23640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_quote_dump(self):
23660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
23670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            Utils.formataddr(('A Silly; Person', 'person@dom.ain')),
23680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            r'"A Silly; Person" <person@dom.ain>')
23690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_fix_eols(self):
23710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
23720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.fix_eols('hello'), 'hello')
23730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.fix_eols('hello\n'), 'hello\r\n')
23740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.fix_eols('hello\r'), 'hello\r\n')
23750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.fix_eols('hello\r\n'), 'hello\r\n')
23760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.fix_eols('hello\n\r'), 'hello\r\n\r\n')
23770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_charset_richcomparisons(self):
23790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
23800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne = self.assertNotEqual
23810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cset1 = Charset()
23820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cset2 = Charset()
23830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(cset1, 'us-ascii')
23840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(cset1, 'US-ASCII')
23850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(cset1, 'Us-AsCiI')
23860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('us-ascii', cset1)
23870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('US-ASCII', cset1)
23880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('Us-AsCiI', cset1)
23890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne(cset1, 'usascii')
23900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne(cset1, 'USASCII')
23910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne(cset1, 'UsAsCiI')
23920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne('usascii', cset1)
23930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne('USASCII', cset1)
23940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ne('UsAsCiI', cset1)
23950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(cset1, cset2)
23960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(cset2, cset1)
23970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
23980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_getaddresses(self):
23990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
24000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.getaddresses(['aperson@dom.ain (Al Person)',
24010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                               'Bud Person <bperson@dom.ain>']),
24020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('Al Person', 'aperson@dom.ain'),
24030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ('Bud Person', 'bperson@dom.ain')])
24040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_getaddresses_nasty(self):
24060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
24070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.getaddresses(['foo: ;']), [('', '')])
24080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.getaddresses(
24090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ['[]*-- =~$']),
24100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('', ''), ('', ''), ('', '*--')])
24110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(Utils.getaddresses(
24120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
24130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
24140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_getaddresses_embedded_comment(self):
24160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """Test proper handling of a nested comment"""
24170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
24180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        addrs = Utils.getaddresses(['User ((nested comment)) <foo@bar.com>'])
24190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(addrs[0][1], 'foo@bar.com')
24200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_utils_quote_unquote(self):
24220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
24230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
24240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('content-disposition', 'attachment',
24250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                       filename='foo\\wacky"name')
24260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_filename(), 'foo\\wacky"name')
24270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_body_encoding_with_bogus_charset(self):
24290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset('not a charset')
24300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(charset.get_body_encoding(), 'base64')
24310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_body_encoding_with_uppercase_charset(self):
24330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
24340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
24350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'text/plain; charset=UTF-8'
24360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-type'], 'text/plain; charset=UTF-8')
24370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charsets = msg.get_charsets()
24380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(charsets), 1)
24390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charsets[0], 'utf-8')
24400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset(charsets[0])
24410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset.get_body_encoding(), 'base64')
24420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('hello world', charset=charset)
24430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=\n')
24440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(decode=True), 'hello world')
24450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], 'base64')
24460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try another one
24470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
24480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg['Content-Type'] = 'text/plain; charset="US-ASCII"'
24490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charsets = msg.get_charsets()
24500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(charsets), 1)
24510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charsets[0], 'us-ascii')
24520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset(charsets[0])
24530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset.get_body_encoding(), Encoders.encode_7or8bit)
24540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_payload('hello world', charset=charset)
24550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), 'hello world')
24560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['content-transfer-encoding'], '7bit')
24570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_charsets_case_insensitive(self):
24590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lc = Charset('us-ascii')
24600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        uc = Charset('US-ASCII')
24610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(lc.get_body_encoding(), uc.get_body_encoding())
24620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
24630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_partial_falls_inside_message_delivery_status(self):
24640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
24650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # The Parser interface provides chunks of data to FeedParser in 8192
24660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # byte gulps.  SF bug #1076485 found one of those chunks inside
24670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # message/delivery-status header block, which triggered an
24680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # unreadline() of NeedMoreData.
24690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_43.txt')
24700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sfp = StringIO()
24710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Iterators._structure(msg, sfp)
24720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(sfp.getvalue(), """\
24730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimultipart/report
24740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    text/plain
24750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    message/delivery-status
24760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
24990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
25000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
25010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        text/plain
25020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    text/rfc822-headers
25030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
25040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the iterator/generators
25080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestIterators(TestEmailBase):
25090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_body_line_iterator(self):
25100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
25110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq = self.ndiffAssertEqual
25120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # First a simple non-multipart message
25130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
25140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        it = Iterators.body_line_iterator(msg)
25150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = list(it)
25160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(lines), 6)
25170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(EMPTYSTRING.join(lines), msg.get_payload())
25180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Now a more complicated multipart
25190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_02.txt')
25200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        it = Iterators.body_line_iterator(msg)
25210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = list(it)
25220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(lines), 43)
25230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_19.txt')
25240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
25250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            neq(EMPTYSTRING.join(lines), fp.read())
25260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
25270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
25280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_typed_subpart_iterator(self):
25300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
25310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_04.txt')
25320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        it = Iterators.typed_subpart_iterator(msg, 'text')
25330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = []
25340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subparts = 0
25350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for subpart in it:
25360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            subparts += 1
25370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            lines.append(subpart.get_payload())
25380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subparts, 2)
25390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(EMPTYSTRING.join(lines), """\
25400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yia simple kind of mirror
25410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yito reflect upon our own
25420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yia simple kind of mirror
25430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yito reflect upon our own
25440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
25450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_typed_subpart_iterator_default_type(self):
25470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
25480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_03.txt')
25490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        it = Iterators.typed_subpart_iterator(msg, 'text', 'plain')
25500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = []
25510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        subparts = 0
25520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for subpart in it:
25530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            subparts += 1
25540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            lines.append(subpart.get_payload())
25550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(subparts, 1)
25560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(EMPTYSTRING.join(lines), """\
25570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHi,
25590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDo you like this message?
25610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi-Me
25630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
25640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_pushCR_LF(self):
25660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        '''FeedParser BufferedSubFile.push() assumed it received complete
25670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           line endings.  A CR ending one push() followed by a LF starting
25680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           the next push() added an empty line.
25690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        '''
25700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        imt = [
25710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("a\r \n",  2),
25720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("b",       0),
25730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("c\n",     1),
25740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("",        0),
25750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("d\r\n",   1),
25760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("e\r",     0),
25770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("\nf",     1),
25780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ("\r\n",    1),
25790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          ]
25800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        from email.feedparser import BufferedSubFile, NeedMoreData
25810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        bsf = BufferedSubFile()
25820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        om = []
25830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        nt = 0
25840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for il, n in imt:
25850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            bsf.push(il)
25860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            nt += n
25870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            n1 = 0
25880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            while True:
25890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ol = bsf.readline()
25900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if ol == NeedMoreData:
25910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    break
25920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                om.append(ol)
25930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                n1 += 1
25940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertTrue(n == n1)
25950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(len(om) == nt)
25960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(''.join([il for il, n in imt]) == ''.join(om))
25970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
25990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestParsers(TestEmailBase):
26010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_parser(self):
26020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
26030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Parse only the headers of a complex multipart MIME document
26040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_02.txt')
26050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
26060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = HeaderParser().parse(fp)
26070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
26080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
26090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['from'], 'ppp-request@zzz.org')
26100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['to'], 'ppp@zzz.org')
26110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_type(), 'multipart/mixed')
26120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(msg.is_multipart())
26130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(isinstance(msg.get_payload(), str))
26140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_whitespace_continuation(self):
26160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
26170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This message contains a line after the Subject: header that has only
26180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # whitespace, but it is not empty!
26190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("""\
26200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aperson@dom.ain
26210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bperson@dom.ain
26220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: the next line has a space on it
26230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\x20
26240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDate: Mon, 8 Apr 2002 15:09:19 -0400
26250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMessage-ID: spam
26260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHere's the message body
26280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
26290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['subject'], 'the next line has a space on it\n ')
26300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['message-id'], 'spam')
26310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), "Here's the message body\n")
26320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_whitespace_continuation_last_header(self):
26340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
26350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Like the previous test, but the subject line is the last
26360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # header.
26370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string("""\
26380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: aperson@dom.ain
26390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bperson@dom.ain
26400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDate: Mon, 8 Apr 2002 15:09:19 -0400
26410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMessage-ID: spam
26420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: the next line has a space on it
26430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\x20
26440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHere's the message body
26460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
26470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['subject'], 'the next line has a space on it\n ')
26480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg['message-id'], 'spam')
26490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), "Here's the message body\n")
26500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_crlf_separation(self):
26520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
26530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_26.txt', mode='rb')
26540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
26550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = Parser().parse(fp)
26560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
26570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
26580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 2)
26590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part1 = msg.get_payload(0)
26600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1.get_content_type(), 'text/plain')
26610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1.get_payload(), 'Simple email with attachment.\r\n\r\n')
26620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part2 = msg.get_payload(1)
26630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part2.get_content_type(), 'application/riscos')
26640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multipart_digest_with_extra_mime_headers(self):
26660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
26670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq = self.ndiffAssertEqual
26680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile('msg_28.txt')
26690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
26700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_file(fp)
26710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
26720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
26730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Structure is:
26740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # multipart/digest
26750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #   message/rfc822
26760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #     text/plain
26770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #   message/rfc822
26780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #     text/plain
26790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.is_multipart(), 1)
26800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.get_payload()), 2)
26810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part1 = msg.get_payload(0)
26820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1.get_content_type(), 'message/rfc822')
26830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1.is_multipart(), 1)
26840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(part1.get_payload()), 1)
26850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part1a = part1.get_payload(0)
26860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1a.is_multipart(), 0)
26870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part1a.get_content_type(), 'text/plain')
26880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(part1a.get_payload(), 'message 1\n')
26890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # next message/rfc822
26900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part2 = msg.get_payload(1)
26910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part2.get_content_type(), 'message/rfc822')
26920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part2.is_multipart(), 1)
26930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(part2.get_payload()), 1)
26940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        part2a = part2.get_payload(0)
26950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part2a.is_multipart(), 0)
26960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(part2a.get_content_type(), 'text/plain')
26970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        neq(part2a.get_payload(), 'message 2\n')
26980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
26990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_three_lines(self):
27000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # A bug report by Andrew McNamara
27010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        lines = ['From: Andrew Person <aperson@dom.ain',
27020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 'Subject: Test',
27030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 'Date: Tue, 20 Aug 2002 16:43:45 +1000']
27040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(NL.join(lines))
27050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg['date'], 'Tue, 20 Aug 2002 16:43:45 +1000')
27060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_strip_line_feed_and_carriage_return_in_headers(self):
27080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # For [ 1002475 ] email message parser doesn't handle \r\n correctly
27100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value1 = 'text'
27110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value2 = 'more text'
27120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = 'Header: %s\r\nNext-Header: %s\r\n\r\nBody\r\n\r\n' % (
27130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            value1, value2)
27140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
27150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get('Header'), value1)
27160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get('Next-Header'), value2)
27170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2822_header_syntax(self):
27190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '>From: foo\nFrom: bar\n!"#QUX;~: zoo\n\nbody'
27210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
27220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.keys()), 3)
27230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        keys = msg.keys()
27240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        keys.sort()
27250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(keys, ['!"#QUX;~', '>From', 'From'])
27260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), 'body')
27270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2822_space_not_allowed_in_header(self):
27290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '>From foo@example.com 11:25:53\nFrom: bar\n!"#QUX;~: zoo\n\nbody'
27310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
27320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(len(msg.keys()), 0)
27330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2822_one_character_header(self):
27350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = 'A: first header\nB: second header\nCC: third header\n\nbody'
27370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
27380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        headers = msg.keys()
27390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        headers.sort()
27400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(headers, ['A', 'B', 'CC'])
27410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_payload(), 'body')
27420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_CRLFLF_at_end_of_part(self):
27440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # issue 5610: feedparser should not eat two chars from body part ending
27450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # with "\r\n\n".
27460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = (
27470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "From: foo@bar.com\n"
27480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "To: baz\n"
27490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "Mime-Version: 1.0\n"
27500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "Content-Type: multipart/mixed; boundary=BOUNDARY\n"
27510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "\n"
27520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "--BOUNDARY\n"
27530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "Content-Type: text/plain\n"
27540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "\n"
27550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "body ending with CRLF newline\r\n"
27560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "\n"
27570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "--BOUNDARY--\n"
27580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          )
27590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
27600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n'))
27610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestBase64(unittest.TestCase):
27640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_len(self):
27650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.base64_len('hello'),
27670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           len(base64MIME.encode('hello', eol='')))
27680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for size in range(15):
27690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if   size == 0 : bsize = 0
27700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            elif size <= 3 : bsize = 4
27710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            elif size <= 6 : bsize = 8
27720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            elif size <= 9 : bsize = 12
27730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            elif size <= 12: bsize = 16
27740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else           : bsize = 20
27750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(base64MIME.base64_len('x'*size), bsize)
27760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_decode(self):
27780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.decode(''), '')
27800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.decode('aGVsbG8='), 'hello')
27810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.decode('aGVsbG8=', 'X'), 'hello')
27820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.decode('aGVsbG8NCndvcmxk\n', 'X'), 'helloXworld')
27830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
27840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encode(self):
27850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
27860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode(''), '')
27870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode('hello'), 'aGVsbG8=\n')
27880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the binary flag
27890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode('hello\n'), 'aGVsbG8K\n')
27900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode('hello\n', 0), 'aGVsbG8NCg==\n')
27910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the maxlinelen arg
27920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40), """\
27930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
27940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
27950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
27960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IA==
27970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
27980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the eol argument
27990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
28000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
28010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
28020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
28030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YieHh4eCB4eHh4IA==\r
28040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
28050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_encode(self):
28070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
28080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        he = base64MIME.header_encode
28090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello'), '=?iso-8859-1?b?aGVsbG8=?=')
28100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello\nworld'), '=?iso-8859-1?b?aGVsbG8NCndvcmxk?=')
28110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the charset option
28120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?b?aGVsbG8=?=')
28130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the keep_eols flag
28140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello\nworld', keep_eols=True),
28150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '=?iso-8859-1?b?aGVsbG8Kd29ybGQ=?=')
28160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the maxlinelen argument
28170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('xxxx ' * 20, maxlinelen=40), """\
28180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=
28190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=
28200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=
28210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=
28220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=
28230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
28240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the eol argument
28250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
28260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=\r
28270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=\r
28280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=\r
28290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=\r
28300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=\r
28310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
28320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestQuopri(unittest.TestCase):
28360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
28370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.hlit = [chr(x) for x in range(ord('a'), ord('z')+1)] + \
28380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    [chr(x) for x in range(ord('A'), ord('Z')+1)] + \
28390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    [chr(x) for x in range(ord('0'), ord('9')+1)] + \
28400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    ['!', '*', '+', '-', '/', ' ']
28410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.hnon = [chr(x) for x in range(256) if chr(x) not in self.hlit]
28420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assert len(self.hlit) + len(self.hnon) == 256
28430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.blit = [chr(x) for x in range(ord(' '), ord('~')+1)] + ['\t']
28440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.blit.remove('=')
28450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.bnon = [chr(x) for x in range(256) if chr(x) not in self.blit]
28460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assert len(self.blit) + len(self.bnon) == 256
28470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_quopri_check(self):
28490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.hlit:
28500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertFalse(quopriMIME.header_quopri_check(c))
28510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.hnon:
28520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertTrue(quopriMIME.header_quopri_check(c))
28530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_body_quopri_check(self):
28550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.blit:
28560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertFalse(quopriMIME.body_quopri_check(c))
28570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.bnon:
28580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertTrue(quopriMIME.body_quopri_check(c))
28590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_quopri_len(self):
28610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
28620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hql = quopriMIME.header_quopri_len
28630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        enc = quopriMIME.header_encode
28640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for s in ('hello', 'h@e@l@l@o@'):
28650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # Empty charset and no line-endings.  7 == RFC chrome
28660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(hql(s), len(enc(s, charset='', eol=''))-7)
28670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.hlit:
28680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(hql(c), 1)
28690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.hnon:
28700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(hql(c), 3)
28710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_body_quopri_len(self):
28730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
28740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        bql = quopriMIME.body_quopri_len
28750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.blit:
28760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(bql(c), 1)
28770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for c in self.bnon:
28780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq(bql(c), 3)
28790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_quote_unquote_idempotent(self):
28810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for x in range(256):
28820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            c = chr(x)
28830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(quopriMIME.unquote(quopriMIME.quote(c)), c)
28840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
28850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_encode(self):
28860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
28870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        he = quopriMIME.header_encode
28880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello'), '=?iso-8859-1?q?hello?=')
28890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello\nworld'), '=?iso-8859-1?q?hello=0D=0Aworld?=')
28900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the charset option
28910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?q?hello?=')
28920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the keep_eols flag
28930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello\nworld', keep_eols=True), '=?iso-8859-1?q?hello=0Aworld?=')
28940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test a non-ASCII character
28950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('hello\xc7there'), '=?iso-8859-1?q?hello=C7there?=')
28960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the maxlinelen argument
28970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('xxxx ' * 20, maxlinelen=40), """\
28980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=
28990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=
29000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=
29010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=
29020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?x_xxxx_xxxx_?=""")
29030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the eol argument
29040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
29050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=\r
29060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=\r
29070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=\r
29080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=\r
29090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?x_xxxx_xxxx_?=""")
29100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_decode(self):
29120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
29130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.decode(''), '')
29140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.decode('hello'), 'hello')
29150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.decode('hello', 'X'), 'hello')
29160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.decode('hello\nworld', 'X'), 'helloXworld')
29170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encode(self):
29190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
29200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode(''), '')
29210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode('hello'), 'hello')
29220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the binary flag
29230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode('hello\r\nworld'), 'hello\nworld')
29240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode('hello\r\nworld', 0), 'hello\nworld')
29250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the maxlinelen arg
29260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40), """\
29270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yixxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=
29280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=
29290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yix xxxx xxxx xxxx xxxx=20""")
29300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test the eol argument
29310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
29320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yixxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=\r
29330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=\r
29340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yix xxxx xxxx xxxx xxxx=20""")
29350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(quopriMIME.encode("""\
29360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yione line
29370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitwo line"""), """\
29390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yione line
29400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitwo line""")
29420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test the Charset class
29460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestCharset(unittest.TestCase):
29470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def tearDown(self):
29480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        from email import Charset as CharsetModule
29490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
29500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            del CharsetModule.CHARSETS['fake']
29510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except KeyError:
29520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
29530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_idempotent(self):
29550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
29560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make sure us-ascii = no Unicode conversion
29570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('us-ascii')
29580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'Hello World!'
29590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sp = c.to_splittable(s)
29600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, c.from_splittable(sp))
29610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # test 8-bit idempotency with us-ascii
29620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = '\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa'
29630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sp = c.to_splittable(s)
29640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, c.from_splittable(sp))
29650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_body_encode(self):
29670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
29680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try a charset with QP body encoding
29690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('iso-8859-1')
29700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('hello w=F6rld', c.body_encode('hello w\xf6rld'))
29710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try a charset with Base64 body encoding
29720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('utf-8')
29730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('aGVsbG8gd29ybGQ=\n', c.body_encode('hello world'))
29740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try a charset with None body encoding
29750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('us-ascii')
29760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('hello world', c.body_encode('hello world'))
29770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Try the convert argument, where input codec != output codec
29780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('euc-jp')
29790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # With apologies to Tokio Kikuchi ;)
29800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
29810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq('\x1b$B5FCO;~IW\x1b(B',
29820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7'))
29830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            eq('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7',
29840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi               c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', False))
29850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except LookupError:
29860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # We probably don't have the Japanese codecs installed
29870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
29880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Testing SF bug #625509, which we have to fake, since there are no
29890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # built-in encodings where the header encoding is QP but the body
29900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # encoding is not.
29910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        from email import Charset as CharsetModule
29920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        CharsetModule.add_charset('fake', CharsetModule.QP, None)
29930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = Charset('fake')
29940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq('hello w\xf6rld', c.body_encode('hello w\xf6rld'))
29950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
29960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_unicode_charset_name(self):
29970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset(u'us-ascii')
29980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(str(charset), 'us-ascii')
29990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertRaises(Errors.CharsetError, Charset, 'asc\xffii')
30000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_codecs_aliases_accepted(self):
30020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset = Charset('utf8')
30030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(str(charset), 'utf-8')
30040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test multilingual MIME headers.
30070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestHeader(TestEmailBase):
30080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_simple(self):
30090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
30100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header('Hello World!')
30110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), 'Hello World!')
30120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(' Goodbye World!')
30130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), 'Hello World!  Goodbye World!')
30140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_simple_surprise(self):
30160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
30170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header('Hello World!')
30180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), 'Hello World!')
30190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('Goodbye World!')
30200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), 'Hello World! Goodbye World!')
30210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_needs_no_decoding(self):
30230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = 'no decoding needed'
30240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(decode_header(h), [(h, None)])
30250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long(self):
30270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header("I am the very model of a modern Major-General; I've information vegetable, animal, and mineral; I know the kings of England, and I quote the fights historical from Marathon to Waterloo, in order categorical; I'm very well acquainted, too, with matters mathematical; I understand equations, both the simple and quadratical; about binomial theorem I'm teeming with a lot o' news, with many cheerful facts about the square of the hypotenuse.",
30280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                   maxlinelen=76)
30290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for l in h.encode(splitchars=' ').split('\n '):
30300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertTrue(len(l) <= 76)
30310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_multilingual(self):
30330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
30340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g = Charset("iso-8859-1")
30350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cz = Charset("iso-8859-2")
30360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        utf8 = Charset("utf-8")
30370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        g_head = "Die Mieter treten hier ein werden mit einem Foerderband komfortabel den Korridor entlang, an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, gegen die rotierenden Klingen bef\xf6rdert. "
30380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
30390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        utf8_head = u"\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066\u3044\u307e\u3059\u3002".encode("utf-8")
30400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(g_head, g)
30410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(cz_head, cz)
30420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(utf8_head, utf8)
30430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        enc = h.encode()
30440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(enc, """\
30450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerderband_ko?=
30460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?mfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndischen_Wan?=
30470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?dgem=E4lden_vorbei=2C_gegen_die_rotierenden_Klingen_bef=F6?=
30480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-1?q?rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se_hroutily?=
30490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?iso-8859-2?q?_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= =?utf-8?b?5q2j56K6?=
30500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb44KT44CC?=
30510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go44Gv44Gn?=
30520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBpc3QgZGFz?=
30530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?q?_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das_Oder_die_Fl?=
30540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?aXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBo+OBpuOBhOOBvuOBmQ==?=
30550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi =?utf-8?b?44CC?=""")
30560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(decode_header(enc),
30570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           [(g_head, "iso-8859-1"), (cz_head, "iso-8859-2"),
30580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            (utf8_head, "utf-8")])
30590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ustr = unicode(h)
30600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(ustr.encode('utf-8'),
30610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'Die Mieter treten hier ein werden mit einem Foerderband '
30620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'komfortabel den Korridor entlang, an s\xc3\xbcdl\xc3\xbcndischen '
30630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'Wandgem\xc3\xa4lden vorbei, gegen die rotierenden Klingen '
30640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'bef\xc3\xb6rdert. Finan\xc4\x8dni metropole se hroutily pod '
30650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'tlakem jejich d\xc5\xafvtipu.. \xe6\xad\xa3\xe7\xa2\xba\xe3\x81'
30660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xab\xe8\xa8\x80\xe3\x81\x86\xe3\x81\xa8\xe7\xbf\xbb\xe8\xa8\xb3'
30670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xe3\x81\xaf\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3'
30680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\x81\xbe\xe3\x81\x9b\xe3\x82\x93\xe3\x80\x82\xe4\xb8\x80\xe9\x83'
30690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xa8\xe3\x81\xaf\xe3\x83\x89\xe3\x82\xa4\xe3\x83\x84\xe8\xaa\x9e'
30700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xe3\x81\xa7\xe3\x81\x99\xe3\x81\x8c\xe3\x80\x81\xe3\x81\x82\xe3'
30710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\x81\xa8\xe3\x81\xaf\xe3\x81\xa7\xe3\x81\x9f\xe3\x82\x89\xe3\x82'
30720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\x81\xe3\x81\xa7\xe3\x81\x99\xe3\x80\x82\xe5\xae\x9f\xe9\x9a\x9b'
30730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x8cWenn ist das Nunstuck git '
30740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt '
30750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'gersput.\xe3\x80\x8d\xe3\x81\xa8\xe8\xa8\x80\xe3\x81\xa3\xe3\x81'
30760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           '\xa6\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82')
30770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Test make_header()
30780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        newh = make_header(decode_header(enc))
30790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(newh, enc)
30800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_header_ctor_default_args(self):
30820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
30830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header()
30840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h, '')
30850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('foo', Charset('iso-8859-1'))
30860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h, '=?iso-8859-1?q?foo?=')
30870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
30880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_explicit_maxlinelen(self):
30890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
30900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hstr = 'A very long line that must get split to something other than at the 76th character boundary to test the non-default behavior'
30910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr)
30920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '''\
30930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiA very long line that must get split to something other than at the 76th
30940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi character boundary to test the non-default behavior''')
30950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, header_name='Subject')
30960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '''\
30970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiA very long line that must get split to something other than at the
30980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 76th character boundary to test the non-default behavior''')
30990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(hstr, maxlinelen=1024, header_name='Subject')
31000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), hstr)
31010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_us_ascii_header(self):
31030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'hello'
31050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x = decode_header(s)
31060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(x, [('hello', None)])
31070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = make_header(x)
31080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, h.encode())
31090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_string_charset(self):
31110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header()
31130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('hello', 'iso-8859-1')
31140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h, '=?iso-8859-1?q?hello?=')
31150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##    def test_unicode_error(self):
31170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises = self.assertRaises
31180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises(UnicodeError, Header, u'[P\xf6stal]', 'us-ascii')
31190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises(UnicodeError, Header, '[P\xf6stal]', 'us-ascii')
31200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        h = Header()
31210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises(UnicodeError, h.append, u'[P\xf6stal]', 'us-ascii')
31220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises(UnicodeError, h.append, '[P\xf6stal]', 'us-ascii')
31230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##        raises(UnicodeError, Header, u'\u83ca\u5730\u6642\u592b', 'iso-8859-1')
31240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_utf8_shortest(self):
31260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(u'p\xf6stal', 'utf-8')
31280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '=?utf-8?q?p=C3=B6stal?=')
31290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header(u'\u83ca\u5730\u6642\u592b', 'utf-8')
31300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), '=?utf-8?b?6I+K5Zyw5pmC5aSr?=')
31310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bad_8bit_header(self):
31330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises = self.assertRaises
31340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x = 'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
31360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises(UnicodeError, Header, x)
31370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header()
31380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises(UnicodeError, h.append, x)
31390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(str(Header(x, errors='replace')), x)
31400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append(x, errors='replace')
31410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(str(h), x)
31420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encoded_adjacent_nonencoded(self):
31440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = Header()
31460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('hello', 'iso-8859-1')
31470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h.append('world')
31480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = h.encode()
31490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, '=?iso-8859-1?q?hello?= world')
31500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = make_header(decode_header(s))
31510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(h.encode(), s)
31520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_whitespace_eater(self):
31540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztk=?= =?koi8-r?q?=CA?= zz.'
31560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        parts = decode_header(s)
31570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(parts, [('Subject:', None), ('\xf0\xd2\xcf\xd7\xc5\xd2\xcb\xc1 \xce\xc1 \xc6\xc9\xce\xc1\xcc\xd8\xce\xd9\xca', 'koi8-r'), ('zz.', None)])
31580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        hdr = make_header(parts)
31590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(hdr.encode(),
31600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztnK?= zz.')
31610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_broken_base64_header(self):
31630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises = self.assertRaises
31640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3I ?='
31650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raises(Errors.HeaderParseError, decode_header, s)
31660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Issue 1078919
31680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_ascii_add_header(self):
31690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
31700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Content-Disposition', 'attachment',
31710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                       filename='bud.gif')
31720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual('attachment; filename="bud.gif"',
31730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg['Content-Disposition'])
31740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_nonascii_add_header_via_triple(self):
31760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
31770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.add_header('Content-Disposition', 'attachment',
31780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            filename=('iso-8859-1', '', 'Fu\xdfballer.ppt'))
31790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
31800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'attachment; filename*="iso-8859-1\'\'Fu%DFballer.ppt"',
31810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg['Content-Disposition'])
31820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_encode_unaliased_charset(self):
31840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Issue 1379416: when the charset has no output conversion,
31850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # output was accidentally getting coerced to unicode.
31860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        res = Header('abc','iso-8859-2').encode()
31870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(res, '=?iso-8859-2?q?abc?=')
31880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertIsInstance(res, str)
31890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
31910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Test RFC 2231 header parameters (en/de)coding
31920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestRFC2231(TestEmailBase):
31930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_param(self):
31940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
31950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_29.txt')
31960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('title'),
31970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
31980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('title', unquote=False),
31990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ('us-ascii', 'en', '"This is even more ***fun*** isn\'t it!"'))
32000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_set_param(self):
32020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
32030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = Message()
32040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
32050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                      charset='us-ascii')
32060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('title'),
32070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ('us-ascii', '', 'This is even more ***fun*** isn\'t it!'))
32080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
32090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                      charset='us-ascii', language='en')
32100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('title'),
32110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
32120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
32130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
32140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                      charset='us-ascii', language='en')
32150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.ndiffAssertEqual(msg.as_string(), """\
32160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReturn-Path: <bbb@zzz.org>
32170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDelivered-To: bbb@zzz.org
32180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: by mail.zzz.org (Postfix, from userid 889)
32190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi id 27CEAD38CC; Fri,  4 May 2001 14:05:44 -0400 (EDT)
32200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
32210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
32220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMessage-ID: <15090.61304.110929.45684@aaa.zzz.org>
32230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bbb@ddd.com (John X. Doe)
32240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bbb@zzz.org
32250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: This is a test message
32260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDate: Fri, 4 May 2001 14:05:44 -0400
32270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset=us-ascii;
32280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
32290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHi,
32320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDo you like this message?
32340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi-Me
32360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
32370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_del_param(self):
32390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.ndiffAssertEqual
32400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_01.txt')
32410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('foo', 'bar', charset='us-ascii', language='en')
32420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
32430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            charset='us-ascii', language='en')
32440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg.del_param('foo', header='Content-Type')
32450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.as_string(), """\
32460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReturn-Path: <bbb@zzz.org>
32470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDelivered-To: bbb@zzz.org
32480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiReceived: by mail.zzz.org (Postfix, from userid 889)
32490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi id 27CEAD38CC; Fri,  4 May 2001 14:05:44 -0400 (EDT)
32500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMIME-Version: 1.0
32510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 7bit
32520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMessage-ID: <15090.61304.110929.45684@aaa.zzz.org>
32530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiFrom: bbb@ddd.com (John X. Doe)
32540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTo: bbb@zzz.org
32550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSubject: This is a test message
32560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDate: Fri, 4 May 2001 14:05:44 -0400
32570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset="us-ascii";
32580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
32590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHi,
32620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiDo you like this message?
32640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi-Me
32660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""")
32670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_get_content_charset(self):
32690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
32700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = self._msgobj('msg_32.txt')
32710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_content_charset(), 'us-ascii')
32720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_language_or_charset(self):
32740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
32750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 8bit
32760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline; filename="file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm"
32770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/html; NAME*0=file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEM; NAME*1=P_nsmail.htm
32780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
32800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
32810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        param = msg.get_param('NAME')
32820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(isinstance(param, tuple))
32830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
32840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            param,
32850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm')
32860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_language_or_charset_in_filename(self):
32880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
32890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
32900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0*="''This%20is%20even%20more%20";
32910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
32920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2="is it not.pdf"
32930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
32950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
32960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(),
32970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'This is even more ***fun*** is it not.pdf')
32980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
32990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_language_or_charset_in_filename_encoded(self):
33000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
33020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0*="''This%20is%20even%20more%20";
33030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
33040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2="is it not.pdf"
33050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(),
33090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'This is even more ***fun*** is it not.pdf')
33100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_partly_encoded(self):
33120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
33140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0="''This%20is%20even%20more%20";
33150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
33160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2="is it not.pdf"
33170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
33210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg.get_filename(),
33220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'This%20is%20even%20more%20***fun*** is it not.pdf')
33230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_partly_nonencoded(self):
33250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
33270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0="This%20is%20even%20more%20";
33280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1="%2A%2A%2Afun%2A%2A%2A%20";
33290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2="is it not.pdf"
33300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(
33340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg.get_filename(),
33350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20is it not.pdf')
33360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_language_or_charset_in_boundary(self):
33380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: multipart/alternative;
33400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tboundary*0*="''This%20is%20even%20more%20";
33410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tboundary*1*="%2A%2A%2Afun%2A%2A%2A%20";
33420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tboundary*2="is it not.pdf"
33430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_boundary(),
33470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'This is even more ***fun*** is it not.pdf')
33480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_language_or_charset_in_charset(self):
33500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This is a nonsensical charset value, but tests the code anyway
33510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain;
33530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tcharset*0*="This%20is%20even%20more%20";
33540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tcharset*1*="%2A%2A%2Afun%2A%2A%2A%20";
33550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tcharset*2="is it not.pdf"
33560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_charset(),
33600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'this is even more ***fun*** is it not.pdf')
33610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_bad_encoding_in_filename(self):
33630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
33650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0*="bogus'xx'This%20is%20even%20more%20";
33660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
33670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2="is it not.pdf"
33680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
33700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(),
33720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         'This is even more ***fun*** is it not.pdf')
33730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_bad_encoding_in_charset(self):
33750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
33760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset*=bogus''utf-8%E2%80%9D
33770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
33790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This should return None because non-ascii characters in the charset
33810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # are not allowed.
33820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_charset(), None)
33830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_bad_character_in_charset(self):
33850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
33860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: text/plain; charset*=ascii''utf-8%E2%80%9D
33870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
33890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
33900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # This should return None because non-ascii characters in the charset
33910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # are not allowed.
33920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_content_charset(), None)
33930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
33940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_bad_character_in_filename(self):
33950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = '''\
33960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline;
33970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*0*="ascii'xx'This%20is%20even%20more%20";
33980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
33990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tfilename*2*="is it not.pdf%E2"
34000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi'''
34020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(),
34040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                         u'This is even more ***fun*** is it not.pdf\ufffd')
34050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_unknown_encoding(self):
34070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Transfer-Encoding: 8bit
34090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Disposition: inline; filename*=X-UNKNOWN''myfile.txt
34100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(msg.get_filename(), 'myfile.txt')
34140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_single_tick_in_filename_extended(self):
34160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
34170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo;
34190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*0*=\"Frank's\"; name*1*=\" Document\"
34200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset, language, s = msg.get_param('name')
34240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset, None)
34250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(language, None)
34260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, "Frank's Document")
34270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_single_tick_in_filename(self):
34290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo; name*0=\"Frank's\"; name*1=\" Document\"
34310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        param = msg.get_param('name')
34350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(isinstance(param, tuple))
34360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(param, "Frank's Document")
34370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_tick_attack_extended(self):
34390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
34400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo;
34420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*0*=\"us-ascii'en-us'Frank's\"; name*1*=\" Document\"
34430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset, language, s = msg.get_param('name')
34470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset, 'us-ascii')
34480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(language, 'en-us')
34490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, "Frank's Document")
34500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_tick_attack(self):
34520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo;
34540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*0=\"us-ascii'en-us'Frank's\"; name*1=\" Document\"
34550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        param = msg.get_param('name')
34590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(isinstance(param, tuple))
34600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(param, "us-ascii'en-us'Frank's Document")
34610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_no_extended_values(self):
34630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
34640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo; name=\"Frank's Document\"
34660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(msg.get_param('name'), "Frank's Document")
34700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_encoded_then_unencoded_segments(self):
34720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
34730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo;
34750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*0*=\"us-ascii'en-us'My\";
34760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*1=\" Document\";
34770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*2*=\" For You\"
34780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset, language, s = msg.get_param('name')
34820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset, 'us-ascii')
34830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(language, 'en-us')
34840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, 'My Document For You')
34850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_rfc2231_unencoded_then_encoded_segments(self):
34870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq = self.assertEqual
34880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = """\
34890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiContent-Type: application/x-foo;
34900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*0=\"us-ascii'en-us'My\";
34910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*1*=\" Document\";
34920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi\tname*2*=\" For You\"
34930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
34940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
34950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        msg = email.message_from_string(m)
34960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        charset, language, s = msg.get_param('name')
34970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(charset, 'us-ascii')
34980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(language, 'en-us')
34990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        eq(s, 'My Document For You')
35000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Tests to ensure that signed parts of an email are completely preserved, as
35040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# required by RFC1847 section 2.1.  Note that these are incomplete, because the
35050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# email package does not currently always preserve the body.  See issue 1670765.
35060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass TestSigned(TestEmailBase):
35070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _msg_and_obj(self, filename):
35090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = openfile(findfile(filename))
35100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
35110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            original = fp.read()
35120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            msg = email.message_from_string(original)
35130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
35140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            fp.close()
35150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return original, msg
35160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _signed_parts_eq(self, original, result):
35180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Extract the first mime part of each message
35190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        import re
35200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        repart = re.compile(r'^--([^\n]+)\n(.*?)\n--\1$', re.S | re.M)
35210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        inpart = repart.search(original).group(2)
35220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        outpart = repart.search(result).group(2)
35230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(outpart, inpart)
35240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_headers_as_string(self):
35260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        original, msg = self._msg_and_obj('msg_45.txt')
35270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        result = msg.as_string()
35280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._signed_parts_eq(original, result)
35290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_long_headers_flatten(self):
35310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        original, msg = self._msg_and_obj('msg_45.txt')
35320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        fp = StringIO()
35330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Generator(fp).flatten(msg)
35340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        result = fp.getvalue()
35350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._signed_parts_eq(original, result)
35360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _testclasses():
35400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod = sys.modules[__name__]
35410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
35420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef suite():
35450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    suite = unittest.TestSuite()
35460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for testclass in _testclasses():
35470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        suite.addTest(unittest.makeSuite(testclass))
35480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return suite
35490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef test_main():
35520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    for testclass in _testclasses():
35530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        run_unittest(testclass)
35540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
35570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif __name__ == '__main__':
35580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    unittest.main(defaultTest='suite')
3559