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