1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Copyright (C) 2001-2010 Python Software Foundation
2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Contact: email-sig@python.org
3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# email package unit tests
4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport os
6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys
7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport time
8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport base64
9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport difflib
10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport unittest
11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport warnings
12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport textwrap
13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom cStringIO import StringIO
14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport email
16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.Charset import Charset
18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.Header import Header, decode_header, make_header
19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.Parser import Parser, HeaderParser
20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.Generator import Generator, DecodedGenerator
21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.Message import Message
22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEAudio import MIMEAudio
23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEText import MIMEText
24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEImage import MIMEImage
25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEBase import MIMEBase
26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEMessage import MIMEMessage
27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.MIMEMultipart import MIMEMultipart
28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import Utils
29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import Errors
30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import Encoders
31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import Iterators
32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import base64MIME
33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email import quopriMIME
34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom test.test_support import findfile, run_unittest
36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom email.test import __file__ as landmark
37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepNL = '\n'
40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepEMPTYSTRING = ''
41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSPACE = ' '
42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef openfile(filename, mode='r'):
46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    path = os.path.join(os.path.dirname(landmark), 'data', filename)
47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return open(path, mode)
48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Base test class
52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestEmailBase(unittest.TestCase):
53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def ndiffAssertEqual(self, first, second):
54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """Like assertEqual except use ndiff for readable output."""
55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if first != second:
56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            sfirst = str(first)
57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ssecond = str(second)
58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines())
59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp = StringIO()
60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            print >> fp, NL, NL.join(diff)
61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            raise self.failureException, fp.getvalue()
62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _msgobj(self, filename):
64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile(findfile(filename))
65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp)
67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return msg
70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test various aspects of the Message class's API
74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMessageAPI(TestEmailBase):
75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_all(self):
76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_20.txt')
78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_all('cc'), ['ccc@zzz.org', 'ddd@zzz.org', 'eee@zzz.org'])
79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_all('xx', 'n/a'), 'n/a')
80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_getset_charset(self):
82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset(), None)
85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset('iso-8859-1')
86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset(charset)
87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['mime-version'], '1.0')
88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="iso-8859-1"')
90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('charset'), 'iso-8859-1')
91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], 'quoted-printable')
92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset().input_charset, 'iso-8859-1')
93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Remove the charset
94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset(None)
95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset(), None)
96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain')
97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try adding a charset when there's already MIME headers present
98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['MIME-Version'] = '2.0'
100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'text/x-weird'
101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Transfer-Encoding'] = 'quinted-puntable'
102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset(charset)
103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['mime-version'], '2.0')
104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/x-weird; charset="iso-8859-1"')
105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], 'quinted-puntable')
106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_charset_from_string(self):
108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset('us-ascii')
111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset().input_charset, 'us-ascii')
112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_payload_with_charset(self):
115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset('iso-8859-1')
117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('This is a string payload', charset)
118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_charset().input_charset, 'iso-8859-1')
119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_charsets(self):
121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_08.txt')
124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charsets = msg.get_charsets()
125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charsets, [None, 'us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r'])
126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_09.txt')
128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charsets = msg.get_charsets('dingbat')
129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charsets, ['dingbat', 'us-ascii', 'iso-8859-1', 'dingbat',
130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      'koi8-r'])
131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_12.txt')
133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charsets = msg.get_charsets()
134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charsets, [None, 'us-ascii', 'iso-8859-1', None, 'iso-8859-2',
135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      'iso-8859-3', 'us-ascii', 'koi8-r'])
136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_filename(self):
138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_04.txt')
141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        filenames = [p.get_filename() for p in msg.get_payload()]
142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(filenames, ['msg.txt', 'msg.txt'])
143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_07.txt')
145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart = msg.get_payload(1)
146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart.get_filename(), 'dingusfish.gif')
147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_filename_with_name_parameter(self):
149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_44.txt')
152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        filenames = [p.get_filename() for p in msg.get_payload()]
153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(filenames, ['msg.txt', 'msg.txt'])
154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_boundary(self):
156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_07.txt')
158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # No quotes!
159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_boundary(), 'BOUNDARY')
160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_boundary(self):
162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This one has no existing boundary parameter, but the Content-Type:
164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # header appears fifth.
165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_boundary('BOUNDARY')
167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        header, value = msg.items()[4]
168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(header.lower(), 'content-type')
169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(value, 'text/plain; charset="us-ascii"; boundary="BOUNDARY"')
170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This one has a Content-Type: header, with a boundary, stuck in the
171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # middle of its headers.  Make sure the order is preserved; it should
172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # be fifth.
173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_04.txt')
174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_boundary('BOUNDARY')
175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        header, value = msg.items()[4]
176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(header.lower(), 'content-type')
177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(value, 'multipart/mixed; boundary="BOUNDARY"')
178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # And this one has no Content-Type: header at all.
179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_03.txt')
180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(Errors.HeaderParseError,
181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                          msg.set_boundary, 'BOUNDARY')
182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_make_boundary(self):
184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEMultipart('form-data')
185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Note that when the boundary gets created is an implementation
186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # detail and might change.
187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.items()[0][1], 'multipart/form-data')
188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Trigger creation of boundary
189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.as_string()
190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.items()[0][1][:33],
191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        'multipart/form-data; boundary="==')
192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX: there ought to be tests of the uniqueness of the boundary, too.
193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_rfc822_only(self):
195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Issue 7970: message/rfc822 not in multipart parsed by
196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # HeaderParser caused an exception when flattened.
197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile(findfile('msg_46.txt'))
198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msgdata = fp.read()
199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        parser = email.Parser.HeaderParser()
200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = parser.parsestr(msgdata)
201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        out = StringIO()
202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        gen = email.Generator.Generator(out, True, 0)
203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        gen.flatten(msg, False)
204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(out.getvalue(), msgdata)
205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_decoded_payload(self):
207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_10.txt')
209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The outer message is a multipart
210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(decode=True), None)
211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 1 is 7bit encoded
212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(0).get_payload(decode=True),
213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'This is a 7bit encoded message.\n')
214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 2 is quopri
215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(1).get_payload(decode=True),
216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xa1This is a Quoted Printable encoded message!\n')
217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 3 is base64
218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(2).get_payload(decode=True),
219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'This is a Base64 encoded message.')
220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 4 is base64 with a trailing newline, which
221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # used to be stripped (issue 7143).
222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(3).get_payload(decode=True),
223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'This is a Base64 encoded message.\n')
224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 5 has no Content-Transfer-Encoding: header.
225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(4).get_payload(decode=True),
226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'This has no Content-Transfer-Encoding: header.\n')
227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_decoded_uu_payload(self):
229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('begin 666 -\n+:&5L;&\\@=V]R;&0 \n \nend\n')
232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg['content-transfer-encoding'] = cte
234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(msg.get_payload(decode=True), 'hello world')
235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Now try some bogus data
236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('foo')
237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(decode=True), 'foo')
238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_decode_bogus_uu_payload_quietly(self):
240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('begin 664 foo.txt\n%<W1F=0000H \n \nend\n')
242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Transfer-Encoding'] = 'x-uuencode'
243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        old_stderr = sys.stderr
244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            sys.stderr = sfp = StringIO()
246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # We don't care about the payload
247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg.get_payload(decode=True)
248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            sys.stderr = old_stderr
250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(sfp.getvalue(), '')
251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_decoded_generator(self):
253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_07.txt')
255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_17.txt')
256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = DecodedGenerator(s)
262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s.getvalue(), text)
264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test__contains__(self):
266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['From'] = 'Me'
268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['to'] = 'You'
269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Check for case insensitivity
270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('from' in msg)
271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('From' in msg)
272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('FROM' in msg)
273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('to' in msg)
274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('To' in msg)
275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('TO' in msg)
276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_as_string(self):
278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_01.txt')
281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # BAW 30-Mar-2009 Evil be here.  So, the generator is broken with
283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # respect to long line breaking.  It's also not idempotent when a
284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # header from a parsed message is continued with tabs rather than
285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # spaces.  Before we fixed bug 1974 it was reversedly broken,
286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # i.e. headers that were continued with spaces got continued with
287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # tabs.  For Python 2.x there's really no good fix and in Python
288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # 3.x all this stuff is re-written to be right(er).  Chris Withers
289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # convinced me that using space as the default continuation
290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # character is less bad for more applications.
291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read().replace('\t', ' ')
292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(text, msg.as_string())
295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fullrepr = str(msg)
296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = fullrepr.split('\n')
297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(lines[0].startswith('From '))
298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(text, NL.join(lines[1:]))
299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_bad_param(self):
301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("Content-Type: blarg; baz; boo\n")
302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('baz'), '')
303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_missing_filename(self):
305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("From: foo\n")
306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(), None)
307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_bogus_filename(self):
309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        "Content-Disposition: blarg; filename\n")
311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(), '')
312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_missing_boundary(self):
314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("From: foo\n")
315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_boundary(), None)
316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_params(self):
318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'X-Header: foo=one; bar=two; baz=three\n')
321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(header='x-header'),
322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('foo', 'one'), ('bar', 'two'), ('baz', 'three')])
323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'X-Header: foo; bar=one; baz=two\n')
325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(header='x-header'),
326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('foo', ''), ('bar', 'one'), ('baz', 'two')])
327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(), None)
328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'X-Header: foo; bar="one"; baz=two\n')
330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(header='x-header'),
331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('foo', ''), ('bar', 'one'), ('baz', 'two')])
332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param_liberal(self):
334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'Content-Type: Multipart/mixed; boundary = "CPIMSSMTPC06p5f3tG"'
336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('boundary'), 'CPIMSSMTPC06p5f3tG')
337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param(self):
339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "X-Header: foo=one; bar=two; baz=three\n")
342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('bar', header='x-header'), 'two')
343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('quuz', header='x-header'), None)
344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('quuz'), None)
345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'X-Header: foo; bar="one"; baz=two\n')
347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('foo', header='x-header'), '')
348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('bar', header='x-header'), 'one')
349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('baz', header='x-header'), 'two')
350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX: We are not RFC-2045 compliant!  We cannot parse:
351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg["Content-Type"] = 'text/plain; weird="hey; dolly? [you] @ <\\"home\\">?"'
352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg.get_param("weird")
353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # yet.
354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param_funky_continuation_lines(self):
356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_22.txt')
357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(1).get_param('name'), 'wibble.JPG')
358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param_with_semis_in_quotes(self):
360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'Content-Type: image/pjpeg; name="Jim&amp;&amp;Jill"\n')
362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('name'), 'Jim&amp;&amp;Jill')
363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('name', unquote=False),
364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         '"Jim&amp;&amp;Jill"')
365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param_with_quotes(self):
367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'Content-Type: foo; bar*0="baz\\"foobar"; bar*1="\\"baz"')
369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz')
370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(
371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "Content-Type: foo; bar*0=\"baz\\\"foobar\"; bar*1=\"\\\"baz\"")
372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz')
373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_has_key(self):
375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string('Header: exists')
376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.has_key('header'))
377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.has_key('Header'))
378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.has_key('HEADER'))
379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertFalse(msg.has_key('headeri'))
380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_param(self):
382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('charset', 'iso-2022-jp')
385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('charset'), 'iso-2022-jp')
386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('importance', 'high value')
387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('importance'), 'high value')
388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('importance', unquote=False), '"high value"')
389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(), [('text/plain', ''),
390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                              ('charset', 'iso-2022-jp'),
391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                              ('importance', 'high value')])
392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(unquote=False), [('text/plain', ''),
393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                       ('charset', '"iso-2022-jp"'),
394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                       ('importance', '"high value"')])
395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('charset', 'iso-9999-xx', header='X-Jimmy')
396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('charset', header='X-Jimmy'), 'iso-9999-xx')
397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_del_param(self):
399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_05.txt')
401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(),
402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('multipart/report', ''), ('report-type', 'delivery-status'),
403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        old_val = msg.get_param("report-type")
405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.del_param("report-type")
406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(),
407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('multipart/report', ''),
408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('boundary', 'D1690A7AC1.996856090/mail.example.com')])
409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param("report-type", old_val)
410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(),
411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('multipart/report', ''),
412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('boundary', 'D1690A7AC1.996856090/mail.example.com'),
413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('report-type', old_val)])
414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_del_param_on_other_header(self):
416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')
418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.del_param('filename', 'content-disposition')
419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg['content-disposition'], 'attachment')
420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_type(self):
422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(ValueError, msg.set_type, 'text')
425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_type('text/plain')
426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain')
427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('charset', 'us-ascii')
428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_type('text/html')
430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/html; charset="us-ascii"')
431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
432edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_type_on_other_header(self):
433edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
434edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['X-Content-Type'] = 'text/plain'
435edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_type('application/octet-stream', 'X-Content-Type')
436edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg['x-content-type'], 'application/octet-stream')
437edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
438edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_missing(self):
439edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
440edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_type(), 'text/plain')
441edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
442edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_missing_with_default_type(self):
443edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
444edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_default_type('message/rfc822')
445edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_type(), 'message/rfc822')
446edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
447edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_from_message_implicit(self):
448edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_30.txt')
449edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_type(),
450edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'message/rfc822')
451edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
452edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_from_message_explicit(self):
453edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_28.txt')
454edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_type(),
455edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'message/rfc822')
456edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
457edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_from_message_text_plain_implicit(self):
458edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_03.txt')
459edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_type(), 'text/plain')
460edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
461edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_type_from_message_text_plain_explicit(self):
462edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
463edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_type(), 'text/plain')
464edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
465edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_missing(self):
466edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
467edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_maintype(), 'text')
468edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
469edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_missing_with_default_type(self):
470edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
471edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_default_type('message/rfc822')
472edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_maintype(), 'message')
473edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
474edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_from_message_implicit(self):
475edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_30.txt')
476edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
477edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
478edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_from_message_explicit(self):
479edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_28.txt')
480edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message')
481edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
482edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_from_message_text_plain_implicit(self):
483edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_03.txt')
484edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_maintype(), 'text')
485edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
486edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_from_message_text_plain_explicit(self):
487edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
488edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_maintype(), 'text')
489edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
490edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_missing(self):
491edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
492edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_subtype(), 'plain')
493edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
494edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_missing_with_default_type(self):
495edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
496edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_default_type('message/rfc822')
497edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_subtype(), 'rfc822')
498edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
499edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_from_message_implicit(self):
500edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_30.txt')
501edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
502edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
503edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_from_message_explicit(self):
504edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_28.txt')
505edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822')
506edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
507edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_from_message_text_plain_implicit(self):
508edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_03.txt')
509edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_subtype(), 'plain')
510edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
511edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_from_message_text_plain_explicit(self):
512edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
513edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_subtype(), 'plain')
514edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
515edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_maintype_error(self):
516edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
517edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'no-slash-in-this-string'
518edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_maintype(), 'text')
519edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
520edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_subtype_error(self):
521edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
522edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'no-slash-in-this-string'
523edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_subtype(), 'plain')
524edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
525edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_replace_header(self):
526edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
527edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
528edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('First', 'One')
529edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Second', 'Two')
530edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Third', 'Three')
531edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.keys(), ['First', 'Second', 'Third'])
532edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.values(), ['One', 'Two', 'Three'])
533edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.replace_header('Second', 'Twenty')
534edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.keys(), ['First', 'Second', 'Third'])
535edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.values(), ['One', 'Twenty', 'Three'])
536edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('First', 'Eleven')
537edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.replace_header('First', 'One Hundred')
538edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.keys(), ['First', 'Second', 'Third', 'First'])
539edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.values(), ['One Hundred', 'Twenty', 'Three', 'Eleven'])
540edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(KeyError, msg.replace_header, 'Fourth', 'Missing')
541edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
542edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_broken_base64_payload(self):
543edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        x = 'AwDp0P7//y6LwKEAcPa/6Q=9'
544edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
545edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['content-type'] = 'audio/x-midi'
546edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['content-transfer-encoding'] = 'base64'
547edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload(x)
548edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_payload(decode=True), x)
549edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
550edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_content_charset(self):
551edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
552edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset('us-ascii')
553edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual('us-ascii', msg.get_content_charset())
554edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset(u'us-ascii')
555edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual('us-ascii', msg.get_content_charset())
556edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
557edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Issue 5871: reject an attempt to embed a header inside a header value
558edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # (header injection attack).
559edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_embeded_header_via_Header_rejected(self):
560edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
561edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Dummy'] = Header('dummy\nX-Injected-Header: test')
562edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(Errors.HeaderParseError, msg.as_string)
563edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
564edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_embeded_header_via_string_rejected(self):
565edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
566edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Dummy'] = 'dummy\nX-Injected-Header: test'
567edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(Errors.HeaderParseError, msg.as_string)
568edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
569edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
570edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the email.Encoders module
571edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestEncoders(unittest.TestCase):
572edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encode_empty_payload(self):
573edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
574edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
575edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_charset('us-ascii')
576edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], '7bit')
577edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
578edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_default_cte(self):
579edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
580edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # 7bit data and the default us-ascii _charset
581edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
582edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], '7bit')
583edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Similar, but with 8bit data
584edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello \xf8 world')
585edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], '8bit')
586edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # And now with a different charset
587edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello \xf8 world', _charset='iso-8859-1')
588edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], 'quoted-printable')
589edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
590edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encode7or8bit(self):
591edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Make sure a charset whose input character set is 8bit but
592edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # whose output character set is 7bit gets a transfer-encoding
593edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # of 7bit.
594edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
595edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.MIMEText.MIMEText('\xca\xb8', _charset='euc-jp')
596edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], '7bit')
597edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
598edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
599edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test long header wrapping
600edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestLongHeaders(TestEmailBase):
601edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_split_long_continuation(self):
602edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
603edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("""\
604edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: bug demonstration
605edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
606edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tmore text
607edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
608edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptest
609edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
610edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
611edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(sfp)
612edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
613edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
614edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: bug demonstration
615edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
616edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep more text
617edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
618edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptest
619edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
620edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
621edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_another_long_almost_unsplittable_header(self):
622edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
623edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hstr = """\
624edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepbug demonstration
625edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
626edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tmore text"""
627edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, continuation_ws='\t')
628edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
629edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepbug demonstration
630edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
631edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tmore text""")
632edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr)
633edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
634edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepbug demonstration
635edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789
636edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep more text""")
637edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
638edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_nonstring(self):
639edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
640edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Charset("iso-8859-1")
641edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cz = Charset("iso-8859-2")
642edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        utf8 = Charset("utf-8")
643edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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. "
644edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
645edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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")
646edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(g_head, g, header_name='Subject')
647edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(cz_head, cz)
648edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(utf8_head, utf8)
649edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
650edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Subject'] = h
651edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
652edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(sfp)
653edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
654edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
655edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
656edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
657edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
658edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
659edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
660edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
661edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
662edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
663edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
664edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
665edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44Gm44GE44G+44GZ44CC?=
666edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
667edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
668edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
669edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerd?=
670edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?erband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndi?=
671edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?schen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Kling?=
672edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?en_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_met?=
673edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-2?q?ropole_se_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?=
674edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE?=
675edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44G+44Gb44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB?=
676edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44GC44Go44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CM?=
677edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?q?Wenn_ist_das_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das?=
678edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?IE9kZXIgZGllIEZsaXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBow==?=
679edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44Gm44GE44G+44GZ44CC?=""")
680edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
681edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_header_encode(self):
682edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
683edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
684edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
685edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   header_name='X-Foobar-Spoink-Defrobnit')
686edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '''\
687edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwasnipoop; giraffes="very-long-necked-animals";
688edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
689edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
690edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_header_encode_with_tab_continuation(self):
691edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
692edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header('wasnipoop; giraffes="very-long-necked-animals"; '
693edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"',
694edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   header_name='X-Foobar-Spoink-Defrobnit',
695edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   continuation_ws='\t')
696edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '''\
697edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwasnipoop; giraffes="very-long-necked-animals";
698edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tspooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''')
699edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
700edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_splitter(self):
701edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
702edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('')
703edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # It'd be great if we could use add_header() here, but that doesn't
704edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # guarantee an order of the parameters.
705edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['X-Foobar-Spoink-Defrobnit'] = (
706edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'wasnipoop; giraffes="very-long-necked-animals"; '
707edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"')
708edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
709edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(sfp)
710edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
711edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), '''\
712edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
713edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
714edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
715edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepX-Foobar-Spoink-Defrobnit: wasnipoop; giraffes="very-long-necked-animals";
716edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"
717edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
718edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
719edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
720edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_semis_header_splitter(self):
721edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
722edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
723edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['From'] = 'test@dom.ain'
724edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['References'] = SPACE.join(['<%d@dom.ain>' % i for i in range(10)])
725edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('Test')
726edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
727edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(sfp)
728edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
729edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
730edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: test@dom.ain
731edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReferences: <0@dom.ain> <1@dom.ain> <2@dom.ain> <3@dom.ain> <4@dom.ain>
732edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep <5@dom.ain> <6@dom.ain> <7@dom.ain> <8@dom.ain> <9@dom.ain>
733edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
734edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTest""")
735edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
736edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_split_long_header(self):
737edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
738edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hstr = 'References: ' + 'x' * 80
739edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, continuation_ws='\t')
740edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
741edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReferences: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""")
742edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
743edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_splitting_multiple_long_lines(self):
744edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
745edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hstr = """\
746edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom 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)
747edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\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)
748edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\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)
749edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
750edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, continuation_ws='\t')
751edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
752edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom babylon.socal-raves.org (localhost [127.0.0.1]);
753edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
754edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfor <mailman-admin@babylon.socal-raves.org>;
755edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tSat, 2 Feb 2002 17:00:06 -0800 (PST)
756edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
757edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
758edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfor <mailman-admin@babylon.socal-raves.org>;
759edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tSat, 2 Feb 2002 17:00:06 -0800 (PST)
760edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfrom babylon.socal-raves.org (localhost [127.0.0.1]);
761edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tby babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81;
762edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfor <mailman-admin@babylon.socal-raves.org>;
763edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tSat, 2 Feb 2002 17:00:06 -0800 (PST)""")
764edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
765edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_splitting_first_line_only_is_long(self):
766edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
767edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hstr = """\
768edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93] helo=cthulhu.gerg.ca)
769edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tby kronos.mems-exchange.org with esmtp (Exim 4.05)
770edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tid 17k4h5-00034i-00
771edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400"""
772edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, maxlinelen=78, header_name='Received',
773edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   continuation_ws='\t')
774edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
775edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93]
776edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\thelo=cthulhu.gerg.ca)
777edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tby kronos.mems-exchange.org with esmtp (Exim 4.05)
778edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tid 17k4h5-00034i-00
779edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400""")
780edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
781edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_8bit_header(self):
782edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
783edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
784edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header('Britische Regierung gibt', 'iso-8859-1',
785edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    header_name='Subject')
786edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte')
787edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Subject'] = h
788edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
789edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: =?iso-8859-1?q?Britische_Regierung_gibt?= =?iso-8859-1?q?gr=FCnes?=
790edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?_Licht_f=FCr_Offshore-Windkraftprojekte?=
791edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
792edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
793edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
794edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_8bit_header_no_charset(self):
795edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
796edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
797edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Reply-To'] = 'Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>'
798edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
799edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReply-To: Britische Regierung gibt gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte <a-very-long-address@example.com>
800edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
801edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
802edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
803edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_to_header(self):
804edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
805edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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>'
806edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
807edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['To'] = to
808edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(0), '''\
809edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: "Someone Test #A" <someone@eecs.umich.edu>, <someone@eecs.umich.edu>,
810edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "Someone Test #B" <someone@umich.edu>,
811edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "Someone Test #C" <someone@eecs.umich.edu>,
812edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "Someone Test #D" <someone@eecs.umich.edu>
813edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
814edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
815edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
816edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_line_after_append(self):
817edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
818edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'This is an example of string which has almost the limit of header length.'
819edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(s)
820edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('Add another line.')
821edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
822edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThis is an example of string which has almost the limit of header length.
823edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Add another line.""")
824edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
825edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_shorter_line_with_append(self):
826edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
827edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'This is a shorter line.'
828edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(s)
829edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('Add another sentence. (Surprise?)')
830edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(),
831edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'This is a shorter line. Add another sentence. (Surprise?)')
832edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
833edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_field_name(self):
834edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
835edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fn = 'X-Very-Very-Very-Long-Header-Name'
836edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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. "
837edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(gs, 'iso-8859-1', header_name=fn)
838edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # BAW: this seems broken because the first line is too long
839edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), """\
840edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?q?Die_Mieter_treten_hier_?=
841edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?ein_werden_mit_einem_Foerderband_komfortabel_den_Korridor_?=
842edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?entlang=2C_an_s=FCdl=FCndischen_Wandgem=E4lden_vorbei=2C_g?=
843edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?egen_die_rotierenden_Klingen_bef=F6rdert=2E_?=""")
844edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
845edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_received_header(self):
846edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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'
847edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
848edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Received-1'] = Header(h, continuation_ws='\t')
849edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Received-2'] = h
850edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.as_string(), """\
851edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
852edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\throthgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
853edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tWed, 05 Mar 2003 18:10:18 -0700
854edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by
855edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP;
856edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Wed, 05 Mar 2003 18:10:18 -0700
857edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
858edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
859edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
860edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_string_headerinst_eq(self):
861edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = '<15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de> (David Bremner\'s message of "Thu, 6 Mar 2003 13:58:21 +0100")'
862edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
863edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Received'] = Header(h, header_name='Received',
864edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                 continuation_ws='\t')
865edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Received'] = h
866edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.ndiffAssertEqual(msg.as_string(), """\
867edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
868edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\t(David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
869edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de>
870edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep (David Bremner's message of "Thu, 6 Mar 2003 13:58:21 +0100")
871edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
872edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
873edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
874edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_unbreakable_lines_with_continuation(self):
875edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
876edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
877edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t = """\
878edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
879edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp"""
880edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Face-1'] = t
881edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Face-2'] = Header(t, header_name='Face-2')
882edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
883edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFace-1: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
884edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
885edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFace-2: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9
886edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp
887edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
888edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
889edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
890edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_another_long_multiline_header(self):
891edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
892edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
893edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with Microsoft SMTPSVC(5.0.2195.4905);
894edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Wed, 16 Oct 2002 07:41:11 -0700'''
895edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
896edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), '''\
897edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with
898edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Microsoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700
899edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
900edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
901edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
902edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_lines_with_different_header(self):
903edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
904edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = """\
905edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepList-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
906edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>"""
907edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
908edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['List'] = h
909edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['List'] = Header(h, header_name='List')
910edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
911edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepList: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
912edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
913edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepList: List-Unsubscribe: <https://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,
914edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe>
915edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
916edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
917edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
918edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
919edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
920edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test mangling of "From " lines in the body of a message
921edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestFromMangling(unittest.TestCase):
922edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
923edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.msg = Message()
924edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.msg['From'] = 'aaa@bbb.org'
925edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.msg.set_payload("""\
926edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom the desk of A.A.A.:
927edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepBlah blah blah
928edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
929edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
930edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_mangled_from(self):
931edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
932edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s, mangle_from_=True)
933edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(self.msg)
934edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(s.getvalue(), """\
935edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aaa@bbb.org
936edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
937edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep>From the desk of A.A.A.:
938edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepBlah blah blah
939edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
940edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
941edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_dont_mangle_from(self):
942edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
943edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s, mangle_from_=False)
944edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(self.msg)
945edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(s.getvalue(), """\
946edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aaa@bbb.org
947edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
948edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom the desk of A.A.A.:
949edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepBlah blah blah
950edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
951edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
952edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_mangle_from_in_preamble_and_epilog(self):
953edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
954edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s, mangle_from_=True)
955edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(textwrap.dedent("""\
956edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            From: foo@bar.com
957edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Mime-Version: 1.0
958edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Content-Type: multipart/mixed; boundary=XXX
959edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
960edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            From somewhere unknown
961edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
962edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            --XXX
963edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Content-Type: text/plain
964edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
965edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            foo
966edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
967edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            --XXX--
968edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
969edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            From somewhere unknowable
970edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            """))
971edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
972edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len([1 for x in s.getvalue().split('\n')
973edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                  if x.startswith('>From ')]), 2)
974edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
975edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
976edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the basic MIMEAudio class
977edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMIMEAudio(unittest.TestCase):
978edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
979edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Make sure we pick up the audiotest.au that lives in email/test/data.
980edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # In Python, there's an audiotest.au living in Lib/test but that isn't
981edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # included in some binary distros that don't include the test
982edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # package.  The trailing empty string on the .join() is significant
983edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # since findfile() will do a dirname().
984edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        datadir = os.path.join(os.path.dirname(landmark), 'data', '')
985edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = open(findfile('audiotest.au', datadir), 'rb')
986edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
987edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._audiodata = fp.read()
988edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
989edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
990edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._au = MIMEAudio(self._audiodata)
991edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
992edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_guess_minor_type(self):
993edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(self._au.get_content_type(), 'audio/basic')
994edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
995edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encoding(self):
996edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = self._au.get_payload()
997edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(base64.decodestring(payload), self._audiodata)
998edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
999edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_checkSetMinor(self):
1000edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        au = MIMEAudio(self._audiodata, 'fish')
1001edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(au.get_content_type(), 'audio/fish')
1002edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1003edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_add_header(self):
1004edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1005edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1006edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._au.add_header('Content-Disposition', 'attachment',
1007edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            filename='audiotest.au')
1008edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._au['content-disposition'],
1009edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'attachment; filename="audiotest.au"')
1010edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._au.get_params(header='content-disposition'),
1011edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('attachment', ''), ('filename', 'audiotest.au')])
1012edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._au.get_param('filename', header='content-disposition'),
1013edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'audiotest.au')
1014edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        missing = []
1015edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._au.get_param('attachment', header='content-disposition'), '')
1016edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._au.get_param('foo', failobj=missing,
1017edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                  header='content-disposition') is missing)
1018edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try some missing stuff
1019edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._au.get_param('foobar', missing) is missing)
1020edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._au.get_param('attachment', missing,
1021edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                  header='foobar') is missing)
1022edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1023edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1024edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1025edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the basic MIMEImage class
1026edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMIMEImage(unittest.TestCase):
1027edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
1028edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('PyBanner048.gif')
1029edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1030edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._imgdata = fp.read()
1031edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1032edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1033edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._im = MIMEImage(self._imgdata)
1034edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1035edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_guess_minor_type(self):
1036edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(self._im.get_content_type(), 'image/gif')
1037edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1038edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encoding(self):
1039edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = self._im.get_payload()
1040edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(base64.decodestring(payload), self._imgdata)
1041edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1042edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_checkSetMinor(self):
1043edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        im = MIMEImage(self._imgdata, 'fish')
1044edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(im.get_content_type(), 'image/fish')
1045edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1046edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_add_header(self):
1047edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1048edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1049edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._im.add_header('Content-Disposition', 'attachment',
1050edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                            filename='dingusfish.gif')
1051edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._im['content-disposition'],
1052edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'attachment; filename="dingusfish.gif"')
1053edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._im.get_params(header='content-disposition'),
1054edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('attachment', ''), ('filename', 'dingusfish.gif')])
1055edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._im.get_param('filename', header='content-disposition'),
1056edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'dingusfish.gif')
1057edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        missing = []
1058edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._im.get_param('attachment', header='content-disposition'), '')
1059edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._im.get_param('foo', failobj=missing,
1060edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                  header='content-disposition') is missing)
1061edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try some missing stuff
1062edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._im.get_param('foobar', missing) is missing)
1063edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._im.get_param('attachment', missing,
1064edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                  header='foobar') is missing)
1065edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1066edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1067edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1068edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the basic MIMEText class
1069edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMIMEText(unittest.TestCase):
1070edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
1071edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._msg = MIMEText('hello there')
1072edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1073edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_types(self):
1074edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1075edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1076edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._msg.get_content_type(), 'text/plain')
1077edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(self._msg.get_param('charset'), 'us-ascii')
1078edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        missing = []
1079edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._msg.get_param('foobar', missing) is missing)
1080edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(self._msg.get_param('charset', missing, header='foobar')
1081edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep               is missing)
1082edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1083edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_payload(self):
1084edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(self._msg.get_payload(), 'hello there')
1085edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(not self._msg.is_multipart())
1086edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1087edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_charset(self):
1088edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1089edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello there', _charset='us-ascii')
1090edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset().input_charset, 'us-ascii')
1091edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
1092edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1093edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_7bit_unicode_input(self):
1094edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1095edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText(u'hello there', _charset='us-ascii')
1096edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset().input_charset, 'us-ascii')
1097edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
1098edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1099edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_7bit_unicode_input_no_charset(self):
1100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText(u'hello there')
1102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset(), 'us-ascii')
1103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="us-ascii"')
1104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue('hello there' in msg.as_string())
1105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_8bit_unicode_input(self):
1107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        teststr = u'\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430'
1108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText(teststr, _charset='utf-8')
1110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_charset().output_charset, 'utf-8')
1111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset="utf-8"')
1112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(decode=True), teststr.encode('utf-8'))
1113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_8bit_unicode_input_no_charset(self):
1115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        teststr = u'\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430'
1116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(UnicodeEncodeError, MIMEText, teststr)
1117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test complicated multipart/* messages
1121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMultipart(TestEmailBase):
1122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
1123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('PyBanner048.gif')
1124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            data = fp.read()
1126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY')
1130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        image = MIMEImage(data, name='dingusfish.gif')
1131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        image.add_header('content-disposition', 'attachment',
1132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         filename='dingusfish.gif')
1133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        intro = MIMEText('''\
1134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHi there,
1135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThis is the dingus fish.
1137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container.attach(intro)
1139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container.attach(image)
1140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container['From'] = 'Barry <barry@digicool.com>'
1141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>'
1142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container['Subject'] = 'Here is your dingus fish'
1143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        now = 987809702.54848599
1145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        timetuple = time.localtime(now)
1146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if timetuple[-1] == 0:
1147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            tzsecs = time.timezone
1148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
1149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            tzsecs = time.altzone
1150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if tzsecs > 0:
1151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            sign = '-'
1152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        else:
1153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            sign = '+'
1154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        tzoffset = ' %s%04d' % (sign, tzsecs // 36)
1155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container['Date'] = time.strftime(
1156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            '%a, %d %b %Y %H:%M:%S',
1157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.localtime(now)) + tzoffset
1158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._msg = container
1159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._im = image
1160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._txt = intro
1161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_hierarchy(self):
1163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # convenience
1164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises = self.assertRaises
1167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # tests
1168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = self._msg
1169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(m.is_multipart())
1170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(m.get_content_type(), 'multipart/mixed')
1171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(m.get_payload()), 2)
1172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises(IndexError, m.get_payload, 2)
1173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m0 = m.get_payload(0)
1174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m1 = m.get_payload(1)
1175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(m0 is self._txt)
1176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(m1 is self._im)
1177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(m.get_payload(), [m0, m1])
1178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(not m0.is_multipart())
1179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(not m1.is_multipart())
1180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_empty_multipart_idempotent(self):
1182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text = """\
1183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
1195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Parser().parsestr(text)
1196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.ndiffAssertEqual(text, msg.as_string())
1197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_parts_in_a_multipart_with_none_epilogue(self):
1199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.ndiffAssertEqual(outer.as_string(), '''\
1205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--''')
1214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_parts_in_a_multipart_with_empty_epilogue(self):
1216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.preamble = ''
1221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.epilogue = ''
1222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.ndiffAssertEqual(outer.as_string(), '''\
1224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_one_part_in_a_multipart(self):
1237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--''')
1259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_seq_parts_in_a_multipart_with_empty_preamble(self):
1261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.preamble = ''
1267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--''')
1285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_seq_parts_in_a_multipart_with_none_preamble(self):
1288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.preamble = None
1294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--''')
1311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_seq_parts_in_a_multipart_with_none_epilogue(self):
1314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.epilogue = None
1320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--''')
1337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_seq_parts_in_a_multipart_with_empty_epilogue(self):
1340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.epilogue = ''
1346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_seq_parts_in_a_multipart_with_nl_epilogue(self):
1367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = MIMEBase('multipart', 'mixed')
1369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['Subject'] = 'A subject'
1370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['To'] = 'aperson@dom.ain'
1371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer['From'] = 'bperson@dom.ain'
1372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.epilogue = '\n'
1373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEText('hello world')
1374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.attach(msg)
1375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer.set_boundary('BOUNDARY')
1376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(outer.as_string(), '''\
1377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: A subject
1380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: aperson@dom.ain
1381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bperson@dom.ain
1382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephello world
1389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_external_body(self):
1394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_36.txt')
1396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 2)
1397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = msg.get_payload(1)
1398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg1.get_content_type(), 'multipart/alternative')
1399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg1.get_payload()), 2)
1400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for subpart in msg1.get_payload():
1401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(subpart.get_content_type(), 'message/external-body')
1402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(len(subpart.get_payload()), 1)
1403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            subsubpart = subpart.get_payload(0)
1404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(subsubpart.get_content_type(), 'text/plain')
1405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_double_boundary(self):
1407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg_37.txt is a multipart that contains two dash-boundary's in a
1408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # row.  Our interpretation of RFC 2046 calls for ignoring the second
1409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # and subsequent boundaries.
1410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_37.txt')
1411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len(msg.get_payload()), 3)
1412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_nested_inner_contains_outer_boundary(self):
1414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg_38.txt has an inner part that contains outer boundaries.  My
1416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # interpretation of RFC 2046 (based on sections 5.1 and 5.1.2) say
1417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # these are illegal and should be interpreted as unterminated inner
1418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # parts.
1419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_38.txt')
1420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
1421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        Iterators._structure(msg, sfp)
1422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
1423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmultipart/mixed
1424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    multipart/mixed
1425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        multipart/alternative
1426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text/plain
1427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
1428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    text/plain
1429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    text/plain
1430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1432edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_nested_with_same_boundary(self):
1433edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1434edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg 39.txt is similarly evil in that it's got inner parts that use
1435edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # the same boundary as outer parts.  Again, I believe the way this is
1436edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # parsed is closest to the spirit of RFC 2046
1437edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_39.txt')
1438edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
1439edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        Iterators._structure(msg, sfp)
1440edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
1441edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmultipart/mixed
1442edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    multipart/mixed
1443edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        multipart/alternative
1444edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        application/octet-stream
1445edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        application/octet-stream
1446edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    text/plain
1447edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1448edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1449edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_boundary_in_non_multipart(self):
1450edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_40.txt')
1451edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.as_string(), '''\
1452edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1453edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/html; boundary="--961284236552522269"
1454edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1455edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep----961284236552522269
1456edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/html;
1457edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7Bit
1458edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1459edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep<html></html>
1460edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1461edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep----961284236552522269--
1462edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1463edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1464edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_boundary_with_leading_space(self):
1465edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1466edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string('''\
1467edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1468edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="    XXXX"
1469edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1470edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--    XXXX
1471edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain
1472edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1473edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1474edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--    XXXX
1475edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain
1476edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1477edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--    XXXX--
1478edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1479edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.is_multipart())
1480edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_boundary(), '    XXXX')
1481edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 2)
1482edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1483edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_boundary_without_trailing_newline(self):
1484edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = Parser().parsestr("""\
1485edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="===============0012394164=="
1486edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1487edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1488edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--===============0012394164==
1489edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: image/file1.jpg
1490edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1491edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: base64
1492edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1493edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepYXNkZg==
1494edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--===============0012394164==--""")
1495edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(m.get_payload(0).get_payload(), 'YXNkZg==')
1496edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1497edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1498edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1499edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test some badly formatted messages
1500edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestNonConformant(TestEmailBase):
1501edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parse_missing_minor_type(self):
1502edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1503edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_14.txt')
1504edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
1505edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_maintype(), 'text')
1506edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_subtype(), 'plain')
1507edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1508edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_same_boundary_inner_outer(self):
1509edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1510edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_15.txt')
1511edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # XXX We can probably eventually do better
1512edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        inner = msg.get_payload(0)
1513edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(hasattr(inner, 'defects'))
1514edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len(inner.defects), 1)
1515edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(inner.defects[0],
1516edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                          Errors.StartBoundaryNotFoundDefect))
1517edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1518edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multipart_no_boundary(self):
1519edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1520edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_25.txt')
1521edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg.get_payload(), str))
1522edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len(msg.defects), 2)
1523edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect))
1524edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg.defects[1],
1525edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                          Errors.MultipartInvariantViolationDefect))
1526edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1527edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_invalid_content_type(self):
1528edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1529edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq = self.ndiffAssertEqual
1530edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
1531edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # RFC 2045, $5.2 says invalid yields text/plain
1532edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'text'
1533edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_maintype(), 'text')
1534edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_subtype(), 'plain')
1535edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
1536edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Clear the old value and try something /really/ invalid
1537edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del msg['content-type']
1538edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'foo'
1539edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_maintype(), 'text')
1540edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_subtype(), 'plain')
1541edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
1542edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Still, make sure that the message is idempotently generated
1543edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
1544edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s)
1545edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
1546edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(s.getvalue(), 'Content-Type: foo\n\n')
1547edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1548edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_start_boundary(self):
1549edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1550edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_31.txt')
1551edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), """\
1552edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1553edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain
1554edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1555edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 1
1556edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1557edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1558edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain
1559edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1560edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 2
1561edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1562edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1563edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1564edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1565edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_separating_blank_line(self):
1566edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1567edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_35.txt')
1568edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
1569edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aperson@dom.ain
1570edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bperson@dom.ain
1571edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: here's something interesting
1572edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1573edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepcounter to RFC 2822, there's no separating newline here
1574edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1575edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1576edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_lying_multipart(self):
1577edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1578edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_41.txt')
1579edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(hasattr(msg, 'defects'))
1580edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len(msg.defects), 2)
1581edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect))
1582edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg.defects[1],
1583edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                          Errors.MultipartInvariantViolationDefect))
1584edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1585edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_missing_start_boundary(self):
1586edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outer = self._msgobj('msg_42.txt')
1587edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The message structure is:
1588edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #
1589edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # multipart/mixed
1590edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #    text/plain
1591edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #    message/rfc822
1592edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #        multipart/mixed [*]
1593edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #
1594edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # [*] This message is missing its start boundary
1595edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        bad = outer.get_payload(1).get_payload(0)
1596edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(len(bad.defects), 1)
1597edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(bad.defects[0],
1598edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                   Errors.StartBoundaryNotFoundDefect))
1599edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1600edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_first_line_is_continuation_header(self):
1601edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1602edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = ' Line 1\nLine 2\nLine 3'
1603edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
1604edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.keys(), [])
1605edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), 'Line 2\nLine 3')
1606edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.defects), 1)
1607edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(msg.defects[0],
1608edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                   Errors.FirstHeaderLineIsContinuationDefect))
1609edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.defects[0].line, ' Line 1\n')
1610edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1611edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1612edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1613edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1614edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test RFC 2047 header encoding and decoding
1615edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestRFC2047(unittest.TestCase):
1616edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2047_multiline(self):
1617edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1618edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz
1619edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep foo bar =?mac-iceland?q?r=8Aksm=9Arg=8Cs?="""
1620edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dh = decode_header(s)
1621edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dh, [
1622edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('Re:', None),
1623edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('r\x8aksm\x9arg\x8cs', 'mac-iceland'),
1624edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('baz foo bar', None),
1625edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('r\x8aksm\x9arg\x8cs', 'mac-iceland')])
1626edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(str(make_header(dh)),
1627edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz foo bar
1628edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?mac-iceland?q?r=8Aksm=9Arg=8Cs?=""")
1629edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1630edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_whitespace_eater_unicode(self):
1631edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1632edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = '=?ISO-8859-1?Q?Andr=E9?= Pirard <pirard@dom.ain>'
1633edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dh = decode_header(s)
1634edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dh, [('Andr\xe9', 'iso-8859-1'), ('Pirard <pirard@dom.ain>', None)])
1635edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hu = unicode(make_header(dh)).encode('latin-1')
1636edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(hu, 'Andr\xe9 Pirard <pirard@dom.ain>')
1637edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1638edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_whitespace_eater_unicode_2(self):
1639edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1640edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'The =?iso-8859-1?b?cXVpY2sgYnJvd24gZm94?= jumped over the =?iso-8859-1?b?bGF6eSBkb2c=?='
1641edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dh = decode_header(s)
1642edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dh, [('The', None), ('quick brown fox', 'iso-8859-1'),
1643edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                ('jumped over the', None), ('lazy dog', 'iso-8859-1')])
1644edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hu = make_header(dh).__unicode__()
1645edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(hu, u'The quick brown fox jumped over the lazy dog')
1646edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1647edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2047_without_whitespace(self):
1648edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'Sm=?ISO-8859-1?B?9g==?=rg=?ISO-8859-1?B?5Q==?=sbord'
1649edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dh = decode_header(s)
1650edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(dh, [(s, None)])
1651edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1652edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2047_with_whitespace(self):
1653edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'Sm =?ISO-8859-1?B?9g==?= rg =?ISO-8859-1?B?5Q==?= sbord'
1654edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dh = decode_header(s)
1655edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(dh, [('Sm', None), ('\xf6', 'iso-8859-1'),
1656edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                              ('rg', None), ('\xe5', 'iso-8859-1'),
1657edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                              ('sbord', None)])
1658edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1659edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2047_B_bad_padding(self):
1660edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = '=?iso-8859-1?B?%s?='
1661edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        data = [                                # only test complete bytes
1662edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('dm==', 'v'), ('dm=', 'v'), ('dm', 'v'),
1663edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('dmk=', 'vi'), ('dmk', 'vi')
1664edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          ]
1665edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for q, a in data:
1666edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            dh = decode_header(s % q)
1667edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertEqual(dh, [(a, 'iso-8859-1')])
1668edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1669edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2047_Q_invalid_digits(self):
1670edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # issue 10004.
1671edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = '=?iso-8659-1?Q?andr=e9=zz?='
1672edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(decode_header(s),
1673edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                        [(b'andr\xe9=zz', 'iso-8659-1')])
1674edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1675edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1676edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the MIMEMessage class
1677edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMIMEMessage(TestEmailBase):
1678edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
1679edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_11.txt')
1680edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1681edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self._text = fp.read()
1682edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1683edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1684edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1685edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_type_error(self):
1686edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(TypeError, MIMEMessage, 'a plain string')
1687edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1688edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_valid_argument(self):
1689edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1690edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1691edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subject = 'A sub-message'
1692edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = Message()
1693edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m['Subject'] = subject
1694edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        r = MIMEMessage(m)
1695edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(r.get_content_type(), 'message/rfc822')
1696edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = r.get_payload()
1697edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(payload, list))
1698edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(payload), 1)
1699edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart = payload[0]
1700edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(subpart is m)
1701edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart['subject'], subject)
1702edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1703edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_bad_multipart(self):
1704edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1705edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = Message()
1706edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1['Subject'] = 'subpart 1'
1707edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg2 = Message()
1708edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg2['Subject'] = 'subpart 2'
1709edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        r = MIMEMessage(msg1)
1710edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(Errors.MultipartConversionError, r.attach, msg2)
1711edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1712edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_generate(self):
1713edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # First craft the message to be encapsulated
1714edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = Message()
1715edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m['Subject'] = 'An enclosed message'
1716edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m.set_payload('Here is the body of the message.\n')
1717edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        r = MIMEMessage(m)
1718edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        r['Subject'] = 'The enclosing message'
1719edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
1720edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s)
1721edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(r)
1722edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(s.getvalue(), """\
1723edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: message/rfc822
1724edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1725edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: The enclosing message
1726edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1727edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: An enclosed message
1728edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1729edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHere is the body of the message.
1730edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1731edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1732edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parse_message_rfc822(self):
1733edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1734edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1735edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_11.txt')
1736edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'message/rfc822')
1737edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = msg.get_payload()
1738edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(payload, list))
1739edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(payload), 1)
1740edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        submsg = payload[0]
1741edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(submsg, Message))
1742edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(submsg['subject'], 'An enclosed message')
1743edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(submsg.get_payload(), 'Here is the body of the message.\n')
1744edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1745edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_dsn(self):
1746edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1747edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
1748edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # msg 16 is a Delivery Status Notification, see RFC 1894
1749edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_16.txt')
1750edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'multipart/report')
1751edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(msg.is_multipart())
1752edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 3)
1753edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 1 is a text/plain, human readable section
1754edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart = msg.get_payload(0)
1755edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart.get_content_type(), 'text/plain')
1756edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart.get_payload(), """\
1757edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThis report relates to a message you sent with the following header fields:
1758edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1759edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  Message-id: <002001c144a6$8752e060$56104586@oxy.edu>
1760edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  Date: Sun, 23 Sep 2001 20:10:55 -0700
1761edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  From: "Ian T. Henry" <henryi@oxy.edu>
1762edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  To: SoCal Raves <scr@socal-raves.org>
1763edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  Subject: [scr] yeah for Ians!!
1764edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1765edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepYour message cannot be delivered to the following recipients:
1766edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1767edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  Recipient address: jangel1@cougar.noc.ucla.edu
1768edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep  Reason: recipient reached disk quota
1769edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1770edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1771edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 2 contains the machine parsable DSN information.  It
1772edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # consists of two blocks of headers, represented by two nested Message
1773edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # objects.
1774edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart = msg.get_payload(1)
1775edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart.get_content_type(), 'message/delivery-status')
1776edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(subpart.get_payload()), 2)
1777edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # message/delivery-status should treat each block as a bunch of
1778edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # headers, i.e. a bunch of Message objects.
1779edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dsn1 = subpart.get_payload(0)
1780edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(dsn1, Message))
1781edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn1['original-envelope-id'], '0GK500B4HD0888@cougar.noc.ucla.edu')
1782edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn1.get_param('dns', header='reporting-mta'), '')
1783edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try a missing one <wink>
1784edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn1.get_param('nsd', header='reporting-mta'), None)
1785edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        dsn2 = subpart.get_payload(1)
1786edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(dsn2, Message))
1787edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn2['action'], 'failed')
1788edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn2.get_params(header='original-recipient'),
1789edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('rfc822', ''), ('jangel1@cougar.noc.ucla.edu', '')])
1790edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(dsn2.get_param('rfc822', header='final-recipient'), '')
1791edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Subpart 3 is the original message
1792edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart = msg.get_payload(2)
1793edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart.get_content_type(), 'message/rfc822')
1794edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = subpart.get_payload()
1795edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(payload, list))
1796edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(payload), 1)
1797edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subsubpart = payload[0]
1798edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(subsubpart, Message))
1799edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subsubpart.get_content_type(), 'text/plain')
1800edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subsubpart['message-id'],
1801edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '<002001c144a6$8752e060$56104586@oxy.edu>')
1802edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1803edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_epilogue(self):
1804edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1805edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_21.txt')
1806edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1807edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
1808edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1809edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1810edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
1811edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['From'] = 'aperson@dom.ain'
1812edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['To'] = 'bperson@dom.ain'
1813edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Subject'] = 'Test'
1814edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.preamble = 'MIME message'
1815edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.epilogue = 'End of MIME message\n'
1816edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = MIMEText('One')
1817edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg2 = MIMEText('Two')
1818edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
1819edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.attach(msg1)
1820edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.attach(msg2)
1821edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
1822edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(sfp)
1823edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
1824edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), text)
1825edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1826edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_nl_preamble(self):
1827edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
1828edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
1829edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['From'] = 'aperson@dom.ain'
1830edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['To'] = 'bperson@dom.ain'
1831edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Subject'] = 'Test'
1832edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.preamble = 'MIME message'
1833edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.epilogue = ''
1834edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = MIMEText('One')
1835edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg2 = MIMEText('Two')
1836edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY')
1837edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.attach(msg1)
1838edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.attach(msg2)
1839edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
1840edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aperson@dom.ain
1841edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bperson@dom.ain
1842edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: Test
1843edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/mixed; boundary="BOUNDARY"
1844edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1845edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME message
1846edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1847edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1848edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1849edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1850edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1851edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepOne
1852edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1853edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1854edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1855edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1856edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1857edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTwo
1858edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1859edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
1860edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1861edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_default_type(self):
1862edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1863edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_30.txt')
1864edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1865edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp)
1866edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1867edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1868edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container1 = msg.get_payload(0)
1869edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1.get_default_type(), 'message/rfc822')
1870edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1.get_content_type(), 'message/rfc822')
1871edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container2 = msg.get_payload(1)
1872edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2.get_default_type(), 'message/rfc822')
1873edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2.get_content_type(), 'message/rfc822')
1874edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container1a = container1.get_payload(0)
1875edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1a.get_default_type(), 'text/plain')
1876edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1a.get_content_type(), 'text/plain')
1877edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container2a = container2.get_payload(0)
1878edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2a.get_default_type(), 'text/plain')
1879edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2a.get_content_type(), 'text/plain')
1880edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1881edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_default_type_with_explicit_container_type(self):
1882edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1883edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_28.txt')
1884edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1885edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp)
1886edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
1887edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
1888edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container1 = msg.get_payload(0)
1889edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1.get_default_type(), 'message/rfc822')
1890edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1.get_content_type(), 'message/rfc822')
1891edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container2 = msg.get_payload(1)
1892edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2.get_default_type(), 'message/rfc822')
1893edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2.get_content_type(), 'message/rfc822')
1894edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container1a = container1.get_payload(0)
1895edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1a.get_default_type(), 'text/plain')
1896edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container1a.get_content_type(), 'text/plain')
1897edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container2a = container2.get_payload(0)
1898edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2a.get_default_type(), 'text/plain')
1899edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(container2a.get_content_type(), 'text/plain')
1900edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1901edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_default_type_non_parsed(self):
1902edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1903edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq = self.ndiffAssertEqual
1904edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Set up container
1905edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container = MIMEMultipart('digest', 'BOUNDARY')
1906edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container.epilogue = ''
1907edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Set up subparts
1908edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart1a = MIMEText('message 1\n')
1909edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart2a = MIMEText('message 2\n')
1910edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart1 = MIMEMessage(subpart1a)
1911edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subpart2 = MIMEMessage(subpart2a)
1912edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container.attach(subpart1)
1913edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        container.attach(subpart2)
1914edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart1.get_content_type(), 'message/rfc822')
1915edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart1.get_default_type(), 'message/rfc822')
1916edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart2.get_content_type(), 'message/rfc822')
1917edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart2.get_default_type(), 'message/rfc822')
1918edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(container.as_string(0), '''\
1919edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/digest; boundary="BOUNDARY"
1920edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1921edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1922edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1923edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: message/rfc822
1924edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1925edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1926edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1927edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1928edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1929edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1930edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 1
1931edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1932edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1933edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: message/rfc822
1934edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1935edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1936edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1937edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1938edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1939edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1940edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 2
1941edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1942edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1943edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1944edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del subpart1['content-type']
1945edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del subpart1['mime-version']
1946edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del subpart2['content-type']
1947edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        del subpart2['mime-version']
1948edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart1.get_content_type(), 'message/rfc822')
1949edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart1.get_default_type(), 'message/rfc822')
1950edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart2.get_content_type(), 'message/rfc822')
1951edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subpart2.get_default_type(), 'message/rfc822')
1952edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(container.as_string(0), '''\
1953edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/digest; boundary="BOUNDARY"
1954edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1955edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1956edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1957edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1958edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1959edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1960edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1961edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1962edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 1
1963edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1964edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY
1965edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1966edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii"
1967edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
1968edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
1969edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1970edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmessage 2
1971edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1972edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep--BOUNDARY--
1973edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep''')
1974edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1975edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_mime_attachments_in_constructor(self):
1976edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
1977edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text1 = MIMEText('')
1978edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text2 = MIMEText('')
1979edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEMultipart(_subparts=(text1, text2))
1980edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 2)
1981edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(0), text1)
1982edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(1), text2)
1983edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1984edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_default_multipart_constructor(self):
1985edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = MIMEMultipart()
1986edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.is_multipart())
1987edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1988edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
1989edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# A general test of parser->model->generator idempotency.  IOW, read a message
1990edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# in, parse it into a message object tree, then without touching the tree,
1991edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# regenerate the plain text.  The original text and the transformed text
1992edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# should be identical.  Note: that we ignore the Unix-From since that may
1993edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# contain a changed date.
1994edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestIdempotent(TestEmailBase):
1995edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _msgobj(self, filename):
1996edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile(filename)
1997edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
1998edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            data = fp.read()
1999edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2000edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2001edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(data)
2002edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return msg, data
2003edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2004edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _idempotent(self, msg, text):
2005edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
2006edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
2007edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s, maxheaderlen=0)
2008edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
2009edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(text, s.getvalue())
2010edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2011edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parse_text_message(self):
2012edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2013edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_01.txt')
2014edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
2015edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_maintype(), 'text')
2016edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_subtype(), 'plain')
2017edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params()[1], ('charset', 'us-ascii'))
2018edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('charset'), 'us-ascii')
2019edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.preamble, None)
2020edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.epilogue, None)
2021edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2022edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2023edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parse_untyped_message(self):
2024edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2025edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_03.txt')
2026edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'text/plain')
2027edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_params(), None)
2028edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('charset'), None)
2029edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2030edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2031edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_simple_multipart(self):
2032edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_04.txt')
2033edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2034edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2035edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_MIME_digest(self):
2036edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_02.txt')
2037edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2038edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2039edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_header(self):
2040edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_27.txt')
2041edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2042edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2043edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_MIME_digest_with_part_headers(self):
2044edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_28.txt')
2045edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2046edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2047edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_mixed_with_image(self):
2048edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_06.txt')
2049edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2050edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2051edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multipart_report(self):
2052edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_05.txt')
2053edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2054edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2055edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_dsn(self):
2056edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_16.txt')
2057edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2058edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2059edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_preamble_epilogue(self):
2060edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_21.txt')
2061edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2062edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2063edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multipart_one_part(self):
2064edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_23.txt')
2065edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2066edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2067edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multipart_no_parts(self):
2068edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_24.txt')
2069edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2070edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2071edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_no_start_boundary(self):
2072edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_31.txt')
2073edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2074edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2075edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_charset(self):
2076edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_32.txt')
2077edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2078edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2079edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_more_rfc2231_parameters(self):
2080edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_33.txt')
2081edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2082edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2083edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_text_plain_in_a_multipart_digest(self):
2084edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_34.txt')
2085edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2086edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2087edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_nested_multipart_mixeds(self):
2088edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_12a.txt')
2089edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2090edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2091edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_external_body_idempotent(self):
2092edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_36.txt')
2093edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._idempotent(msg, text)
2094edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2095edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_content_type(self):
2096edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2097edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
2098edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Get a message object and reset the seek pointer for other tests
2099edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_05.txt')
2100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'multipart/report')
2101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the Content-Type: parameters
2102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        params = {}
2103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for pk, pv in msg.get_params():
2104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            params[pk] = pv
2105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(params['report-type'], 'delivery-status')
2106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(params['boundary'], 'D1690A7AC1.996856090/mail.example.com')
2107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.preamble, 'This is a MIME-encapsulated message.\n')
2108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.epilogue, '\n')
2109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 3)
2110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Make sure the subparts are what we expect
2111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = msg.get_payload(0)
2112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg1.get_content_type(), 'text/plain')
2113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg1.get_payload(), 'Yadda yadda yadda\n')
2114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg2 = msg.get_payload(1)
2115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg2.get_content_type(), 'text/plain')
2116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg2.get_payload(), 'Yadda yadda yadda\n')
2117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg3 = msg.get_payload(2)
2118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg3.get_content_type(), 'message/rfc822')
2119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(msg3, Message))
2120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = msg3.get_payload()
2121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(payload, list))
2122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(payload), 1)
2123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg4 = payload[0]
2124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg4, Message))
2125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg4.get_payload(), 'Yadda yadda yadda\n')
2126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parser(self):
2128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
2130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg, text = self._msgobj('msg_06.txt')
2131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Check some of the outer headers
2132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'message/rfc822')
2133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Make sure the payload is a list of exactly one sub-Message, and that
2134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # that submessage has a type of text/plain
2135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        payload = msg.get_payload()
2136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(payload, list))
2137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(payload), 1)
2138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg1 = payload[0]
2139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(msg1, Message))
2140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg1.get_content_type(), 'text/plain')
2141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(msg1.get_payload(), str))
2142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg1.get_payload(), '\n')
2143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test various other bits of the package's functionality
2147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestMiscellaneous(TestEmailBase):
2148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_from_string(self):
2149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_01.txt')
2150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
2152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(text)
2155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = StringIO()
2156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Don't wrap/continue long headers since we're trying to test
2157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # idempotency.
2158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Generator(s, maxheaderlen=0)
2159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g.flatten(msg)
2160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(text, s.getvalue())
2161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_from_file(self):
2163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_01.txt')
2164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
2166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.seek(0)
2167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp)
2168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            s = StringIO()
2169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # Don't wrap/continue long headers since we're trying to test
2170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # idempotency.
2171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            g = Generator(s, maxheaderlen=0)
2172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            g.flatten(msg)
2173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertEqual(text, s.getvalue())
2174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_from_string_with_class(self):
2178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
2179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_01.txt')
2180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
2182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Create a subclass
2185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        class MyMessage(Message):
2186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
2187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(text, MyMessage)
2189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg, MyMessage))
2190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try something more complicated
2191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_02.txt')
2192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            text = fp.read()
2194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(text, MyMessage)
2197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for subpart in msg.walk():
2198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            unless(isinstance(subpart, MyMessage))
2199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_message_from_file_with_class(self):
2201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless = self.assertTrue
2202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Create a subclass
2203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        class MyMessage(Message):
2204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
2205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_01.txt')
2207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp, MyMessage)
2209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        unless(isinstance(msg, MyMessage))
2212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try something more complicated
2213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_02.txt')
2214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp, MyMessage)
2216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for subpart in msg.walk():
2219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            unless(isinstance(subpart, MyMessage))
2220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test__all__(self):
2222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        module = __import__('email')
2223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        all = module.__all__
2224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        all.sort()
2225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(all, [
2226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # Old names
2227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'Charset', 'Encoders', 'Errors', 'Generator',
2228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'Header', 'Iterators', 'MIMEAudio', 'MIMEBase',
2229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'MIMEImage', 'MIMEMessage', 'MIMEMultipart',
2230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'MIMENonMultipart', 'MIMEText', 'Message',
2231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'Parser', 'Utils', 'base64MIME',
2232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # new names
2233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'base64mime', 'charset', 'encoders', 'errors', 'generator',
2234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'header', 'iterators', 'message', 'message_from_file',
2235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'message_from_string', 'mime', 'parser',
2236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'quopriMIME', 'quoprimime', 'utils',
2237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ])
2238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_formatdate(self):
2240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        now = time.time()
2241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parsedate(Utils.formatdate(now))[:6],
2242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         time.gmtime(now)[:6])
2243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_formatdate_localtime(self):
2245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        now = time.time()
2246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.parsedate(Utils.formatdate(now, localtime=True))[:6],
2248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.localtime(now)[:6])
2249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_formatdate_usegmt(self):
2251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        now = time.time()
2252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formatdate(now, localtime=False),
2254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.strftime('%a, %d %b %Y %H:%M:%S -0000', time.gmtime(now)))
2255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formatdate(now, localtime=False, usegmt=True),
2257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(now)))
2258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_none(self):
2260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parsedate(''), None)
2261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_compact(self):
2263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The FWS after the comma is optional
2264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
2265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         Utils.parsedate('Wed, 3 Apr 2002 14:58:26 +0800'))
2266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_no_dayofweek(self):
2268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'),
2270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           (2003, 2, 25, 13, 47, 26, 0, 1, -1, -28800))
2271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_compact_no_dayofweek(self):
2273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
2275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
2276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_acceptable_to_time_functions(self):
2278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        timetup = Utils.parsedate('5 Feb 2003 13:47:26 -0800')
2280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t = int(time.mktime(timetup))
2281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(time.localtime(t)[:6], timetup[:6])
2282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(int(time.strftime('%Y', timetup)), 2003)
2283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        timetup = Utils.parsedate_tz('5 Feb 2003 13:47:26 -0800')
2284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t = int(time.mktime(timetup[:9]))
2285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(time.localtime(t)[:6], timetup[:6])
2286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(int(time.strftime('%Y', timetup[:9])), 2003)
2287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_mktime_tz(self):
2289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
2290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                          -1, -1, -1, 0)), 0)
2291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.mktime_tz((1970, 1, 1, 0, 0, 0,
2292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                                          -1, -1, -1, 1234)), -1234)
2293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parsedate_y2k(self):
2295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """Test for parsing a date with a two-digit year.
2296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        Parsing a date with a two-digit year should return the correct
2298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        four-digit year. RFC822 allows two-digit years, but RFC2822 (which
2299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        obsoletes RFC822) requires four-digit years.
2300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """
2302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parsedate_tz('25 Feb 03 13:47:26 -0800'),
2303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         Utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'))
2304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parsedate_tz('25 Feb 71 13:47:26 -0800'),
2305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         Utils.parsedate_tz('25 Feb 1971 13:47:26 -0800'))
2306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parseaddr_empty(self):
2308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr('<>'), ('', ''))
2309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.formataddr(Utils.parseaddr('<>')), '')
2310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_noquote_dump(self):
2312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formataddr(('A Silly Person', 'person@dom.ain')),
2314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'A Silly Person <person@dom.ain>')
2315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_escape_dump(self):
2317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formataddr(('A (Very) Silly Person', 'person@dom.ain')),
2319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            r'"A \(Very\) Silly Person" <person@dom.ain>')
2320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        a = r'A \(Special\) Person'
2321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        b = 'person@dom.ain'
2322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
2323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_escape_backslashes(self):
2325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formataddr(('Arthur \Backslash\ Foobar', 'person@dom.ain')),
2327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>')
2328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        a = r'Arthur \Backslash\ Foobar'
2329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        b = 'person@dom.ain'
2330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr(Utils.formataddr((a, b))), (a, b))
2331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_name_with_dot(self):
2333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        x = 'John X. Doe <jxd@example.com>'
2334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        y = '"John X. Doe" <jxd@example.com>'
2335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        a, b = ('John X. Doe', 'jxd@example.com')
2336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr(x), (a, b))
2337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr(y), (a, b))
2338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # formataddr() quotes the name if there's a dot in it
2339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.formataddr((a, b)), y)
2340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_parseaddr_preserves_quoted_pairs_in_addresses(self):
2342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # issue 10005.  Note that in the third test the second pair of
2343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # backslashes is not actually a quoted pair because it is not inside a
2344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # comment or quoted string: the address being parsed has a quoted
2345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # string containing a quoted backslash, followed by 'example' and two
2346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # backslashes, followed by another quoted string containing a space and
2347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # the word 'example'.  parseaddr copies those two backslashes
2348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # literally.  Per rfc5322 this is not technically correct since a \ may
2349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # not appear in an address outside of a quoted string.  It is probably
2350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # a sensible Postel interpretation, though.
2351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.parseaddr('""example" example"@example.com'),
2353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          ('', '""example" example"@example.com'))
2354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.parseaddr('"\\"example\\" example"@example.com'),
2355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          ('', '"\\"example\\" example"@example.com'))
2356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.parseaddr('"\\\\"example\\\\" example"@example.com'),
2357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          ('', '"\\\\"example\\\\" example"@example.com'))
2358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multiline_from_comment(self):
2360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        x = """\
2361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFoo
2362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tBar <foo@example.com>"""
2363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(Utils.parseaddr(x), ('Foo Bar', 'foo@example.com'))
2364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_quote_dump(self):
2366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
2367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            Utils.formataddr(('A Silly; Person', 'person@dom.ain')),
2368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            r'"A Silly; Person" <person@dom.ain>')
2369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_fix_eols(self):
2371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.fix_eols('hello'), 'hello')
2373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.fix_eols('hello\n'), 'hello\r\n')
2374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.fix_eols('hello\r'), 'hello\r\n')
2375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.fix_eols('hello\r\n'), 'hello\r\n')
2376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.fix_eols('hello\n\r'), 'hello\r\n\r\n')
2377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_charset_richcomparisons(self):
2379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne = self.assertNotEqual
2381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cset1 = Charset()
2382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cset2 = Charset()
2383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(cset1, 'us-ascii')
2384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(cset1, 'US-ASCII')
2385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(cset1, 'Us-AsCiI')
2386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('us-ascii', cset1)
2387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('US-ASCII', cset1)
2388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('Us-AsCiI', cset1)
2389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne(cset1, 'usascii')
2390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne(cset1, 'USASCII')
2391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne(cset1, 'UsAsCiI')
2392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne('usascii', cset1)
2393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne('USASCII', cset1)
2394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ne('UsAsCiI', cset1)
2395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(cset1, cset2)
2396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(cset2, cset1)
2397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_getaddresses(self):
2399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.getaddresses(['aperson@dom.ain (Al Person)',
2401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                               'Bud Person <bperson@dom.ain>']),
2402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('Al Person', 'aperson@dom.ain'),
2403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ('Bud Person', 'bperson@dom.ain')])
2404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_getaddresses_nasty(self):
2406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.getaddresses(['foo: ;']), [('', '')])
2408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.getaddresses(
2409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ['[]*-- =~$']),
2410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('', ''), ('', ''), ('', '*--')])
2411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(Utils.getaddresses(
2412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
2413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
2414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_getaddresses_embedded_comment(self):
2416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        """Test proper handling of a nested comment"""
2417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        addrs = Utils.getaddresses(['User ((nested comment)) <foo@bar.com>'])
2419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(addrs[0][1], 'foo@bar.com')
2420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_utils_quote_unquote(self):
2422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
2424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('content-disposition', 'attachment',
2425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                       filename='foo\\wacky"name')
2426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_filename(), 'foo\\wacky"name')
2427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_body_encoding_with_bogus_charset(self):
2429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset('not a charset')
2430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(charset.get_body_encoding(), 'base64')
2431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2432edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_body_encoding_with_uppercase_charset(self):
2433edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2434edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
2435edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'text/plain; charset=UTF-8'
2436edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-type'], 'text/plain; charset=UTF-8')
2437edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charsets = msg.get_charsets()
2438edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(charsets), 1)
2439edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charsets[0], 'utf-8')
2440edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset(charsets[0])
2441edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset.get_body_encoding(), 'base64')
2442edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('hello world', charset=charset)
2443edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=\n')
2444edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(decode=True), 'hello world')
2445edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], 'base64')
2446edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try another one
2447edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
2448edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg['Content-Type'] = 'text/plain; charset="US-ASCII"'
2449edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charsets = msg.get_charsets()
2450edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(charsets), 1)
2451edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charsets[0], 'us-ascii')
2452edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset(charsets[0])
2453edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset.get_body_encoding(), Encoders.encode_7or8bit)
2454edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_payload('hello world', charset=charset)
2455edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), 'hello world')
2456edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['content-transfer-encoding'], '7bit')
2457edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2458edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_charsets_case_insensitive(self):
2459edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lc = Charset('us-ascii')
2460edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        uc = Charset('US-ASCII')
2461edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(lc.get_body_encoding(), uc.get_body_encoding())
2462edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2463edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_partial_falls_inside_message_delivery_status(self):
2464edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
2465edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # The Parser interface provides chunks of data to FeedParser in 8192
2466edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # byte gulps.  SF bug #1076485 found one of those chunks inside
2467edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # message/delivery-status header block, which triggered an
2468edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # unreadline() of NeedMoreData.
2469edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_43.txt')
2470edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sfp = StringIO()
2471edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        Iterators._structure(msg, sfp)
2472edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(sfp.getvalue(), """\
2473edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmultipart/report
2474edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    text/plain
2475edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    message/delivery-status
2476edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2477edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2478edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2479edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2480edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2481edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2482edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2483edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2484edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2485edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2486edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2487edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2488edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2489edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2490edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2491edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2492edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2493edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2494edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2495edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2496edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2497edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2498edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2499edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2500edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2501edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        text/plain
2502edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    text/rfc822-headers
2503edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2504edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2505edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2506edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2507edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the iterator/generators
2508edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestIterators(TestEmailBase):
2509edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_body_line_iterator(self):
2510edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2511edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq = self.ndiffAssertEqual
2512edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # First a simple non-multipart message
2513edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
2514edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        it = Iterators.body_line_iterator(msg)
2515edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = list(it)
2516edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(lines), 6)
2517edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(EMPTYSTRING.join(lines), msg.get_payload())
2518edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Now a more complicated multipart
2519edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_02.txt')
2520edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        it = Iterators.body_line_iterator(msg)
2521edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = list(it)
2522edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(lines), 43)
2523edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_19.txt')
2524edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2525edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            neq(EMPTYSTRING.join(lines), fp.read())
2526edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2527edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2528edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2529edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_typed_subpart_iterator(self):
2530edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2531edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_04.txt')
2532edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        it = Iterators.typed_subpart_iterator(msg, 'text')
2533edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = []
2534edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subparts = 0
2535edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for subpart in it:
2536edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            subparts += 1
2537edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            lines.append(subpart.get_payload())
2538edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subparts, 2)
2539edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(EMPTYSTRING.join(lines), """\
2540edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepa simple kind of mirror
2541edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepto reflect upon our own
2542edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepa simple kind of mirror
2543edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepto reflect upon our own
2544edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2545edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2546edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_typed_subpart_iterator_default_type(self):
2547edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2548edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_03.txt')
2549edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        it = Iterators.typed_subpart_iterator(msg, 'text', 'plain')
2550edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = []
2551edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        subparts = 0
2552edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for subpart in it:
2553edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            subparts += 1
2554edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            lines.append(subpart.get_payload())
2555edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(subparts, 1)
2556edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(EMPTYSTRING.join(lines), """\
2557edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2558edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHi,
2559edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2560edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDo you like this message?
2561edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2562edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep-Me
2563edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2564edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2565edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_pushCR_LF(self):
2566edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        '''FeedParser BufferedSubFile.push() assumed it received complete
2567edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           line endings.  A CR ending one push() followed by a LF starting
2568edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           the next push() added an empty line.
2569edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        '''
2570edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        imt = [
2571edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("a\r \n",  2),
2572edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("b",       0),
2573edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("c\n",     1),
2574edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("",        0),
2575edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("d\r\n",   1),
2576edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("e\r",     0),
2577edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("\nf",     1),
2578edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            ("\r\n",    1),
2579edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          ]
2580edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        from email.feedparser import BufferedSubFile, NeedMoreData
2581edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        bsf = BufferedSubFile()
2582edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        om = []
2583edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        nt = 0
2584edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for il, n in imt:
2585edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            bsf.push(il)
2586edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            nt += n
2587edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            n1 = 0
2588edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            while True:
2589edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                ol = bsf.readline()
2590edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if ol == NeedMoreData:
2591edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    break
2592edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                om.append(ol)
2593edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                n1 += 1
2594edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertTrue(n == n1)
2595edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(len(om) == nt)
2596edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(''.join([il for il, n in imt]) == ''.join(om))
2597edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2598edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2599edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2600edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestParsers(TestEmailBase):
2601edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_parser(self):
2602edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2603edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Parse only the headers of a complex multipart MIME document
2604edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_02.txt')
2605edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2606edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = HeaderParser().parse(fp)
2607edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2608edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2609edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['from'], 'ppp-request@zzz.org')
2610edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['to'], 'ppp@zzz.org')
2611edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_type(), 'multipart/mixed')
2612edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertFalse(msg.is_multipart())
2613edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(isinstance(msg.get_payload(), str))
2614edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2615edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_whitespace_continuation(self):
2616edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2617edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This message contains a line after the Subject: header that has only
2618edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # whitespace, but it is not empty!
2619edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("""\
2620edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aperson@dom.ain
2621edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bperson@dom.ain
2622edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: the next line has a space on it
2623edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\x20
2624edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDate: Mon, 8 Apr 2002 15:09:19 -0400
2625edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMessage-ID: spam
2626edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2627edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHere's the message body
2628edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2629edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['subject'], 'the next line has a space on it\n ')
2630edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['message-id'], 'spam')
2631edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), "Here's the message body\n")
2632edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2633edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_whitespace_continuation_last_header(self):
2634edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2635edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Like the previous test, but the subject line is the last
2636edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # header.
2637edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string("""\
2638edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: aperson@dom.ain
2639edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bperson@dom.ain
2640edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDate: Mon, 8 Apr 2002 15:09:19 -0400
2641edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMessage-ID: spam
2642edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: the next line has a space on it
2643edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\x20
2644edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2645edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHere's the message body
2646edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2647edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['subject'], 'the next line has a space on it\n ')
2648edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg['message-id'], 'spam')
2649edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), "Here's the message body\n")
2650edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2651edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_crlf_separation(self):
2652edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2653edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_26.txt', mode='rb')
2654edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2655edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = Parser().parse(fp)
2656edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2657edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2658edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 2)
2659edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part1 = msg.get_payload(0)
2660edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1.get_content_type(), 'text/plain')
2661edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1.get_payload(), 'Simple email with attachment.\r\n\r\n')
2662edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part2 = msg.get_payload(1)
2663edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part2.get_content_type(), 'application/riscos')
2664edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2665edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multipart_digest_with_extra_mime_headers(self):
2666edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2667edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq = self.ndiffAssertEqual
2668edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile('msg_28.txt')
2669edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2670edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_file(fp)
2671edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
2672edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
2673edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Structure is:
2674edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # multipart/digest
2675edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #   message/rfc822
2676edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #     text/plain
2677edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #   message/rfc822
2678edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #     text/plain
2679edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.is_multipart(), 1)
2680edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.get_payload()), 2)
2681edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part1 = msg.get_payload(0)
2682edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1.get_content_type(), 'message/rfc822')
2683edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1.is_multipart(), 1)
2684edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(part1.get_payload()), 1)
2685edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part1a = part1.get_payload(0)
2686edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1a.is_multipart(), 0)
2687edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part1a.get_content_type(), 'text/plain')
2688edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(part1a.get_payload(), 'message 1\n')
2689edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # next message/rfc822
2690edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part2 = msg.get_payload(1)
2691edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part2.get_content_type(), 'message/rfc822')
2692edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part2.is_multipart(), 1)
2693edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(part2.get_payload()), 1)
2694edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        part2a = part2.get_payload(0)
2695edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part2a.is_multipart(), 0)
2696edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(part2a.get_content_type(), 'text/plain')
2697edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        neq(part2a.get_payload(), 'message 2\n')
2698edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2699edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_three_lines(self):
2700edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # A bug report by Andrew McNamara
2701edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        lines = ['From: Andrew Person <aperson@dom.ain',
2702edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                 'Subject: Test',
2703edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                 'Date: Tue, 20 Aug 2002 16:43:45 +1000']
2704edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(NL.join(lines))
2705edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg['date'], 'Tue, 20 Aug 2002 16:43:45 +1000')
2706edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2707edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_strip_line_feed_and_carriage_return_in_headers(self):
2708edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2709edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # For [ 1002475 ] email message parser doesn't handle \r\n correctly
2710edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        value1 = 'text'
2711edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        value2 = 'more text'
2712edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = 'Header: %s\r\nNext-Header: %s\r\n\r\nBody\r\n\r\n' % (
2713edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            value1, value2)
2714edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
2715edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get('Header'), value1)
2716edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get('Next-Header'), value2)
2717edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2718edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2822_header_syntax(self):
2719edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2720edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '>From: foo\nFrom: bar\n!"#QUX;~: zoo\n\nbody'
2721edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
2722edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.keys()), 3)
2723edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        keys = msg.keys()
2724edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        keys.sort()
2725edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(keys, ['!"#QUX;~', '>From', 'From'])
2726edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), 'body')
2727edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2728edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2822_space_not_allowed_in_header(self):
2729edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2730edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '>From foo@example.com 11:25:53\nFrom: bar\n!"#QUX;~: zoo\n\nbody'
2731edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
2732edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(len(msg.keys()), 0)
2733edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2734edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2822_one_character_header(self):
2735edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2736edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = 'A: first header\nB: second header\nCC: third header\n\nbody'
2737edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
2738edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        headers = msg.keys()
2739edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        headers.sort()
2740edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(headers, ['A', 'B', 'CC'])
2741edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_payload(), 'body')
2742edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2743edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_CRLFLF_at_end_of_part(self):
2744edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # issue 5610: feedparser should not eat two chars from body part ending
2745edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # with "\r\n\n".
2746edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = (
2747edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "From: foo@bar.com\n"
2748edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "To: baz\n"
2749edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "Mime-Version: 1.0\n"
2750edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "Content-Type: multipart/mixed; boundary=BOUNDARY\n"
2751edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "\n"
2752edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "--BOUNDARY\n"
2753edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "Content-Type: text/plain\n"
2754edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "\n"
2755edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "body ending with CRLF newline\r\n"
2756edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "\n"
2757edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            "--BOUNDARY--\n"
2758edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep          )
2759edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
2760edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n'))
2761edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2762edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2763edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestBase64(unittest.TestCase):
2764edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_len(self):
2765edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2766edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.base64_len('hello'),
2767edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           len(base64MIME.encode('hello', eol='')))
2768edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for size in range(15):
2769edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if   size == 0 : bsize = 0
2770edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif size <= 3 : bsize = 4
2771edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif size <= 6 : bsize = 8
2772edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif size <= 9 : bsize = 12
2773edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            elif size <= 12: bsize = 16
2774edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            else           : bsize = 20
2775edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(base64MIME.base64_len('x'*size), bsize)
2776edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2777edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_decode(self):
2778edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2779edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.decode(''), '')
2780edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.decode('aGVsbG8='), 'hello')
2781edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.decode('aGVsbG8=', 'X'), 'hello')
2782edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.decode('aGVsbG8NCndvcmxk\n', 'X'), 'helloXworld')
2783edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2784edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encode(self):
2785edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2786edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode(''), '')
2787edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode('hello'), 'aGVsbG8=\n')
2788edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the binary flag
2789edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode('hello\n'), 'aGVsbG8K\n')
2790edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode('hello\n', 0), 'aGVsbG8NCg==\n')
2791edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the maxlinelen arg
2792edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40), """\
2793edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2794edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2795edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
2796edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IA==
2797edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2798edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the eol argument
2799edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(base64MIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2800edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2801edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2802edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
2803edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepeHh4eCB4eHh4IA==\r
2804edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
2805edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2806edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_encode(self):
2807edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2808edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        he = base64MIME.header_encode
2809edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello'), '=?iso-8859-1?b?aGVsbG8=?=')
2810edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello\nworld'), '=?iso-8859-1?b?aGVsbG8NCndvcmxk?=')
2811edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the charset option
2812edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?b?aGVsbG8=?=')
2813edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the keep_eols flag
2814edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello\nworld', keep_eols=True),
2815edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '=?iso-8859-1?b?aGVsbG8Kd29ybGQ=?=')
2816edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the maxlinelen argument
2817edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('xxxx ' * 20, maxlinelen=40), """\
2818edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=
2819edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=
2820edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=
2821edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=
2822edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=
2823edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
2824edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the eol argument
2825edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2826edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?b?eHh4eCB4eHh4IHh4eHggeHg=?=\r
2827edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHggeHh4eCB4eHh4IHh4eHg=?=\r
2828edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?IHh4eHggeHh4eCB4eHh4IHg=?=\r
2829edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHh4IHh4eHggeHh4eCB4eHg=?=\r
2830edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eCB4eHh4IHh4eHggeHh4eCA=?=\r
2831edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?b?eHh4eCB4eHh4IHh4eHgg?=""")
2832edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2833edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2834edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2835edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestQuopri(unittest.TestCase):
2836edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def setUp(self):
2837edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.hlit = [chr(x) for x in range(ord('a'), ord('z')+1)] + \
2838edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    [chr(x) for x in range(ord('A'), ord('Z')+1)] + \
2839edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    [chr(x) for x in range(ord('0'), ord('9')+1)] + \
2840edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    ['!', '*', '+', '-', '/', ' ']
2841edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.hnon = [chr(x) for x in range(256) if chr(x) not in self.hlit]
2842edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        assert len(self.hlit) + len(self.hnon) == 256
2843edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.blit = [chr(x) for x in range(ord(' '), ord('~')+1)] + ['\t']
2844edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.blit.remove('=')
2845edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.bnon = [chr(x) for x in range(256) if chr(x) not in self.blit]
2846edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        assert len(self.blit) + len(self.bnon) == 256
2847edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2848edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_quopri_check(self):
2849edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.hlit:
2850edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertFalse(quopriMIME.header_quopri_check(c))
2851edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.hnon:
2852edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertTrue(quopriMIME.header_quopri_check(c))
2853edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2854edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_body_quopri_check(self):
2855edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.blit:
2856edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertFalse(quopriMIME.body_quopri_check(c))
2857edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.bnon:
2858edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertTrue(quopriMIME.body_quopri_check(c))
2859edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2860edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_quopri_len(self):
2861edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2862edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hql = quopriMIME.header_quopri_len
2863edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        enc = quopriMIME.header_encode
2864edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for s in ('hello', 'h@e@l@l@o@'):
2865edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # Empty charset and no line-endings.  7 == RFC chrome
2866edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(hql(s), len(enc(s, charset='', eol=''))-7)
2867edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.hlit:
2868edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(hql(c), 1)
2869edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.hnon:
2870edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(hql(c), 3)
2871edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2872edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_body_quopri_len(self):
2873edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2874edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        bql = quopriMIME.body_quopri_len
2875edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.blit:
2876edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(bql(c), 1)
2877edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for c in self.bnon:
2878edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq(bql(c), 3)
2879edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2880edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_quote_unquote_idempotent(self):
2881edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for x in range(256):
2882edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            c = chr(x)
2883edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertEqual(quopriMIME.unquote(quopriMIME.quote(c)), c)
2884edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2885edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_encode(self):
2886edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2887edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        he = quopriMIME.header_encode
2888edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello'), '=?iso-8859-1?q?hello?=')
2889edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello\nworld'), '=?iso-8859-1?q?hello=0D=0Aworld?=')
2890edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the charset option
2891edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?q?hello?=')
2892edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the keep_eols flag
2893edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello\nworld', keep_eols=True), '=?iso-8859-1?q?hello=0Aworld?=')
2894edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test a non-ASCII character
2895edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('hello\xc7there'), '=?iso-8859-1?q?hello=C7there?=')
2896edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the maxlinelen argument
2897edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('xxxx ' * 20, maxlinelen=40), """\
2898edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=
2899edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=
2900edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=
2901edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=
2902edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?x_xxxx_xxxx_?=""")
2903edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the eol argument
2904edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(he('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2905edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?=\r
2906edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?=\r
2907edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?_xxxx_xxxx_xxxx_xxxx_x?=\r
2908edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?xxx_xxxx_xxxx_xxxx_xxx?=\r
2909edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?x_xxxx_xxxx_?=""")
2910edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2911edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_decode(self):
2912edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2913edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.decode(''), '')
2914edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.decode('hello'), 'hello')
2915edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.decode('hello', 'X'), 'hello')
2916edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.decode('hello\nworld', 'X'), 'helloXworld')
2917edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2918edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encode(self):
2919edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2920edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode(''), '')
2921edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode('hello'), 'hello')
2922edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the binary flag
2923edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode('hello\r\nworld'), 'hello\nworld')
2924edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode('hello\r\nworld', 0), 'hello\nworld')
2925edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the maxlinelen arg
2926edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40), """\
2927edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepxxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=
2928edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=
2929edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepx xxxx xxxx xxxx xxxx=20""")
2930edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test the eol argument
2931edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), """\
2932edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepxxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=\r
2933edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=\r
2934edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepx xxxx xxxx xxxx xxxx=20""")
2935edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(quopriMIME.encode("""\
2936edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepone line
2937edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2938edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptwo line"""), """\
2939edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepone line
2940edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2941edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptwo line""")
2942edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2943edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2944edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2945edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test the Charset class
2946edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestCharset(unittest.TestCase):
2947edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def tearDown(self):
2948edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        from email import Charset as CharsetModule
2949edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2950edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            del CharsetModule.CHARSETS['fake']
2951edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except KeyError:
2952edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
2953edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2954edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_idempotent(self):
2955edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2956edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Make sure us-ascii = no Unicode conversion
2957edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('us-ascii')
2958edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'Hello World!'
2959edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sp = c.to_splittable(s)
2960edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, c.from_splittable(sp))
2961edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # test 8-bit idempotency with us-ascii
2962edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = '\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa'
2963edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        sp = c.to_splittable(s)
2964edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, c.from_splittable(sp))
2965edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2966edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_body_encode(self):
2967edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
2968edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try a charset with QP body encoding
2969edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('iso-8859-1')
2970edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('hello w=F6rld', c.body_encode('hello w\xf6rld'))
2971edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try a charset with Base64 body encoding
2972edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('utf-8')
2973edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('aGVsbG8gd29ybGQ=\n', c.body_encode('hello world'))
2974edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try a charset with None body encoding
2975edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('us-ascii')
2976edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('hello world', c.body_encode('hello world'))
2977edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Try the convert argument, where input codec != output codec
2978edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('euc-jp')
2979edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # With apologies to Tokio Kikuchi ;)
2980edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
2981edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq('\x1b$B5FCO;~IW\x1b(B',
2982edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep               c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7'))
2983edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            eq('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7',
2984edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep               c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', False))
2985edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        except LookupError:
2986edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # We probably don't have the Japanese codecs installed
2987edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            pass
2988edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Testing SF bug #625509, which we have to fake, since there are no
2989edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # built-in encodings where the header encoding is QP but the body
2990edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # encoding is not.
2991edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        from email import Charset as CharsetModule
2992edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        CharsetModule.add_charset('fake', CharsetModule.QP, None)
2993edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        c = Charset('fake')
2994edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq('hello w\xf6rld', c.body_encode('hello w\xf6rld'))
2995edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
2996edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_unicode_charset_name(self):
2997edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset(u'us-ascii')
2998edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(str(charset), 'us-ascii')
2999edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertRaises(Errors.CharsetError, Charset, 'asc\xffii')
3000edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3001edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_codecs_aliases_accepted(self):
3002edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset = Charset('utf8')
3003edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(str(charset), 'utf-8')
3004edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3005edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3006edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test multilingual MIME headers.
3007edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestHeader(TestEmailBase):
3008edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_simple(self):
3009edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3010edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header('Hello World!')
3011edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), 'Hello World!')
3012edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(' Goodbye World!')
3013edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), 'Hello World!  Goodbye World!')
3014edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3015edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_simple_surprise(self):
3016edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3017edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header('Hello World!')
3018edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), 'Hello World!')
3019edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('Goodbye World!')
3020edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), 'Hello World! Goodbye World!')
3021edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3022edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_needs_no_decoding(self):
3023edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = 'no decoding needed'
3024edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(decode_header(h), [(h, None)])
3025edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3026edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long(self):
3027edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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.",
3028edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                   maxlinelen=76)
3029edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for l in h.encode(splitchars=' ').split('\n '):
3030edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertTrue(len(l) <= 76)
3031edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3032edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_multilingual(self):
3033edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3034edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        g = Charset("iso-8859-1")
3035edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cz = Charset("iso-8859-2")
3036edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        utf8 = Charset("utf-8")
3037edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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. "
3038edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        cz_head = "Finan\xe8ni metropole se hroutily pod tlakem jejich d\xf9vtipu.. "
3039edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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")
3040edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(g_head, g)
3041edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(cz_head, cz)
3042edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(utf8_head, utf8)
3043edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        enc = h.encode()
3044edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(enc, """\
3045edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerderband_ko?=
3046edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?mfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndischen_Wan?=
3047edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?dgem=E4lden_vorbei=2C_gegen_die_rotierenden_Klingen_bef=F6?=
3048edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-1?q?rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se_hroutily?=
3049edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?iso-8859-2?q?_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= =?utf-8?b?5q2j56K6?=
3050edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb44KT44CC?=
3051edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go44Gv44Gn?=
3052edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBpc3QgZGFz?=
3053edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?q?_Nunstuck_git_und_Slotermeyer=3F_Ja!_Beiherhund_das_Oder_die_Fl?=
3054edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?aXBwZXJ3YWxkdCBnZXJzcHV0LuOAjeOBqOiogOOBo+OBpuOBhOOBvuOBmQ==?=
3055edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep =?utf-8?b?44CC?=""")
3056edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(decode_header(enc),
3057edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           [(g_head, "iso-8859-1"), (cz_head, "iso-8859-2"),
3058edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            (utf8_head, "utf-8")])
3059edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        ustr = unicode(h)
3060edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(ustr.encode('utf-8'),
3061edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'Die Mieter treten hier ein werden mit einem Foerderband '
3062edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'komfortabel den Korridor entlang, an s\xc3\xbcdl\xc3\xbcndischen '
3063edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'Wandgem\xc3\xa4lden vorbei, gegen die rotierenden Klingen '
3064edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'bef\xc3\xb6rdert. Finan\xc4\x8dni metropole se hroutily pod '
3065edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'tlakem jejich d\xc5\xafvtipu.. \xe6\xad\xa3\xe7\xa2\xba\xe3\x81'
3066edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xab\xe8\xa8\x80\xe3\x81\x86\xe3\x81\xa8\xe7\xbf\xbb\xe8\xa8\xb3'
3067edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xe3\x81\xaf\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3'
3068edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\x81\xbe\xe3\x81\x9b\xe3\x82\x93\xe3\x80\x82\xe4\xb8\x80\xe9\x83'
3069edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xa8\xe3\x81\xaf\xe3\x83\x89\xe3\x82\xa4\xe3\x83\x84\xe8\xaa\x9e'
3070edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xe3\x81\xa7\xe3\x81\x99\xe3\x81\x8c\xe3\x80\x81\xe3\x81\x82\xe3'
3071edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\x81\xa8\xe3\x81\xaf\xe3\x81\xa7\xe3\x81\x9f\xe3\x82\x89\xe3\x82'
3072edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\x81\xe3\x81\xa7\xe3\x81\x99\xe3\x80\x82\xe5\xae\x9f\xe9\x9a\x9b'
3073edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x8cWenn ist das Nunstuck git '
3074edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt '
3075edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'gersput.\xe3\x80\x8d\xe3\x81\xa8\xe8\xa8\x80\xe3\x81\xa3\xe3\x81'
3076edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           '\xa6\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82')
3077edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Test make_header()
3078edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        newh = make_header(decode_header(enc))
3079edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(newh, enc)
3080edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3081edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_header_ctor_default_args(self):
3082edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3083edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header()
3084edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h, '')
3085edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('foo', Charset('iso-8859-1'))
3086edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h, '=?iso-8859-1?q?foo?=')
3087edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3088edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_explicit_maxlinelen(self):
3089edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3090edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hstr = 'A very long line that must get split to something other than at the 76th character boundary to test the non-default behavior'
3091edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr)
3092edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '''\
3093edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepA very long line that must get split to something other than at the 76th
3094edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep character boundary to test the non-default behavior''')
3095edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, header_name='Subject')
3096edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '''\
3097edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepA very long line that must get split to something other than at the
3098edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 76th character boundary to test the non-default behavior''')
3099edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(hstr, maxlinelen=1024, header_name='Subject')
3100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), hstr)
3101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_us_ascii_header(self):
3103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'hello'
3105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        x = decode_header(s)
3106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(x, [('hello', None)])
3107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = make_header(x)
3108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, h.encode())
3109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_string_charset(self):
3111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header()
3113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('hello', 'iso-8859-1')
3114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h, '=?iso-8859-1?q?hello?=')
3115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##    def test_unicode_error(self):
3117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises = self.assertRaises
3118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises(UnicodeError, Header, u'[P\xf6stal]', 'us-ascii')
3119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises(UnicodeError, Header, '[P\xf6stal]', 'us-ascii')
3120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        h = Header()
3121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises(UnicodeError, h.append, u'[P\xf6stal]', 'us-ascii')
3122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises(UnicodeError, h.append, '[P\xf6stal]', 'us-ascii')
3123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep##        raises(UnicodeError, Header, u'\u83ca\u5730\u6642\u592b', 'iso-8859-1')
3124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_utf8_shortest(self):
3126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(u'p\xf6stal', 'utf-8')
3128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '=?utf-8?q?p=C3=B6stal?=')
3129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header(u'\u83ca\u5730\u6642\u592b', 'utf-8')
3130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), '=?utf-8?b?6I+K5Zyw5pmC5aSr?=')
3131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_bad_8bit_header(self):
3133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises = self.assertRaises
3134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        x = 'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
3136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises(UnicodeError, Header, x)
3137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header()
3138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises(UnicodeError, h.append, x)
3139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(str(Header(x, errors='replace')), x)
3140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append(x, errors='replace')
3141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(str(h), x)
3142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encoded_adjacent_nonencoded(self):
3144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = Header()
3146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('hello', 'iso-8859-1')
3147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h.append('world')
3148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = h.encode()
3149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, '=?iso-8859-1?q?hello?= world')
3150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        h = make_header(decode_header(s))
3151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(h.encode(), s)
3152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_whitespace_eater(self):
3154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztk=?= =?koi8-r?q?=CA?= zz.'
3156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        parts = decode_header(s)
3157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        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)])
3158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        hdr = make_header(parts)
3159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(hdr.encode(),
3160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztnK?= zz.')
3161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_broken_base64_header(self):
3163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises = self.assertRaises
3164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3I ?='
3165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        raises(Errors.HeaderParseError, decode_header, s)
3166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    # Issue 1078919
3168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_ascii_add_header(self):
3169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
3170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Content-Disposition', 'attachment',
3171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                       filename='bud.gif')
3172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual('attachment; filename="bud.gif"',
3173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg['Content-Disposition'])
3174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_nonascii_add_header_via_triple(self):
3176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
3177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.add_header('Content-Disposition', 'attachment',
3178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            filename=('iso-8859-1', '', 'Fu\xdfballer.ppt'))
3179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
3180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'attachment; filename*="iso-8859-1\'\'Fu%DFballer.ppt"',
3181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg['Content-Disposition'])
3182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_encode_unaliased_charset(self):
3184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Issue 1379416: when the charset has no output conversion,
3185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # output was accidentally getting coerced to unicode.
3186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        res = Header('abc','iso-8859-2').encode()
3187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(res, '=?iso-8859-2?q?abc?=')
3188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertIsInstance(res, str)
3189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Test RFC 2231 header parameters (en/de)coding
3192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestRFC2231(TestEmailBase):
3193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_get_param(self):
3194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_29.txt')
3196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('title'),
3197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
3198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('title', unquote=False),
3199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ('us-ascii', 'en', '"This is even more ***fun*** isn\'t it!"'))
3200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_set_param(self):
3202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = Message()
3204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
3205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      charset='us-ascii')
3206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('title'),
3207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ('us-ascii', '', 'This is even more ***fun*** isn\'t it!'))
3208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
3209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      charset='us-ascii', language='en')
3210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('title'),
3211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep           ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!'))
3212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
3213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
3214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                      charset='us-ascii', language='en')
3215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.ndiffAssertEqual(msg.as_string(), """\
3216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReturn-Path: <bbb@zzz.org>
3217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDelivered-To: bbb@zzz.org
3218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: by mail.zzz.org (Postfix, from userid 889)
3219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep id 27CEAD38CC; Fri,  4 May 2001 14:05:44 -0400 (EDT)
3220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
3221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
3222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMessage-ID: <15090.61304.110929.45684@aaa.zzz.org>
3223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bbb@ddd.com (John X. Doe)
3224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bbb@zzz.org
3225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: This is a test message
3226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDate: Fri, 4 May 2001 14:05:44 -0400
3227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset=us-ascii;
3228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
3229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHi,
3232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDo you like this message?
3234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep-Me
3236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
3237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_del_param(self):
3239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.ndiffAssertEqual
3240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_01.txt')
3241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('foo', 'bar', charset='us-ascii', language='en')
3242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.set_param('title', 'This is even more ***fun*** isn\'t it!',
3243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            charset='us-ascii', language='en')
3244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg.del_param('foo', header='Content-Type')
3245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.as_string(), """\
3246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReturn-Path: <bbb@zzz.org>
3247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDelivered-To: bbb@zzz.org
3248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepReceived: by mail.zzz.org (Postfix, from userid 889)
3249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep id 27CEAD38CC; Fri,  4 May 2001 14:05:44 -0400 (EDT)
3250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMIME-Version: 1.0
3251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 7bit
3252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepMessage-ID: <15090.61304.110929.45684@aaa.zzz.org>
3253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFrom: bbb@ddd.com (John X. Doe)
3254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo: bbb@zzz.org
3255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepSubject: This is a test message
3256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDate: Fri, 4 May 2001 14:05:44 -0400
3257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset="us-ascii";
3258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
3259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepHi,
3262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepDo you like this message?
3264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep-Me
3266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""")
3267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_get_content_charset(self):
3269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = self._msgobj('msg_32.txt')
3271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_content_charset(), 'us-ascii')
3272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_language_or_charset(self):
3274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 8bit
3276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline; filename="file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm"
3277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/html; NAME*0=file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEM; NAME*1=P_nsmail.htm
3278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        param = msg.get_param('NAME')
3282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertFalse(isinstance(param, tuple))
3283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
3284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            param,
3285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm')
3286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_language_or_charset_in_filename(self):
3288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0*="''This%20is%20even%20more%20";
3291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
3292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2="is it not.pdf"
3293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(),
3297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'This is even more ***fun*** is it not.pdf')
3298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_language_or_charset_in_filename_encoded(self):
3300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0*="''This%20is%20even%20more%20";
3303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
3304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2="is it not.pdf"
3305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(),
3309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'This is even more ***fun*** is it not.pdf')
3310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_partly_encoded(self):
3312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0="''This%20is%20even%20more%20";
3315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
3316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2="is it not.pdf"
3317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
3321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg.get_filename(),
3322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'This%20is%20even%20more%20***fun*** is it not.pdf')
3323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_partly_nonencoded(self):
3325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0="This%20is%20even%20more%20";
3328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1="%2A%2A%2Afun%2A%2A%2A%20";
3329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2="is it not.pdf"
3330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(
3334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg.get_filename(),
3335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20is it not.pdf')
3336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_language_or_charset_in_boundary(self):
3338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: multipart/alternative;
3340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tboundary*0*="''This%20is%20even%20more%20";
3341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tboundary*1*="%2A%2A%2Afun%2A%2A%2A%20";
3342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tboundary*2="is it not.pdf"
3343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_boundary(),
3347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'This is even more ***fun*** is it not.pdf')
3348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_language_or_charset_in_charset(self):
3350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This is a nonsensical charset value, but tests the code anyway
3351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain;
3353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tcharset*0*="This%20is%20even%20more%20";
3354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tcharset*1*="%2A%2A%2Afun%2A%2A%2A%20";
3355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tcharset*2="is it not.pdf"
3356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_charset(),
3360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'this is even more ***fun*** is it not.pdf')
3361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_bad_encoding_in_filename(self):
3363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0*="bogus'xx'This%20is%20even%20more%20";
3366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
3367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2="is it not.pdf"
3368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(),
3372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         'This is even more ***fun*** is it not.pdf')
3373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_bad_encoding_in_charset(self):
3375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset*=bogus''utf-8%E2%80%9D
3377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This should return None because non-ascii characters in the charset
3381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # are not allowed.
3382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_charset(), None)
3383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_bad_character_in_charset(self):
3385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: text/plain; charset*=ascii''utf-8%E2%80%9D
3387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # This should return None because non-ascii characters in the charset
3391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # are not allowed.
3392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_content_charset(), None)
3393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_bad_character_in_filename(self):
3395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = '''\
3396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline;
3397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*0*="ascii'xx'This%20is%20even%20more%20";
3398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
3399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tfilename*2*="is it not.pdf%E2"
3400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep'''
3402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(),
3404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                         u'This is even more ***fun*** is it not.pdf\ufffd')
3405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_unknown_encoding(self):
3407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Transfer-Encoding: 8bit
3409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Disposition: inline; filename*=X-UNKNOWN''myfile.txt
3410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(msg.get_filename(), 'myfile.txt')
3414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_single_tick_in_filename_extended(self):
3416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo;
3419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*0*=\"Frank's\"; name*1*=\" Document\"
3420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset, language, s = msg.get_param('name')
3424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset, None)
3425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(language, None)
3426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, "Frank's Document")
3427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_single_tick_in_filename(self):
3429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo; name*0=\"Frank's\"; name*1=\" Document\"
3431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3432edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3433edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3434edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        param = msg.get_param('name')
3435edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertFalse(isinstance(param, tuple))
3436edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(param, "Frank's Document")
3437edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3438edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_tick_attack_extended(self):
3439edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3440edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3441edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo;
3442edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*0*=\"us-ascii'en-us'Frank's\"; name*1*=\" Document\"
3443edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3444edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3445edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3446edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset, language, s = msg.get_param('name')
3447edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset, 'us-ascii')
3448edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(language, 'en-us')
3449edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, "Frank's Document")
3450edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3451edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_tick_attack(self):
3452edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3453edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo;
3454edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*0=\"us-ascii'en-us'Frank's\"; name*1=\" Document\"
3455edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3456edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3457edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3458edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        param = msg.get_param('name')
3459edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertFalse(isinstance(param, tuple))
3460edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(param, "us-ascii'en-us'Frank's Document")
3461edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3462edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_no_extended_values(self):
3463edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3464edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3465edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo; name=\"Frank's Document\"
3466edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3467edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3468edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3469edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(msg.get_param('name'), "Frank's Document")
3470edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3471edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_encoded_then_unencoded_segments(self):
3472edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3473edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3474edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo;
3475edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*0*=\"us-ascii'en-us'My\";
3476edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*1=\" Document\";
3477edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*2*=\" For You\"
3478edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3479edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3480edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3481edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset, language, s = msg.get_param('name')
3482edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset, 'us-ascii')
3483edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(language, 'en-us')
3484edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, 'My Document For You')
3485edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3486edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_rfc2231_unencoded_then_encoded_segments(self):
3487edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq = self.assertEqual
3488edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        m = """\
3489edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepContent-Type: application/x-foo;
3490edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*0=\"us-ascii'en-us'My\";
3491edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*1*=\" Document\";
3492edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep\tname*2*=\" For You\"
3493edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3494edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""
3495edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        msg = email.message_from_string(m)
3496edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        charset, language, s = msg.get_param('name')
3497edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(charset, 'us-ascii')
3498edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(language, 'en-us')
3499edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        eq(s, 'My Document For You')
3500edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3501edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3502edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3503edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Tests to ensure that signed parts of an email are completely preserved, as
3504edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# required by RFC1847 section 2.1.  Note that these are incomplete, because the
3505edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# email package does not currently always preserve the body.  See issue 1670765.
3506edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestSigned(TestEmailBase):
3507edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3508edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _msg_and_obj(self, filename):
3509edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = openfile(findfile(filename))
3510edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
3511edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            original = fp.read()
3512edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            msg = email.message_from_string(original)
3513edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
3514edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            fp.close()
3515edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        return original, msg
3516edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3517edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def _signed_parts_eq(self, original, result):
3518edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # Extract the first mime part of each message
3519edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        import re
3520edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        repart = re.compile(r'^--([^\n]+)\n(.*?)\n--\1$', re.S | re.M)
3521edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        inpart = repart.search(original).group(2)
3522edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        outpart = repart.search(result).group(2)
3523edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.assertEqual(outpart, inpart)
3524edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3525edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_headers_as_string(self):
3526edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        original, msg = self._msg_and_obj('msg_45.txt')
3527edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        result = msg.as_string()
3528edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._signed_parts_eq(original, result)
3529edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3530edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_long_headers_flatten(self):
3531edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        original, msg = self._msg_and_obj('msg_45.txt')
3532edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        fp = StringIO()
3533edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        Generator(fp).flatten(msg)
3534edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        result = fp.getvalue()
3535edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self._signed_parts_eq(original, result)
3536edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3537edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3538edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3539edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _testclasses():
3540edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    mod = sys.modules[__name__]
3541edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
3542edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3543edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3544edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef suite():
3545edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    suite = unittest.TestSuite()
3546edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for testclass in _testclasses():
3547edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        suite.addTest(unittest.makeSuite(testclass))
3548edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    return suite
3549edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3550edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3551edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef test_main():
3552edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for testclass in _testclasses():
3553edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        run_unittest(testclass)
3554edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3555edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3556edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
3557edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif __name__ == '__main__':
3558edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    unittest.main(defaultTest='suite')
3559