17db96d56Sopenharmony_ci# Copyright (C) 2001-2010 Python Software Foundation 27db96d56Sopenharmony_ci# Contact: email-sig@python.org 37db96d56Sopenharmony_ci# email package unit tests 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ciimport re 67db96d56Sopenharmony_ciimport time 77db96d56Sopenharmony_ciimport base64 87db96d56Sopenharmony_ciimport unittest 97db96d56Sopenharmony_ciimport textwrap 107db96d56Sopenharmony_ciimport warnings 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_cifrom io import StringIO, BytesIO 137db96d56Sopenharmony_cifrom itertools import chain 147db96d56Sopenharmony_cifrom random import choice 157db96d56Sopenharmony_cifrom threading import Thread 167db96d56Sopenharmony_cifrom unittest.mock import patch 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciimport email 197db96d56Sopenharmony_ciimport email.policy 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_cifrom email.charset import Charset 227db96d56Sopenharmony_cifrom email.generator import Generator, DecodedGenerator, BytesGenerator 237db96d56Sopenharmony_cifrom email.header import Header, decode_header, make_header 247db96d56Sopenharmony_cifrom email.headerregistry import HeaderRegistry 257db96d56Sopenharmony_cifrom email.message import Message 267db96d56Sopenharmony_cifrom email.mime.application import MIMEApplication 277db96d56Sopenharmony_cifrom email.mime.audio import MIMEAudio 287db96d56Sopenharmony_cifrom email.mime.base import MIMEBase 297db96d56Sopenharmony_cifrom email.mime.image import MIMEImage 307db96d56Sopenharmony_cifrom email.mime.message import MIMEMessage 317db96d56Sopenharmony_cifrom email.mime.multipart import MIMEMultipart 327db96d56Sopenharmony_cifrom email.mime.nonmultipart import MIMENonMultipart 337db96d56Sopenharmony_cifrom email.mime.text import MIMEText 347db96d56Sopenharmony_cifrom email.parser import Parser, HeaderParser 357db96d56Sopenharmony_cifrom email import base64mime 367db96d56Sopenharmony_cifrom email import encoders 377db96d56Sopenharmony_cifrom email import errors 387db96d56Sopenharmony_cifrom email import iterators 397db96d56Sopenharmony_cifrom email import quoprimime 407db96d56Sopenharmony_cifrom email import utils 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_cifrom test.support import threading_helper 437db96d56Sopenharmony_cifrom test.support.os_helper import unlink 447db96d56Sopenharmony_cifrom test.test_email import openfile, TestEmailBase 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci# These imports are documented to work, but we are testing them using a 477db96d56Sopenharmony_ci# different path, so we import them here just to make sure they are importable. 487db96d56Sopenharmony_cifrom email.parser import FeedParser, BytesFeedParser 497db96d56Sopenharmony_ci 507db96d56Sopenharmony_ciNL = '\n' 517db96d56Sopenharmony_ciEMPTYSTRING = '' 527db96d56Sopenharmony_ciSPACE = ' ' 537db96d56Sopenharmony_ci 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci# Test various aspects of the Message class's API 567db96d56Sopenharmony_ciclass TestMessageAPI(TestEmailBase): 577db96d56Sopenharmony_ci def test_get_all(self): 587db96d56Sopenharmony_ci eq = self.assertEqual 597db96d56Sopenharmony_ci msg = self._msgobj('msg_20.txt') 607db96d56Sopenharmony_ci eq(msg.get_all('cc'), ['ccc@zzz.org', 'ddd@zzz.org', 'eee@zzz.org']) 617db96d56Sopenharmony_ci eq(msg.get_all('xx', 'n/a'), 'n/a') 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci def test_getset_charset(self): 647db96d56Sopenharmony_ci eq = self.assertEqual 657db96d56Sopenharmony_ci msg = Message() 667db96d56Sopenharmony_ci eq(msg.get_charset(), None) 677db96d56Sopenharmony_ci charset = Charset('iso-8859-1') 687db96d56Sopenharmony_ci msg.set_charset(charset) 697db96d56Sopenharmony_ci eq(msg['mime-version'], '1.0') 707db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 717db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="iso-8859-1"') 727db96d56Sopenharmony_ci eq(msg.get_param('charset'), 'iso-8859-1') 737db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'quoted-printable') 747db96d56Sopenharmony_ci eq(msg.get_charset().input_charset, 'iso-8859-1') 757db96d56Sopenharmony_ci # Remove the charset 767db96d56Sopenharmony_ci msg.set_charset(None) 777db96d56Sopenharmony_ci eq(msg.get_charset(), None) 787db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain') 797db96d56Sopenharmony_ci # Try adding a charset when there's already MIME headers present 807db96d56Sopenharmony_ci msg = Message() 817db96d56Sopenharmony_ci msg['MIME-Version'] = '2.0' 827db96d56Sopenharmony_ci msg['Content-Type'] = 'text/x-weird' 837db96d56Sopenharmony_ci msg['Content-Transfer-Encoding'] = 'quinted-puntable' 847db96d56Sopenharmony_ci msg.set_charset(charset) 857db96d56Sopenharmony_ci eq(msg['mime-version'], '2.0') 867db96d56Sopenharmony_ci eq(msg['content-type'], 'text/x-weird; charset="iso-8859-1"') 877db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'quinted-puntable') 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci def test_set_charset_from_string(self): 907db96d56Sopenharmony_ci eq = self.assertEqual 917db96d56Sopenharmony_ci msg = Message() 927db96d56Sopenharmony_ci msg.set_charset('us-ascii') 937db96d56Sopenharmony_ci eq(msg.get_charset().input_charset, 'us-ascii') 947db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="us-ascii"') 957db96d56Sopenharmony_ci 967db96d56Sopenharmony_ci def test_set_payload_with_charset(self): 977db96d56Sopenharmony_ci msg = Message() 987db96d56Sopenharmony_ci charset = Charset('iso-8859-1') 997db96d56Sopenharmony_ci msg.set_payload('This is a string payload', charset) 1007db96d56Sopenharmony_ci self.assertEqual(msg.get_charset().input_charset, 'iso-8859-1') 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci def test_set_payload_with_8bit_data_and_charset(self): 1037db96d56Sopenharmony_ci data = b'\xd0\x90\xd0\x91\xd0\x92' 1047db96d56Sopenharmony_ci charset = Charset('utf-8') 1057db96d56Sopenharmony_ci msg = Message() 1067db96d56Sopenharmony_ci msg.set_payload(data, charset) 1077db96d56Sopenharmony_ci self.assertEqual(msg['content-transfer-encoding'], 'base64') 1087db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), data) 1097db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '0JDQkdCS\n') 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ci def test_set_payload_with_non_ascii_and_charset_body_encoding_none(self): 1127db96d56Sopenharmony_ci data = b'\xd0\x90\xd0\x91\xd0\x92' 1137db96d56Sopenharmony_ci charset = Charset('utf-8') 1147db96d56Sopenharmony_ci charset.body_encoding = None # Disable base64 encoding 1157db96d56Sopenharmony_ci msg = Message() 1167db96d56Sopenharmony_ci msg.set_payload(data.decode('utf-8'), charset) 1177db96d56Sopenharmony_ci self.assertEqual(msg['content-transfer-encoding'], '8bit') 1187db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), data) 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci def test_set_payload_with_8bit_data_and_charset_body_encoding_none(self): 1217db96d56Sopenharmony_ci data = b'\xd0\x90\xd0\x91\xd0\x92' 1227db96d56Sopenharmony_ci charset = Charset('utf-8') 1237db96d56Sopenharmony_ci charset.body_encoding = None # Disable base64 encoding 1247db96d56Sopenharmony_ci msg = Message() 1257db96d56Sopenharmony_ci msg.set_payload(data, charset) 1267db96d56Sopenharmony_ci self.assertEqual(msg['content-transfer-encoding'], '8bit') 1277db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), data) 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci def test_set_payload_to_list(self): 1307db96d56Sopenharmony_ci msg = Message() 1317db96d56Sopenharmony_ci msg.set_payload([]) 1327db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), []) 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ci def test_attach_when_payload_is_string(self): 1357db96d56Sopenharmony_ci msg = Message() 1367db96d56Sopenharmony_ci msg['Content-Type'] = 'multipart/mixed' 1377db96d56Sopenharmony_ci msg.set_payload('string payload') 1387db96d56Sopenharmony_ci sub_msg = MIMEMessage(Message()) 1397db96d56Sopenharmony_ci self.assertRaisesRegex(TypeError, "[Aa]ttach.*non-multipart", 1407db96d56Sopenharmony_ci msg.attach, sub_msg) 1417db96d56Sopenharmony_ci 1427db96d56Sopenharmony_ci def test_get_charsets(self): 1437db96d56Sopenharmony_ci eq = self.assertEqual 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci msg = self._msgobj('msg_08.txt') 1467db96d56Sopenharmony_ci charsets = msg.get_charsets() 1477db96d56Sopenharmony_ci eq(charsets, [None, 'us-ascii', 'iso-8859-1', 'iso-8859-2', 'koi8-r']) 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci msg = self._msgobj('msg_09.txt') 1507db96d56Sopenharmony_ci charsets = msg.get_charsets('dingbat') 1517db96d56Sopenharmony_ci eq(charsets, ['dingbat', 'us-ascii', 'iso-8859-1', 'dingbat', 1527db96d56Sopenharmony_ci 'koi8-r']) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci msg = self._msgobj('msg_12.txt') 1557db96d56Sopenharmony_ci charsets = msg.get_charsets() 1567db96d56Sopenharmony_ci eq(charsets, [None, 'us-ascii', 'iso-8859-1', None, 'iso-8859-2', 1577db96d56Sopenharmony_ci 'iso-8859-3', 'us-ascii', 'koi8-r']) 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci def test_get_filename(self): 1607db96d56Sopenharmony_ci eq = self.assertEqual 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci msg = self._msgobj('msg_04.txt') 1637db96d56Sopenharmony_ci filenames = [p.get_filename() for p in msg.get_payload()] 1647db96d56Sopenharmony_ci eq(filenames, ['msg.txt', 'msg.txt']) 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci msg = self._msgobj('msg_07.txt') 1677db96d56Sopenharmony_ci subpart = msg.get_payload(1) 1687db96d56Sopenharmony_ci eq(subpart.get_filename(), 'dingusfish.gif') 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci def test_get_filename_with_name_parameter(self): 1717db96d56Sopenharmony_ci eq = self.assertEqual 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci msg = self._msgobj('msg_44.txt') 1747db96d56Sopenharmony_ci filenames = [p.get_filename() for p in msg.get_payload()] 1757db96d56Sopenharmony_ci eq(filenames, ['msg.txt', 'msg.txt']) 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ci def test_get_boundary(self): 1787db96d56Sopenharmony_ci eq = self.assertEqual 1797db96d56Sopenharmony_ci msg = self._msgobj('msg_07.txt') 1807db96d56Sopenharmony_ci # No quotes! 1817db96d56Sopenharmony_ci eq(msg.get_boundary(), 'BOUNDARY') 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci def test_set_boundary(self): 1847db96d56Sopenharmony_ci eq = self.assertEqual 1857db96d56Sopenharmony_ci # This one has no existing boundary parameter, but the Content-Type: 1867db96d56Sopenharmony_ci # header appears fifth. 1877db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 1887db96d56Sopenharmony_ci msg.set_boundary('BOUNDARY') 1897db96d56Sopenharmony_ci header, value = msg.items()[4] 1907db96d56Sopenharmony_ci eq(header.lower(), 'content-type') 1917db96d56Sopenharmony_ci eq(value, 'text/plain; charset="us-ascii"; boundary="BOUNDARY"') 1927db96d56Sopenharmony_ci # This one has a Content-Type: header, with a boundary, stuck in the 1937db96d56Sopenharmony_ci # middle of its headers. Make sure the order is preserved; it should 1947db96d56Sopenharmony_ci # be fifth. 1957db96d56Sopenharmony_ci msg = self._msgobj('msg_04.txt') 1967db96d56Sopenharmony_ci msg.set_boundary('BOUNDARY') 1977db96d56Sopenharmony_ci header, value = msg.items()[4] 1987db96d56Sopenharmony_ci eq(header.lower(), 'content-type') 1997db96d56Sopenharmony_ci eq(value, 'multipart/mixed; boundary="BOUNDARY"') 2007db96d56Sopenharmony_ci # And this one has no Content-Type: header at all. 2017db96d56Sopenharmony_ci msg = self._msgobj('msg_03.txt') 2027db96d56Sopenharmony_ci self.assertRaises(errors.HeaderParseError, 2037db96d56Sopenharmony_ci msg.set_boundary, 'BOUNDARY') 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci def test_make_boundary(self): 2067db96d56Sopenharmony_ci msg = MIMEMultipart('form-data') 2077db96d56Sopenharmony_ci # Note that when the boundary gets created is an implementation 2087db96d56Sopenharmony_ci # detail and might change. 2097db96d56Sopenharmony_ci self.assertEqual(msg.items()[0][1], 'multipart/form-data') 2107db96d56Sopenharmony_ci # Trigger creation of boundary 2117db96d56Sopenharmony_ci msg.as_string() 2127db96d56Sopenharmony_ci self.assertEqual(msg.items()[0][1][:33], 2137db96d56Sopenharmony_ci 'multipart/form-data; boundary="==') 2147db96d56Sopenharmony_ci # XXX: there ought to be tests of the uniqueness of the boundary, too. 2157db96d56Sopenharmony_ci 2167db96d56Sopenharmony_ci def test_message_rfc822_only(self): 2177db96d56Sopenharmony_ci # Issue 7970: message/rfc822 not in multipart parsed by 2187db96d56Sopenharmony_ci # HeaderParser caused an exception when flattened. 2197db96d56Sopenharmony_ci with openfile('msg_46.txt', encoding="utf-8") as fp: 2207db96d56Sopenharmony_ci msgdata = fp.read() 2217db96d56Sopenharmony_ci parser = HeaderParser() 2227db96d56Sopenharmony_ci msg = parser.parsestr(msgdata) 2237db96d56Sopenharmony_ci out = StringIO() 2247db96d56Sopenharmony_ci gen = Generator(out, True, 0) 2257db96d56Sopenharmony_ci gen.flatten(msg, False) 2267db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), msgdata) 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci def test_byte_message_rfc822_only(self): 2297db96d56Sopenharmony_ci # Make sure new bytes header parser also passes this. 2307db96d56Sopenharmony_ci with openfile('msg_46.txt', encoding="utf-8") as fp: 2317db96d56Sopenharmony_ci msgdata = fp.read().encode('ascii') 2327db96d56Sopenharmony_ci parser = email.parser.BytesHeaderParser() 2337db96d56Sopenharmony_ci msg = parser.parsebytes(msgdata) 2347db96d56Sopenharmony_ci out = BytesIO() 2357db96d56Sopenharmony_ci gen = email.generator.BytesGenerator(out) 2367db96d56Sopenharmony_ci gen.flatten(msg) 2377db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), msgdata) 2387db96d56Sopenharmony_ci 2397db96d56Sopenharmony_ci def test_get_decoded_payload(self): 2407db96d56Sopenharmony_ci eq = self.assertEqual 2417db96d56Sopenharmony_ci msg = self._msgobj('msg_10.txt') 2427db96d56Sopenharmony_ci # The outer message is a multipart 2437db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), None) 2447db96d56Sopenharmony_ci # Subpart 1 is 7bit encoded 2457db96d56Sopenharmony_ci eq(msg.get_payload(0).get_payload(decode=True), 2467db96d56Sopenharmony_ci b'This is a 7bit encoded message.\n') 2477db96d56Sopenharmony_ci # Subpart 2 is quopri 2487db96d56Sopenharmony_ci eq(msg.get_payload(1).get_payload(decode=True), 2497db96d56Sopenharmony_ci b'\xa1This is a Quoted Printable encoded message!\n') 2507db96d56Sopenharmony_ci # Subpart 3 is base64 2517db96d56Sopenharmony_ci eq(msg.get_payload(2).get_payload(decode=True), 2527db96d56Sopenharmony_ci b'This is a Base64 encoded message.') 2537db96d56Sopenharmony_ci # Subpart 4 is base64 with a trailing newline, which 2547db96d56Sopenharmony_ci # used to be stripped (issue 7143). 2557db96d56Sopenharmony_ci eq(msg.get_payload(3).get_payload(decode=True), 2567db96d56Sopenharmony_ci b'This is a Base64 encoded message.\n') 2577db96d56Sopenharmony_ci # Subpart 5 has no Content-Transfer-Encoding: header. 2587db96d56Sopenharmony_ci eq(msg.get_payload(4).get_payload(decode=True), 2597db96d56Sopenharmony_ci b'This has no Content-Transfer-Encoding: header.\n') 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci def test_get_decoded_uu_payload(self): 2627db96d56Sopenharmony_ci eq = self.assertEqual 2637db96d56Sopenharmony_ci msg = Message() 2647db96d56Sopenharmony_ci msg.set_payload('begin 666 -\n+:&5L;&\\@=V]R;&0 \n \nend\n') 2657db96d56Sopenharmony_ci for cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'): 2667db96d56Sopenharmony_ci msg['content-transfer-encoding'] = cte 2677db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), b'hello world') 2687db96d56Sopenharmony_ci # Now try some bogus data 2697db96d56Sopenharmony_ci msg.set_payload('foo') 2707db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), b'foo') 2717db96d56Sopenharmony_ci 2727db96d56Sopenharmony_ci def test_get_payload_n_raises_on_non_multipart(self): 2737db96d56Sopenharmony_ci msg = Message() 2747db96d56Sopenharmony_ci self.assertRaises(TypeError, msg.get_payload, 1) 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci def test_decoded_generator(self): 2777db96d56Sopenharmony_ci eq = self.assertEqual 2787db96d56Sopenharmony_ci msg = self._msgobj('msg_07.txt') 2797db96d56Sopenharmony_ci with openfile('msg_17.txt', encoding="utf-8") as fp: 2807db96d56Sopenharmony_ci text = fp.read() 2817db96d56Sopenharmony_ci s = StringIO() 2827db96d56Sopenharmony_ci g = DecodedGenerator(s) 2837db96d56Sopenharmony_ci g.flatten(msg) 2847db96d56Sopenharmony_ci eq(s.getvalue(), text) 2857db96d56Sopenharmony_ci 2867db96d56Sopenharmony_ci def test__contains__(self): 2877db96d56Sopenharmony_ci msg = Message() 2887db96d56Sopenharmony_ci msg['From'] = 'Me' 2897db96d56Sopenharmony_ci msg['to'] = 'You' 2907db96d56Sopenharmony_ci # Check for case insensitivity 2917db96d56Sopenharmony_ci self.assertIn('from', msg) 2927db96d56Sopenharmony_ci self.assertIn('From', msg) 2937db96d56Sopenharmony_ci self.assertIn('FROM', msg) 2947db96d56Sopenharmony_ci self.assertIn('to', msg) 2957db96d56Sopenharmony_ci self.assertIn('To', msg) 2967db96d56Sopenharmony_ci self.assertIn('TO', msg) 2977db96d56Sopenharmony_ci 2987db96d56Sopenharmony_ci def test_as_string(self): 2997db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 3007db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 3017db96d56Sopenharmony_ci text = fp.read() 3027db96d56Sopenharmony_ci self.assertEqual(text, str(msg)) 3037db96d56Sopenharmony_ci fullrepr = msg.as_string(unixfrom=True) 3047db96d56Sopenharmony_ci lines = fullrepr.split('\n') 3057db96d56Sopenharmony_ci self.assertTrue(lines[0].startswith('From ')) 3067db96d56Sopenharmony_ci self.assertEqual(text, NL.join(lines[1:])) 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci def test_as_string_policy(self): 3097db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 3107db96d56Sopenharmony_ci newpolicy = msg.policy.clone(linesep='\r\n') 3117db96d56Sopenharmony_ci fullrepr = msg.as_string(policy=newpolicy) 3127db96d56Sopenharmony_ci s = StringIO() 3137db96d56Sopenharmony_ci g = Generator(s, policy=newpolicy) 3147db96d56Sopenharmony_ci g.flatten(msg) 3157db96d56Sopenharmony_ci self.assertEqual(fullrepr, s.getvalue()) 3167db96d56Sopenharmony_ci 3177db96d56Sopenharmony_ci def test_nonascii_as_string_without_cte(self): 3187db96d56Sopenharmony_ci m = textwrap.dedent("""\ 3197db96d56Sopenharmony_ci MIME-Version: 1.0 3207db96d56Sopenharmony_ci Content-type: text/plain; charset="iso-8859-1" 3217db96d56Sopenharmony_ci 3227db96d56Sopenharmony_ci Test if non-ascii messages with no Content-Transfer-Encoding set 3237db96d56Sopenharmony_ci can be as_string'd: 3247db96d56Sopenharmony_ci Föö bär 3257db96d56Sopenharmony_ci """) 3267db96d56Sopenharmony_ci source = m.encode('iso-8859-1') 3277db96d56Sopenharmony_ci expected = textwrap.dedent("""\ 3287db96d56Sopenharmony_ci MIME-Version: 1.0 3297db96d56Sopenharmony_ci Content-type: text/plain; charset="iso-8859-1" 3307db96d56Sopenharmony_ci Content-Transfer-Encoding: quoted-printable 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci Test if non-ascii messages with no Content-Transfer-Encoding set 3337db96d56Sopenharmony_ci can be as_string'd: 3347db96d56Sopenharmony_ci F=F6=F6 b=E4r 3357db96d56Sopenharmony_ci """) 3367db96d56Sopenharmony_ci msg = email.message_from_bytes(source) 3377db96d56Sopenharmony_ci self.assertEqual(msg.as_string(), expected) 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci def test_nonascii_as_string_without_content_type_and_cte(self): 3407db96d56Sopenharmony_ci m = textwrap.dedent("""\ 3417db96d56Sopenharmony_ci MIME-Version: 1.0 3427db96d56Sopenharmony_ci 3437db96d56Sopenharmony_ci Test if non-ascii messages with no Content-Type nor 3447db96d56Sopenharmony_ci Content-Transfer-Encoding set can be as_string'd: 3457db96d56Sopenharmony_ci Föö bär 3467db96d56Sopenharmony_ci """) 3477db96d56Sopenharmony_ci source = m.encode('iso-8859-1') 3487db96d56Sopenharmony_ci expected = source.decode('ascii', 'replace') 3497db96d56Sopenharmony_ci msg = email.message_from_bytes(source) 3507db96d56Sopenharmony_ci self.assertEqual(msg.as_string(), expected) 3517db96d56Sopenharmony_ci 3527db96d56Sopenharmony_ci def test_as_bytes(self): 3537db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 3547db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 3557db96d56Sopenharmony_ci data = fp.read().encode('ascii') 3567db96d56Sopenharmony_ci self.assertEqual(data, bytes(msg)) 3577db96d56Sopenharmony_ci fullrepr = msg.as_bytes(unixfrom=True) 3587db96d56Sopenharmony_ci lines = fullrepr.split(b'\n') 3597db96d56Sopenharmony_ci self.assertTrue(lines[0].startswith(b'From ')) 3607db96d56Sopenharmony_ci self.assertEqual(data, b'\n'.join(lines[1:])) 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci def test_as_bytes_policy(self): 3637db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 3647db96d56Sopenharmony_ci newpolicy = msg.policy.clone(linesep='\r\n') 3657db96d56Sopenharmony_ci fullrepr = msg.as_bytes(policy=newpolicy) 3667db96d56Sopenharmony_ci s = BytesIO() 3677db96d56Sopenharmony_ci g = BytesGenerator(s,policy=newpolicy) 3687db96d56Sopenharmony_ci g.flatten(msg) 3697db96d56Sopenharmony_ci self.assertEqual(fullrepr, s.getvalue()) 3707db96d56Sopenharmony_ci 3717db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.bad_params 3727db96d56Sopenharmony_ci def test_bad_param(self): 3737db96d56Sopenharmony_ci msg = email.message_from_string("Content-Type: blarg; baz; boo\n") 3747db96d56Sopenharmony_ci self.assertEqual(msg.get_param('baz'), '') 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci def test_missing_filename(self): 3777db96d56Sopenharmony_ci msg = email.message_from_string("From: foo\n") 3787db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), None) 3797db96d56Sopenharmony_ci 3807db96d56Sopenharmony_ci def test_bogus_filename(self): 3817db96d56Sopenharmony_ci msg = email.message_from_string( 3827db96d56Sopenharmony_ci "Content-Disposition: blarg; filename\n") 3837db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), '') 3847db96d56Sopenharmony_ci 3857db96d56Sopenharmony_ci def test_missing_boundary(self): 3867db96d56Sopenharmony_ci msg = email.message_from_string("From: foo\n") 3877db96d56Sopenharmony_ci self.assertEqual(msg.get_boundary(), None) 3887db96d56Sopenharmony_ci 3897db96d56Sopenharmony_ci def test_get_params(self): 3907db96d56Sopenharmony_ci eq = self.assertEqual 3917db96d56Sopenharmony_ci msg = email.message_from_string( 3927db96d56Sopenharmony_ci 'X-Header: foo=one; bar=two; baz=three\n') 3937db96d56Sopenharmony_ci eq(msg.get_params(header='x-header'), 3947db96d56Sopenharmony_ci [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]) 3957db96d56Sopenharmony_ci msg = email.message_from_string( 3967db96d56Sopenharmony_ci 'X-Header: foo; bar=one; baz=two\n') 3977db96d56Sopenharmony_ci eq(msg.get_params(header='x-header'), 3987db96d56Sopenharmony_ci [('foo', ''), ('bar', 'one'), ('baz', 'two')]) 3997db96d56Sopenharmony_ci eq(msg.get_params(), None) 4007db96d56Sopenharmony_ci msg = email.message_from_string( 4017db96d56Sopenharmony_ci 'X-Header: foo; bar="one"; baz=two\n') 4027db96d56Sopenharmony_ci eq(msg.get_params(header='x-header'), 4037db96d56Sopenharmony_ci [('foo', ''), ('bar', 'one'), ('baz', 'two')]) 4047db96d56Sopenharmony_ci 4057db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.spaces_around_param_equals 4067db96d56Sopenharmony_ci def test_get_param_liberal(self): 4077db96d56Sopenharmony_ci msg = Message() 4087db96d56Sopenharmony_ci msg['Content-Type'] = 'Content-Type: Multipart/mixed; boundary = "CPIMSSMTPC06p5f3tG"' 4097db96d56Sopenharmony_ci self.assertEqual(msg.get_param('boundary'), 'CPIMSSMTPC06p5f3tG') 4107db96d56Sopenharmony_ci 4117db96d56Sopenharmony_ci def test_get_param(self): 4127db96d56Sopenharmony_ci eq = self.assertEqual 4137db96d56Sopenharmony_ci msg = email.message_from_string( 4147db96d56Sopenharmony_ci "X-Header: foo=one; bar=two; baz=three\n") 4157db96d56Sopenharmony_ci eq(msg.get_param('bar', header='x-header'), 'two') 4167db96d56Sopenharmony_ci eq(msg.get_param('quuz', header='x-header'), None) 4177db96d56Sopenharmony_ci eq(msg.get_param('quuz'), None) 4187db96d56Sopenharmony_ci msg = email.message_from_string( 4197db96d56Sopenharmony_ci 'X-Header: foo; bar="one"; baz=two\n') 4207db96d56Sopenharmony_ci eq(msg.get_param('foo', header='x-header'), '') 4217db96d56Sopenharmony_ci eq(msg.get_param('bar', header='x-header'), 'one') 4227db96d56Sopenharmony_ci eq(msg.get_param('baz', header='x-header'), 'two') 4237db96d56Sopenharmony_ci # XXX: We are not RFC-2045 compliant! We cannot parse: 4247db96d56Sopenharmony_ci # msg["Content-Type"] = 'text/plain; weird="hey; dolly? [you] @ <\\"home\\">?"' 4257db96d56Sopenharmony_ci # msg.get_param("weird") 4267db96d56Sopenharmony_ci # yet. 4277db96d56Sopenharmony_ci 4287db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.spaces_around_semis 4297db96d56Sopenharmony_ci def test_get_param_funky_continuation_lines(self): 4307db96d56Sopenharmony_ci msg = self._msgobj('msg_22.txt') 4317db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(1).get_param('name'), 'wibble.JPG') 4327db96d56Sopenharmony_ci 4337db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.semis_inside_quotes 4347db96d56Sopenharmony_ci def test_get_param_with_semis_in_quotes(self): 4357db96d56Sopenharmony_ci msg = email.message_from_string( 4367db96d56Sopenharmony_ci 'Content-Type: image/pjpeg; name="Jim&&Jill"\n') 4377db96d56Sopenharmony_ci self.assertEqual(msg.get_param('name'), 'Jim&&Jill') 4387db96d56Sopenharmony_ci self.assertEqual(msg.get_param('name', unquote=False), 4397db96d56Sopenharmony_ci '"Jim&&Jill"') 4407db96d56Sopenharmony_ci 4417db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.quotes_inside_rfc2231_value 4427db96d56Sopenharmony_ci def test_get_param_with_quotes(self): 4437db96d56Sopenharmony_ci msg = email.message_from_string( 4447db96d56Sopenharmony_ci 'Content-Type: foo; bar*0="baz\\"foobar"; bar*1="\\"baz"') 4457db96d56Sopenharmony_ci self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz') 4467db96d56Sopenharmony_ci msg = email.message_from_string( 4477db96d56Sopenharmony_ci "Content-Type: foo; bar*0=\"baz\\\"foobar\"; bar*1=\"\\\"baz\"") 4487db96d56Sopenharmony_ci self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz') 4497db96d56Sopenharmony_ci 4507db96d56Sopenharmony_ci def test_field_containment(self): 4517db96d56Sopenharmony_ci msg = email.message_from_string('Header: exists') 4527db96d56Sopenharmony_ci self.assertIn('header', msg) 4537db96d56Sopenharmony_ci self.assertIn('Header', msg) 4547db96d56Sopenharmony_ci self.assertIn('HEADER', msg) 4557db96d56Sopenharmony_ci self.assertNotIn('headerx', msg) 4567db96d56Sopenharmony_ci 4577db96d56Sopenharmony_ci def test_set_param(self): 4587db96d56Sopenharmony_ci eq = self.assertEqual 4597db96d56Sopenharmony_ci msg = Message() 4607db96d56Sopenharmony_ci msg.set_param('charset', 'iso-2022-jp') 4617db96d56Sopenharmony_ci eq(msg.get_param('charset'), 'iso-2022-jp') 4627db96d56Sopenharmony_ci msg.set_param('importance', 'high value') 4637db96d56Sopenharmony_ci eq(msg.get_param('importance'), 'high value') 4647db96d56Sopenharmony_ci eq(msg.get_param('importance', unquote=False), '"high value"') 4657db96d56Sopenharmony_ci eq(msg.get_params(), [('text/plain', ''), 4667db96d56Sopenharmony_ci ('charset', 'iso-2022-jp'), 4677db96d56Sopenharmony_ci ('importance', 'high value')]) 4687db96d56Sopenharmony_ci eq(msg.get_params(unquote=False), [('text/plain', ''), 4697db96d56Sopenharmony_ci ('charset', '"iso-2022-jp"'), 4707db96d56Sopenharmony_ci ('importance', '"high value"')]) 4717db96d56Sopenharmony_ci msg.set_param('charset', 'iso-9999-xx', header='X-Jimmy') 4727db96d56Sopenharmony_ci eq(msg.get_param('charset', header='X-Jimmy'), 'iso-9999-xx') 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ci def test_del_param(self): 4757db96d56Sopenharmony_ci eq = self.assertEqual 4767db96d56Sopenharmony_ci msg = self._msgobj('msg_05.txt') 4777db96d56Sopenharmony_ci eq(msg.get_params(), 4787db96d56Sopenharmony_ci [('multipart/report', ''), ('report-type', 'delivery-status'), 4797db96d56Sopenharmony_ci ('boundary', 'D1690A7AC1.996856090/mail.example.com')]) 4807db96d56Sopenharmony_ci old_val = msg.get_param("report-type") 4817db96d56Sopenharmony_ci msg.del_param("report-type") 4827db96d56Sopenharmony_ci eq(msg.get_params(), 4837db96d56Sopenharmony_ci [('multipart/report', ''), 4847db96d56Sopenharmony_ci ('boundary', 'D1690A7AC1.996856090/mail.example.com')]) 4857db96d56Sopenharmony_ci msg.set_param("report-type", old_val) 4867db96d56Sopenharmony_ci eq(msg.get_params(), 4877db96d56Sopenharmony_ci [('multipart/report', ''), 4887db96d56Sopenharmony_ci ('boundary', 'D1690A7AC1.996856090/mail.example.com'), 4897db96d56Sopenharmony_ci ('report-type', old_val)]) 4907db96d56Sopenharmony_ci 4917db96d56Sopenharmony_ci def test_del_param_on_other_header(self): 4927db96d56Sopenharmony_ci msg = Message() 4937db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', filename='bud.gif') 4947db96d56Sopenharmony_ci msg.del_param('filename', 'content-disposition') 4957db96d56Sopenharmony_ci self.assertEqual(msg['content-disposition'], 'attachment') 4967db96d56Sopenharmony_ci 4977db96d56Sopenharmony_ci def test_del_param_on_nonexistent_header(self): 4987db96d56Sopenharmony_ci msg = Message() 4997db96d56Sopenharmony_ci # Deleting param on empty msg should not raise exception. 5007db96d56Sopenharmony_ci msg.del_param('filename', 'content-disposition') 5017db96d56Sopenharmony_ci 5027db96d56Sopenharmony_ci def test_del_nonexistent_param(self): 5037db96d56Sopenharmony_ci msg = Message() 5047db96d56Sopenharmony_ci msg.add_header('Content-Type', 'text/plain', charset='utf-8') 5057db96d56Sopenharmony_ci existing_header = msg['Content-Type'] 5067db96d56Sopenharmony_ci msg.del_param('foobar', header='Content-Type') 5077db96d56Sopenharmony_ci self.assertEqual(msg['Content-Type'], existing_header) 5087db96d56Sopenharmony_ci 5097db96d56Sopenharmony_ci def test_set_type(self): 5107db96d56Sopenharmony_ci eq = self.assertEqual 5117db96d56Sopenharmony_ci msg = Message() 5127db96d56Sopenharmony_ci self.assertRaises(ValueError, msg.set_type, 'text') 5137db96d56Sopenharmony_ci msg.set_type('text/plain') 5147db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain') 5157db96d56Sopenharmony_ci msg.set_param('charset', 'us-ascii') 5167db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="us-ascii"') 5177db96d56Sopenharmony_ci msg.set_type('text/html') 5187db96d56Sopenharmony_ci eq(msg['content-type'], 'text/html; charset="us-ascii"') 5197db96d56Sopenharmony_ci 5207db96d56Sopenharmony_ci def test_set_type_on_other_header(self): 5217db96d56Sopenharmony_ci msg = Message() 5227db96d56Sopenharmony_ci msg['X-Content-Type'] = 'text/plain' 5237db96d56Sopenharmony_ci msg.set_type('application/octet-stream', 'X-Content-Type') 5247db96d56Sopenharmony_ci self.assertEqual(msg['x-content-type'], 'application/octet-stream') 5257db96d56Sopenharmony_ci 5267db96d56Sopenharmony_ci def test_get_content_type_missing(self): 5277db96d56Sopenharmony_ci msg = Message() 5287db96d56Sopenharmony_ci self.assertEqual(msg.get_content_type(), 'text/plain') 5297db96d56Sopenharmony_ci 5307db96d56Sopenharmony_ci def test_get_content_type_missing_with_default_type(self): 5317db96d56Sopenharmony_ci msg = Message() 5327db96d56Sopenharmony_ci msg.set_default_type('message/rfc822') 5337db96d56Sopenharmony_ci self.assertEqual(msg.get_content_type(), 'message/rfc822') 5347db96d56Sopenharmony_ci 5357db96d56Sopenharmony_ci def test_get_content_type_from_message_implicit(self): 5367db96d56Sopenharmony_ci msg = self._msgobj('msg_30.txt') 5377db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_type(), 5387db96d56Sopenharmony_ci 'message/rfc822') 5397db96d56Sopenharmony_ci 5407db96d56Sopenharmony_ci def test_get_content_type_from_message_explicit(self): 5417db96d56Sopenharmony_ci msg = self._msgobj('msg_28.txt') 5427db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_type(), 5437db96d56Sopenharmony_ci 'message/rfc822') 5447db96d56Sopenharmony_ci 5457db96d56Sopenharmony_ci def test_get_content_type_from_message_text_plain_implicit(self): 5467db96d56Sopenharmony_ci msg = self._msgobj('msg_03.txt') 5477db96d56Sopenharmony_ci self.assertEqual(msg.get_content_type(), 'text/plain') 5487db96d56Sopenharmony_ci 5497db96d56Sopenharmony_ci def test_get_content_type_from_message_text_plain_explicit(self): 5507db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 5517db96d56Sopenharmony_ci self.assertEqual(msg.get_content_type(), 'text/plain') 5527db96d56Sopenharmony_ci 5537db96d56Sopenharmony_ci def test_get_content_maintype_missing(self): 5547db96d56Sopenharmony_ci msg = Message() 5557db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'text') 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci def test_get_content_maintype_missing_with_default_type(self): 5587db96d56Sopenharmony_ci msg = Message() 5597db96d56Sopenharmony_ci msg.set_default_type('message/rfc822') 5607db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'message') 5617db96d56Sopenharmony_ci 5627db96d56Sopenharmony_ci def test_get_content_maintype_from_message_implicit(self): 5637db96d56Sopenharmony_ci msg = self._msgobj('msg_30.txt') 5647db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message') 5657db96d56Sopenharmony_ci 5667db96d56Sopenharmony_ci def test_get_content_maintype_from_message_explicit(self): 5677db96d56Sopenharmony_ci msg = self._msgobj('msg_28.txt') 5687db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_maintype(), 'message') 5697db96d56Sopenharmony_ci 5707db96d56Sopenharmony_ci def test_get_content_maintype_from_message_text_plain_implicit(self): 5717db96d56Sopenharmony_ci msg = self._msgobj('msg_03.txt') 5727db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'text') 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci def test_get_content_maintype_from_message_text_plain_explicit(self): 5757db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 5767db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'text') 5777db96d56Sopenharmony_ci 5787db96d56Sopenharmony_ci def test_get_content_subtype_missing(self): 5797db96d56Sopenharmony_ci msg = Message() 5807db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), 'plain') 5817db96d56Sopenharmony_ci 5827db96d56Sopenharmony_ci def test_get_content_subtype_missing_with_default_type(self): 5837db96d56Sopenharmony_ci msg = Message() 5847db96d56Sopenharmony_ci msg.set_default_type('message/rfc822') 5857db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), 'rfc822') 5867db96d56Sopenharmony_ci 5877db96d56Sopenharmony_ci def test_get_content_subtype_from_message_implicit(self): 5887db96d56Sopenharmony_ci msg = self._msgobj('msg_30.txt') 5897db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822') 5907db96d56Sopenharmony_ci 5917db96d56Sopenharmony_ci def test_get_content_subtype_from_message_explicit(self): 5927db96d56Sopenharmony_ci msg = self._msgobj('msg_28.txt') 5937db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(0).get_content_subtype(), 'rfc822') 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci def test_get_content_subtype_from_message_text_plain_implicit(self): 5967db96d56Sopenharmony_ci msg = self._msgobj('msg_03.txt') 5977db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), 'plain') 5987db96d56Sopenharmony_ci 5997db96d56Sopenharmony_ci def test_get_content_subtype_from_message_text_plain_explicit(self): 6007db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 6017db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), 'plain') 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci def test_get_content_maintype_error(self): 6047db96d56Sopenharmony_ci msg = Message() 6057db96d56Sopenharmony_ci msg['Content-Type'] = 'no-slash-in-this-string' 6067db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'text') 6077db96d56Sopenharmony_ci 6087db96d56Sopenharmony_ci def test_get_content_subtype_error(self): 6097db96d56Sopenharmony_ci msg = Message() 6107db96d56Sopenharmony_ci msg['Content-Type'] = 'no-slash-in-this-string' 6117db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), 'plain') 6127db96d56Sopenharmony_ci 6137db96d56Sopenharmony_ci def test_replace_header(self): 6147db96d56Sopenharmony_ci eq = self.assertEqual 6157db96d56Sopenharmony_ci msg = Message() 6167db96d56Sopenharmony_ci msg.add_header('First', 'One') 6177db96d56Sopenharmony_ci msg.add_header('Second', 'Two') 6187db96d56Sopenharmony_ci msg.add_header('Third', 'Three') 6197db96d56Sopenharmony_ci eq(msg.keys(), ['First', 'Second', 'Third']) 6207db96d56Sopenharmony_ci eq(msg.values(), ['One', 'Two', 'Three']) 6217db96d56Sopenharmony_ci msg.replace_header('Second', 'Twenty') 6227db96d56Sopenharmony_ci eq(msg.keys(), ['First', 'Second', 'Third']) 6237db96d56Sopenharmony_ci eq(msg.values(), ['One', 'Twenty', 'Three']) 6247db96d56Sopenharmony_ci msg.add_header('First', 'Eleven') 6257db96d56Sopenharmony_ci msg.replace_header('First', 'One Hundred') 6267db96d56Sopenharmony_ci eq(msg.keys(), ['First', 'Second', 'Third', 'First']) 6277db96d56Sopenharmony_ci eq(msg.values(), ['One Hundred', 'Twenty', 'Three', 'Eleven']) 6287db96d56Sopenharmony_ci self.assertRaises(KeyError, msg.replace_header, 'Fourth', 'Missing') 6297db96d56Sopenharmony_ci 6307db96d56Sopenharmony_ci def test_get_content_disposition(self): 6317db96d56Sopenharmony_ci msg = Message() 6327db96d56Sopenharmony_ci self.assertIsNone(msg.get_content_disposition()) 6337db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 6347db96d56Sopenharmony_ci filename='random.avi') 6357db96d56Sopenharmony_ci self.assertEqual(msg.get_content_disposition(), 'attachment') 6367db96d56Sopenharmony_ci msg.replace_header('Content-Disposition', 'inline') 6377db96d56Sopenharmony_ci self.assertEqual(msg.get_content_disposition(), 'inline') 6387db96d56Sopenharmony_ci msg.replace_header('Content-Disposition', 'InlinE') 6397db96d56Sopenharmony_ci self.assertEqual(msg.get_content_disposition(), 'inline') 6407db96d56Sopenharmony_ci 6417db96d56Sopenharmony_ci # test_defect_handling:test_invalid_chars_in_base64_payload 6427db96d56Sopenharmony_ci def test_broken_base64_payload(self): 6437db96d56Sopenharmony_ci x = 'AwDp0P7//y6LwKEAcPa/6Q=9' 6447db96d56Sopenharmony_ci msg = Message() 6457db96d56Sopenharmony_ci msg['content-type'] = 'audio/x-midi' 6467db96d56Sopenharmony_ci msg['content-transfer-encoding'] = 'base64' 6477db96d56Sopenharmony_ci msg.set_payload(x) 6487db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 6497db96d56Sopenharmony_ci (b'\x03\x00\xe9\xd0\xfe\xff\xff.\x8b\xc0' 6507db96d56Sopenharmony_ci b'\xa1\x00p\xf6\xbf\xe9\x0f')) 6517db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[0], 6527db96d56Sopenharmony_ci errors.InvalidBase64CharactersDefect) 6537db96d56Sopenharmony_ci 6547db96d56Sopenharmony_ci def test_broken_unicode_payload(self): 6557db96d56Sopenharmony_ci # This test improves coverage but is not a compliance test. 6567db96d56Sopenharmony_ci # The behavior in this situation is currently undefined by the API. 6577db96d56Sopenharmony_ci x = 'this is a br\xf6ken thing to do' 6587db96d56Sopenharmony_ci msg = Message() 6597db96d56Sopenharmony_ci msg['content-type'] = 'text/plain' 6607db96d56Sopenharmony_ci msg['content-transfer-encoding'] = '8bit' 6617db96d56Sopenharmony_ci msg.set_payload(x) 6627db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 6637db96d56Sopenharmony_ci bytes(x, 'raw-unicode-escape')) 6647db96d56Sopenharmony_ci 6657db96d56Sopenharmony_ci def test_questionable_bytes_payload(self): 6667db96d56Sopenharmony_ci # This test improves coverage but is not a compliance test, 6677db96d56Sopenharmony_ci # since it involves poking inside the black box. 6687db96d56Sopenharmony_ci x = 'this is a quéstionable thing to do'.encode('utf-8') 6697db96d56Sopenharmony_ci msg = Message() 6707db96d56Sopenharmony_ci msg['content-type'] = 'text/plain; charset="utf-8"' 6717db96d56Sopenharmony_ci msg['content-transfer-encoding'] = '8bit' 6727db96d56Sopenharmony_ci msg._payload = x 6737db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), x) 6747db96d56Sopenharmony_ci 6757db96d56Sopenharmony_ci # Issue 1078919 6767db96d56Sopenharmony_ci def test_ascii_add_header(self): 6777db96d56Sopenharmony_ci msg = Message() 6787db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 6797db96d56Sopenharmony_ci filename='bud.gif') 6807db96d56Sopenharmony_ci self.assertEqual('attachment; filename="bud.gif"', 6817db96d56Sopenharmony_ci msg['Content-Disposition']) 6827db96d56Sopenharmony_ci 6837db96d56Sopenharmony_ci def test_noascii_add_header(self): 6847db96d56Sopenharmony_ci msg = Message() 6857db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 6867db96d56Sopenharmony_ci filename="Fußballer.ppt") 6877db96d56Sopenharmony_ci self.assertEqual( 6887db96d56Sopenharmony_ci 'attachment; filename*=utf-8\'\'Fu%C3%9Fballer.ppt', 6897db96d56Sopenharmony_ci msg['Content-Disposition']) 6907db96d56Sopenharmony_ci 6917db96d56Sopenharmony_ci def test_nonascii_add_header_via_triple(self): 6927db96d56Sopenharmony_ci msg = Message() 6937db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 6947db96d56Sopenharmony_ci filename=('iso-8859-1', '', 'Fußballer.ppt')) 6957db96d56Sopenharmony_ci self.assertEqual( 6967db96d56Sopenharmony_ci 'attachment; filename*=iso-8859-1\'\'Fu%DFballer.ppt', 6977db96d56Sopenharmony_ci msg['Content-Disposition']) 6987db96d56Sopenharmony_ci 6997db96d56Sopenharmony_ci def test_ascii_add_header_with_tspecial(self): 7007db96d56Sopenharmony_ci msg = Message() 7017db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 7027db96d56Sopenharmony_ci filename="windows [filename].ppt") 7037db96d56Sopenharmony_ci self.assertEqual( 7047db96d56Sopenharmony_ci 'attachment; filename="windows [filename].ppt"', 7057db96d56Sopenharmony_ci msg['Content-Disposition']) 7067db96d56Sopenharmony_ci 7077db96d56Sopenharmony_ci def test_nonascii_add_header_with_tspecial(self): 7087db96d56Sopenharmony_ci msg = Message() 7097db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'attachment', 7107db96d56Sopenharmony_ci filename="Fußballer [filename].ppt") 7117db96d56Sopenharmony_ci self.assertEqual( 7127db96d56Sopenharmony_ci "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt", 7137db96d56Sopenharmony_ci msg['Content-Disposition']) 7147db96d56Sopenharmony_ci 7157db96d56Sopenharmony_ci def test_binary_quopri_payload(self): 7167db96d56Sopenharmony_ci for charset in ('latin-1', 'ascii'): 7177db96d56Sopenharmony_ci msg = Message() 7187db96d56Sopenharmony_ci msg['content-type'] = 'text/plain; charset=%s' % charset 7197db96d56Sopenharmony_ci msg['content-transfer-encoding'] = 'quoted-printable' 7207db96d56Sopenharmony_ci msg.set_payload(b'foo=e6=96=87bar') 7217db96d56Sopenharmony_ci self.assertEqual( 7227db96d56Sopenharmony_ci msg.get_payload(decode=True), 7237db96d56Sopenharmony_ci b'foo\xe6\x96\x87bar', 7247db96d56Sopenharmony_ci 'get_payload returns wrong result with charset %s.' % charset) 7257db96d56Sopenharmony_ci 7267db96d56Sopenharmony_ci def test_binary_base64_payload(self): 7277db96d56Sopenharmony_ci for charset in ('latin-1', 'ascii'): 7287db96d56Sopenharmony_ci msg = Message() 7297db96d56Sopenharmony_ci msg['content-type'] = 'text/plain; charset=%s' % charset 7307db96d56Sopenharmony_ci msg['content-transfer-encoding'] = 'base64' 7317db96d56Sopenharmony_ci msg.set_payload(b'Zm9v5paHYmFy') 7327db96d56Sopenharmony_ci self.assertEqual( 7337db96d56Sopenharmony_ci msg.get_payload(decode=True), 7347db96d56Sopenharmony_ci b'foo\xe6\x96\x87bar', 7357db96d56Sopenharmony_ci 'get_payload returns wrong result with charset %s.' % charset) 7367db96d56Sopenharmony_ci 7377db96d56Sopenharmony_ci def test_binary_uuencode_payload(self): 7387db96d56Sopenharmony_ci for charset in ('latin-1', 'ascii'): 7397db96d56Sopenharmony_ci for encoding in ('x-uuencode', 'uuencode', 'uue', 'x-uue'): 7407db96d56Sopenharmony_ci msg = Message() 7417db96d56Sopenharmony_ci msg['content-type'] = 'text/plain; charset=%s' % charset 7427db96d56Sopenharmony_ci msg['content-transfer-encoding'] = encoding 7437db96d56Sopenharmony_ci msg.set_payload(b"begin 666 -\n)9F]OYI:'8F%R\n \nend\n") 7447db96d56Sopenharmony_ci self.assertEqual( 7457db96d56Sopenharmony_ci msg.get_payload(decode=True), 7467db96d56Sopenharmony_ci b'foo\xe6\x96\x87bar', 7477db96d56Sopenharmony_ci str(('get_payload returns wrong result ', 7487db96d56Sopenharmony_ci 'with charset {0} and encoding {1}.')).\ 7497db96d56Sopenharmony_ci format(charset, encoding)) 7507db96d56Sopenharmony_ci 7517db96d56Sopenharmony_ci def test_add_header_with_name_only_param(self): 7527db96d56Sopenharmony_ci msg = Message() 7537db96d56Sopenharmony_ci msg.add_header('Content-Disposition', 'inline', foo_bar=None) 7547db96d56Sopenharmony_ci self.assertEqual("inline; foo-bar", msg['Content-Disposition']) 7557db96d56Sopenharmony_ci 7567db96d56Sopenharmony_ci def test_add_header_with_no_value(self): 7577db96d56Sopenharmony_ci msg = Message() 7587db96d56Sopenharmony_ci msg.add_header('X-Status', None) 7597db96d56Sopenharmony_ci self.assertEqual('', msg['X-Status']) 7607db96d56Sopenharmony_ci 7617db96d56Sopenharmony_ci # Issue 5871: reject an attempt to embed a header inside a header value 7627db96d56Sopenharmony_ci # (header injection attack). 7637db96d56Sopenharmony_ci def test_embedded_header_via_Header_rejected(self): 7647db96d56Sopenharmony_ci msg = Message() 7657db96d56Sopenharmony_ci msg['Dummy'] = Header('dummy\nX-Injected-Header: test') 7667db96d56Sopenharmony_ci self.assertRaises(errors.HeaderParseError, msg.as_string) 7677db96d56Sopenharmony_ci 7687db96d56Sopenharmony_ci def test_embedded_header_via_string_rejected(self): 7697db96d56Sopenharmony_ci msg = Message() 7707db96d56Sopenharmony_ci msg['Dummy'] = 'dummy\nX-Injected-Header: test' 7717db96d56Sopenharmony_ci self.assertRaises(errors.HeaderParseError, msg.as_string) 7727db96d56Sopenharmony_ci 7737db96d56Sopenharmony_ci def test_unicode_header_defaults_to_utf8_encoding(self): 7747db96d56Sopenharmony_ci # Issue 14291 7757db96d56Sopenharmony_ci m = MIMEText('abc\n') 7767db96d56Sopenharmony_ci m['Subject'] = 'É test' 7777db96d56Sopenharmony_ci self.assertEqual(str(m),textwrap.dedent("""\ 7787db96d56Sopenharmony_ci Content-Type: text/plain; charset="us-ascii" 7797db96d56Sopenharmony_ci MIME-Version: 1.0 7807db96d56Sopenharmony_ci Content-Transfer-Encoding: 7bit 7817db96d56Sopenharmony_ci Subject: =?utf-8?q?=C3=89_test?= 7827db96d56Sopenharmony_ci 7837db96d56Sopenharmony_ci abc 7847db96d56Sopenharmony_ci """)) 7857db96d56Sopenharmony_ci 7867db96d56Sopenharmony_ci def test_unicode_body_defaults_to_utf8_encoding(self): 7877db96d56Sopenharmony_ci # Issue 14291 7887db96d56Sopenharmony_ci m = MIMEText('É testabc\n') 7897db96d56Sopenharmony_ci self.assertEqual(str(m),textwrap.dedent("""\ 7907db96d56Sopenharmony_ci Content-Type: text/plain; charset="utf-8" 7917db96d56Sopenharmony_ci MIME-Version: 1.0 7927db96d56Sopenharmony_ci Content-Transfer-Encoding: base64 7937db96d56Sopenharmony_ci 7947db96d56Sopenharmony_ci w4kgdGVzdGFiYwo= 7957db96d56Sopenharmony_ci """)) 7967db96d56Sopenharmony_ci 7977db96d56Sopenharmony_ci 7987db96d56Sopenharmony_ci# Test the email.encoders module 7997db96d56Sopenharmony_ciclass TestEncoders(unittest.TestCase): 8007db96d56Sopenharmony_ci 8017db96d56Sopenharmony_ci def test_EncodersEncode_base64(self): 8027db96d56Sopenharmony_ci with openfile('python.gif', 'rb') as fp: 8037db96d56Sopenharmony_ci bindata = fp.read() 8047db96d56Sopenharmony_ci mimed = email.mime.image.MIMEImage(bindata) 8057db96d56Sopenharmony_ci base64ed = mimed.get_payload() 8067db96d56Sopenharmony_ci # the transfer-encoded body lines should all be <=76 characters 8077db96d56Sopenharmony_ci lines = base64ed.split('\n') 8087db96d56Sopenharmony_ci self.assertLessEqual(max([ len(x) for x in lines ]), 76) 8097db96d56Sopenharmony_ci 8107db96d56Sopenharmony_ci def test_encode_empty_payload(self): 8117db96d56Sopenharmony_ci eq = self.assertEqual 8127db96d56Sopenharmony_ci msg = Message() 8137db96d56Sopenharmony_ci msg.set_charset('us-ascii') 8147db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], '7bit') 8157db96d56Sopenharmony_ci 8167db96d56Sopenharmony_ci def test_default_cte(self): 8177db96d56Sopenharmony_ci eq = self.assertEqual 8187db96d56Sopenharmony_ci # 7bit data and the default us-ascii _charset 8197db96d56Sopenharmony_ci msg = MIMEText('hello world') 8207db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], '7bit') 8217db96d56Sopenharmony_ci # Similar, but with 8bit data 8227db96d56Sopenharmony_ci msg = MIMEText('hello \xf8 world') 8237db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'base64') 8247db96d56Sopenharmony_ci # And now with a different charset 8257db96d56Sopenharmony_ci msg = MIMEText('hello \xf8 world', _charset='iso-8859-1') 8267db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'quoted-printable') 8277db96d56Sopenharmony_ci 8287db96d56Sopenharmony_ci def test_encode7or8bit(self): 8297db96d56Sopenharmony_ci # Make sure a charset whose input character set is 8bit but 8307db96d56Sopenharmony_ci # whose output character set is 7bit gets a transfer-encoding 8317db96d56Sopenharmony_ci # of 7bit. 8327db96d56Sopenharmony_ci eq = self.assertEqual 8337db96d56Sopenharmony_ci msg = MIMEText('文\n', _charset='euc-jp') 8347db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], '7bit') 8357db96d56Sopenharmony_ci eq(msg.as_string(), textwrap.dedent("""\ 8367db96d56Sopenharmony_ci MIME-Version: 1.0 8377db96d56Sopenharmony_ci Content-Type: text/plain; charset="iso-2022-jp" 8387db96d56Sopenharmony_ci Content-Transfer-Encoding: 7bit 8397db96d56Sopenharmony_ci 8407db96d56Sopenharmony_ci \x1b$BJ8\x1b(B 8417db96d56Sopenharmony_ci """)) 8427db96d56Sopenharmony_ci 8437db96d56Sopenharmony_ci def test_qp_encode_latin1(self): 8447db96d56Sopenharmony_ci msg = MIMEText('\xe1\xf6\n', 'text', 'ISO-8859-1') 8457db96d56Sopenharmony_ci self.assertEqual(str(msg), textwrap.dedent("""\ 8467db96d56Sopenharmony_ci MIME-Version: 1.0 8477db96d56Sopenharmony_ci Content-Type: text/text; charset="iso-8859-1" 8487db96d56Sopenharmony_ci Content-Transfer-Encoding: quoted-printable 8497db96d56Sopenharmony_ci 8507db96d56Sopenharmony_ci =E1=F6 8517db96d56Sopenharmony_ci """)) 8527db96d56Sopenharmony_ci 8537db96d56Sopenharmony_ci def test_qp_encode_non_latin1(self): 8547db96d56Sopenharmony_ci # Issue 16948 8557db96d56Sopenharmony_ci msg = MIMEText('\u017c\n', 'text', 'ISO-8859-2') 8567db96d56Sopenharmony_ci self.assertEqual(str(msg), textwrap.dedent("""\ 8577db96d56Sopenharmony_ci MIME-Version: 1.0 8587db96d56Sopenharmony_ci Content-Type: text/text; charset="iso-8859-2" 8597db96d56Sopenharmony_ci Content-Transfer-Encoding: quoted-printable 8607db96d56Sopenharmony_ci 8617db96d56Sopenharmony_ci =BF 8627db96d56Sopenharmony_ci """)) 8637db96d56Sopenharmony_ci 8647db96d56Sopenharmony_ci 8657db96d56Sopenharmony_ci# Test long header wrapping 8667db96d56Sopenharmony_ciclass TestLongHeaders(TestEmailBase): 8677db96d56Sopenharmony_ci 8687db96d56Sopenharmony_ci maxDiff = None 8697db96d56Sopenharmony_ci 8707db96d56Sopenharmony_ci def test_split_long_continuation(self): 8717db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 8727db96d56Sopenharmony_ci msg = email.message_from_string("""\ 8737db96d56Sopenharmony_ciSubject: bug demonstration 8747db96d56Sopenharmony_ci\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789 8757db96d56Sopenharmony_ci\tmore text 8767db96d56Sopenharmony_ci 8777db96d56Sopenharmony_citest 8787db96d56Sopenharmony_ci""") 8797db96d56Sopenharmony_ci sfp = StringIO() 8807db96d56Sopenharmony_ci g = Generator(sfp) 8817db96d56Sopenharmony_ci g.flatten(msg) 8827db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 8837db96d56Sopenharmony_ciSubject: bug demonstration 8847db96d56Sopenharmony_ci\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789 8857db96d56Sopenharmony_ci\tmore text 8867db96d56Sopenharmony_ci 8877db96d56Sopenharmony_citest 8887db96d56Sopenharmony_ci""") 8897db96d56Sopenharmony_ci 8907db96d56Sopenharmony_ci def test_another_long_almost_unsplittable_header(self): 8917db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 8927db96d56Sopenharmony_ci hstr = """\ 8937db96d56Sopenharmony_cibug demonstration 8947db96d56Sopenharmony_ci\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789 8957db96d56Sopenharmony_ci\tmore text""" 8967db96d56Sopenharmony_ci h = Header(hstr, continuation_ws='\t') 8977db96d56Sopenharmony_ci eq(h.encode(), """\ 8987db96d56Sopenharmony_cibug demonstration 8997db96d56Sopenharmony_ci\t12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789 9007db96d56Sopenharmony_ci\tmore text""") 9017db96d56Sopenharmony_ci h = Header(hstr.replace('\t', ' ')) 9027db96d56Sopenharmony_ci eq(h.encode(), """\ 9037db96d56Sopenharmony_cibug demonstration 9047db96d56Sopenharmony_ci 12345678911234567892123456789312345678941234567895123456789612345678971234567898112345678911234567892123456789112345678911234567892123456789 9057db96d56Sopenharmony_ci more text""") 9067db96d56Sopenharmony_ci 9077db96d56Sopenharmony_ci def test_long_nonstring(self): 9087db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 9097db96d56Sopenharmony_ci g = Charset("iso-8859-1") 9107db96d56Sopenharmony_ci cz = Charset("iso-8859-2") 9117db96d56Sopenharmony_ci utf8 = Charset("utf-8") 9127db96d56Sopenharmony_ci g_head = (b'Die Mieter treten hier ein werden mit einem Foerderband ' 9137db96d56Sopenharmony_ci b'komfortabel den Korridor entlang, an s\xfcdl\xfcndischen ' 9147db96d56Sopenharmony_ci b'Wandgem\xe4lden vorbei, gegen die rotierenden Klingen ' 9157db96d56Sopenharmony_ci b'bef\xf6rdert. ') 9167db96d56Sopenharmony_ci cz_head = (b'Finan\xe8ni metropole se hroutily pod tlakem jejich ' 9177db96d56Sopenharmony_ci b'd\xf9vtipu.. ') 9187db96d56Sopenharmony_ci utf8_head = ('\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f' 9197db96d56Sopenharmony_ci '\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00' 9207db96d56Sopenharmony_ci '\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c' 9217db96d56Sopenharmony_ci '\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067' 9227db96d56Sopenharmony_ci '\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das ' 9237db96d56Sopenharmony_ci 'Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder ' 9247db96d56Sopenharmony_ci 'die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066' 9257db96d56Sopenharmony_ci '\u3044\u307e\u3059\u3002') 9267db96d56Sopenharmony_ci h = Header(g_head, g, header_name='Subject') 9277db96d56Sopenharmony_ci h.append(cz_head, cz) 9287db96d56Sopenharmony_ci h.append(utf8_head, utf8) 9297db96d56Sopenharmony_ci msg = Message() 9307db96d56Sopenharmony_ci msg['Subject'] = h 9317db96d56Sopenharmony_ci sfp = StringIO() 9327db96d56Sopenharmony_ci g = Generator(sfp) 9337db96d56Sopenharmony_ci g.flatten(msg) 9347db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 9357db96d56Sopenharmony_ciSubject: =?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerderb?= 9367db96d56Sopenharmony_ci =?iso-8859-1?q?and_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndischen?= 9377db96d56Sopenharmony_ci =?iso-8859-1?q?_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Klingen_bef?= 9387db96d56Sopenharmony_ci =?iso-8859-1?q?=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se_hrouti?= 9397db96d56Sopenharmony_ci =?iso-8859-2?q?ly_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= =?utf-8?b?5q2j56K6?= 9407db96d56Sopenharmony_ci =?utf-8?b?44Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb44KT44CC5LiA?= 9417db96d56Sopenharmony_ci =?utf-8?b?6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go44Gv44Gn44Gf44KJ?= 9427db96d56Sopenharmony_ci =?utf-8?b?44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBpc3QgZGFzIE51bnN0dWNr?= 9437db96d56Sopenharmony_ci =?utf-8?b?IGdpdCB1bmQgU2xvdGVybWV5ZXI/IEphISBCZWloZXJodW5kIGRhcyBPZGVyIGRp?= 9447db96d56Sopenharmony_ci =?utf-8?b?ZSBGbGlwcGVyd2FsZHQgZ2Vyc3B1dC7jgI3jgajoqIDjgaPjgabjgYTjgb7jgZk=?= 9457db96d56Sopenharmony_ci =?utf-8?b?44CC?= 9467db96d56Sopenharmony_ci 9477db96d56Sopenharmony_ci""") 9487db96d56Sopenharmony_ci eq(h.encode(maxlinelen=76), """\ 9497db96d56Sopenharmony_ci=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerde?= 9507db96d56Sopenharmony_ci =?iso-8859-1?q?rband_komfortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndis?= 9517db96d56Sopenharmony_ci =?iso-8859-1?q?chen_Wandgem=E4lden_vorbei=2C_gegen_die_rotierenden_Klinge?= 9527db96d56Sopenharmony_ci =?iso-8859-1?q?n_bef=F6rdert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se?= 9537db96d56Sopenharmony_ci =?iso-8859-2?q?_hroutily_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= 9547db96d56Sopenharmony_ci =?utf-8?b?5q2j56K644Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb?= 9557db96d56Sopenharmony_ci =?utf-8?b?44KT44CC5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go?= 9567db96d56Sopenharmony_ci =?utf-8?b?44Gv44Gn44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBp?= 9577db96d56Sopenharmony_ci =?utf-8?b?c3QgZGFzIE51bnN0dWNrIGdpdCB1bmQgU2xvdGVybWV5ZXI/IEphISBCZWlo?= 9587db96d56Sopenharmony_ci =?utf-8?b?ZXJodW5kIGRhcyBPZGVyIGRpZSBGbGlwcGVyd2FsZHQgZ2Vyc3B1dC7jgI0=?= 9597db96d56Sopenharmony_ci =?utf-8?b?44Go6KiA44Gj44Gm44GE44G+44GZ44CC?=""") 9607db96d56Sopenharmony_ci 9617db96d56Sopenharmony_ci def test_long_header_encode(self): 9627db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 9637db96d56Sopenharmony_ci h = Header('wasnipoop; giraffes="very-long-necked-animals"; ' 9647db96d56Sopenharmony_ci 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"', 9657db96d56Sopenharmony_ci header_name='X-Foobar-Spoink-Defrobnit') 9667db96d56Sopenharmony_ci eq(h.encode(), '''\ 9677db96d56Sopenharmony_ciwasnipoop; giraffes="very-long-necked-animals"; 9687db96d56Sopenharmony_ci spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''') 9697db96d56Sopenharmony_ci 9707db96d56Sopenharmony_ci def test_long_header_encode_with_tab_continuation_is_just_a_hint(self): 9717db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 9727db96d56Sopenharmony_ci h = Header('wasnipoop; giraffes="very-long-necked-animals"; ' 9737db96d56Sopenharmony_ci 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"', 9747db96d56Sopenharmony_ci header_name='X-Foobar-Spoink-Defrobnit', 9757db96d56Sopenharmony_ci continuation_ws='\t') 9767db96d56Sopenharmony_ci eq(h.encode(), '''\ 9777db96d56Sopenharmony_ciwasnipoop; giraffes="very-long-necked-animals"; 9787db96d56Sopenharmony_ci spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''') 9797db96d56Sopenharmony_ci 9807db96d56Sopenharmony_ci def test_long_header_encode_with_tab_continuation(self): 9817db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 9827db96d56Sopenharmony_ci h = Header('wasnipoop; giraffes="very-long-necked-animals";\t' 9837db96d56Sopenharmony_ci 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"', 9847db96d56Sopenharmony_ci header_name='X-Foobar-Spoink-Defrobnit', 9857db96d56Sopenharmony_ci continuation_ws='\t') 9867db96d56Sopenharmony_ci eq(h.encode(), '''\ 9877db96d56Sopenharmony_ciwasnipoop; giraffes="very-long-necked-animals"; 9887db96d56Sopenharmony_ci\tspooge="yummy"; hippos="gargantuan"; marshmallows="gooey"''') 9897db96d56Sopenharmony_ci 9907db96d56Sopenharmony_ci def test_header_encode_with_different_output_charset(self): 9917db96d56Sopenharmony_ci h = Header('文', 'euc-jp') 9927db96d56Sopenharmony_ci self.assertEqual(h.encode(), "=?iso-2022-jp?b?GyRCSjgbKEI=?=") 9937db96d56Sopenharmony_ci 9947db96d56Sopenharmony_ci def test_long_header_encode_with_different_output_charset(self): 9957db96d56Sopenharmony_ci h = Header(b'test-ja \xa4\xd8\xc5\xea\xb9\xc6\xa4\xb5\xa4\xec\xa4' 9967db96d56Sopenharmony_ci b'\xbf\xa5\xe1\xa1\xbc\xa5\xeb\xa4\xcf\xbb\xca\xb2\xf1\xbc\xd4' 9977db96d56Sopenharmony_ci b'\xa4\xce\xbe\xb5\xc7\xa7\xa4\xf2\xc2\xd4\xa4\xc3\xa4\xc6\xa4' 9987db96d56Sopenharmony_ci b'\xa4\xa4\xde\xa4\xb9'.decode('euc-jp'), 'euc-jp') 9997db96d56Sopenharmony_ci res = """\ 10007db96d56Sopenharmony_ci=?iso-2022-jp?b?dGVzdC1qYSAbJEIkWEVqOUYkNSRsJD8lYSE8JWskTztKMnE8VCROPjUbKEI=?= 10017db96d56Sopenharmony_ci =?iso-2022-jp?b?GyRCRyckckJUJEMkRiQkJF4kORsoQg==?=""" 10027db96d56Sopenharmony_ci self.assertEqual(h.encode(), res) 10037db96d56Sopenharmony_ci 10047db96d56Sopenharmony_ci def test_header_splitter(self): 10057db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10067db96d56Sopenharmony_ci msg = MIMEText('') 10077db96d56Sopenharmony_ci # It'd be great if we could use add_header() here, but that doesn't 10087db96d56Sopenharmony_ci # guarantee an order of the parameters. 10097db96d56Sopenharmony_ci msg['X-Foobar-Spoink-Defrobnit'] = ( 10107db96d56Sopenharmony_ci 'wasnipoop; giraffes="very-long-necked-animals"; ' 10117db96d56Sopenharmony_ci 'spooge="yummy"; hippos="gargantuan"; marshmallows="gooey"') 10127db96d56Sopenharmony_ci sfp = StringIO() 10137db96d56Sopenharmony_ci g = Generator(sfp) 10147db96d56Sopenharmony_ci g.flatten(msg) 10157db96d56Sopenharmony_ci eq(sfp.getvalue(), '''\ 10167db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 10177db96d56Sopenharmony_ciMIME-Version: 1.0 10187db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 10197db96d56Sopenharmony_ciX-Foobar-Spoink-Defrobnit: wasnipoop; giraffes="very-long-necked-animals"; 10207db96d56Sopenharmony_ci spooge="yummy"; hippos="gargantuan"; marshmallows="gooey" 10217db96d56Sopenharmony_ci 10227db96d56Sopenharmony_ci''') 10237db96d56Sopenharmony_ci 10247db96d56Sopenharmony_ci def test_no_semis_header_splitter(self): 10257db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10267db96d56Sopenharmony_ci msg = Message() 10277db96d56Sopenharmony_ci msg['From'] = 'test@dom.ain' 10287db96d56Sopenharmony_ci msg['References'] = SPACE.join('<%d@dom.ain>' % i for i in range(10)) 10297db96d56Sopenharmony_ci msg.set_payload('Test') 10307db96d56Sopenharmony_ci sfp = StringIO() 10317db96d56Sopenharmony_ci g = Generator(sfp) 10327db96d56Sopenharmony_ci g.flatten(msg) 10337db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 10347db96d56Sopenharmony_ciFrom: test@dom.ain 10357db96d56Sopenharmony_ciReferences: <0@dom.ain> <1@dom.ain> <2@dom.ain> <3@dom.ain> <4@dom.ain> 10367db96d56Sopenharmony_ci <5@dom.ain> <6@dom.ain> <7@dom.ain> <8@dom.ain> <9@dom.ain> 10377db96d56Sopenharmony_ci 10387db96d56Sopenharmony_ciTest""") 10397db96d56Sopenharmony_ci 10407db96d56Sopenharmony_ci def test_last_split_chunk_does_not_fit(self): 10417db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10427db96d56Sopenharmony_ci h = Header('Subject: the first part of this is short, but_the_second' 10437db96d56Sopenharmony_ci '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' 10447db96d56Sopenharmony_ci '_all_by_itself') 10457db96d56Sopenharmony_ci eq(h.encode(), """\ 10467db96d56Sopenharmony_ciSubject: the first part of this is short, 10477db96d56Sopenharmony_ci but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") 10487db96d56Sopenharmony_ci 10497db96d56Sopenharmony_ci def test_splittable_leading_char_followed_by_overlong_unsplittable(self): 10507db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10517db96d56Sopenharmony_ci h = Header(', but_the_second' 10527db96d56Sopenharmony_ci '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' 10537db96d56Sopenharmony_ci '_all_by_itself') 10547db96d56Sopenharmony_ci eq(h.encode(), """\ 10557db96d56Sopenharmony_ci, 10567db96d56Sopenharmony_ci but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") 10577db96d56Sopenharmony_ci 10587db96d56Sopenharmony_ci def test_multiple_splittable_leading_char_followed_by_overlong_unsplittable(self): 10597db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10607db96d56Sopenharmony_ci h = Header(', , but_the_second' 10617db96d56Sopenharmony_ci '_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line' 10627db96d56Sopenharmony_ci '_all_by_itself') 10637db96d56Sopenharmony_ci eq(h.encode(), """\ 10647db96d56Sopenharmony_ci, , 10657db96d56Sopenharmony_ci but_the_second_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself""") 10667db96d56Sopenharmony_ci 10677db96d56Sopenharmony_ci def test_trailing_splittable_on_overlong_unsplittable(self): 10687db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10697db96d56Sopenharmony_ci h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' 10707db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself;') 10717db96d56Sopenharmony_ci eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_should_" 10727db96d56Sopenharmony_ci "be_on_a_line_all_by_itself;") 10737db96d56Sopenharmony_ci 10747db96d56Sopenharmony_ci def test_trailing_splittable_on_overlong_unsplittable_with_leading_splittable(self): 10757db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10767db96d56Sopenharmony_ci h = Header('; ' 10777db96d56Sopenharmony_ci 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' 10787db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself; ') 10797db96d56Sopenharmony_ci eq(h.encode(), """\ 10807db96d56Sopenharmony_ci; 10817db96d56Sopenharmony_ci this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) 10827db96d56Sopenharmony_ci 10837db96d56Sopenharmony_ci def test_long_header_with_multiple_sequential_split_chars(self): 10847db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10857db96d56Sopenharmony_ci h = Header('This is a long line that has two whitespaces in a row. ' 10867db96d56Sopenharmony_ci 'This used to cause truncation of the header when folded') 10877db96d56Sopenharmony_ci eq(h.encode(), """\ 10887db96d56Sopenharmony_ciThis is a long line that has two whitespaces in a row. This used to cause 10897db96d56Sopenharmony_ci truncation of the header when folded""") 10907db96d56Sopenharmony_ci 10917db96d56Sopenharmony_ci def test_splitter_split_on_punctuation_only_if_fws_with_header(self): 10927db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 10937db96d56Sopenharmony_ci h = Header('thisverylongheaderhas;semicolons;and,commas,but' 10947db96d56Sopenharmony_ci 'they;arenotlegal;fold,points') 10957db96d56Sopenharmony_ci eq(h.encode(), "thisverylongheaderhas;semicolons;and,commas,butthey;" 10967db96d56Sopenharmony_ci "arenotlegal;fold,points") 10977db96d56Sopenharmony_ci 10987db96d56Sopenharmony_ci def test_leading_splittable_in_the_middle_just_before_overlong_last_part(self): 10997db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11007db96d56Sopenharmony_ci h = Header('this is a test where we need to have more than one line ' 11017db96d56Sopenharmony_ci 'before; our final line that is just too big to fit;; ' 11027db96d56Sopenharmony_ci 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' 11037db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself;') 11047db96d56Sopenharmony_ci eq(h.encode(), """\ 11057db96d56Sopenharmony_cithis is a test where we need to have more than one line before; 11067db96d56Sopenharmony_ci our final line that is just too big to fit;; 11077db96d56Sopenharmony_ci this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself;""") 11087db96d56Sopenharmony_ci 11097db96d56Sopenharmony_ci def test_overlong_last_part_followed_by_split_point(self): 11107db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11117db96d56Sopenharmony_ci h = Header('this_part_does_not_fit_within_maxlinelen_and_thus_should_' 11127db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself ') 11137db96d56Sopenharmony_ci eq(h.encode(), "this_part_does_not_fit_within_maxlinelen_and_thus_" 11147db96d56Sopenharmony_ci "should_be_on_a_line_all_by_itself ") 11157db96d56Sopenharmony_ci 11167db96d56Sopenharmony_ci def test_multiline_with_overlong_parts_separated_by_two_split_points(self): 11177db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11187db96d56Sopenharmony_ci h = Header('this_is_a__test_where_we_need_to_have_more_than_one_line_' 11197db96d56Sopenharmony_ci 'before_our_final_line_; ; ' 11207db96d56Sopenharmony_ci 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' 11217db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself; ') 11227db96d56Sopenharmony_ci eq(h.encode(), """\ 11237db96d56Sopenharmony_cithis_is_a__test_where_we_need_to_have_more_than_one_line_before_our_final_line_; 11247db96d56Sopenharmony_ci ; 11257db96d56Sopenharmony_ci this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) 11267db96d56Sopenharmony_ci 11277db96d56Sopenharmony_ci def test_multiline_with_overlong_last_part_followed_by_split_point(self): 11287db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11297db96d56Sopenharmony_ci h = Header('this is a test where we need to have more than one line ' 11307db96d56Sopenharmony_ci 'before our final line; ; ' 11317db96d56Sopenharmony_ci 'this_part_does_not_fit_within_maxlinelen_and_thus_should_' 11327db96d56Sopenharmony_ci 'be_on_a_line_all_by_itself; ') 11337db96d56Sopenharmony_ci eq(h.encode(), """\ 11347db96d56Sopenharmony_cithis is a test where we need to have more than one line before our final line; 11357db96d56Sopenharmony_ci ; 11367db96d56Sopenharmony_ci this_part_does_not_fit_within_maxlinelen_and_thus_should_be_on_a_line_all_by_itself; """) 11377db96d56Sopenharmony_ci 11387db96d56Sopenharmony_ci def test_long_header_with_whitespace_runs(self): 11397db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11407db96d56Sopenharmony_ci msg = Message() 11417db96d56Sopenharmony_ci msg['From'] = 'test@dom.ain' 11427db96d56Sopenharmony_ci msg['References'] = SPACE.join(['<foo@dom.ain> '] * 10) 11437db96d56Sopenharmony_ci msg.set_payload('Test') 11447db96d56Sopenharmony_ci sfp = StringIO() 11457db96d56Sopenharmony_ci g = Generator(sfp) 11467db96d56Sopenharmony_ci g.flatten(msg) 11477db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 11487db96d56Sopenharmony_ciFrom: test@dom.ain 11497db96d56Sopenharmony_ciReferences: <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> 11507db96d56Sopenharmony_ci <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> 11517db96d56Sopenharmony_ci <foo@dom.ain> <foo@dom.ain>\x20\x20 11527db96d56Sopenharmony_ci 11537db96d56Sopenharmony_ciTest""") 11547db96d56Sopenharmony_ci 11557db96d56Sopenharmony_ci def test_long_run_with_semi_header_splitter(self): 11567db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11577db96d56Sopenharmony_ci msg = Message() 11587db96d56Sopenharmony_ci msg['From'] = 'test@dom.ain' 11597db96d56Sopenharmony_ci msg['References'] = SPACE.join(['<foo@dom.ain>'] * 10) + '; abc' 11607db96d56Sopenharmony_ci msg.set_payload('Test') 11617db96d56Sopenharmony_ci sfp = StringIO() 11627db96d56Sopenharmony_ci g = Generator(sfp) 11637db96d56Sopenharmony_ci g.flatten(msg) 11647db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 11657db96d56Sopenharmony_ciFrom: test@dom.ain 11667db96d56Sopenharmony_ciReferences: <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> 11677db96d56Sopenharmony_ci <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> <foo@dom.ain> 11687db96d56Sopenharmony_ci <foo@dom.ain>; abc 11697db96d56Sopenharmony_ci 11707db96d56Sopenharmony_ciTest""") 11717db96d56Sopenharmony_ci 11727db96d56Sopenharmony_ci def test_splitter_split_on_punctuation_only_if_fws(self): 11737db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11747db96d56Sopenharmony_ci msg = Message() 11757db96d56Sopenharmony_ci msg['From'] = 'test@dom.ain' 11767db96d56Sopenharmony_ci msg['References'] = ('thisverylongheaderhas;semicolons;and,commas,but' 11777db96d56Sopenharmony_ci 'they;arenotlegal;fold,points') 11787db96d56Sopenharmony_ci msg.set_payload('Test') 11797db96d56Sopenharmony_ci sfp = StringIO() 11807db96d56Sopenharmony_ci g = Generator(sfp) 11817db96d56Sopenharmony_ci g.flatten(msg) 11827db96d56Sopenharmony_ci # XXX the space after the header should not be there. 11837db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 11847db96d56Sopenharmony_ciFrom: test@dom.ain 11857db96d56Sopenharmony_ciReferences:\x20 11867db96d56Sopenharmony_ci thisverylongheaderhas;semicolons;and,commas,butthey;arenotlegal;fold,points 11877db96d56Sopenharmony_ci 11887db96d56Sopenharmony_ciTest""") 11897db96d56Sopenharmony_ci 11907db96d56Sopenharmony_ci def test_no_split_long_header(self): 11917db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 11927db96d56Sopenharmony_ci hstr = 'References: ' + 'x' * 80 11937db96d56Sopenharmony_ci h = Header(hstr) 11947db96d56Sopenharmony_ci # These come on two lines because Headers are really field value 11957db96d56Sopenharmony_ci # classes and don't really know about their field names. 11967db96d56Sopenharmony_ci eq(h.encode(), """\ 11977db96d56Sopenharmony_ciReferences: 11987db96d56Sopenharmony_ci xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx""") 11997db96d56Sopenharmony_ci h = Header('x' * 80) 12007db96d56Sopenharmony_ci eq(h.encode(), 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') 12017db96d56Sopenharmony_ci 12027db96d56Sopenharmony_ci def test_splitting_multiple_long_lines(self): 12037db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 12047db96d56Sopenharmony_ci hstr = """\ 12057db96d56Sopenharmony_cifrom 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) 12067db96d56Sopenharmony_ci\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) 12077db96d56Sopenharmony_ci\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) 12087db96d56Sopenharmony_ci""" 12097db96d56Sopenharmony_ci h = Header(hstr, continuation_ws='\t') 12107db96d56Sopenharmony_ci eq(h.encode(), """\ 12117db96d56Sopenharmony_cifrom babylon.socal-raves.org (localhost [127.0.0.1]); 12127db96d56Sopenharmony_ci by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; 12137db96d56Sopenharmony_ci for <mailman-admin@babylon.socal-raves.org>; 12147db96d56Sopenharmony_ci Sat, 2 Feb 2002 17:00:06 -0800 (PST) 12157db96d56Sopenharmony_ci\tfrom babylon.socal-raves.org (localhost [127.0.0.1]); 12167db96d56Sopenharmony_ci by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; 12177db96d56Sopenharmony_ci for <mailman-admin@babylon.socal-raves.org>; 12187db96d56Sopenharmony_ci Sat, 2 Feb 2002 17:00:06 -0800 (PST) 12197db96d56Sopenharmony_ci\tfrom babylon.socal-raves.org (localhost [127.0.0.1]); 12207db96d56Sopenharmony_ci by babylon.socal-raves.org (Postfix) with ESMTP id B570E51B81; 12217db96d56Sopenharmony_ci for <mailman-admin@babylon.socal-raves.org>; 12227db96d56Sopenharmony_ci Sat, 2 Feb 2002 17:00:06 -0800 (PST)""") 12237db96d56Sopenharmony_ci 12247db96d56Sopenharmony_ci def test_splitting_first_line_only_is_long(self): 12257db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 12267db96d56Sopenharmony_ci hstr = """\ 12277db96d56Sopenharmony_cifrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93] helo=cthulhu.gerg.ca) 12287db96d56Sopenharmony_ci\tby kronos.mems-exchange.org with esmtp (Exim 4.05) 12297db96d56Sopenharmony_ci\tid 17k4h5-00034i-00 12307db96d56Sopenharmony_ci\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400""" 12317db96d56Sopenharmony_ci h = Header(hstr, maxlinelen=78, header_name='Received', 12327db96d56Sopenharmony_ci continuation_ws='\t') 12337db96d56Sopenharmony_ci eq(h.encode(), """\ 12347db96d56Sopenharmony_cifrom modemcable093.139-201-24.que.mc.videotron.ca ([24.201.139.93] 12357db96d56Sopenharmony_ci helo=cthulhu.gerg.ca) 12367db96d56Sopenharmony_ci\tby kronos.mems-exchange.org with esmtp (Exim 4.05) 12377db96d56Sopenharmony_ci\tid 17k4h5-00034i-00 12387db96d56Sopenharmony_ci\tfor test@mems-exchange.org; Wed, 28 Aug 2002 11:25:20 -0400""") 12397db96d56Sopenharmony_ci 12407db96d56Sopenharmony_ci def test_long_8bit_header(self): 12417db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 12427db96d56Sopenharmony_ci msg = Message() 12437db96d56Sopenharmony_ci h = Header('Britische Regierung gibt', 'iso-8859-1', 12447db96d56Sopenharmony_ci header_name='Subject') 12457db96d56Sopenharmony_ci h.append('gr\xfcnes Licht f\xfcr Offshore-Windkraftprojekte') 12467db96d56Sopenharmony_ci eq(h.encode(maxlinelen=76), """\ 12477db96d56Sopenharmony_ci=?iso-8859-1?q?Britische_Regierung_gibt_gr=FCnes_Licht_f=FCr_Offs?= 12487db96d56Sopenharmony_ci =?iso-8859-1?q?hore-Windkraftprojekte?=""") 12497db96d56Sopenharmony_ci msg['Subject'] = h 12507db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=76), """\ 12517db96d56Sopenharmony_ciSubject: =?iso-8859-1?q?Britische_Regierung_gibt_gr=FCnes_Licht_f=FCr_Offs?= 12527db96d56Sopenharmony_ci =?iso-8859-1?q?hore-Windkraftprojekte?= 12537db96d56Sopenharmony_ci 12547db96d56Sopenharmony_ci""") 12557db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=0), """\ 12567db96d56Sopenharmony_ciSubject: =?iso-8859-1?q?Britische_Regierung_gibt_gr=FCnes_Licht_f=FCr_Offshore-Windkraftprojekte?= 12577db96d56Sopenharmony_ci 12587db96d56Sopenharmony_ci""") 12597db96d56Sopenharmony_ci 12607db96d56Sopenharmony_ci def test_long_8bit_header_no_charset(self): 12617db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 12627db96d56Sopenharmony_ci msg = Message() 12637db96d56Sopenharmony_ci header_string = ('Britische Regierung gibt gr\xfcnes Licht ' 12647db96d56Sopenharmony_ci 'f\xfcr Offshore-Windkraftprojekte ' 12657db96d56Sopenharmony_ci '<a-very-long-address@example.com>') 12667db96d56Sopenharmony_ci msg['Reply-To'] = header_string 12677db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 12687db96d56Sopenharmony_ciReply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= 12697db96d56Sopenharmony_ci =?utf-8?q?hore-Windkraftprojekte_=3Ca-very-long-address=40example=2Ecom=3E?= 12707db96d56Sopenharmony_ci 12717db96d56Sopenharmony_ci""") 12727db96d56Sopenharmony_ci msg = Message() 12737db96d56Sopenharmony_ci msg['Reply-To'] = Header(header_string, 12747db96d56Sopenharmony_ci header_name='Reply-To') 12757db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 12767db96d56Sopenharmony_ciReply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= 12777db96d56Sopenharmony_ci =?utf-8?q?hore-Windkraftprojekte_=3Ca-very-long-address=40example=2Ecom=3E?= 12787db96d56Sopenharmony_ci 12797db96d56Sopenharmony_ci""") 12807db96d56Sopenharmony_ci 12817db96d56Sopenharmony_ci def test_long_to_header(self): 12827db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 12837db96d56Sopenharmony_ci to = ('"Someone Test #A" <someone@eecs.umich.edu>,' 12847db96d56Sopenharmony_ci '<someone@eecs.umich.edu>, ' 12857db96d56Sopenharmony_ci '"Someone Test #B" <someone@umich.edu>, ' 12867db96d56Sopenharmony_ci '"Someone Test #C" <someone@eecs.umich.edu>, ' 12877db96d56Sopenharmony_ci '"Someone Test #D" <someone@eecs.umich.edu>') 12887db96d56Sopenharmony_ci msg = Message() 12897db96d56Sopenharmony_ci msg['To'] = to 12907db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), '''\ 12917db96d56Sopenharmony_ciTo: "Someone Test #A" <someone@eecs.umich.edu>,<someone@eecs.umich.edu>, 12927db96d56Sopenharmony_ci "Someone Test #B" <someone@umich.edu>, 12937db96d56Sopenharmony_ci "Someone Test #C" <someone@eecs.umich.edu>, 12947db96d56Sopenharmony_ci "Someone Test #D" <someone@eecs.umich.edu> 12957db96d56Sopenharmony_ci 12967db96d56Sopenharmony_ci''') 12977db96d56Sopenharmony_ci 12987db96d56Sopenharmony_ci def test_long_line_after_append(self): 12997db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 13007db96d56Sopenharmony_ci s = 'This is an example of string which has almost the limit of header length.' 13017db96d56Sopenharmony_ci h = Header(s) 13027db96d56Sopenharmony_ci h.append('Add another line.') 13037db96d56Sopenharmony_ci eq(h.encode(maxlinelen=76), """\ 13047db96d56Sopenharmony_ciThis is an example of string which has almost the limit of header length. 13057db96d56Sopenharmony_ci Add another line.""") 13067db96d56Sopenharmony_ci 13077db96d56Sopenharmony_ci def test_shorter_line_with_append(self): 13087db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 13097db96d56Sopenharmony_ci s = 'This is a shorter line.' 13107db96d56Sopenharmony_ci h = Header(s) 13117db96d56Sopenharmony_ci h.append('Add another sentence. (Surprise?)') 13127db96d56Sopenharmony_ci eq(h.encode(), 13137db96d56Sopenharmony_ci 'This is a shorter line. Add another sentence. (Surprise?)') 13147db96d56Sopenharmony_ci 13157db96d56Sopenharmony_ci def test_long_field_name(self): 13167db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 13177db96d56Sopenharmony_ci fn = 'X-Very-Very-Very-Long-Header-Name' 13187db96d56Sopenharmony_ci gs = ('Die Mieter treten hier ein werden mit einem Foerderband ' 13197db96d56Sopenharmony_ci 'komfortabel den Korridor entlang, an s\xfcdl\xfcndischen ' 13207db96d56Sopenharmony_ci 'Wandgem\xe4lden vorbei, gegen die rotierenden Klingen ' 13217db96d56Sopenharmony_ci 'bef\xf6rdert. ') 13227db96d56Sopenharmony_ci h = Header(gs, 'iso-8859-1', header_name=fn) 13237db96d56Sopenharmony_ci # BAW: this seems broken because the first line is too long 13247db96d56Sopenharmony_ci eq(h.encode(maxlinelen=76), """\ 13257db96d56Sopenharmony_ci=?iso-8859-1?q?Die_Mieter_treten_hier_e?= 13267db96d56Sopenharmony_ci =?iso-8859-1?q?in_werden_mit_einem_Foerderband_komfortabel_den_Korridor_e?= 13277db96d56Sopenharmony_ci =?iso-8859-1?q?ntlang=2C_an_s=FCdl=FCndischen_Wandgem=E4lden_vorbei=2C_ge?= 13287db96d56Sopenharmony_ci =?iso-8859-1?q?gen_die_rotierenden_Klingen_bef=F6rdert=2E_?=""") 13297db96d56Sopenharmony_ci 13307db96d56Sopenharmony_ci def test_long_received_header(self): 13317db96d56Sopenharmony_ci h = ('from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) ' 13327db96d56Sopenharmony_ci 'by hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; ' 13337db96d56Sopenharmony_ci 'Wed, 05 Mar 2003 18:10:18 -0700') 13347db96d56Sopenharmony_ci msg = Message() 13357db96d56Sopenharmony_ci msg['Received-1'] = Header(h, continuation_ws='\t') 13367db96d56Sopenharmony_ci msg['Received-2'] = h 13377db96d56Sopenharmony_ci # This should be splitting on spaces not semicolons. 13387db96d56Sopenharmony_ci self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ 13397db96d56Sopenharmony_ciReceived-1: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by 13407db96d56Sopenharmony_ci hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; 13417db96d56Sopenharmony_ci Wed, 05 Mar 2003 18:10:18 -0700 13427db96d56Sopenharmony_ciReceived-2: from FOO.TLD (vizworld.acl.foo.tld [123.452.678.9]) by 13437db96d56Sopenharmony_ci hrothgar.la.mastaler.com (tmda-ofmipd) with ESMTP; 13447db96d56Sopenharmony_ci Wed, 05 Mar 2003 18:10:18 -0700 13457db96d56Sopenharmony_ci 13467db96d56Sopenharmony_ci""") 13477db96d56Sopenharmony_ci 13487db96d56Sopenharmony_ci def test_string_headerinst_eq(self): 13497db96d56Sopenharmony_ci h = ('<15975.17901.207240.414604@sgigritzmann1.mathematik.' 13507db96d56Sopenharmony_ci 'tu-muenchen.de> (David Bremner\'s message of ' 13517db96d56Sopenharmony_ci '"Thu, 6 Mar 2003 13:58:21 +0100")') 13527db96d56Sopenharmony_ci msg = Message() 13537db96d56Sopenharmony_ci msg['Received-1'] = Header(h, header_name='Received-1', 13547db96d56Sopenharmony_ci continuation_ws='\t') 13557db96d56Sopenharmony_ci msg['Received-2'] = h 13567db96d56Sopenharmony_ci # XXX The space after the ':' should not be there. 13577db96d56Sopenharmony_ci self.ndiffAssertEqual(msg.as_string(maxheaderlen=78), """\ 13587db96d56Sopenharmony_ciReceived-1:\x20 13597db96d56Sopenharmony_ci <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de> (David 13607db96d56Sopenharmony_ci Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") 13617db96d56Sopenharmony_ciReceived-2:\x20 13627db96d56Sopenharmony_ci <15975.17901.207240.414604@sgigritzmann1.mathematik.tu-muenchen.de> (David 13637db96d56Sopenharmony_ci Bremner's message of \"Thu, 6 Mar 2003 13:58:21 +0100\") 13647db96d56Sopenharmony_ci 13657db96d56Sopenharmony_ci""") 13667db96d56Sopenharmony_ci 13677db96d56Sopenharmony_ci def test_long_unbreakable_lines_with_continuation(self): 13687db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 13697db96d56Sopenharmony_ci msg = Message() 13707db96d56Sopenharmony_ci t = """\ 13717db96d56Sopenharmony_ciiVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 13727db96d56Sopenharmony_ci locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp""" 13737db96d56Sopenharmony_ci msg['Face-1'] = t 13747db96d56Sopenharmony_ci msg['Face-2'] = Header(t, header_name='Face-2') 13757db96d56Sopenharmony_ci msg['Face-3'] = ' ' + t 13767db96d56Sopenharmony_ci # XXX This splitting is all wrong. It the first value line should be 13777db96d56Sopenharmony_ci # snug against the field name or the space after the header not there. 13787db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 13797db96d56Sopenharmony_ciFace-1:\x20 13807db96d56Sopenharmony_ci iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 13817db96d56Sopenharmony_ci locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp 13827db96d56Sopenharmony_ciFace-2:\x20 13837db96d56Sopenharmony_ci iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 13847db96d56Sopenharmony_ci locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp 13857db96d56Sopenharmony_ciFace-3:\x20 13867db96d56Sopenharmony_ci iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAGFBMVEUAAAAkHiJeRUIcGBi9 13877db96d56Sopenharmony_ci locQDQ4zJykFBAXJfWDjAAACYUlEQVR4nF2TQY/jIAyFc6lydlG5x8Nyp1Y69wj1PN2I5gzp 13887db96d56Sopenharmony_ci 13897db96d56Sopenharmony_ci""") 13907db96d56Sopenharmony_ci 13917db96d56Sopenharmony_ci def test_another_long_multiline_header(self): 13927db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 13937db96d56Sopenharmony_ci m = ('Received: from siimage.com ' 13947db96d56Sopenharmony_ci '([172.25.1.3]) by zima.siliconimage.com with ' 13957db96d56Sopenharmony_ci 'Microsoft SMTPSVC(5.0.2195.4905); ' 13967db96d56Sopenharmony_ci 'Wed, 16 Oct 2002 07:41:11 -0700') 13977db96d56Sopenharmony_ci msg = email.message_from_string(m) 13987db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), '''\ 13997db96d56Sopenharmony_ciReceived: from siimage.com ([172.25.1.3]) by zima.siliconimage.com with 14007db96d56Sopenharmony_ci Microsoft SMTPSVC(5.0.2195.4905); Wed, 16 Oct 2002 07:41:11 -0700 14017db96d56Sopenharmony_ci 14027db96d56Sopenharmony_ci''') 14037db96d56Sopenharmony_ci 14047db96d56Sopenharmony_ci def test_long_lines_with_different_header(self): 14057db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 14067db96d56Sopenharmony_ci h = ('List-Unsubscribe: ' 14077db96d56Sopenharmony_ci '<http://lists.sourceforge.net/lists/listinfo/spamassassin-talk>,' 14087db96d56Sopenharmony_ci ' <mailto:spamassassin-talk-request@lists.sourceforge.net' 14097db96d56Sopenharmony_ci '?subject=unsubscribe>') 14107db96d56Sopenharmony_ci msg = Message() 14117db96d56Sopenharmony_ci msg['List'] = h 14127db96d56Sopenharmony_ci msg['List'] = Header(h, header_name='List') 14137db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 14147db96d56Sopenharmony_ciList: List-Unsubscribe: 14157db96d56Sopenharmony_ci <http://lists.sourceforge.net/lists/listinfo/spamassassin-talk>, 14167db96d56Sopenharmony_ci <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe> 14177db96d56Sopenharmony_ciList: List-Unsubscribe: 14187db96d56Sopenharmony_ci <http://lists.sourceforge.net/lists/listinfo/spamassassin-talk>, 14197db96d56Sopenharmony_ci <mailto:spamassassin-talk-request@lists.sourceforge.net?subject=unsubscribe> 14207db96d56Sopenharmony_ci 14217db96d56Sopenharmony_ci""") 14227db96d56Sopenharmony_ci 14237db96d56Sopenharmony_ci def test_long_rfc2047_header_with_embedded_fws(self): 14247db96d56Sopenharmony_ci h = Header(textwrap.dedent("""\ 14257db96d56Sopenharmony_ci We're going to pretend this header is in a non-ascii character set 14267db96d56Sopenharmony_ci \tto see if line wrapping with encoded words and embedded 14277db96d56Sopenharmony_ci folding white space works"""), 14287db96d56Sopenharmony_ci charset='utf-8', 14297db96d56Sopenharmony_ci header_name='Test') 14307db96d56Sopenharmony_ci self.assertEqual(h.encode()+'\n', textwrap.dedent("""\ 14317db96d56Sopenharmony_ci =?utf-8?q?We=27re_going_to_pretend_this_header_is_in_a_non-ascii_chara?= 14327db96d56Sopenharmony_ci =?utf-8?q?cter_set?= 14337db96d56Sopenharmony_ci =?utf-8?q?_to_see_if_line_wrapping_with_encoded_words_and_embedded?= 14347db96d56Sopenharmony_ci =?utf-8?q?_folding_white_space_works?=""")+'\n') 14357db96d56Sopenharmony_ci 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci 14387db96d56Sopenharmony_ci# Test mangling of "From " lines in the body of a message 14397db96d56Sopenharmony_ciclass TestFromMangling(unittest.TestCase): 14407db96d56Sopenharmony_ci def setUp(self): 14417db96d56Sopenharmony_ci self.msg = Message() 14427db96d56Sopenharmony_ci self.msg['From'] = 'aaa@bbb.org' 14437db96d56Sopenharmony_ci self.msg.set_payload("""\ 14447db96d56Sopenharmony_ciFrom the desk of A.A.A.: 14457db96d56Sopenharmony_ciBlah blah blah 14467db96d56Sopenharmony_ci""") 14477db96d56Sopenharmony_ci 14487db96d56Sopenharmony_ci def test_mangled_from(self): 14497db96d56Sopenharmony_ci s = StringIO() 14507db96d56Sopenharmony_ci g = Generator(s, mangle_from_=True) 14517db96d56Sopenharmony_ci g.flatten(self.msg) 14527db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), """\ 14537db96d56Sopenharmony_ciFrom: aaa@bbb.org 14547db96d56Sopenharmony_ci 14557db96d56Sopenharmony_ci>From the desk of A.A.A.: 14567db96d56Sopenharmony_ciBlah blah blah 14577db96d56Sopenharmony_ci""") 14587db96d56Sopenharmony_ci 14597db96d56Sopenharmony_ci def test_dont_mangle_from(self): 14607db96d56Sopenharmony_ci s = StringIO() 14617db96d56Sopenharmony_ci g = Generator(s, mangle_from_=False) 14627db96d56Sopenharmony_ci g.flatten(self.msg) 14637db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), """\ 14647db96d56Sopenharmony_ciFrom: aaa@bbb.org 14657db96d56Sopenharmony_ci 14667db96d56Sopenharmony_ciFrom the desk of A.A.A.: 14677db96d56Sopenharmony_ciBlah blah blah 14687db96d56Sopenharmony_ci""") 14697db96d56Sopenharmony_ci 14707db96d56Sopenharmony_ci def test_mangle_from_in_preamble_and_epilog(self): 14717db96d56Sopenharmony_ci s = StringIO() 14727db96d56Sopenharmony_ci g = Generator(s, mangle_from_=True) 14737db96d56Sopenharmony_ci msg = email.message_from_string(textwrap.dedent("""\ 14747db96d56Sopenharmony_ci From: foo@bar.com 14757db96d56Sopenharmony_ci Mime-Version: 1.0 14767db96d56Sopenharmony_ci Content-Type: multipart/mixed; boundary=XXX 14777db96d56Sopenharmony_ci 14787db96d56Sopenharmony_ci From somewhere unknown 14797db96d56Sopenharmony_ci 14807db96d56Sopenharmony_ci --XXX 14817db96d56Sopenharmony_ci Content-Type: text/plain 14827db96d56Sopenharmony_ci 14837db96d56Sopenharmony_ci foo 14847db96d56Sopenharmony_ci 14857db96d56Sopenharmony_ci --XXX-- 14867db96d56Sopenharmony_ci 14877db96d56Sopenharmony_ci From somewhere unknowable 14887db96d56Sopenharmony_ci """)) 14897db96d56Sopenharmony_ci g.flatten(msg) 14907db96d56Sopenharmony_ci self.assertEqual(len([1 for x in s.getvalue().split('\n') 14917db96d56Sopenharmony_ci if x.startswith('>From ')]), 2) 14927db96d56Sopenharmony_ci 14937db96d56Sopenharmony_ci def test_mangled_from_with_bad_bytes(self): 14947db96d56Sopenharmony_ci source = textwrap.dedent("""\ 14957db96d56Sopenharmony_ci Content-Type: text/plain; charset="utf-8" 14967db96d56Sopenharmony_ci MIME-Version: 1.0 14977db96d56Sopenharmony_ci Content-Transfer-Encoding: 8bit 14987db96d56Sopenharmony_ci From: aaa@bbb.org 14997db96d56Sopenharmony_ci 15007db96d56Sopenharmony_ci """).encode('utf-8') 15017db96d56Sopenharmony_ci msg = email.message_from_bytes(source + b'From R\xc3\xb6lli\n') 15027db96d56Sopenharmony_ci b = BytesIO() 15037db96d56Sopenharmony_ci g = BytesGenerator(b, mangle_from_=True) 15047db96d56Sopenharmony_ci g.flatten(msg) 15057db96d56Sopenharmony_ci self.assertEqual(b.getvalue(), source + b'>From R\xc3\xb6lli\n') 15067db96d56Sopenharmony_ci 15077db96d56Sopenharmony_ci def test_multipart_with_bad_bytes_in_cte(self): 15087db96d56Sopenharmony_ci # bpo30835 15097db96d56Sopenharmony_ci source = textwrap.dedent("""\ 15107db96d56Sopenharmony_ci From: aperson@example.com 15117db96d56Sopenharmony_ci Content-Type: multipart/mixed; boundary="1" 15127db96d56Sopenharmony_ci Content-Transfer-Encoding: \xc8 15137db96d56Sopenharmony_ci """).encode('utf-8') 15147db96d56Sopenharmony_ci msg = email.message_from_bytes(source) 15157db96d56Sopenharmony_ci 15167db96d56Sopenharmony_ci 15177db96d56Sopenharmony_ci# Test the basic MIMEAudio class 15187db96d56Sopenharmony_ciclass TestMIMEAudio(unittest.TestCase): 15197db96d56Sopenharmony_ci def _make_audio(self, ext): 15207db96d56Sopenharmony_ci with openfile(f'sndhdr.{ext}', 'rb') as fp: 15217db96d56Sopenharmony_ci self._audiodata = fp.read() 15227db96d56Sopenharmony_ci self._au = MIMEAudio(self._audiodata) 15237db96d56Sopenharmony_ci 15247db96d56Sopenharmony_ci def test_guess_minor_type(self): 15257db96d56Sopenharmony_ci for ext, subtype in { 15267db96d56Sopenharmony_ci 'aifc': 'x-aiff', 15277db96d56Sopenharmony_ci 'aiff': 'x-aiff', 15287db96d56Sopenharmony_ci 'wav': 'x-wav', 15297db96d56Sopenharmony_ci 'au': 'basic', 15307db96d56Sopenharmony_ci }.items(): 15317db96d56Sopenharmony_ci self._make_audio(ext) 15327db96d56Sopenharmony_ci subtype = ext if subtype is None else subtype 15337db96d56Sopenharmony_ci self.assertEqual(self._au.get_content_type(), f'audio/{subtype}') 15347db96d56Sopenharmony_ci 15357db96d56Sopenharmony_ci def test_encoding(self): 15367db96d56Sopenharmony_ci self._make_audio('au') 15377db96d56Sopenharmony_ci payload = self._au.get_payload() 15387db96d56Sopenharmony_ci self.assertEqual(base64.decodebytes(bytes(payload, 'ascii')), 15397db96d56Sopenharmony_ci self._audiodata) 15407db96d56Sopenharmony_ci 15417db96d56Sopenharmony_ci def test_checkSetMinor(self): 15427db96d56Sopenharmony_ci self._make_audio('au') 15437db96d56Sopenharmony_ci au = MIMEAudio(self._audiodata, 'fish') 15447db96d56Sopenharmony_ci self.assertEqual(au.get_content_type(), 'audio/fish') 15457db96d56Sopenharmony_ci 15467db96d56Sopenharmony_ci def test_add_header(self): 15477db96d56Sopenharmony_ci self._make_audio('au') 15487db96d56Sopenharmony_ci eq = self.assertEqual 15497db96d56Sopenharmony_ci self._au.add_header('Content-Disposition', 'attachment', 15507db96d56Sopenharmony_ci filename='sndhdr.au') 15517db96d56Sopenharmony_ci eq(self._au['content-disposition'], 15527db96d56Sopenharmony_ci 'attachment; filename="sndhdr.au"') 15537db96d56Sopenharmony_ci eq(self._au.get_params(header='content-disposition'), 15547db96d56Sopenharmony_ci [('attachment', ''), ('filename', 'sndhdr.au')]) 15557db96d56Sopenharmony_ci eq(self._au.get_param('filename', header='content-disposition'), 15567db96d56Sopenharmony_ci 'sndhdr.au') 15577db96d56Sopenharmony_ci missing = [] 15587db96d56Sopenharmony_ci eq(self._au.get_param('attachment', header='content-disposition'), '') 15597db96d56Sopenharmony_ci self.assertIs(self._au.get_param( 15607db96d56Sopenharmony_ci 'foo', failobj=missing, 15617db96d56Sopenharmony_ci header='content-disposition'), missing) 15627db96d56Sopenharmony_ci # Try some missing stuff 15637db96d56Sopenharmony_ci self.assertIs(self._au.get_param('foobar', missing), missing) 15647db96d56Sopenharmony_ci self.assertIs(self._au.get_param('attachment', missing, 15657db96d56Sopenharmony_ci header='foobar'), missing) 15667db96d56Sopenharmony_ci 15677db96d56Sopenharmony_ci 15687db96d56Sopenharmony_ci 15697db96d56Sopenharmony_ci# Test the basic MIMEImage class 15707db96d56Sopenharmony_ciclass TestMIMEImage(unittest.TestCase): 15717db96d56Sopenharmony_ci def _make_image(self, ext): 15727db96d56Sopenharmony_ci with openfile(f'python.{ext}', 'rb') as fp: 15737db96d56Sopenharmony_ci self._imgdata = fp.read() 15747db96d56Sopenharmony_ci self._im = MIMEImage(self._imgdata) 15757db96d56Sopenharmony_ci 15767db96d56Sopenharmony_ci def test_guess_minor_type(self): 15777db96d56Sopenharmony_ci for ext, subtype in { 15787db96d56Sopenharmony_ci 'bmp': None, 15797db96d56Sopenharmony_ci 'exr': None, 15807db96d56Sopenharmony_ci 'gif': None, 15817db96d56Sopenharmony_ci 'jpg': 'jpeg', 15827db96d56Sopenharmony_ci 'pbm': None, 15837db96d56Sopenharmony_ci 'pgm': None, 15847db96d56Sopenharmony_ci 'png': None, 15857db96d56Sopenharmony_ci 'ppm': None, 15867db96d56Sopenharmony_ci 'ras': 'rast', 15877db96d56Sopenharmony_ci 'sgi': 'rgb', 15887db96d56Sopenharmony_ci 'tiff': None, 15897db96d56Sopenharmony_ci 'webp': None, 15907db96d56Sopenharmony_ci 'xbm': None, 15917db96d56Sopenharmony_ci }.items(): 15927db96d56Sopenharmony_ci self._make_image(ext) 15937db96d56Sopenharmony_ci subtype = ext if subtype is None else subtype 15947db96d56Sopenharmony_ci self.assertEqual(self._im.get_content_type(), f'image/{subtype}') 15957db96d56Sopenharmony_ci 15967db96d56Sopenharmony_ci def test_encoding(self): 15977db96d56Sopenharmony_ci self._make_image('gif') 15987db96d56Sopenharmony_ci payload = self._im.get_payload() 15997db96d56Sopenharmony_ci self.assertEqual(base64.decodebytes(bytes(payload, 'ascii')), 16007db96d56Sopenharmony_ci self._imgdata) 16017db96d56Sopenharmony_ci 16027db96d56Sopenharmony_ci def test_checkSetMinor(self): 16037db96d56Sopenharmony_ci self._make_image('gif') 16047db96d56Sopenharmony_ci im = MIMEImage(self._imgdata, 'fish') 16057db96d56Sopenharmony_ci self.assertEqual(im.get_content_type(), 'image/fish') 16067db96d56Sopenharmony_ci 16077db96d56Sopenharmony_ci def test_add_header(self): 16087db96d56Sopenharmony_ci self._make_image('gif') 16097db96d56Sopenharmony_ci eq = self.assertEqual 16107db96d56Sopenharmony_ci self._im.add_header('Content-Disposition', 'attachment', 16117db96d56Sopenharmony_ci filename='dingusfish.gif') 16127db96d56Sopenharmony_ci eq(self._im['content-disposition'], 16137db96d56Sopenharmony_ci 'attachment; filename="dingusfish.gif"') 16147db96d56Sopenharmony_ci eq(self._im.get_params(header='content-disposition'), 16157db96d56Sopenharmony_ci [('attachment', ''), ('filename', 'dingusfish.gif')]) 16167db96d56Sopenharmony_ci eq(self._im.get_param('filename', header='content-disposition'), 16177db96d56Sopenharmony_ci 'dingusfish.gif') 16187db96d56Sopenharmony_ci missing = [] 16197db96d56Sopenharmony_ci eq(self._im.get_param('attachment', header='content-disposition'), '') 16207db96d56Sopenharmony_ci self.assertIs(self._im.get_param('foo', failobj=missing, 16217db96d56Sopenharmony_ci header='content-disposition'), missing) 16227db96d56Sopenharmony_ci # Try some missing stuff 16237db96d56Sopenharmony_ci self.assertIs(self._im.get_param('foobar', missing), missing) 16247db96d56Sopenharmony_ci self.assertIs(self._im.get_param('attachment', missing, 16257db96d56Sopenharmony_ci header='foobar'), missing) 16267db96d56Sopenharmony_ci 16277db96d56Sopenharmony_ci 16287db96d56Sopenharmony_ci# Test the basic MIMEApplication class 16297db96d56Sopenharmony_ciclass TestMIMEApplication(unittest.TestCase): 16307db96d56Sopenharmony_ci def test_headers(self): 16317db96d56Sopenharmony_ci eq = self.assertEqual 16327db96d56Sopenharmony_ci msg = MIMEApplication(b'\xfa\xfb\xfc\xfd\xfe\xff') 16337db96d56Sopenharmony_ci eq(msg.get_content_type(), 'application/octet-stream') 16347db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'base64') 16357db96d56Sopenharmony_ci 16367db96d56Sopenharmony_ci def test_body(self): 16377db96d56Sopenharmony_ci eq = self.assertEqual 16387db96d56Sopenharmony_ci bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff' 16397db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata) 16407db96d56Sopenharmony_ci # whitespace in the cte encoded block is RFC-irrelevant. 16417db96d56Sopenharmony_ci eq(msg.get_payload().strip(), '+vv8/f7/') 16427db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), bytesdata) 16437db96d56Sopenharmony_ci 16447db96d56Sopenharmony_ci def test_binary_body_with_encode_7or8bit(self): 16457db96d56Sopenharmony_ci # Issue 17171. 16467db96d56Sopenharmony_ci bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff' 16477db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata, _encoder=encoders.encode_7or8bit) 16487db96d56Sopenharmony_ci # Treated as a string, this will be invalid code points. 16497db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '\uFFFD' * len(bytesdata)) 16507db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), bytesdata) 16517db96d56Sopenharmony_ci self.assertEqual(msg['Content-Transfer-Encoding'], '8bit') 16527db96d56Sopenharmony_ci s = BytesIO() 16537db96d56Sopenharmony_ci g = BytesGenerator(s) 16547db96d56Sopenharmony_ci g.flatten(msg) 16557db96d56Sopenharmony_ci wireform = s.getvalue() 16567db96d56Sopenharmony_ci msg2 = email.message_from_bytes(wireform) 16577db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '\uFFFD' * len(bytesdata)) 16587db96d56Sopenharmony_ci self.assertEqual(msg2.get_payload(decode=True), bytesdata) 16597db96d56Sopenharmony_ci self.assertEqual(msg2['Content-Transfer-Encoding'], '8bit') 16607db96d56Sopenharmony_ci 16617db96d56Sopenharmony_ci def test_binary_body_with_encode_noop(self): 16627db96d56Sopenharmony_ci # Issue 16564: This does not produce an RFC valid message, since to be 16637db96d56Sopenharmony_ci # valid it should have a CTE of binary. But the below works in 16647db96d56Sopenharmony_ci # Python2, and is documented as working this way. 16657db96d56Sopenharmony_ci bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff' 16667db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata, _encoder=encoders.encode_noop) 16677db96d56Sopenharmony_ci # Treated as a string, this will be invalid code points. 16687db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '\uFFFD' * len(bytesdata)) 16697db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), bytesdata) 16707db96d56Sopenharmony_ci s = BytesIO() 16717db96d56Sopenharmony_ci g = BytesGenerator(s) 16727db96d56Sopenharmony_ci g.flatten(msg) 16737db96d56Sopenharmony_ci wireform = s.getvalue() 16747db96d56Sopenharmony_ci msg2 = email.message_from_bytes(wireform) 16757db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '\uFFFD' * len(bytesdata)) 16767db96d56Sopenharmony_ci self.assertEqual(msg2.get_payload(decode=True), bytesdata) 16777db96d56Sopenharmony_ci 16787db96d56Sopenharmony_ci def test_binary_body_with_unicode_linend_encode_noop(self): 16797db96d56Sopenharmony_ci # Issue 19003: This is a variation on #16564. 16807db96d56Sopenharmony_ci bytesdata = b'\x0b\xfa\xfb\xfc\xfd\xfe\xff' 16817db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata, _encoder=encoders.encode_noop) 16827db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), bytesdata) 16837db96d56Sopenharmony_ci s = BytesIO() 16847db96d56Sopenharmony_ci g = BytesGenerator(s) 16857db96d56Sopenharmony_ci g.flatten(msg) 16867db96d56Sopenharmony_ci wireform = s.getvalue() 16877db96d56Sopenharmony_ci msg2 = email.message_from_bytes(wireform) 16887db96d56Sopenharmony_ci self.assertEqual(msg2.get_payload(decode=True), bytesdata) 16897db96d56Sopenharmony_ci 16907db96d56Sopenharmony_ci def test_binary_body_with_encode_quopri(self): 16917db96d56Sopenharmony_ci # Issue 14360. 16927db96d56Sopenharmony_ci bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff ' 16937db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata, _encoder=encoders.encode_quopri) 16947db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '=FA=FB=FC=FD=FE=FF=20') 16957db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), bytesdata) 16967db96d56Sopenharmony_ci self.assertEqual(msg['Content-Transfer-Encoding'], 'quoted-printable') 16977db96d56Sopenharmony_ci s = BytesIO() 16987db96d56Sopenharmony_ci g = BytesGenerator(s) 16997db96d56Sopenharmony_ci g.flatten(msg) 17007db96d56Sopenharmony_ci wireform = s.getvalue() 17017db96d56Sopenharmony_ci msg2 = email.message_from_bytes(wireform) 17027db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '=FA=FB=FC=FD=FE=FF=20') 17037db96d56Sopenharmony_ci self.assertEqual(msg2.get_payload(decode=True), bytesdata) 17047db96d56Sopenharmony_ci self.assertEqual(msg2['Content-Transfer-Encoding'], 'quoted-printable') 17057db96d56Sopenharmony_ci 17067db96d56Sopenharmony_ci def test_binary_body_with_encode_base64(self): 17077db96d56Sopenharmony_ci bytesdata = b'\xfa\xfb\xfc\xfd\xfe\xff' 17087db96d56Sopenharmony_ci msg = MIMEApplication(bytesdata, _encoder=encoders.encode_base64) 17097db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '+vv8/f7/\n') 17107db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), bytesdata) 17117db96d56Sopenharmony_ci s = BytesIO() 17127db96d56Sopenharmony_ci g = BytesGenerator(s) 17137db96d56Sopenharmony_ci g.flatten(msg) 17147db96d56Sopenharmony_ci wireform = s.getvalue() 17157db96d56Sopenharmony_ci msg2 = email.message_from_bytes(wireform) 17167db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), '+vv8/f7/\n') 17177db96d56Sopenharmony_ci self.assertEqual(msg2.get_payload(decode=True), bytesdata) 17187db96d56Sopenharmony_ci 17197db96d56Sopenharmony_ci 17207db96d56Sopenharmony_ci# Test the basic MIMEText class 17217db96d56Sopenharmony_ciclass TestMIMEText(unittest.TestCase): 17227db96d56Sopenharmony_ci def setUp(self): 17237db96d56Sopenharmony_ci self._msg = MIMEText('hello there') 17247db96d56Sopenharmony_ci 17257db96d56Sopenharmony_ci def test_types(self): 17267db96d56Sopenharmony_ci eq = self.assertEqual 17277db96d56Sopenharmony_ci eq(self._msg.get_content_type(), 'text/plain') 17287db96d56Sopenharmony_ci eq(self._msg.get_param('charset'), 'us-ascii') 17297db96d56Sopenharmony_ci missing = [] 17307db96d56Sopenharmony_ci self.assertIs(self._msg.get_param('foobar', missing), missing) 17317db96d56Sopenharmony_ci self.assertIs(self._msg.get_param('charset', missing, header='foobar'), 17327db96d56Sopenharmony_ci missing) 17337db96d56Sopenharmony_ci 17347db96d56Sopenharmony_ci def test_payload(self): 17357db96d56Sopenharmony_ci self.assertEqual(self._msg.get_payload(), 'hello there') 17367db96d56Sopenharmony_ci self.assertFalse(self._msg.is_multipart()) 17377db96d56Sopenharmony_ci 17387db96d56Sopenharmony_ci def test_charset(self): 17397db96d56Sopenharmony_ci eq = self.assertEqual 17407db96d56Sopenharmony_ci msg = MIMEText('hello there', _charset='us-ascii') 17417db96d56Sopenharmony_ci eq(msg.get_charset().input_charset, 'us-ascii') 17427db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="us-ascii"') 17437db96d56Sopenharmony_ci # Also accept a Charset instance 17447db96d56Sopenharmony_ci charset = Charset('utf-8') 17457db96d56Sopenharmony_ci charset.body_encoding = None 17467db96d56Sopenharmony_ci msg = MIMEText('hello there', _charset=charset) 17477db96d56Sopenharmony_ci eq(msg.get_charset().input_charset, 'utf-8') 17487db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="utf-8"') 17497db96d56Sopenharmony_ci eq(msg.get_payload(), 'hello there') 17507db96d56Sopenharmony_ci 17517db96d56Sopenharmony_ci def test_7bit_input(self): 17527db96d56Sopenharmony_ci eq = self.assertEqual 17537db96d56Sopenharmony_ci msg = MIMEText('hello there', _charset='us-ascii') 17547db96d56Sopenharmony_ci eq(msg.get_charset().input_charset, 'us-ascii') 17557db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="us-ascii"') 17567db96d56Sopenharmony_ci 17577db96d56Sopenharmony_ci def test_7bit_input_no_charset(self): 17587db96d56Sopenharmony_ci eq = self.assertEqual 17597db96d56Sopenharmony_ci msg = MIMEText('hello there') 17607db96d56Sopenharmony_ci eq(msg.get_charset(), 'us-ascii') 17617db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="us-ascii"') 17627db96d56Sopenharmony_ci self.assertIn('hello there', msg.as_string()) 17637db96d56Sopenharmony_ci 17647db96d56Sopenharmony_ci def test_utf8_input(self): 17657db96d56Sopenharmony_ci teststr = '\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430' 17667db96d56Sopenharmony_ci eq = self.assertEqual 17677db96d56Sopenharmony_ci msg = MIMEText(teststr, _charset='utf-8') 17687db96d56Sopenharmony_ci eq(msg.get_charset().output_charset, 'utf-8') 17697db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset="utf-8"') 17707db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), teststr.encode('utf-8')) 17717db96d56Sopenharmony_ci 17727db96d56Sopenharmony_ci @unittest.skip("can't fix because of backward compat in email5, " 17737db96d56Sopenharmony_ci "will fix in email6") 17747db96d56Sopenharmony_ci def test_utf8_input_no_charset(self): 17757db96d56Sopenharmony_ci teststr = '\u043a\u0438\u0440\u0438\u043b\u0438\u0446\u0430' 17767db96d56Sopenharmony_ci self.assertRaises(UnicodeEncodeError, MIMEText, teststr) 17777db96d56Sopenharmony_ci 17787db96d56Sopenharmony_ci 17797db96d56Sopenharmony_ci 17807db96d56Sopenharmony_ci# Test complicated multipart/* messages 17817db96d56Sopenharmony_ciclass TestMultipart(TestEmailBase): 17827db96d56Sopenharmony_ci def setUp(self): 17837db96d56Sopenharmony_ci with openfile('python.gif', 'rb') as fp: 17847db96d56Sopenharmony_ci data = fp.read() 17857db96d56Sopenharmony_ci container = MIMEBase('multipart', 'mixed', boundary='BOUNDARY') 17867db96d56Sopenharmony_ci image = MIMEImage(data, name='dingusfish.gif') 17877db96d56Sopenharmony_ci image.add_header('content-disposition', 'attachment', 17887db96d56Sopenharmony_ci filename='dingusfish.gif') 17897db96d56Sopenharmony_ci intro = MIMEText('''\ 17907db96d56Sopenharmony_ciHi there, 17917db96d56Sopenharmony_ci 17927db96d56Sopenharmony_ciThis is the dingus fish. 17937db96d56Sopenharmony_ci''') 17947db96d56Sopenharmony_ci container.attach(intro) 17957db96d56Sopenharmony_ci container.attach(image) 17967db96d56Sopenharmony_ci container['From'] = 'Barry <barry@digicool.com>' 17977db96d56Sopenharmony_ci container['To'] = 'Dingus Lovers <cravindogs@cravindogs.com>' 17987db96d56Sopenharmony_ci container['Subject'] = 'Here is your dingus fish' 17997db96d56Sopenharmony_ci 18007db96d56Sopenharmony_ci now = 987809702.54848599 18017db96d56Sopenharmony_ci timetuple = time.localtime(now) 18027db96d56Sopenharmony_ci if timetuple[-1] == 0: 18037db96d56Sopenharmony_ci tzsecs = time.timezone 18047db96d56Sopenharmony_ci else: 18057db96d56Sopenharmony_ci tzsecs = time.altzone 18067db96d56Sopenharmony_ci if tzsecs > 0: 18077db96d56Sopenharmony_ci sign = '-' 18087db96d56Sopenharmony_ci else: 18097db96d56Sopenharmony_ci sign = '+' 18107db96d56Sopenharmony_ci tzoffset = ' %s%04d' % (sign, tzsecs / 36) 18117db96d56Sopenharmony_ci container['Date'] = time.strftime( 18127db96d56Sopenharmony_ci '%a, %d %b %Y %H:%M:%S', 18137db96d56Sopenharmony_ci time.localtime(now)) + tzoffset 18147db96d56Sopenharmony_ci self._msg = container 18157db96d56Sopenharmony_ci self._im = image 18167db96d56Sopenharmony_ci self._txt = intro 18177db96d56Sopenharmony_ci 18187db96d56Sopenharmony_ci def test_hierarchy(self): 18197db96d56Sopenharmony_ci # convenience 18207db96d56Sopenharmony_ci eq = self.assertEqual 18217db96d56Sopenharmony_ci raises = self.assertRaises 18227db96d56Sopenharmony_ci # tests 18237db96d56Sopenharmony_ci m = self._msg 18247db96d56Sopenharmony_ci self.assertTrue(m.is_multipart()) 18257db96d56Sopenharmony_ci eq(m.get_content_type(), 'multipart/mixed') 18267db96d56Sopenharmony_ci eq(len(m.get_payload()), 2) 18277db96d56Sopenharmony_ci raises(IndexError, m.get_payload, 2) 18287db96d56Sopenharmony_ci m0 = m.get_payload(0) 18297db96d56Sopenharmony_ci m1 = m.get_payload(1) 18307db96d56Sopenharmony_ci self.assertIs(m0, self._txt) 18317db96d56Sopenharmony_ci self.assertIs(m1, self._im) 18327db96d56Sopenharmony_ci eq(m.get_payload(), [m0, m1]) 18337db96d56Sopenharmony_ci self.assertFalse(m0.is_multipart()) 18347db96d56Sopenharmony_ci self.assertFalse(m1.is_multipart()) 18357db96d56Sopenharmony_ci 18367db96d56Sopenharmony_ci def test_empty_multipart_idempotent(self): 18377db96d56Sopenharmony_ci text = """\ 18387db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 18397db96d56Sopenharmony_ciMIME-Version: 1.0 18407db96d56Sopenharmony_ciSubject: A subject 18417db96d56Sopenharmony_ciTo: aperson@dom.ain 18427db96d56Sopenharmony_ciFrom: bperson@dom.ain 18437db96d56Sopenharmony_ci 18447db96d56Sopenharmony_ci 18457db96d56Sopenharmony_ci--BOUNDARY 18467db96d56Sopenharmony_ci 18477db96d56Sopenharmony_ci 18487db96d56Sopenharmony_ci--BOUNDARY-- 18497db96d56Sopenharmony_ci""" 18507db96d56Sopenharmony_ci msg = Parser().parsestr(text) 18517db96d56Sopenharmony_ci self.ndiffAssertEqual(text, msg.as_string()) 18527db96d56Sopenharmony_ci 18537db96d56Sopenharmony_ci def test_no_parts_in_a_multipart_with_none_epilogue(self): 18547db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 18557db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 18567db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 18577db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 18587db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 18597db96d56Sopenharmony_ci self.ndiffAssertEqual(outer.as_string(), '''\ 18607db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 18617db96d56Sopenharmony_ciMIME-Version: 1.0 18627db96d56Sopenharmony_ciSubject: A subject 18637db96d56Sopenharmony_ciTo: aperson@dom.ain 18647db96d56Sopenharmony_ciFrom: bperson@dom.ain 18657db96d56Sopenharmony_ci 18667db96d56Sopenharmony_ci--BOUNDARY 18677db96d56Sopenharmony_ci 18687db96d56Sopenharmony_ci--BOUNDARY-- 18697db96d56Sopenharmony_ci''') 18707db96d56Sopenharmony_ci 18717db96d56Sopenharmony_ci def test_no_parts_in_a_multipart_with_empty_epilogue(self): 18727db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 18737db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 18747db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 18757db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 18767db96d56Sopenharmony_ci outer.preamble = '' 18777db96d56Sopenharmony_ci outer.epilogue = '' 18787db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 18797db96d56Sopenharmony_ci self.ndiffAssertEqual(outer.as_string(), '''\ 18807db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 18817db96d56Sopenharmony_ciMIME-Version: 1.0 18827db96d56Sopenharmony_ciSubject: A subject 18837db96d56Sopenharmony_ciTo: aperson@dom.ain 18847db96d56Sopenharmony_ciFrom: bperson@dom.ain 18857db96d56Sopenharmony_ci 18867db96d56Sopenharmony_ci 18877db96d56Sopenharmony_ci--BOUNDARY 18887db96d56Sopenharmony_ci 18897db96d56Sopenharmony_ci--BOUNDARY-- 18907db96d56Sopenharmony_ci''') 18917db96d56Sopenharmony_ci 18927db96d56Sopenharmony_ci def test_one_part_in_a_multipart(self): 18937db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 18947db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 18957db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 18967db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 18977db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 18987db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 18997db96d56Sopenharmony_ci msg = MIMEText('hello world') 19007db96d56Sopenharmony_ci outer.attach(msg) 19017db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 19027db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 19037db96d56Sopenharmony_ciMIME-Version: 1.0 19047db96d56Sopenharmony_ciSubject: A subject 19057db96d56Sopenharmony_ciTo: aperson@dom.ain 19067db96d56Sopenharmony_ciFrom: bperson@dom.ain 19077db96d56Sopenharmony_ci 19087db96d56Sopenharmony_ci--BOUNDARY 19097db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 19107db96d56Sopenharmony_ciMIME-Version: 1.0 19117db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 19127db96d56Sopenharmony_ci 19137db96d56Sopenharmony_cihello world 19147db96d56Sopenharmony_ci--BOUNDARY-- 19157db96d56Sopenharmony_ci''') 19167db96d56Sopenharmony_ci 19177db96d56Sopenharmony_ci def test_seq_parts_in_a_multipart_with_empty_preamble(self): 19187db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 19197db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 19207db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 19217db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 19227db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 19237db96d56Sopenharmony_ci outer.preamble = '' 19247db96d56Sopenharmony_ci msg = MIMEText('hello world') 19257db96d56Sopenharmony_ci outer.attach(msg) 19267db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 19277db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 19287db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 19297db96d56Sopenharmony_ciMIME-Version: 1.0 19307db96d56Sopenharmony_ciSubject: A subject 19317db96d56Sopenharmony_ciTo: aperson@dom.ain 19327db96d56Sopenharmony_ciFrom: bperson@dom.ain 19337db96d56Sopenharmony_ci 19347db96d56Sopenharmony_ci 19357db96d56Sopenharmony_ci--BOUNDARY 19367db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 19377db96d56Sopenharmony_ciMIME-Version: 1.0 19387db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 19397db96d56Sopenharmony_ci 19407db96d56Sopenharmony_cihello world 19417db96d56Sopenharmony_ci--BOUNDARY-- 19427db96d56Sopenharmony_ci''') 19437db96d56Sopenharmony_ci 19447db96d56Sopenharmony_ci 19457db96d56Sopenharmony_ci def test_seq_parts_in_a_multipart_with_none_preamble(self): 19467db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 19477db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 19487db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 19497db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 19507db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 19517db96d56Sopenharmony_ci outer.preamble = None 19527db96d56Sopenharmony_ci msg = MIMEText('hello world') 19537db96d56Sopenharmony_ci outer.attach(msg) 19547db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 19557db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 19567db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 19577db96d56Sopenharmony_ciMIME-Version: 1.0 19587db96d56Sopenharmony_ciSubject: A subject 19597db96d56Sopenharmony_ciTo: aperson@dom.ain 19607db96d56Sopenharmony_ciFrom: bperson@dom.ain 19617db96d56Sopenharmony_ci 19627db96d56Sopenharmony_ci--BOUNDARY 19637db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 19647db96d56Sopenharmony_ciMIME-Version: 1.0 19657db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 19667db96d56Sopenharmony_ci 19677db96d56Sopenharmony_cihello world 19687db96d56Sopenharmony_ci--BOUNDARY-- 19697db96d56Sopenharmony_ci''') 19707db96d56Sopenharmony_ci 19717db96d56Sopenharmony_ci 19727db96d56Sopenharmony_ci def test_seq_parts_in_a_multipart_with_none_epilogue(self): 19737db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 19747db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 19757db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 19767db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 19777db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 19787db96d56Sopenharmony_ci outer.epilogue = None 19797db96d56Sopenharmony_ci msg = MIMEText('hello world') 19807db96d56Sopenharmony_ci outer.attach(msg) 19817db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 19827db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 19837db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 19847db96d56Sopenharmony_ciMIME-Version: 1.0 19857db96d56Sopenharmony_ciSubject: A subject 19867db96d56Sopenharmony_ciTo: aperson@dom.ain 19877db96d56Sopenharmony_ciFrom: bperson@dom.ain 19887db96d56Sopenharmony_ci 19897db96d56Sopenharmony_ci--BOUNDARY 19907db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 19917db96d56Sopenharmony_ciMIME-Version: 1.0 19927db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 19937db96d56Sopenharmony_ci 19947db96d56Sopenharmony_cihello world 19957db96d56Sopenharmony_ci--BOUNDARY-- 19967db96d56Sopenharmony_ci''') 19977db96d56Sopenharmony_ci 19987db96d56Sopenharmony_ci 19997db96d56Sopenharmony_ci def test_seq_parts_in_a_multipart_with_empty_epilogue(self): 20007db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 20017db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 20027db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 20037db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 20047db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 20057db96d56Sopenharmony_ci outer.epilogue = '' 20067db96d56Sopenharmony_ci msg = MIMEText('hello world') 20077db96d56Sopenharmony_ci outer.attach(msg) 20087db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 20097db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 20107db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 20117db96d56Sopenharmony_ciMIME-Version: 1.0 20127db96d56Sopenharmony_ciSubject: A subject 20137db96d56Sopenharmony_ciTo: aperson@dom.ain 20147db96d56Sopenharmony_ciFrom: bperson@dom.ain 20157db96d56Sopenharmony_ci 20167db96d56Sopenharmony_ci--BOUNDARY 20177db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 20187db96d56Sopenharmony_ciMIME-Version: 1.0 20197db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 20207db96d56Sopenharmony_ci 20217db96d56Sopenharmony_cihello world 20227db96d56Sopenharmony_ci--BOUNDARY-- 20237db96d56Sopenharmony_ci''') 20247db96d56Sopenharmony_ci 20257db96d56Sopenharmony_ci 20267db96d56Sopenharmony_ci def test_seq_parts_in_a_multipart_with_nl_epilogue(self): 20277db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 20287db96d56Sopenharmony_ci outer = MIMEBase('multipart', 'mixed') 20297db96d56Sopenharmony_ci outer['Subject'] = 'A subject' 20307db96d56Sopenharmony_ci outer['To'] = 'aperson@dom.ain' 20317db96d56Sopenharmony_ci outer['From'] = 'bperson@dom.ain' 20327db96d56Sopenharmony_ci outer.epilogue = '\n' 20337db96d56Sopenharmony_ci msg = MIMEText('hello world') 20347db96d56Sopenharmony_ci outer.attach(msg) 20357db96d56Sopenharmony_ci outer.set_boundary('BOUNDARY') 20367db96d56Sopenharmony_ci eq(outer.as_string(), '''\ 20377db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 20387db96d56Sopenharmony_ciMIME-Version: 1.0 20397db96d56Sopenharmony_ciSubject: A subject 20407db96d56Sopenharmony_ciTo: aperson@dom.ain 20417db96d56Sopenharmony_ciFrom: bperson@dom.ain 20427db96d56Sopenharmony_ci 20437db96d56Sopenharmony_ci--BOUNDARY 20447db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 20457db96d56Sopenharmony_ciMIME-Version: 1.0 20467db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 20477db96d56Sopenharmony_ci 20487db96d56Sopenharmony_cihello world 20497db96d56Sopenharmony_ci--BOUNDARY-- 20507db96d56Sopenharmony_ci 20517db96d56Sopenharmony_ci''') 20527db96d56Sopenharmony_ci 20537db96d56Sopenharmony_ci def test_message_external_body(self): 20547db96d56Sopenharmony_ci eq = self.assertEqual 20557db96d56Sopenharmony_ci msg = self._msgobj('msg_36.txt') 20567db96d56Sopenharmony_ci eq(len(msg.get_payload()), 2) 20577db96d56Sopenharmony_ci msg1 = msg.get_payload(1) 20587db96d56Sopenharmony_ci eq(msg1.get_content_type(), 'multipart/alternative') 20597db96d56Sopenharmony_ci eq(len(msg1.get_payload()), 2) 20607db96d56Sopenharmony_ci for subpart in msg1.get_payload(): 20617db96d56Sopenharmony_ci eq(subpart.get_content_type(), 'message/external-body') 20627db96d56Sopenharmony_ci eq(len(subpart.get_payload()), 1) 20637db96d56Sopenharmony_ci subsubpart = subpart.get_payload(0) 20647db96d56Sopenharmony_ci eq(subsubpart.get_content_type(), 'text/plain') 20657db96d56Sopenharmony_ci 20667db96d56Sopenharmony_ci def test_double_boundary(self): 20677db96d56Sopenharmony_ci # msg_37.txt is a multipart that contains two dash-boundary's in a 20687db96d56Sopenharmony_ci # row. Our interpretation of RFC 2046 calls for ignoring the second 20697db96d56Sopenharmony_ci # and subsequent boundaries. 20707db96d56Sopenharmony_ci msg = self._msgobj('msg_37.txt') 20717db96d56Sopenharmony_ci self.assertEqual(len(msg.get_payload()), 3) 20727db96d56Sopenharmony_ci 20737db96d56Sopenharmony_ci def test_nested_inner_contains_outer_boundary(self): 20747db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 20757db96d56Sopenharmony_ci # msg_38.txt has an inner part that contains outer boundaries. My 20767db96d56Sopenharmony_ci # interpretation of RFC 2046 (based on sections 5.1 and 5.1.2) say 20777db96d56Sopenharmony_ci # these are illegal and should be interpreted as unterminated inner 20787db96d56Sopenharmony_ci # parts. 20797db96d56Sopenharmony_ci msg = self._msgobj('msg_38.txt') 20807db96d56Sopenharmony_ci sfp = StringIO() 20817db96d56Sopenharmony_ci iterators._structure(msg, sfp) 20827db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 20837db96d56Sopenharmony_cimultipart/mixed 20847db96d56Sopenharmony_ci multipart/mixed 20857db96d56Sopenharmony_ci multipart/alternative 20867db96d56Sopenharmony_ci text/plain 20877db96d56Sopenharmony_ci text/plain 20887db96d56Sopenharmony_ci text/plain 20897db96d56Sopenharmony_ci text/plain 20907db96d56Sopenharmony_ci""") 20917db96d56Sopenharmony_ci 20927db96d56Sopenharmony_ci def test_nested_with_same_boundary(self): 20937db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 20947db96d56Sopenharmony_ci # msg 39.txt is similarly evil in that it's got inner parts that use 20957db96d56Sopenharmony_ci # the same boundary as outer parts. Again, I believe the way this is 20967db96d56Sopenharmony_ci # parsed is closest to the spirit of RFC 2046 20977db96d56Sopenharmony_ci msg = self._msgobj('msg_39.txt') 20987db96d56Sopenharmony_ci sfp = StringIO() 20997db96d56Sopenharmony_ci iterators._structure(msg, sfp) 21007db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 21017db96d56Sopenharmony_cimultipart/mixed 21027db96d56Sopenharmony_ci multipart/mixed 21037db96d56Sopenharmony_ci multipart/alternative 21047db96d56Sopenharmony_ci application/octet-stream 21057db96d56Sopenharmony_ci application/octet-stream 21067db96d56Sopenharmony_ci text/plain 21077db96d56Sopenharmony_ci""") 21087db96d56Sopenharmony_ci 21097db96d56Sopenharmony_ci def test_boundary_in_non_multipart(self): 21107db96d56Sopenharmony_ci msg = self._msgobj('msg_40.txt') 21117db96d56Sopenharmony_ci self.assertEqual(msg.as_string(), '''\ 21127db96d56Sopenharmony_ciMIME-Version: 1.0 21137db96d56Sopenharmony_ciContent-Type: text/html; boundary="--961284236552522269" 21147db96d56Sopenharmony_ci 21157db96d56Sopenharmony_ci----961284236552522269 21167db96d56Sopenharmony_ciContent-Type: text/html; 21177db96d56Sopenharmony_ciContent-Transfer-Encoding: 7Bit 21187db96d56Sopenharmony_ci 21197db96d56Sopenharmony_ci<html></html> 21207db96d56Sopenharmony_ci 21217db96d56Sopenharmony_ci----961284236552522269-- 21227db96d56Sopenharmony_ci''') 21237db96d56Sopenharmony_ci 21247db96d56Sopenharmony_ci def test_boundary_with_leading_space(self): 21257db96d56Sopenharmony_ci eq = self.assertEqual 21267db96d56Sopenharmony_ci msg = email.message_from_string('''\ 21277db96d56Sopenharmony_ciMIME-Version: 1.0 21287db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary=" XXXX" 21297db96d56Sopenharmony_ci 21307db96d56Sopenharmony_ci-- XXXX 21317db96d56Sopenharmony_ciContent-Type: text/plain 21327db96d56Sopenharmony_ci 21337db96d56Sopenharmony_ci 21347db96d56Sopenharmony_ci-- XXXX 21357db96d56Sopenharmony_ciContent-Type: text/plain 21367db96d56Sopenharmony_ci 21377db96d56Sopenharmony_ci-- XXXX-- 21387db96d56Sopenharmony_ci''') 21397db96d56Sopenharmony_ci self.assertTrue(msg.is_multipart()) 21407db96d56Sopenharmony_ci eq(msg.get_boundary(), ' XXXX') 21417db96d56Sopenharmony_ci eq(len(msg.get_payload()), 2) 21427db96d56Sopenharmony_ci 21437db96d56Sopenharmony_ci def test_boundary_without_trailing_newline(self): 21447db96d56Sopenharmony_ci m = Parser().parsestr("""\ 21457db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="===============0012394164==" 21467db96d56Sopenharmony_ciMIME-Version: 1.0 21477db96d56Sopenharmony_ci 21487db96d56Sopenharmony_ci--===============0012394164== 21497db96d56Sopenharmony_ciContent-Type: image/file1.jpg 21507db96d56Sopenharmony_ciMIME-Version: 1.0 21517db96d56Sopenharmony_ciContent-Transfer-Encoding: base64 21527db96d56Sopenharmony_ci 21537db96d56Sopenharmony_ciYXNkZg== 21547db96d56Sopenharmony_ci--===============0012394164==--""") 21557db96d56Sopenharmony_ci self.assertEqual(m.get_payload(0).get_payload(), 'YXNkZg==') 21567db96d56Sopenharmony_ci 21577db96d56Sopenharmony_ci def test_mimebase_default_policy(self): 21587db96d56Sopenharmony_ci m = MIMEBase('multipart', 'mixed') 21597db96d56Sopenharmony_ci self.assertIs(m.policy, email.policy.compat32) 21607db96d56Sopenharmony_ci 21617db96d56Sopenharmony_ci def test_mimebase_custom_policy(self): 21627db96d56Sopenharmony_ci m = MIMEBase('multipart', 'mixed', policy=email.policy.default) 21637db96d56Sopenharmony_ci self.assertIs(m.policy, email.policy.default) 21647db96d56Sopenharmony_ci 21657db96d56Sopenharmony_ci# Test some badly formatted messages 21667db96d56Sopenharmony_ciclass TestNonConformant(TestEmailBase): 21677db96d56Sopenharmony_ci 21687db96d56Sopenharmony_ci def test_parse_missing_minor_type(self): 21697db96d56Sopenharmony_ci eq = self.assertEqual 21707db96d56Sopenharmony_ci msg = self._msgobj('msg_14.txt') 21717db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 21727db96d56Sopenharmony_ci eq(msg.get_content_maintype(), 'text') 21737db96d56Sopenharmony_ci eq(msg.get_content_subtype(), 'plain') 21747db96d56Sopenharmony_ci 21757db96d56Sopenharmony_ci # test_defect_handling 21767db96d56Sopenharmony_ci def test_same_boundary_inner_outer(self): 21777db96d56Sopenharmony_ci msg = self._msgobj('msg_15.txt') 21787db96d56Sopenharmony_ci # XXX We can probably eventually do better 21797db96d56Sopenharmony_ci inner = msg.get_payload(0) 21807db96d56Sopenharmony_ci self.assertTrue(hasattr(inner, 'defects')) 21817db96d56Sopenharmony_ci self.assertEqual(len(inner.defects), 1) 21827db96d56Sopenharmony_ci self.assertIsInstance(inner.defects[0], 21837db96d56Sopenharmony_ci errors.StartBoundaryNotFoundDefect) 21847db96d56Sopenharmony_ci 21857db96d56Sopenharmony_ci # test_defect_handling 21867db96d56Sopenharmony_ci def test_multipart_no_boundary(self): 21877db96d56Sopenharmony_ci msg = self._msgobj('msg_25.txt') 21887db96d56Sopenharmony_ci self.assertIsInstance(msg.get_payload(), str) 21897db96d56Sopenharmony_ci self.assertEqual(len(msg.defects), 2) 21907db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[0], 21917db96d56Sopenharmony_ci errors.NoBoundaryInMultipartDefect) 21927db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[1], 21937db96d56Sopenharmony_ci errors.MultipartInvariantViolationDefect) 21947db96d56Sopenharmony_ci 21957db96d56Sopenharmony_ci multipart_msg = textwrap.dedent("""\ 21967db96d56Sopenharmony_ci Date: Wed, 14 Nov 2007 12:56:23 GMT 21977db96d56Sopenharmony_ci From: foo@bar.invalid 21987db96d56Sopenharmony_ci To: foo@bar.invalid 21997db96d56Sopenharmony_ci Subject: Content-Transfer-Encoding: base64 and multipart 22007db96d56Sopenharmony_ci MIME-Version: 1.0 22017db96d56Sopenharmony_ci Content-Type: multipart/mixed; 22027db96d56Sopenharmony_ci boundary="===============3344438784458119861=="{} 22037db96d56Sopenharmony_ci 22047db96d56Sopenharmony_ci --===============3344438784458119861== 22057db96d56Sopenharmony_ci Content-Type: text/plain 22067db96d56Sopenharmony_ci 22077db96d56Sopenharmony_ci Test message 22087db96d56Sopenharmony_ci 22097db96d56Sopenharmony_ci --===============3344438784458119861== 22107db96d56Sopenharmony_ci Content-Type: application/octet-stream 22117db96d56Sopenharmony_ci Content-Transfer-Encoding: base64 22127db96d56Sopenharmony_ci 22137db96d56Sopenharmony_ci YWJj 22147db96d56Sopenharmony_ci 22157db96d56Sopenharmony_ci --===============3344438784458119861==-- 22167db96d56Sopenharmony_ci """) 22177db96d56Sopenharmony_ci 22187db96d56Sopenharmony_ci # test_defect_handling 22197db96d56Sopenharmony_ci def test_multipart_invalid_cte(self): 22207db96d56Sopenharmony_ci msg = self._str_msg( 22217db96d56Sopenharmony_ci self.multipart_msg.format("\nContent-Transfer-Encoding: base64")) 22227db96d56Sopenharmony_ci self.assertEqual(len(msg.defects), 1) 22237db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[0], 22247db96d56Sopenharmony_ci errors.InvalidMultipartContentTransferEncodingDefect) 22257db96d56Sopenharmony_ci 22267db96d56Sopenharmony_ci # test_defect_handling 22277db96d56Sopenharmony_ci def test_multipart_no_cte_no_defect(self): 22287db96d56Sopenharmony_ci msg = self._str_msg(self.multipart_msg.format('')) 22297db96d56Sopenharmony_ci self.assertEqual(len(msg.defects), 0) 22307db96d56Sopenharmony_ci 22317db96d56Sopenharmony_ci # test_defect_handling 22327db96d56Sopenharmony_ci def test_multipart_valid_cte_no_defect(self): 22337db96d56Sopenharmony_ci for cte in ('7bit', '8bit', 'BINary'): 22347db96d56Sopenharmony_ci msg = self._str_msg( 22357db96d56Sopenharmony_ci self.multipart_msg.format( 22367db96d56Sopenharmony_ci "\nContent-Transfer-Encoding: {}".format(cte))) 22377db96d56Sopenharmony_ci self.assertEqual(len(msg.defects), 0) 22387db96d56Sopenharmony_ci 22397db96d56Sopenharmony_ci # test_headerregistry.TestContentTyopeHeader invalid_1 and invalid_2. 22407db96d56Sopenharmony_ci def test_invalid_content_type(self): 22417db96d56Sopenharmony_ci eq = self.assertEqual 22427db96d56Sopenharmony_ci neq = self.ndiffAssertEqual 22437db96d56Sopenharmony_ci msg = Message() 22447db96d56Sopenharmony_ci # RFC 2045, $5.2 says invalid yields text/plain 22457db96d56Sopenharmony_ci msg['Content-Type'] = 'text' 22467db96d56Sopenharmony_ci eq(msg.get_content_maintype(), 'text') 22477db96d56Sopenharmony_ci eq(msg.get_content_subtype(), 'plain') 22487db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 22497db96d56Sopenharmony_ci # Clear the old value and try something /really/ invalid 22507db96d56Sopenharmony_ci del msg['content-type'] 22517db96d56Sopenharmony_ci msg['Content-Type'] = 'foo' 22527db96d56Sopenharmony_ci eq(msg.get_content_maintype(), 'text') 22537db96d56Sopenharmony_ci eq(msg.get_content_subtype(), 'plain') 22547db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 22557db96d56Sopenharmony_ci # Still, make sure that the message is idempotently generated 22567db96d56Sopenharmony_ci s = StringIO() 22577db96d56Sopenharmony_ci g = Generator(s) 22587db96d56Sopenharmony_ci g.flatten(msg) 22597db96d56Sopenharmony_ci neq(s.getvalue(), 'Content-Type: foo\n\n') 22607db96d56Sopenharmony_ci 22617db96d56Sopenharmony_ci def test_no_start_boundary(self): 22627db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 22637db96d56Sopenharmony_ci msg = self._msgobj('msg_31.txt') 22647db96d56Sopenharmony_ci eq(msg.get_payload(), """\ 22657db96d56Sopenharmony_ci--BOUNDARY 22667db96d56Sopenharmony_ciContent-Type: text/plain 22677db96d56Sopenharmony_ci 22687db96d56Sopenharmony_cimessage 1 22697db96d56Sopenharmony_ci 22707db96d56Sopenharmony_ci--BOUNDARY 22717db96d56Sopenharmony_ciContent-Type: text/plain 22727db96d56Sopenharmony_ci 22737db96d56Sopenharmony_cimessage 2 22747db96d56Sopenharmony_ci 22757db96d56Sopenharmony_ci--BOUNDARY-- 22767db96d56Sopenharmony_ci""") 22777db96d56Sopenharmony_ci 22787db96d56Sopenharmony_ci def test_no_separating_blank_line(self): 22797db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 22807db96d56Sopenharmony_ci msg = self._msgobj('msg_35.txt') 22817db96d56Sopenharmony_ci eq(msg.as_string(), """\ 22827db96d56Sopenharmony_ciFrom: aperson@dom.ain 22837db96d56Sopenharmony_ciTo: bperson@dom.ain 22847db96d56Sopenharmony_ciSubject: here's something interesting 22857db96d56Sopenharmony_ci 22867db96d56Sopenharmony_cicounter to RFC 2822, there's no separating newline here 22877db96d56Sopenharmony_ci""") 22887db96d56Sopenharmony_ci 22897db96d56Sopenharmony_ci # test_defect_handling 22907db96d56Sopenharmony_ci def test_lying_multipart(self): 22917db96d56Sopenharmony_ci msg = self._msgobj('msg_41.txt') 22927db96d56Sopenharmony_ci self.assertTrue(hasattr(msg, 'defects')) 22937db96d56Sopenharmony_ci self.assertEqual(len(msg.defects), 2) 22947db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[0], 22957db96d56Sopenharmony_ci errors.NoBoundaryInMultipartDefect) 22967db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[1], 22977db96d56Sopenharmony_ci errors.MultipartInvariantViolationDefect) 22987db96d56Sopenharmony_ci 22997db96d56Sopenharmony_ci # test_defect_handling 23007db96d56Sopenharmony_ci def test_missing_start_boundary(self): 23017db96d56Sopenharmony_ci outer = self._msgobj('msg_42.txt') 23027db96d56Sopenharmony_ci # The message structure is: 23037db96d56Sopenharmony_ci # 23047db96d56Sopenharmony_ci # multipart/mixed 23057db96d56Sopenharmony_ci # text/plain 23067db96d56Sopenharmony_ci # message/rfc822 23077db96d56Sopenharmony_ci # multipart/mixed [*] 23087db96d56Sopenharmony_ci # 23097db96d56Sopenharmony_ci # [*] This message is missing its start boundary 23107db96d56Sopenharmony_ci bad = outer.get_payload(1).get_payload(0) 23117db96d56Sopenharmony_ci self.assertEqual(len(bad.defects), 1) 23127db96d56Sopenharmony_ci self.assertIsInstance(bad.defects[0], 23137db96d56Sopenharmony_ci errors.StartBoundaryNotFoundDefect) 23147db96d56Sopenharmony_ci 23157db96d56Sopenharmony_ci # test_defect_handling 23167db96d56Sopenharmony_ci def test_first_line_is_continuation_header(self): 23177db96d56Sopenharmony_ci eq = self.assertEqual 23187db96d56Sopenharmony_ci m = ' Line 1\nSubject: test\n\nbody' 23197db96d56Sopenharmony_ci msg = email.message_from_string(m) 23207db96d56Sopenharmony_ci eq(msg.keys(), ['Subject']) 23217db96d56Sopenharmony_ci eq(msg.get_payload(), 'body') 23227db96d56Sopenharmony_ci eq(len(msg.defects), 1) 23237db96d56Sopenharmony_ci self.assertDefectsEqual(msg.defects, 23247db96d56Sopenharmony_ci [errors.FirstHeaderLineIsContinuationDefect]) 23257db96d56Sopenharmony_ci eq(msg.defects[0].line, ' Line 1\n') 23267db96d56Sopenharmony_ci 23277db96d56Sopenharmony_ci # test_defect_handling 23287db96d56Sopenharmony_ci def test_missing_header_body_separator(self): 23297db96d56Sopenharmony_ci # Our heuristic if we see a line that doesn't look like a header (no 23307db96d56Sopenharmony_ci # leading whitespace but no ':') is to assume that the blank line that 23317db96d56Sopenharmony_ci # separates the header from the body is missing, and to stop parsing 23327db96d56Sopenharmony_ci # headers and start parsing the body. 23337db96d56Sopenharmony_ci msg = self._str_msg('Subject: test\nnot a header\nTo: abc\n\nb\n') 23347db96d56Sopenharmony_ci self.assertEqual(msg.keys(), ['Subject']) 23357db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), 'not a header\nTo: abc\n\nb\n') 23367db96d56Sopenharmony_ci self.assertDefectsEqual(msg.defects, 23377db96d56Sopenharmony_ci [errors.MissingHeaderBodySeparatorDefect]) 23387db96d56Sopenharmony_ci 23397db96d56Sopenharmony_ci 23407db96d56Sopenharmony_ci# Test RFC 2047 header encoding and decoding 23417db96d56Sopenharmony_ciclass TestRFC2047(TestEmailBase): 23427db96d56Sopenharmony_ci def test_rfc2047_multiline(self): 23437db96d56Sopenharmony_ci eq = self.assertEqual 23447db96d56Sopenharmony_ci s = """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz 23457db96d56Sopenharmony_ci foo bar =?mac-iceland?q?r=8Aksm=9Arg=8Cs?=""" 23467db96d56Sopenharmony_ci dh = decode_header(s) 23477db96d56Sopenharmony_ci eq(dh, [ 23487db96d56Sopenharmony_ci (b'Re: ', None), 23497db96d56Sopenharmony_ci (b'r\x8aksm\x9arg\x8cs', 'mac-iceland'), 23507db96d56Sopenharmony_ci (b' baz foo bar ', None), 23517db96d56Sopenharmony_ci (b'r\x8aksm\x9arg\x8cs', 'mac-iceland')]) 23527db96d56Sopenharmony_ci header = make_header(dh) 23537db96d56Sopenharmony_ci eq(str(header), 23547db96d56Sopenharmony_ci 'Re: r\xe4ksm\xf6rg\xe5s baz foo bar r\xe4ksm\xf6rg\xe5s') 23557db96d56Sopenharmony_ci self.ndiffAssertEqual(header.encode(maxlinelen=76), """\ 23567db96d56Sopenharmony_ciRe: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz foo bar =?mac-iceland?q?r=8Aksm?= 23577db96d56Sopenharmony_ci =?mac-iceland?q?=9Arg=8Cs?=""") 23587db96d56Sopenharmony_ci 23597db96d56Sopenharmony_ci def test_whitespace_keeper_unicode(self): 23607db96d56Sopenharmony_ci eq = self.assertEqual 23617db96d56Sopenharmony_ci s = '=?ISO-8859-1?Q?Andr=E9?= Pirard <pirard@dom.ain>' 23627db96d56Sopenharmony_ci dh = decode_header(s) 23637db96d56Sopenharmony_ci eq(dh, [(b'Andr\xe9', 'iso-8859-1'), 23647db96d56Sopenharmony_ci (b' Pirard <pirard@dom.ain>', None)]) 23657db96d56Sopenharmony_ci header = str(make_header(dh)) 23667db96d56Sopenharmony_ci eq(header, 'Andr\xe9 Pirard <pirard@dom.ain>') 23677db96d56Sopenharmony_ci 23687db96d56Sopenharmony_ci def test_whitespace_keeper_unicode_2(self): 23697db96d56Sopenharmony_ci eq = self.assertEqual 23707db96d56Sopenharmony_ci s = 'The =?iso-8859-1?b?cXVpY2sgYnJvd24gZm94?= jumped over the =?iso-8859-1?b?bGF6eSBkb2c=?=' 23717db96d56Sopenharmony_ci dh = decode_header(s) 23727db96d56Sopenharmony_ci eq(dh, [(b'The ', None), (b'quick brown fox', 'iso-8859-1'), 23737db96d56Sopenharmony_ci (b' jumped over the ', None), (b'lazy dog', 'iso-8859-1')]) 23747db96d56Sopenharmony_ci hu = str(make_header(dh)) 23757db96d56Sopenharmony_ci eq(hu, 'The quick brown fox jumped over the lazy dog') 23767db96d56Sopenharmony_ci 23777db96d56Sopenharmony_ci def test_rfc2047_missing_whitespace(self): 23787db96d56Sopenharmony_ci s = 'Sm=?ISO-8859-1?B?9g==?=rg=?ISO-8859-1?B?5Q==?=sbord' 23797db96d56Sopenharmony_ci dh = decode_header(s) 23807db96d56Sopenharmony_ci self.assertEqual(dh, [(b'Sm', None), (b'\xf6', 'iso-8859-1'), 23817db96d56Sopenharmony_ci (b'rg', None), (b'\xe5', 'iso-8859-1'), 23827db96d56Sopenharmony_ci (b'sbord', None)]) 23837db96d56Sopenharmony_ci 23847db96d56Sopenharmony_ci def test_rfc2047_with_whitespace(self): 23857db96d56Sopenharmony_ci s = 'Sm =?ISO-8859-1?B?9g==?= rg =?ISO-8859-1?B?5Q==?= sbord' 23867db96d56Sopenharmony_ci dh = decode_header(s) 23877db96d56Sopenharmony_ci self.assertEqual(dh, [(b'Sm ', None), (b'\xf6', 'iso-8859-1'), 23887db96d56Sopenharmony_ci (b' rg ', None), (b'\xe5', 'iso-8859-1'), 23897db96d56Sopenharmony_ci (b' sbord', None)]) 23907db96d56Sopenharmony_ci 23917db96d56Sopenharmony_ci def test_rfc2047_B_bad_padding(self): 23927db96d56Sopenharmony_ci s = '=?iso-8859-1?B?%s?=' 23937db96d56Sopenharmony_ci data = [ # only test complete bytes 23947db96d56Sopenharmony_ci ('dm==', b'v'), ('dm=', b'v'), ('dm', b'v'), 23957db96d56Sopenharmony_ci ('dmk=', b'vi'), ('dmk', b'vi') 23967db96d56Sopenharmony_ci ] 23977db96d56Sopenharmony_ci for q, a in data: 23987db96d56Sopenharmony_ci dh = decode_header(s % q) 23997db96d56Sopenharmony_ci self.assertEqual(dh, [(a, 'iso-8859-1')]) 24007db96d56Sopenharmony_ci 24017db96d56Sopenharmony_ci def test_rfc2047_Q_invalid_digits(self): 24027db96d56Sopenharmony_ci # issue 10004. 24037db96d56Sopenharmony_ci s = '=?iso-8859-1?Q?andr=e9=zz?=' 24047db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24057db96d56Sopenharmony_ci [(b'andr\xe9=zz', 'iso-8859-1')]) 24067db96d56Sopenharmony_ci 24077db96d56Sopenharmony_ci def test_rfc2047_rfc2047_1(self): 24087db96d56Sopenharmony_ci # 1st testcase at end of rfc2047 24097db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?=)' 24107db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24117db96d56Sopenharmony_ci [(b'(', None), (b'a', 'iso-8859-1'), (b')', None)]) 24127db96d56Sopenharmony_ci 24137db96d56Sopenharmony_ci def test_rfc2047_rfc2047_2(self): 24147db96d56Sopenharmony_ci # 2nd testcase at end of rfc2047 24157db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?= b)' 24167db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24177db96d56Sopenharmony_ci [(b'(', None), (b'a', 'iso-8859-1'), (b' b)', None)]) 24187db96d56Sopenharmony_ci 24197db96d56Sopenharmony_ci def test_rfc2047_rfc2047_3(self): 24207db96d56Sopenharmony_ci # 3rd testcase at end of rfc2047 24217db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)' 24227db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24237db96d56Sopenharmony_ci [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) 24247db96d56Sopenharmony_ci 24257db96d56Sopenharmony_ci def test_rfc2047_rfc2047_4(self): 24267db96d56Sopenharmony_ci # 4th testcase at end of rfc2047 24277db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)' 24287db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24297db96d56Sopenharmony_ci [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) 24307db96d56Sopenharmony_ci 24317db96d56Sopenharmony_ci def test_rfc2047_rfc2047_5a(self): 24327db96d56Sopenharmony_ci # 5th testcase at end of rfc2047 newline is \r\n 24337db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?=)' 24347db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24357db96d56Sopenharmony_ci [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) 24367db96d56Sopenharmony_ci 24377db96d56Sopenharmony_ci def test_rfc2047_rfc2047_5b(self): 24387db96d56Sopenharmony_ci # 5th testcase at end of rfc2047 newline is \n 24397db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?=\n =?ISO-8859-1?Q?b?=)' 24407db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24417db96d56Sopenharmony_ci [(b'(', None), (b'ab', 'iso-8859-1'), (b')', None)]) 24427db96d56Sopenharmony_ci 24437db96d56Sopenharmony_ci def test_rfc2047_rfc2047_6(self): 24447db96d56Sopenharmony_ci # 6th testcase at end of rfc2047 24457db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a_b?=)' 24467db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24477db96d56Sopenharmony_ci [(b'(', None), (b'a b', 'iso-8859-1'), (b')', None)]) 24487db96d56Sopenharmony_ci 24497db96d56Sopenharmony_ci def test_rfc2047_rfc2047_7(self): 24507db96d56Sopenharmony_ci # 7th testcase at end of rfc2047 24517db96d56Sopenharmony_ci s = '(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)' 24527db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24537db96d56Sopenharmony_ci [(b'(', None), (b'a', 'iso-8859-1'), (b' b', 'iso-8859-2'), 24547db96d56Sopenharmony_ci (b')', None)]) 24557db96d56Sopenharmony_ci self.assertEqual(make_header(decode_header(s)).encode(), s.lower()) 24567db96d56Sopenharmony_ci self.assertEqual(str(make_header(decode_header(s))), '(a b)') 24577db96d56Sopenharmony_ci 24587db96d56Sopenharmony_ci def test_multiline_header(self): 24597db96d56Sopenharmony_ci s = '=?windows-1252?q?=22M=FCller_T=22?=\r\n <T.Mueller@xxx.com>' 24607db96d56Sopenharmony_ci self.assertEqual(decode_header(s), 24617db96d56Sopenharmony_ci [(b'"M\xfcller T"', 'windows-1252'), 24627db96d56Sopenharmony_ci (b'<T.Mueller@xxx.com>', None)]) 24637db96d56Sopenharmony_ci self.assertEqual(make_header(decode_header(s)).encode(), 24647db96d56Sopenharmony_ci ''.join(s.splitlines())) 24657db96d56Sopenharmony_ci self.assertEqual(str(make_header(decode_header(s))), 24667db96d56Sopenharmony_ci '"Müller T" <T.Mueller@xxx.com>') 24677db96d56Sopenharmony_ci 24687db96d56Sopenharmony_ci 24697db96d56Sopenharmony_ci# Test the MIMEMessage class 24707db96d56Sopenharmony_ciclass TestMIMEMessage(TestEmailBase): 24717db96d56Sopenharmony_ci def setUp(self): 24727db96d56Sopenharmony_ci with openfile('msg_11.txt', encoding="utf-8") as fp: 24737db96d56Sopenharmony_ci self._text = fp.read() 24747db96d56Sopenharmony_ci 24757db96d56Sopenharmony_ci def test_type_error(self): 24767db96d56Sopenharmony_ci self.assertRaises(TypeError, MIMEMessage, 'a plain string') 24777db96d56Sopenharmony_ci 24787db96d56Sopenharmony_ci def test_valid_argument(self): 24797db96d56Sopenharmony_ci eq = self.assertEqual 24807db96d56Sopenharmony_ci subject = 'A sub-message' 24817db96d56Sopenharmony_ci m = Message() 24827db96d56Sopenharmony_ci m['Subject'] = subject 24837db96d56Sopenharmony_ci r = MIMEMessage(m) 24847db96d56Sopenharmony_ci eq(r.get_content_type(), 'message/rfc822') 24857db96d56Sopenharmony_ci payload = r.get_payload() 24867db96d56Sopenharmony_ci self.assertIsInstance(payload, list) 24877db96d56Sopenharmony_ci eq(len(payload), 1) 24887db96d56Sopenharmony_ci subpart = payload[0] 24897db96d56Sopenharmony_ci self.assertIs(subpart, m) 24907db96d56Sopenharmony_ci eq(subpart['subject'], subject) 24917db96d56Sopenharmony_ci 24927db96d56Sopenharmony_ci def test_bad_multipart(self): 24937db96d56Sopenharmony_ci msg1 = Message() 24947db96d56Sopenharmony_ci msg1['Subject'] = 'subpart 1' 24957db96d56Sopenharmony_ci msg2 = Message() 24967db96d56Sopenharmony_ci msg2['Subject'] = 'subpart 2' 24977db96d56Sopenharmony_ci r = MIMEMessage(msg1) 24987db96d56Sopenharmony_ci self.assertRaises(errors.MultipartConversionError, r.attach, msg2) 24997db96d56Sopenharmony_ci 25007db96d56Sopenharmony_ci def test_generate(self): 25017db96d56Sopenharmony_ci # First craft the message to be encapsulated 25027db96d56Sopenharmony_ci m = Message() 25037db96d56Sopenharmony_ci m['Subject'] = 'An enclosed message' 25047db96d56Sopenharmony_ci m.set_payload('Here is the body of the message.\n') 25057db96d56Sopenharmony_ci r = MIMEMessage(m) 25067db96d56Sopenharmony_ci r['Subject'] = 'The enclosing message' 25077db96d56Sopenharmony_ci s = StringIO() 25087db96d56Sopenharmony_ci g = Generator(s) 25097db96d56Sopenharmony_ci g.flatten(r) 25107db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), """\ 25117db96d56Sopenharmony_ciContent-Type: message/rfc822 25127db96d56Sopenharmony_ciMIME-Version: 1.0 25137db96d56Sopenharmony_ciSubject: The enclosing message 25147db96d56Sopenharmony_ci 25157db96d56Sopenharmony_ciSubject: An enclosed message 25167db96d56Sopenharmony_ci 25177db96d56Sopenharmony_ciHere is the body of the message. 25187db96d56Sopenharmony_ci""") 25197db96d56Sopenharmony_ci 25207db96d56Sopenharmony_ci def test_parse_message_rfc822(self): 25217db96d56Sopenharmony_ci eq = self.assertEqual 25227db96d56Sopenharmony_ci msg = self._msgobj('msg_11.txt') 25237db96d56Sopenharmony_ci eq(msg.get_content_type(), 'message/rfc822') 25247db96d56Sopenharmony_ci payload = msg.get_payload() 25257db96d56Sopenharmony_ci self.assertIsInstance(payload, list) 25267db96d56Sopenharmony_ci eq(len(payload), 1) 25277db96d56Sopenharmony_ci submsg = payload[0] 25287db96d56Sopenharmony_ci self.assertIsInstance(submsg, Message) 25297db96d56Sopenharmony_ci eq(submsg['subject'], 'An enclosed message') 25307db96d56Sopenharmony_ci eq(submsg.get_payload(), 'Here is the body of the message.\n') 25317db96d56Sopenharmony_ci 25327db96d56Sopenharmony_ci def test_dsn(self): 25337db96d56Sopenharmony_ci eq = self.assertEqual 25347db96d56Sopenharmony_ci # msg 16 is a Delivery Status Notification, see RFC 1894 25357db96d56Sopenharmony_ci msg = self._msgobj('msg_16.txt') 25367db96d56Sopenharmony_ci eq(msg.get_content_type(), 'multipart/report') 25377db96d56Sopenharmony_ci self.assertTrue(msg.is_multipart()) 25387db96d56Sopenharmony_ci eq(len(msg.get_payload()), 3) 25397db96d56Sopenharmony_ci # Subpart 1 is a text/plain, human readable section 25407db96d56Sopenharmony_ci subpart = msg.get_payload(0) 25417db96d56Sopenharmony_ci eq(subpart.get_content_type(), 'text/plain') 25427db96d56Sopenharmony_ci eq(subpart.get_payload(), """\ 25437db96d56Sopenharmony_ciThis report relates to a message you sent with the following header fields: 25447db96d56Sopenharmony_ci 25457db96d56Sopenharmony_ci Message-id: <002001c144a6$8752e060$56104586@oxy.edu> 25467db96d56Sopenharmony_ci Date: Sun, 23 Sep 2001 20:10:55 -0700 25477db96d56Sopenharmony_ci From: "Ian T. Henry" <henryi@oxy.edu> 25487db96d56Sopenharmony_ci To: SoCal Raves <scr@socal-raves.org> 25497db96d56Sopenharmony_ci Subject: [scr] yeah for Ians!! 25507db96d56Sopenharmony_ci 25517db96d56Sopenharmony_ciYour message cannot be delivered to the following recipients: 25527db96d56Sopenharmony_ci 25537db96d56Sopenharmony_ci Recipient address: jangel1@cougar.noc.ucla.edu 25547db96d56Sopenharmony_ci Reason: recipient reached disk quota 25557db96d56Sopenharmony_ci 25567db96d56Sopenharmony_ci""") 25577db96d56Sopenharmony_ci # Subpart 2 contains the machine parsable DSN information. It 25587db96d56Sopenharmony_ci # consists of two blocks of headers, represented by two nested Message 25597db96d56Sopenharmony_ci # objects. 25607db96d56Sopenharmony_ci subpart = msg.get_payload(1) 25617db96d56Sopenharmony_ci eq(subpart.get_content_type(), 'message/delivery-status') 25627db96d56Sopenharmony_ci eq(len(subpart.get_payload()), 2) 25637db96d56Sopenharmony_ci # message/delivery-status should treat each block as a bunch of 25647db96d56Sopenharmony_ci # headers, i.e. a bunch of Message objects. 25657db96d56Sopenharmony_ci dsn1 = subpart.get_payload(0) 25667db96d56Sopenharmony_ci self.assertIsInstance(dsn1, Message) 25677db96d56Sopenharmony_ci eq(dsn1['original-envelope-id'], '0GK500B4HD0888@cougar.noc.ucla.edu') 25687db96d56Sopenharmony_ci eq(dsn1.get_param('dns', header='reporting-mta'), '') 25697db96d56Sopenharmony_ci # Try a missing one <wink> 25707db96d56Sopenharmony_ci eq(dsn1.get_param('nsd', header='reporting-mta'), None) 25717db96d56Sopenharmony_ci dsn2 = subpart.get_payload(1) 25727db96d56Sopenharmony_ci self.assertIsInstance(dsn2, Message) 25737db96d56Sopenharmony_ci eq(dsn2['action'], 'failed') 25747db96d56Sopenharmony_ci eq(dsn2.get_params(header='original-recipient'), 25757db96d56Sopenharmony_ci [('rfc822', ''), ('jangel1@cougar.noc.ucla.edu', '')]) 25767db96d56Sopenharmony_ci eq(dsn2.get_param('rfc822', header='final-recipient'), '') 25777db96d56Sopenharmony_ci # Subpart 3 is the original message 25787db96d56Sopenharmony_ci subpart = msg.get_payload(2) 25797db96d56Sopenharmony_ci eq(subpart.get_content_type(), 'message/rfc822') 25807db96d56Sopenharmony_ci payload = subpart.get_payload() 25817db96d56Sopenharmony_ci self.assertIsInstance(payload, list) 25827db96d56Sopenharmony_ci eq(len(payload), 1) 25837db96d56Sopenharmony_ci subsubpart = payload[0] 25847db96d56Sopenharmony_ci self.assertIsInstance(subsubpart, Message) 25857db96d56Sopenharmony_ci eq(subsubpart.get_content_type(), 'text/plain') 25867db96d56Sopenharmony_ci eq(subsubpart['message-id'], 25877db96d56Sopenharmony_ci '<002001c144a6$8752e060$56104586@oxy.edu>') 25887db96d56Sopenharmony_ci 25897db96d56Sopenharmony_ci def test_epilogue(self): 25907db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 25917db96d56Sopenharmony_ci with openfile('msg_21.txt', encoding="utf-8") as fp: 25927db96d56Sopenharmony_ci text = fp.read() 25937db96d56Sopenharmony_ci msg = Message() 25947db96d56Sopenharmony_ci msg['From'] = 'aperson@dom.ain' 25957db96d56Sopenharmony_ci msg['To'] = 'bperson@dom.ain' 25967db96d56Sopenharmony_ci msg['Subject'] = 'Test' 25977db96d56Sopenharmony_ci msg.preamble = 'MIME message' 25987db96d56Sopenharmony_ci msg.epilogue = 'End of MIME message\n' 25997db96d56Sopenharmony_ci msg1 = MIMEText('One') 26007db96d56Sopenharmony_ci msg2 = MIMEText('Two') 26017db96d56Sopenharmony_ci msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY') 26027db96d56Sopenharmony_ci msg.attach(msg1) 26037db96d56Sopenharmony_ci msg.attach(msg2) 26047db96d56Sopenharmony_ci sfp = StringIO() 26057db96d56Sopenharmony_ci g = Generator(sfp) 26067db96d56Sopenharmony_ci g.flatten(msg) 26077db96d56Sopenharmony_ci eq(sfp.getvalue(), text) 26087db96d56Sopenharmony_ci 26097db96d56Sopenharmony_ci def test_no_nl_preamble(self): 26107db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 26117db96d56Sopenharmony_ci msg = Message() 26127db96d56Sopenharmony_ci msg['From'] = 'aperson@dom.ain' 26137db96d56Sopenharmony_ci msg['To'] = 'bperson@dom.ain' 26147db96d56Sopenharmony_ci msg['Subject'] = 'Test' 26157db96d56Sopenharmony_ci msg.preamble = 'MIME message' 26167db96d56Sopenharmony_ci msg.epilogue = '' 26177db96d56Sopenharmony_ci msg1 = MIMEText('One') 26187db96d56Sopenharmony_ci msg2 = MIMEText('Two') 26197db96d56Sopenharmony_ci msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY') 26207db96d56Sopenharmony_ci msg.attach(msg1) 26217db96d56Sopenharmony_ci msg.attach(msg2) 26227db96d56Sopenharmony_ci eq(msg.as_string(), """\ 26237db96d56Sopenharmony_ciFrom: aperson@dom.ain 26247db96d56Sopenharmony_ciTo: bperson@dom.ain 26257db96d56Sopenharmony_ciSubject: Test 26267db96d56Sopenharmony_ciContent-Type: multipart/mixed; boundary="BOUNDARY" 26277db96d56Sopenharmony_ci 26287db96d56Sopenharmony_ciMIME message 26297db96d56Sopenharmony_ci--BOUNDARY 26307db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 26317db96d56Sopenharmony_ciMIME-Version: 1.0 26327db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 26337db96d56Sopenharmony_ci 26347db96d56Sopenharmony_ciOne 26357db96d56Sopenharmony_ci--BOUNDARY 26367db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 26377db96d56Sopenharmony_ciMIME-Version: 1.0 26387db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 26397db96d56Sopenharmony_ci 26407db96d56Sopenharmony_ciTwo 26417db96d56Sopenharmony_ci--BOUNDARY-- 26427db96d56Sopenharmony_ci""") 26437db96d56Sopenharmony_ci 26447db96d56Sopenharmony_ci def test_default_type(self): 26457db96d56Sopenharmony_ci eq = self.assertEqual 26467db96d56Sopenharmony_ci with openfile('msg_30.txt', encoding="utf-8") as fp: 26477db96d56Sopenharmony_ci msg = email.message_from_file(fp) 26487db96d56Sopenharmony_ci container1 = msg.get_payload(0) 26497db96d56Sopenharmony_ci eq(container1.get_default_type(), 'message/rfc822') 26507db96d56Sopenharmony_ci eq(container1.get_content_type(), 'message/rfc822') 26517db96d56Sopenharmony_ci container2 = msg.get_payload(1) 26527db96d56Sopenharmony_ci eq(container2.get_default_type(), 'message/rfc822') 26537db96d56Sopenharmony_ci eq(container2.get_content_type(), 'message/rfc822') 26547db96d56Sopenharmony_ci container1a = container1.get_payload(0) 26557db96d56Sopenharmony_ci eq(container1a.get_default_type(), 'text/plain') 26567db96d56Sopenharmony_ci eq(container1a.get_content_type(), 'text/plain') 26577db96d56Sopenharmony_ci container2a = container2.get_payload(0) 26587db96d56Sopenharmony_ci eq(container2a.get_default_type(), 'text/plain') 26597db96d56Sopenharmony_ci eq(container2a.get_content_type(), 'text/plain') 26607db96d56Sopenharmony_ci 26617db96d56Sopenharmony_ci def test_default_type_with_explicit_container_type(self): 26627db96d56Sopenharmony_ci eq = self.assertEqual 26637db96d56Sopenharmony_ci with openfile('msg_28.txt', encoding="utf-8") as fp: 26647db96d56Sopenharmony_ci msg = email.message_from_file(fp) 26657db96d56Sopenharmony_ci container1 = msg.get_payload(0) 26667db96d56Sopenharmony_ci eq(container1.get_default_type(), 'message/rfc822') 26677db96d56Sopenharmony_ci eq(container1.get_content_type(), 'message/rfc822') 26687db96d56Sopenharmony_ci container2 = msg.get_payload(1) 26697db96d56Sopenharmony_ci eq(container2.get_default_type(), 'message/rfc822') 26707db96d56Sopenharmony_ci eq(container2.get_content_type(), 'message/rfc822') 26717db96d56Sopenharmony_ci container1a = container1.get_payload(0) 26727db96d56Sopenharmony_ci eq(container1a.get_default_type(), 'text/plain') 26737db96d56Sopenharmony_ci eq(container1a.get_content_type(), 'text/plain') 26747db96d56Sopenharmony_ci container2a = container2.get_payload(0) 26757db96d56Sopenharmony_ci eq(container2a.get_default_type(), 'text/plain') 26767db96d56Sopenharmony_ci eq(container2a.get_content_type(), 'text/plain') 26777db96d56Sopenharmony_ci 26787db96d56Sopenharmony_ci def test_default_type_non_parsed(self): 26797db96d56Sopenharmony_ci eq = self.assertEqual 26807db96d56Sopenharmony_ci neq = self.ndiffAssertEqual 26817db96d56Sopenharmony_ci # Set up container 26827db96d56Sopenharmony_ci container = MIMEMultipart('digest', 'BOUNDARY') 26837db96d56Sopenharmony_ci container.epilogue = '' 26847db96d56Sopenharmony_ci # Set up subparts 26857db96d56Sopenharmony_ci subpart1a = MIMEText('message 1\n') 26867db96d56Sopenharmony_ci subpart2a = MIMEText('message 2\n') 26877db96d56Sopenharmony_ci subpart1 = MIMEMessage(subpart1a) 26887db96d56Sopenharmony_ci subpart2 = MIMEMessage(subpart2a) 26897db96d56Sopenharmony_ci container.attach(subpart1) 26907db96d56Sopenharmony_ci container.attach(subpart2) 26917db96d56Sopenharmony_ci eq(subpart1.get_content_type(), 'message/rfc822') 26927db96d56Sopenharmony_ci eq(subpart1.get_default_type(), 'message/rfc822') 26937db96d56Sopenharmony_ci eq(subpart2.get_content_type(), 'message/rfc822') 26947db96d56Sopenharmony_ci eq(subpart2.get_default_type(), 'message/rfc822') 26957db96d56Sopenharmony_ci neq(container.as_string(0), '''\ 26967db96d56Sopenharmony_ciContent-Type: multipart/digest; boundary="BOUNDARY" 26977db96d56Sopenharmony_ciMIME-Version: 1.0 26987db96d56Sopenharmony_ci 26997db96d56Sopenharmony_ci--BOUNDARY 27007db96d56Sopenharmony_ciContent-Type: message/rfc822 27017db96d56Sopenharmony_ciMIME-Version: 1.0 27027db96d56Sopenharmony_ci 27037db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 27047db96d56Sopenharmony_ciMIME-Version: 1.0 27057db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 27067db96d56Sopenharmony_ci 27077db96d56Sopenharmony_cimessage 1 27087db96d56Sopenharmony_ci 27097db96d56Sopenharmony_ci--BOUNDARY 27107db96d56Sopenharmony_ciContent-Type: message/rfc822 27117db96d56Sopenharmony_ciMIME-Version: 1.0 27127db96d56Sopenharmony_ci 27137db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 27147db96d56Sopenharmony_ciMIME-Version: 1.0 27157db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 27167db96d56Sopenharmony_ci 27177db96d56Sopenharmony_cimessage 2 27187db96d56Sopenharmony_ci 27197db96d56Sopenharmony_ci--BOUNDARY-- 27207db96d56Sopenharmony_ci''') 27217db96d56Sopenharmony_ci del subpart1['content-type'] 27227db96d56Sopenharmony_ci del subpart1['mime-version'] 27237db96d56Sopenharmony_ci del subpart2['content-type'] 27247db96d56Sopenharmony_ci del subpart2['mime-version'] 27257db96d56Sopenharmony_ci eq(subpart1.get_content_type(), 'message/rfc822') 27267db96d56Sopenharmony_ci eq(subpart1.get_default_type(), 'message/rfc822') 27277db96d56Sopenharmony_ci eq(subpart2.get_content_type(), 'message/rfc822') 27287db96d56Sopenharmony_ci eq(subpart2.get_default_type(), 'message/rfc822') 27297db96d56Sopenharmony_ci neq(container.as_string(0), '''\ 27307db96d56Sopenharmony_ciContent-Type: multipart/digest; boundary="BOUNDARY" 27317db96d56Sopenharmony_ciMIME-Version: 1.0 27327db96d56Sopenharmony_ci 27337db96d56Sopenharmony_ci--BOUNDARY 27347db96d56Sopenharmony_ci 27357db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 27367db96d56Sopenharmony_ciMIME-Version: 1.0 27377db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 27387db96d56Sopenharmony_ci 27397db96d56Sopenharmony_cimessage 1 27407db96d56Sopenharmony_ci 27417db96d56Sopenharmony_ci--BOUNDARY 27427db96d56Sopenharmony_ci 27437db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii" 27447db96d56Sopenharmony_ciMIME-Version: 1.0 27457db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 27467db96d56Sopenharmony_ci 27477db96d56Sopenharmony_cimessage 2 27487db96d56Sopenharmony_ci 27497db96d56Sopenharmony_ci--BOUNDARY-- 27507db96d56Sopenharmony_ci''') 27517db96d56Sopenharmony_ci 27527db96d56Sopenharmony_ci def test_mime_attachments_in_constructor(self): 27537db96d56Sopenharmony_ci eq = self.assertEqual 27547db96d56Sopenharmony_ci text1 = MIMEText('') 27557db96d56Sopenharmony_ci text2 = MIMEText('') 27567db96d56Sopenharmony_ci msg = MIMEMultipart(_subparts=(text1, text2)) 27577db96d56Sopenharmony_ci eq(len(msg.get_payload()), 2) 27587db96d56Sopenharmony_ci eq(msg.get_payload(0), text1) 27597db96d56Sopenharmony_ci eq(msg.get_payload(1), text2) 27607db96d56Sopenharmony_ci 27617db96d56Sopenharmony_ci def test_default_multipart_constructor(self): 27627db96d56Sopenharmony_ci msg = MIMEMultipart() 27637db96d56Sopenharmony_ci self.assertTrue(msg.is_multipart()) 27647db96d56Sopenharmony_ci 27657db96d56Sopenharmony_ci def test_multipart_default_policy(self): 27667db96d56Sopenharmony_ci msg = MIMEMultipart() 27677db96d56Sopenharmony_ci msg['To'] = 'a@b.com' 27687db96d56Sopenharmony_ci msg['To'] = 'c@d.com' 27697db96d56Sopenharmony_ci self.assertEqual(msg.get_all('to'), ['a@b.com', 'c@d.com']) 27707db96d56Sopenharmony_ci 27717db96d56Sopenharmony_ci def test_multipart_custom_policy(self): 27727db96d56Sopenharmony_ci msg = MIMEMultipart(policy=email.policy.default) 27737db96d56Sopenharmony_ci msg['To'] = 'a@b.com' 27747db96d56Sopenharmony_ci with self.assertRaises(ValueError) as cm: 27757db96d56Sopenharmony_ci msg['To'] = 'c@d.com' 27767db96d56Sopenharmony_ci self.assertEqual(str(cm.exception), 27777db96d56Sopenharmony_ci 'There may be at most 1 To headers in a message') 27787db96d56Sopenharmony_ci 27797db96d56Sopenharmony_ci 27807db96d56Sopenharmony_ci# Test the NonMultipart class 27817db96d56Sopenharmony_ciclass TestNonMultipart(TestEmailBase): 27827db96d56Sopenharmony_ci def test_nonmultipart_is_not_multipart(self): 27837db96d56Sopenharmony_ci msg = MIMENonMultipart('text', 'plain') 27847db96d56Sopenharmony_ci self.assertFalse(msg.is_multipart()) 27857db96d56Sopenharmony_ci 27867db96d56Sopenharmony_ci def test_attach_raises_exception(self): 27877db96d56Sopenharmony_ci msg = Message() 27887db96d56Sopenharmony_ci msg['Subject'] = 'subpart 1' 27897db96d56Sopenharmony_ci r = MIMENonMultipart('text', 'plain') 27907db96d56Sopenharmony_ci self.assertRaises(errors.MultipartConversionError, r.attach, msg) 27917db96d56Sopenharmony_ci 27927db96d56Sopenharmony_ci 27937db96d56Sopenharmony_ci# A general test of parser->model->generator idempotency. IOW, read a message 27947db96d56Sopenharmony_ci# in, parse it into a message object tree, then without touching the tree, 27957db96d56Sopenharmony_ci# regenerate the plain text. The original text and the transformed text 27967db96d56Sopenharmony_ci# should be identical. Note: that we ignore the Unix-From since that may 27977db96d56Sopenharmony_ci# contain a changed date. 27987db96d56Sopenharmony_ciclass TestIdempotent(TestEmailBase): 27997db96d56Sopenharmony_ci 28007db96d56Sopenharmony_ci linesep = '\n' 28017db96d56Sopenharmony_ci 28027db96d56Sopenharmony_ci def _msgobj(self, filename): 28037db96d56Sopenharmony_ci with openfile(filename, encoding="utf-8") as fp: 28047db96d56Sopenharmony_ci data = fp.read() 28057db96d56Sopenharmony_ci msg = email.message_from_string(data) 28067db96d56Sopenharmony_ci return msg, data 28077db96d56Sopenharmony_ci 28087db96d56Sopenharmony_ci def _idempotent(self, msg, text, unixfrom=False): 28097db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 28107db96d56Sopenharmony_ci s = StringIO() 28117db96d56Sopenharmony_ci g = Generator(s, maxheaderlen=0) 28127db96d56Sopenharmony_ci g.flatten(msg, unixfrom=unixfrom) 28137db96d56Sopenharmony_ci eq(text, s.getvalue()) 28147db96d56Sopenharmony_ci 28157db96d56Sopenharmony_ci def test_parse_text_message(self): 28167db96d56Sopenharmony_ci eq = self.assertEqual 28177db96d56Sopenharmony_ci msg, text = self._msgobj('msg_01.txt') 28187db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 28197db96d56Sopenharmony_ci eq(msg.get_content_maintype(), 'text') 28207db96d56Sopenharmony_ci eq(msg.get_content_subtype(), 'plain') 28217db96d56Sopenharmony_ci eq(msg.get_params()[1], ('charset', 'us-ascii')) 28227db96d56Sopenharmony_ci eq(msg.get_param('charset'), 'us-ascii') 28237db96d56Sopenharmony_ci eq(msg.preamble, None) 28247db96d56Sopenharmony_ci eq(msg.epilogue, None) 28257db96d56Sopenharmony_ci self._idempotent(msg, text) 28267db96d56Sopenharmony_ci 28277db96d56Sopenharmony_ci def test_parse_untyped_message(self): 28287db96d56Sopenharmony_ci eq = self.assertEqual 28297db96d56Sopenharmony_ci msg, text = self._msgobj('msg_03.txt') 28307db96d56Sopenharmony_ci eq(msg.get_content_type(), 'text/plain') 28317db96d56Sopenharmony_ci eq(msg.get_params(), None) 28327db96d56Sopenharmony_ci eq(msg.get_param('charset'), None) 28337db96d56Sopenharmony_ci self._idempotent(msg, text) 28347db96d56Sopenharmony_ci 28357db96d56Sopenharmony_ci def test_simple_multipart(self): 28367db96d56Sopenharmony_ci msg, text = self._msgobj('msg_04.txt') 28377db96d56Sopenharmony_ci self._idempotent(msg, text) 28387db96d56Sopenharmony_ci 28397db96d56Sopenharmony_ci def test_MIME_digest(self): 28407db96d56Sopenharmony_ci msg, text = self._msgobj('msg_02.txt') 28417db96d56Sopenharmony_ci self._idempotent(msg, text) 28427db96d56Sopenharmony_ci 28437db96d56Sopenharmony_ci def test_long_header(self): 28447db96d56Sopenharmony_ci msg, text = self._msgobj('msg_27.txt') 28457db96d56Sopenharmony_ci self._idempotent(msg, text) 28467db96d56Sopenharmony_ci 28477db96d56Sopenharmony_ci def test_MIME_digest_with_part_headers(self): 28487db96d56Sopenharmony_ci msg, text = self._msgobj('msg_28.txt') 28497db96d56Sopenharmony_ci self._idempotent(msg, text) 28507db96d56Sopenharmony_ci 28517db96d56Sopenharmony_ci def test_mixed_with_image(self): 28527db96d56Sopenharmony_ci msg, text = self._msgobj('msg_06.txt') 28537db96d56Sopenharmony_ci self._idempotent(msg, text) 28547db96d56Sopenharmony_ci 28557db96d56Sopenharmony_ci def test_multipart_report(self): 28567db96d56Sopenharmony_ci msg, text = self._msgobj('msg_05.txt') 28577db96d56Sopenharmony_ci self._idempotent(msg, text) 28587db96d56Sopenharmony_ci 28597db96d56Sopenharmony_ci def test_dsn(self): 28607db96d56Sopenharmony_ci msg, text = self._msgobj('msg_16.txt') 28617db96d56Sopenharmony_ci self._idempotent(msg, text) 28627db96d56Sopenharmony_ci 28637db96d56Sopenharmony_ci def test_preamble_epilogue(self): 28647db96d56Sopenharmony_ci msg, text = self._msgobj('msg_21.txt') 28657db96d56Sopenharmony_ci self._idempotent(msg, text) 28667db96d56Sopenharmony_ci 28677db96d56Sopenharmony_ci def test_multipart_one_part(self): 28687db96d56Sopenharmony_ci msg, text = self._msgobj('msg_23.txt') 28697db96d56Sopenharmony_ci self._idempotent(msg, text) 28707db96d56Sopenharmony_ci 28717db96d56Sopenharmony_ci def test_multipart_no_parts(self): 28727db96d56Sopenharmony_ci msg, text = self._msgobj('msg_24.txt') 28737db96d56Sopenharmony_ci self._idempotent(msg, text) 28747db96d56Sopenharmony_ci 28757db96d56Sopenharmony_ci def test_no_start_boundary(self): 28767db96d56Sopenharmony_ci msg, text = self._msgobj('msg_31.txt') 28777db96d56Sopenharmony_ci self._idempotent(msg, text) 28787db96d56Sopenharmony_ci 28797db96d56Sopenharmony_ci def test_rfc2231_charset(self): 28807db96d56Sopenharmony_ci msg, text = self._msgobj('msg_32.txt') 28817db96d56Sopenharmony_ci self._idempotent(msg, text) 28827db96d56Sopenharmony_ci 28837db96d56Sopenharmony_ci def test_more_rfc2231_parameters(self): 28847db96d56Sopenharmony_ci msg, text = self._msgobj('msg_33.txt') 28857db96d56Sopenharmony_ci self._idempotent(msg, text) 28867db96d56Sopenharmony_ci 28877db96d56Sopenharmony_ci def test_text_plain_in_a_multipart_digest(self): 28887db96d56Sopenharmony_ci msg, text = self._msgobj('msg_34.txt') 28897db96d56Sopenharmony_ci self._idempotent(msg, text) 28907db96d56Sopenharmony_ci 28917db96d56Sopenharmony_ci def test_nested_multipart_mixeds(self): 28927db96d56Sopenharmony_ci msg, text = self._msgobj('msg_12a.txt') 28937db96d56Sopenharmony_ci self._idempotent(msg, text) 28947db96d56Sopenharmony_ci 28957db96d56Sopenharmony_ci def test_message_external_body_idempotent(self): 28967db96d56Sopenharmony_ci msg, text = self._msgobj('msg_36.txt') 28977db96d56Sopenharmony_ci self._idempotent(msg, text) 28987db96d56Sopenharmony_ci 28997db96d56Sopenharmony_ci def test_message_delivery_status(self): 29007db96d56Sopenharmony_ci msg, text = self._msgobj('msg_43.txt') 29017db96d56Sopenharmony_ci self._idempotent(msg, text, unixfrom=True) 29027db96d56Sopenharmony_ci 29037db96d56Sopenharmony_ci def test_message_signed_idempotent(self): 29047db96d56Sopenharmony_ci msg, text = self._msgobj('msg_45.txt') 29057db96d56Sopenharmony_ci self._idempotent(msg, text) 29067db96d56Sopenharmony_ci 29077db96d56Sopenharmony_ci def test_content_type(self): 29087db96d56Sopenharmony_ci eq = self.assertEqual 29097db96d56Sopenharmony_ci # Get a message object and reset the seek pointer for other tests 29107db96d56Sopenharmony_ci msg, text = self._msgobj('msg_05.txt') 29117db96d56Sopenharmony_ci eq(msg.get_content_type(), 'multipart/report') 29127db96d56Sopenharmony_ci # Test the Content-Type: parameters 29137db96d56Sopenharmony_ci params = {} 29147db96d56Sopenharmony_ci for pk, pv in msg.get_params(): 29157db96d56Sopenharmony_ci params[pk] = pv 29167db96d56Sopenharmony_ci eq(params['report-type'], 'delivery-status') 29177db96d56Sopenharmony_ci eq(params['boundary'], 'D1690A7AC1.996856090/mail.example.com') 29187db96d56Sopenharmony_ci eq(msg.preamble, 'This is a MIME-encapsulated message.' + self.linesep) 29197db96d56Sopenharmony_ci eq(msg.epilogue, self.linesep) 29207db96d56Sopenharmony_ci eq(len(msg.get_payload()), 3) 29217db96d56Sopenharmony_ci # Make sure the subparts are what we expect 29227db96d56Sopenharmony_ci msg1 = msg.get_payload(0) 29237db96d56Sopenharmony_ci eq(msg1.get_content_type(), 'text/plain') 29247db96d56Sopenharmony_ci eq(msg1.get_payload(), 'Yadda yadda yadda' + self.linesep) 29257db96d56Sopenharmony_ci msg2 = msg.get_payload(1) 29267db96d56Sopenharmony_ci eq(msg2.get_content_type(), 'text/plain') 29277db96d56Sopenharmony_ci eq(msg2.get_payload(), 'Yadda yadda yadda' + self.linesep) 29287db96d56Sopenharmony_ci msg3 = msg.get_payload(2) 29297db96d56Sopenharmony_ci eq(msg3.get_content_type(), 'message/rfc822') 29307db96d56Sopenharmony_ci self.assertIsInstance(msg3, Message) 29317db96d56Sopenharmony_ci payload = msg3.get_payload() 29327db96d56Sopenharmony_ci self.assertIsInstance(payload, list) 29337db96d56Sopenharmony_ci eq(len(payload), 1) 29347db96d56Sopenharmony_ci msg4 = payload[0] 29357db96d56Sopenharmony_ci self.assertIsInstance(msg4, Message) 29367db96d56Sopenharmony_ci eq(msg4.get_payload(), 'Yadda yadda yadda' + self.linesep) 29377db96d56Sopenharmony_ci 29387db96d56Sopenharmony_ci def test_parser(self): 29397db96d56Sopenharmony_ci eq = self.assertEqual 29407db96d56Sopenharmony_ci msg, text = self._msgobj('msg_06.txt') 29417db96d56Sopenharmony_ci # Check some of the outer headers 29427db96d56Sopenharmony_ci eq(msg.get_content_type(), 'message/rfc822') 29437db96d56Sopenharmony_ci # Make sure the payload is a list of exactly one sub-Message, and that 29447db96d56Sopenharmony_ci # that submessage has a type of text/plain 29457db96d56Sopenharmony_ci payload = msg.get_payload() 29467db96d56Sopenharmony_ci self.assertIsInstance(payload, list) 29477db96d56Sopenharmony_ci eq(len(payload), 1) 29487db96d56Sopenharmony_ci msg1 = payload[0] 29497db96d56Sopenharmony_ci self.assertIsInstance(msg1, Message) 29507db96d56Sopenharmony_ci eq(msg1.get_content_type(), 'text/plain') 29517db96d56Sopenharmony_ci self.assertIsInstance(msg1.get_payload(), str) 29527db96d56Sopenharmony_ci eq(msg1.get_payload(), self.linesep) 29537db96d56Sopenharmony_ci 29547db96d56Sopenharmony_ci 29557db96d56Sopenharmony_ci 29567db96d56Sopenharmony_ci# Test various other bits of the package's functionality 29577db96d56Sopenharmony_ciclass TestMiscellaneous(TestEmailBase): 29587db96d56Sopenharmony_ci def test_message_from_string(self): 29597db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 29607db96d56Sopenharmony_ci text = fp.read() 29617db96d56Sopenharmony_ci msg = email.message_from_string(text) 29627db96d56Sopenharmony_ci s = StringIO() 29637db96d56Sopenharmony_ci # Don't wrap/continue long headers since we're trying to test 29647db96d56Sopenharmony_ci # idempotency. 29657db96d56Sopenharmony_ci g = Generator(s, maxheaderlen=0) 29667db96d56Sopenharmony_ci g.flatten(msg) 29677db96d56Sopenharmony_ci self.assertEqual(text, s.getvalue()) 29687db96d56Sopenharmony_ci 29697db96d56Sopenharmony_ci def test_message_from_file(self): 29707db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 29717db96d56Sopenharmony_ci text = fp.read() 29727db96d56Sopenharmony_ci fp.seek(0) 29737db96d56Sopenharmony_ci msg = email.message_from_file(fp) 29747db96d56Sopenharmony_ci s = StringIO() 29757db96d56Sopenharmony_ci # Don't wrap/continue long headers since we're trying to test 29767db96d56Sopenharmony_ci # idempotency. 29777db96d56Sopenharmony_ci g = Generator(s, maxheaderlen=0) 29787db96d56Sopenharmony_ci g.flatten(msg) 29797db96d56Sopenharmony_ci self.assertEqual(text, s.getvalue()) 29807db96d56Sopenharmony_ci 29817db96d56Sopenharmony_ci def test_message_from_string_with_class(self): 29827db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 29837db96d56Sopenharmony_ci text = fp.read() 29847db96d56Sopenharmony_ci 29857db96d56Sopenharmony_ci # Create a subclass 29867db96d56Sopenharmony_ci class MyMessage(Message): 29877db96d56Sopenharmony_ci pass 29887db96d56Sopenharmony_ci 29897db96d56Sopenharmony_ci msg = email.message_from_string(text, MyMessage) 29907db96d56Sopenharmony_ci self.assertIsInstance(msg, MyMessage) 29917db96d56Sopenharmony_ci # Try something more complicated 29927db96d56Sopenharmony_ci with openfile('msg_02.txt', encoding="utf-8") as fp: 29937db96d56Sopenharmony_ci text = fp.read() 29947db96d56Sopenharmony_ci msg = email.message_from_string(text, MyMessage) 29957db96d56Sopenharmony_ci for subpart in msg.walk(): 29967db96d56Sopenharmony_ci self.assertIsInstance(subpart, MyMessage) 29977db96d56Sopenharmony_ci 29987db96d56Sopenharmony_ci def test_message_from_file_with_class(self): 29997db96d56Sopenharmony_ci # Create a subclass 30007db96d56Sopenharmony_ci class MyMessage(Message): 30017db96d56Sopenharmony_ci pass 30027db96d56Sopenharmony_ci 30037db96d56Sopenharmony_ci with openfile('msg_01.txt', encoding="utf-8") as fp: 30047db96d56Sopenharmony_ci msg = email.message_from_file(fp, MyMessage) 30057db96d56Sopenharmony_ci self.assertIsInstance(msg, MyMessage) 30067db96d56Sopenharmony_ci # Try something more complicated 30077db96d56Sopenharmony_ci with openfile('msg_02.txt', encoding="utf-8") as fp: 30087db96d56Sopenharmony_ci msg = email.message_from_file(fp, MyMessage) 30097db96d56Sopenharmony_ci for subpart in msg.walk(): 30107db96d56Sopenharmony_ci self.assertIsInstance(subpart, MyMessage) 30117db96d56Sopenharmony_ci 30127db96d56Sopenharmony_ci def test_custom_message_does_not_require_arguments(self): 30137db96d56Sopenharmony_ci class MyMessage(Message): 30147db96d56Sopenharmony_ci def __init__(self): 30157db96d56Sopenharmony_ci super().__init__() 30167db96d56Sopenharmony_ci msg = self._str_msg("Subject: test\n\ntest", MyMessage) 30177db96d56Sopenharmony_ci self.assertIsInstance(msg, MyMessage) 30187db96d56Sopenharmony_ci 30197db96d56Sopenharmony_ci def test__all__(self): 30207db96d56Sopenharmony_ci module = __import__('email') 30217db96d56Sopenharmony_ci self.assertEqual(sorted(module.__all__), [ 30227db96d56Sopenharmony_ci 'base64mime', 'charset', 'encoders', 'errors', 'feedparser', 30237db96d56Sopenharmony_ci 'generator', 'header', 'iterators', 'message', 30247db96d56Sopenharmony_ci 'message_from_binary_file', 'message_from_bytes', 30257db96d56Sopenharmony_ci 'message_from_file', 'message_from_string', 'mime', 'parser', 30267db96d56Sopenharmony_ci 'quoprimime', 'utils', 30277db96d56Sopenharmony_ci ]) 30287db96d56Sopenharmony_ci 30297db96d56Sopenharmony_ci def test_formatdate(self): 30307db96d56Sopenharmony_ci now = time.time() 30317db96d56Sopenharmony_ci self.assertEqual(utils.parsedate(utils.formatdate(now))[:6], 30327db96d56Sopenharmony_ci time.gmtime(now)[:6]) 30337db96d56Sopenharmony_ci 30347db96d56Sopenharmony_ci def test_formatdate_localtime(self): 30357db96d56Sopenharmony_ci now = time.time() 30367db96d56Sopenharmony_ci self.assertEqual( 30377db96d56Sopenharmony_ci utils.parsedate(utils.formatdate(now, localtime=True))[:6], 30387db96d56Sopenharmony_ci time.localtime(now)[:6]) 30397db96d56Sopenharmony_ci 30407db96d56Sopenharmony_ci def test_formatdate_usegmt(self): 30417db96d56Sopenharmony_ci now = time.time() 30427db96d56Sopenharmony_ci self.assertEqual( 30437db96d56Sopenharmony_ci utils.formatdate(now, localtime=False), 30447db96d56Sopenharmony_ci time.strftime('%a, %d %b %Y %H:%M:%S -0000', time.gmtime(now))) 30457db96d56Sopenharmony_ci self.assertEqual( 30467db96d56Sopenharmony_ci utils.formatdate(now, localtime=False, usegmt=True), 30477db96d56Sopenharmony_ci time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(now))) 30487db96d56Sopenharmony_ci 30497db96d56Sopenharmony_ci # parsedate and parsedate_tz will become deprecated interfaces someday 30507db96d56Sopenharmony_ci def test_parsedate_returns_None_for_invalid_strings(self): 30517db96d56Sopenharmony_ci # See also test_parsedate_to_datetime_with_invalid_raises_valueerror 30527db96d56Sopenharmony_ci # in test_utils. 30537db96d56Sopenharmony_ci invalid_dates = [ 30547db96d56Sopenharmony_ci '', 30557db96d56Sopenharmony_ci ' ', 30567db96d56Sopenharmony_ci '0', 30577db96d56Sopenharmony_ci 'A Complete Waste of Time', 30587db96d56Sopenharmony_ci 'Wed, 3 Apr 2002 12.34.56.78+0800', 30597db96d56Sopenharmony_ci '17 June , 2022', 30607db96d56Sopenharmony_ci 'Friday, -Nov-82 16:14:55 EST', 30617db96d56Sopenharmony_ci 'Friday, Nov--82 16:14:55 EST', 30627db96d56Sopenharmony_ci 'Friday, 19-Nov- 16:14:55 EST', 30637db96d56Sopenharmony_ci ] 30647db96d56Sopenharmony_ci for dtstr in invalid_dates: 30657db96d56Sopenharmony_ci with self.subTest(dtstr=dtstr): 30667db96d56Sopenharmony_ci self.assertIsNone(utils.parsedate(dtstr)) 30677db96d56Sopenharmony_ci self.assertIsNone(utils.parsedate_tz(dtstr)) 30687db96d56Sopenharmony_ci # Not a part of the spec but, but this has historically worked: 30697db96d56Sopenharmony_ci self.assertIsNone(utils.parsedate(None)) 30707db96d56Sopenharmony_ci self.assertIsNone(utils.parsedate_tz(None)) 30717db96d56Sopenharmony_ci 30727db96d56Sopenharmony_ci def test_parsedate_compact(self): 30737db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26 +0800'), 30747db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800)) 30757db96d56Sopenharmony_ci # The FWS after the comma is optional 30767db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed,3 Apr 2002 14:58:26 +0800'), 30777db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800)) 30787db96d56Sopenharmony_ci # The comma is optional 30797db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed 3 Apr 2002 14:58:26 +0800'), 30807db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800)) 30817db96d56Sopenharmony_ci 30827db96d56Sopenharmony_ci def test_parsedate_no_dayofweek(self): 30837db96d56Sopenharmony_ci eq = self.assertEqual 30847db96d56Sopenharmony_ci eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'), 30857db96d56Sopenharmony_ci (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800)) 30867db96d56Sopenharmony_ci eq(utils.parsedate_tz('February 5, 2003 13:47:26 -0800'), 30877db96d56Sopenharmony_ci (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800)) 30887db96d56Sopenharmony_ci 30897db96d56Sopenharmony_ci def test_parsedate_no_space_before_positive_offset(self): 30907db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'), 30917db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800)) 30927db96d56Sopenharmony_ci 30937db96d56Sopenharmony_ci def test_parsedate_no_space_before_negative_offset(self): 30947db96d56Sopenharmony_ci # Issue 1155362: we already handled '+' for this case. 30957db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26-0800'), 30967db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, -28800)) 30977db96d56Sopenharmony_ci 30987db96d56Sopenharmony_ci def test_parsedate_accepts_time_with_dots(self): 30997db96d56Sopenharmony_ci eq = self.assertEqual 31007db96d56Sopenharmony_ci eq(utils.parsedate_tz('5 Feb 2003 13.47.26 -0800'), 31017db96d56Sopenharmony_ci (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800)) 31027db96d56Sopenharmony_ci eq(utils.parsedate_tz('5 Feb 2003 13.47 -0800'), 31037db96d56Sopenharmony_ci (2003, 2, 5, 13, 47, 0, 0, 1, -1, -28800)) 31047db96d56Sopenharmony_ci 31057db96d56Sopenharmony_ci def test_parsedate_rfc_850(self): 31067db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Friday, 19-Nov-82 16:14:55 EST'), 31077db96d56Sopenharmony_ci (1982, 11, 19, 16, 14, 55, 0, 1, -1, -18000)) 31087db96d56Sopenharmony_ci 31097db96d56Sopenharmony_ci def test_parsedate_no_seconds(self): 31107db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58 +0800'), 31117db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800)) 31127db96d56Sopenharmony_ci 31137db96d56Sopenharmony_ci def test_parsedate_dot_time_delimiter(self): 31147db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58.26 +0800'), 31157db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800)) 31167db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58 +0800'), 31177db96d56Sopenharmony_ci (2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800)) 31187db96d56Sopenharmony_ci 31197db96d56Sopenharmony_ci def test_parsedate_acceptable_to_time_functions(self): 31207db96d56Sopenharmony_ci eq = self.assertEqual 31217db96d56Sopenharmony_ci timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800') 31227db96d56Sopenharmony_ci t = int(time.mktime(timetup)) 31237db96d56Sopenharmony_ci eq(time.localtime(t)[:6], timetup[:6]) 31247db96d56Sopenharmony_ci eq(int(time.strftime('%Y', timetup)), 2003) 31257db96d56Sopenharmony_ci timetup = utils.parsedate_tz('5 Feb 2003 13:47:26 -0800') 31267db96d56Sopenharmony_ci t = int(time.mktime(timetup[:9])) 31277db96d56Sopenharmony_ci eq(time.localtime(t)[:6], timetup[:6]) 31287db96d56Sopenharmony_ci eq(int(time.strftime('%Y', timetup[:9])), 2003) 31297db96d56Sopenharmony_ci 31307db96d56Sopenharmony_ci def test_mktime_tz(self): 31317db96d56Sopenharmony_ci self.assertEqual(utils.mktime_tz((1970, 1, 1, 0, 0, 0, 31327db96d56Sopenharmony_ci -1, -1, -1, 0)), 0) 31337db96d56Sopenharmony_ci self.assertEqual(utils.mktime_tz((1970, 1, 1, 0, 0, 0, 31347db96d56Sopenharmony_ci -1, -1, -1, 1234)), -1234) 31357db96d56Sopenharmony_ci 31367db96d56Sopenharmony_ci def test_parsedate_y2k(self): 31377db96d56Sopenharmony_ci """Test for parsing a date with a two-digit year. 31387db96d56Sopenharmony_ci 31397db96d56Sopenharmony_ci Parsing a date with a two-digit year should return the correct 31407db96d56Sopenharmony_ci four-digit year. RFC822 allows two-digit years, but RFC2822 (which 31417db96d56Sopenharmony_ci obsoletes RFC822) requires four-digit years. 31427db96d56Sopenharmony_ci 31437db96d56Sopenharmony_ci """ 31447db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('25 Feb 03 13:47:26 -0800'), 31457db96d56Sopenharmony_ci utils.parsedate_tz('25 Feb 2003 13:47:26 -0800')) 31467db96d56Sopenharmony_ci self.assertEqual(utils.parsedate_tz('25 Feb 71 13:47:26 -0800'), 31477db96d56Sopenharmony_ci utils.parsedate_tz('25 Feb 1971 13:47:26 -0800')) 31487db96d56Sopenharmony_ci 31497db96d56Sopenharmony_ci def test_parseaddr_empty(self): 31507db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr('<>'), ('', '')) 31517db96d56Sopenharmony_ci self.assertEqual(utils.formataddr(utils.parseaddr('<>')), '') 31527db96d56Sopenharmony_ci 31537db96d56Sopenharmony_ci def test_parseaddr_multiple_domains(self): 31547db96d56Sopenharmony_ci self.assertEqual( 31557db96d56Sopenharmony_ci utils.parseaddr('a@b@c'), 31567db96d56Sopenharmony_ci ('', '') 31577db96d56Sopenharmony_ci ) 31587db96d56Sopenharmony_ci self.assertEqual( 31597db96d56Sopenharmony_ci utils.parseaddr('a@b.c@c'), 31607db96d56Sopenharmony_ci ('', '') 31617db96d56Sopenharmony_ci ) 31627db96d56Sopenharmony_ci self.assertEqual( 31637db96d56Sopenharmony_ci utils.parseaddr('a@172.17.0.1@c'), 31647db96d56Sopenharmony_ci ('', '') 31657db96d56Sopenharmony_ci ) 31667db96d56Sopenharmony_ci 31677db96d56Sopenharmony_ci def test_noquote_dump(self): 31687db96d56Sopenharmony_ci self.assertEqual( 31697db96d56Sopenharmony_ci utils.formataddr(('A Silly Person', 'person@dom.ain')), 31707db96d56Sopenharmony_ci 'A Silly Person <person@dom.ain>') 31717db96d56Sopenharmony_ci 31727db96d56Sopenharmony_ci def test_escape_dump(self): 31737db96d56Sopenharmony_ci self.assertEqual( 31747db96d56Sopenharmony_ci utils.formataddr(('A (Very) Silly Person', 'person@dom.ain')), 31757db96d56Sopenharmony_ci r'"A (Very) Silly Person" <person@dom.ain>') 31767db96d56Sopenharmony_ci self.assertEqual( 31777db96d56Sopenharmony_ci utils.parseaddr(r'"A \(Very\) Silly Person" <person@dom.ain>'), 31787db96d56Sopenharmony_ci ('A (Very) Silly Person', 'person@dom.ain')) 31797db96d56Sopenharmony_ci a = r'A \(Special\) Person' 31807db96d56Sopenharmony_ci b = 'person@dom.ain' 31817db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) 31827db96d56Sopenharmony_ci 31837db96d56Sopenharmony_ci def test_escape_backslashes(self): 31847db96d56Sopenharmony_ci self.assertEqual( 31857db96d56Sopenharmony_ci utils.formataddr((r'Arthur \Backslash\ Foobar', 'person@dom.ain')), 31867db96d56Sopenharmony_ci r'"Arthur \\Backslash\\ Foobar" <person@dom.ain>') 31877db96d56Sopenharmony_ci a = r'Arthur \Backslash\ Foobar' 31887db96d56Sopenharmony_ci b = 'person@dom.ain' 31897db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) 31907db96d56Sopenharmony_ci 31917db96d56Sopenharmony_ci def test_quotes_unicode_names(self): 31927db96d56Sopenharmony_ci # issue 1690608. email.utils.formataddr() should be rfc2047 aware. 31937db96d56Sopenharmony_ci name = "H\u00e4ns W\u00fcrst" 31947db96d56Sopenharmony_ci addr = 'person@dom.ain' 31957db96d56Sopenharmony_ci utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= <person@dom.ain>" 31967db96d56Sopenharmony_ci latin1_quopri = "=?iso-8859-1?q?H=E4ns_W=FCrst?= <person@dom.ain>" 31977db96d56Sopenharmony_ci self.assertEqual(utils.formataddr((name, addr)), utf8_base64) 31987db96d56Sopenharmony_ci self.assertEqual(utils.formataddr((name, addr), 'iso-8859-1'), 31997db96d56Sopenharmony_ci latin1_quopri) 32007db96d56Sopenharmony_ci 32017db96d56Sopenharmony_ci def test_accepts_any_charset_like_object(self): 32027db96d56Sopenharmony_ci # issue 1690608. email.utils.formataddr() should be rfc2047 aware. 32037db96d56Sopenharmony_ci name = "H\u00e4ns W\u00fcrst" 32047db96d56Sopenharmony_ci addr = 'person@dom.ain' 32057db96d56Sopenharmony_ci utf8_base64 = "=?utf-8?b?SMOkbnMgV8O8cnN0?= <person@dom.ain>" 32067db96d56Sopenharmony_ci foobar = "FOOBAR" 32077db96d56Sopenharmony_ci class CharsetMock: 32087db96d56Sopenharmony_ci def header_encode(self, string): 32097db96d56Sopenharmony_ci return foobar 32107db96d56Sopenharmony_ci mock = CharsetMock() 32117db96d56Sopenharmony_ci mock_expected = "%s <%s>" % (foobar, addr) 32127db96d56Sopenharmony_ci self.assertEqual(utils.formataddr((name, addr), mock), mock_expected) 32137db96d56Sopenharmony_ci self.assertEqual(utils.formataddr((name, addr), Charset('utf-8')), 32147db96d56Sopenharmony_ci utf8_base64) 32157db96d56Sopenharmony_ci 32167db96d56Sopenharmony_ci def test_invalid_charset_like_object_raises_error(self): 32177db96d56Sopenharmony_ci # issue 1690608. email.utils.formataddr() should be rfc2047 aware. 32187db96d56Sopenharmony_ci name = "H\u00e4ns W\u00fcrst" 32197db96d56Sopenharmony_ci addr = 'person@dom.ain' 32207db96d56Sopenharmony_ci # An object without a header_encode method: 32217db96d56Sopenharmony_ci bad_charset = object() 32227db96d56Sopenharmony_ci self.assertRaises(AttributeError, utils.formataddr, (name, addr), 32237db96d56Sopenharmony_ci bad_charset) 32247db96d56Sopenharmony_ci 32257db96d56Sopenharmony_ci def test_unicode_address_raises_error(self): 32267db96d56Sopenharmony_ci # issue 1690608. email.utils.formataddr() should be rfc2047 aware. 32277db96d56Sopenharmony_ci addr = 'pers\u00f6n@dom.in' 32287db96d56Sopenharmony_ci self.assertRaises(UnicodeError, utils.formataddr, (None, addr)) 32297db96d56Sopenharmony_ci self.assertRaises(UnicodeError, utils.formataddr, ("Name", addr)) 32307db96d56Sopenharmony_ci 32317db96d56Sopenharmony_ci def test_name_with_dot(self): 32327db96d56Sopenharmony_ci x = 'John X. Doe <jxd@example.com>' 32337db96d56Sopenharmony_ci y = '"John X. Doe" <jxd@example.com>' 32347db96d56Sopenharmony_ci a, b = ('John X. Doe', 'jxd@example.com') 32357db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(x), (a, b)) 32367db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(y), (a, b)) 32377db96d56Sopenharmony_ci # formataddr() quotes the name if there's a dot in it 32387db96d56Sopenharmony_ci self.assertEqual(utils.formataddr((a, b)), y) 32397db96d56Sopenharmony_ci 32407db96d56Sopenharmony_ci def test_parseaddr_preserves_quoted_pairs_in_addresses(self): 32417db96d56Sopenharmony_ci # issue 10005. Note that in the third test the second pair of 32427db96d56Sopenharmony_ci # backslashes is not actually a quoted pair because it is not inside a 32437db96d56Sopenharmony_ci # comment or quoted string: the address being parsed has a quoted 32447db96d56Sopenharmony_ci # string containing a quoted backslash, followed by 'example' and two 32457db96d56Sopenharmony_ci # backslashes, followed by another quoted string containing a space and 32467db96d56Sopenharmony_ci # the word 'example'. parseaddr copies those two backslashes 32477db96d56Sopenharmony_ci # literally. Per rfc5322 this is not technically correct since a \ may 32487db96d56Sopenharmony_ci # not appear in an address outside of a quoted string. It is probably 32497db96d56Sopenharmony_ci # a sensible Postel interpretation, though. 32507db96d56Sopenharmony_ci eq = self.assertEqual 32517db96d56Sopenharmony_ci eq(utils.parseaddr('""example" example"@example.com'), 32527db96d56Sopenharmony_ci ('', '""example" example"@example.com')) 32537db96d56Sopenharmony_ci eq(utils.parseaddr('"\\"example\\" example"@example.com'), 32547db96d56Sopenharmony_ci ('', '"\\"example\\" example"@example.com')) 32557db96d56Sopenharmony_ci eq(utils.parseaddr('"\\\\"example\\\\" example"@example.com'), 32567db96d56Sopenharmony_ci ('', '"\\\\"example\\\\" example"@example.com')) 32577db96d56Sopenharmony_ci 32587db96d56Sopenharmony_ci def test_parseaddr_preserves_spaces_in_local_part(self): 32597db96d56Sopenharmony_ci # issue 9286. A normal RFC5322 local part should not contain any 32607db96d56Sopenharmony_ci # folding white space, but legacy local parts can (they are a sequence 32617db96d56Sopenharmony_ci # of atoms, not dotatoms). On the other hand we strip whitespace from 32627db96d56Sopenharmony_ci # before the @ and around dots, on the assumption that the whitespace 32637db96d56Sopenharmony_ci # around the punctuation is a mistake in what would otherwise be 32647db96d56Sopenharmony_ci # an RFC5322 local part. Leading whitespace is, usual, stripped as well. 32657db96d56Sopenharmony_ci self.assertEqual(('', "merwok wok@xample.com"), 32667db96d56Sopenharmony_ci utils.parseaddr("merwok wok@xample.com")) 32677db96d56Sopenharmony_ci self.assertEqual(('', "merwok wok@xample.com"), 32687db96d56Sopenharmony_ci utils.parseaddr("merwok wok@xample.com")) 32697db96d56Sopenharmony_ci self.assertEqual(('', "merwok wok@xample.com"), 32707db96d56Sopenharmony_ci utils.parseaddr(" merwok wok @xample.com")) 32717db96d56Sopenharmony_ci self.assertEqual(('', 'merwok"wok" wok@xample.com'), 32727db96d56Sopenharmony_ci utils.parseaddr('merwok"wok" wok@xample.com')) 32737db96d56Sopenharmony_ci self.assertEqual(('', 'merwok.wok.wok@xample.com'), 32747db96d56Sopenharmony_ci utils.parseaddr('merwok. wok . wok@xample.com')) 32757db96d56Sopenharmony_ci 32767db96d56Sopenharmony_ci def test_formataddr_does_not_quote_parens_in_quoted_string(self): 32777db96d56Sopenharmony_ci addr = ("'foo@example.com' (foo@example.com)", 32787db96d56Sopenharmony_ci 'foo@example.com') 32797db96d56Sopenharmony_ci addrstr = ('"\'foo@example.com\' ' 32807db96d56Sopenharmony_ci '(foo@example.com)" <foo@example.com>') 32817db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(addrstr), addr) 32827db96d56Sopenharmony_ci self.assertEqual(utils.formataddr(addr), addrstr) 32837db96d56Sopenharmony_ci 32847db96d56Sopenharmony_ci 32857db96d56Sopenharmony_ci def test_multiline_from_comment(self): 32867db96d56Sopenharmony_ci x = """\ 32877db96d56Sopenharmony_ciFoo 32887db96d56Sopenharmony_ci\tBar <foo@example.com>""" 32897db96d56Sopenharmony_ci self.assertEqual(utils.parseaddr(x), ('Foo Bar', 'foo@example.com')) 32907db96d56Sopenharmony_ci 32917db96d56Sopenharmony_ci def test_quote_dump(self): 32927db96d56Sopenharmony_ci self.assertEqual( 32937db96d56Sopenharmony_ci utils.formataddr(('A Silly; Person', 'person@dom.ain')), 32947db96d56Sopenharmony_ci r'"A Silly; Person" <person@dom.ain>') 32957db96d56Sopenharmony_ci 32967db96d56Sopenharmony_ci def test_charset_richcomparisons(self): 32977db96d56Sopenharmony_ci eq = self.assertEqual 32987db96d56Sopenharmony_ci ne = self.assertNotEqual 32997db96d56Sopenharmony_ci cset1 = Charset() 33007db96d56Sopenharmony_ci cset2 = Charset() 33017db96d56Sopenharmony_ci eq(cset1, 'us-ascii') 33027db96d56Sopenharmony_ci eq(cset1, 'US-ASCII') 33037db96d56Sopenharmony_ci eq(cset1, 'Us-AsCiI') 33047db96d56Sopenharmony_ci eq('us-ascii', cset1) 33057db96d56Sopenharmony_ci eq('US-ASCII', cset1) 33067db96d56Sopenharmony_ci eq('Us-AsCiI', cset1) 33077db96d56Sopenharmony_ci ne(cset1, 'usascii') 33087db96d56Sopenharmony_ci ne(cset1, 'USASCII') 33097db96d56Sopenharmony_ci ne(cset1, 'UsAsCiI') 33107db96d56Sopenharmony_ci ne('usascii', cset1) 33117db96d56Sopenharmony_ci ne('USASCII', cset1) 33127db96d56Sopenharmony_ci ne('UsAsCiI', cset1) 33137db96d56Sopenharmony_ci eq(cset1, cset2) 33147db96d56Sopenharmony_ci eq(cset2, cset1) 33157db96d56Sopenharmony_ci 33167db96d56Sopenharmony_ci def test_getaddresses(self): 33177db96d56Sopenharmony_ci eq = self.assertEqual 33187db96d56Sopenharmony_ci eq(utils.getaddresses(['aperson@dom.ain (Al Person)', 33197db96d56Sopenharmony_ci 'Bud Person <bperson@dom.ain>']), 33207db96d56Sopenharmony_ci [('Al Person', 'aperson@dom.ain'), 33217db96d56Sopenharmony_ci ('Bud Person', 'bperson@dom.ain')]) 33227db96d56Sopenharmony_ci 33237db96d56Sopenharmony_ci def test_getaddresses_nasty(self): 33247db96d56Sopenharmony_ci eq = self.assertEqual 33257db96d56Sopenharmony_ci eq(utils.getaddresses(['foo: ;']), [('', '')]) 33267db96d56Sopenharmony_ci eq(utils.getaddresses( 33277db96d56Sopenharmony_ci ['[]*-- =~$']), 33287db96d56Sopenharmony_ci [('', ''), ('', ''), ('', '*--')]) 33297db96d56Sopenharmony_ci eq(utils.getaddresses( 33307db96d56Sopenharmony_ci ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']), 33317db96d56Sopenharmony_ci [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) 33327db96d56Sopenharmony_ci 33337db96d56Sopenharmony_ci def test_getaddresses_embedded_comment(self): 33347db96d56Sopenharmony_ci """Test proper handling of a nested comment""" 33357db96d56Sopenharmony_ci eq = self.assertEqual 33367db96d56Sopenharmony_ci addrs = utils.getaddresses(['User ((nested comment)) <foo@bar.com>']) 33377db96d56Sopenharmony_ci eq(addrs[0][1], 'foo@bar.com') 33387db96d56Sopenharmony_ci 33397db96d56Sopenharmony_ci def test_getaddresses_header_obj(self): 33407db96d56Sopenharmony_ci """Test the handling of a Header object.""" 33417db96d56Sopenharmony_ci addrs = utils.getaddresses([Header('Al Person <aperson@dom.ain>')]) 33427db96d56Sopenharmony_ci self.assertEqual(addrs[0][1], 'aperson@dom.ain') 33437db96d56Sopenharmony_ci 33447db96d56Sopenharmony_ci @threading_helper.requires_working_threading() 33457db96d56Sopenharmony_ci def test_make_msgid_collisions(self): 33467db96d56Sopenharmony_ci # Test make_msgid uniqueness, even with multiple threads 33477db96d56Sopenharmony_ci class MsgidsThread(Thread): 33487db96d56Sopenharmony_ci def run(self): 33497db96d56Sopenharmony_ci # generate msgids for 3 seconds 33507db96d56Sopenharmony_ci self.msgids = [] 33517db96d56Sopenharmony_ci append = self.msgids.append 33527db96d56Sopenharmony_ci make_msgid = utils.make_msgid 33537db96d56Sopenharmony_ci clock = time.monotonic 33547db96d56Sopenharmony_ci tfin = clock() + 3.0 33557db96d56Sopenharmony_ci while clock() < tfin: 33567db96d56Sopenharmony_ci append(make_msgid(domain='testdomain-string')) 33577db96d56Sopenharmony_ci 33587db96d56Sopenharmony_ci threads = [MsgidsThread() for i in range(5)] 33597db96d56Sopenharmony_ci with threading_helper.start_threads(threads): 33607db96d56Sopenharmony_ci pass 33617db96d56Sopenharmony_ci all_ids = sum([t.msgids for t in threads], []) 33627db96d56Sopenharmony_ci self.assertEqual(len(set(all_ids)), len(all_ids)) 33637db96d56Sopenharmony_ci 33647db96d56Sopenharmony_ci def test_utils_quote_unquote(self): 33657db96d56Sopenharmony_ci eq = self.assertEqual 33667db96d56Sopenharmony_ci msg = Message() 33677db96d56Sopenharmony_ci msg.add_header('content-disposition', 'attachment', 33687db96d56Sopenharmony_ci filename='foo\\wacky"name') 33697db96d56Sopenharmony_ci eq(msg.get_filename(), 'foo\\wacky"name') 33707db96d56Sopenharmony_ci 33717db96d56Sopenharmony_ci def test_get_body_encoding_with_bogus_charset(self): 33727db96d56Sopenharmony_ci charset = Charset('not a charset') 33737db96d56Sopenharmony_ci self.assertEqual(charset.get_body_encoding(), 'base64') 33747db96d56Sopenharmony_ci 33757db96d56Sopenharmony_ci def test_get_body_encoding_with_uppercase_charset(self): 33767db96d56Sopenharmony_ci eq = self.assertEqual 33777db96d56Sopenharmony_ci msg = Message() 33787db96d56Sopenharmony_ci msg['Content-Type'] = 'text/plain; charset=UTF-8' 33797db96d56Sopenharmony_ci eq(msg['content-type'], 'text/plain; charset=UTF-8') 33807db96d56Sopenharmony_ci charsets = msg.get_charsets() 33817db96d56Sopenharmony_ci eq(len(charsets), 1) 33827db96d56Sopenharmony_ci eq(charsets[0], 'utf-8') 33837db96d56Sopenharmony_ci charset = Charset(charsets[0]) 33847db96d56Sopenharmony_ci eq(charset.get_body_encoding(), 'base64') 33857db96d56Sopenharmony_ci msg.set_payload(b'hello world', charset=charset) 33867db96d56Sopenharmony_ci eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=\n') 33877db96d56Sopenharmony_ci eq(msg.get_payload(decode=True), b'hello world') 33887db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], 'base64') 33897db96d56Sopenharmony_ci # Try another one 33907db96d56Sopenharmony_ci msg = Message() 33917db96d56Sopenharmony_ci msg['Content-Type'] = 'text/plain; charset="US-ASCII"' 33927db96d56Sopenharmony_ci charsets = msg.get_charsets() 33937db96d56Sopenharmony_ci eq(len(charsets), 1) 33947db96d56Sopenharmony_ci eq(charsets[0], 'us-ascii') 33957db96d56Sopenharmony_ci charset = Charset(charsets[0]) 33967db96d56Sopenharmony_ci eq(charset.get_body_encoding(), encoders.encode_7or8bit) 33977db96d56Sopenharmony_ci msg.set_payload('hello world', charset=charset) 33987db96d56Sopenharmony_ci eq(msg.get_payload(), 'hello world') 33997db96d56Sopenharmony_ci eq(msg['content-transfer-encoding'], '7bit') 34007db96d56Sopenharmony_ci 34017db96d56Sopenharmony_ci def test_charsets_case_insensitive(self): 34027db96d56Sopenharmony_ci lc = Charset('us-ascii') 34037db96d56Sopenharmony_ci uc = Charset('US-ASCII') 34047db96d56Sopenharmony_ci self.assertEqual(lc.get_body_encoding(), uc.get_body_encoding()) 34057db96d56Sopenharmony_ci 34067db96d56Sopenharmony_ci def test_partial_falls_inside_message_delivery_status(self): 34077db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 34087db96d56Sopenharmony_ci # The Parser interface provides chunks of data to FeedParser in 8192 34097db96d56Sopenharmony_ci # byte gulps. SF bug #1076485 found one of those chunks inside 34107db96d56Sopenharmony_ci # message/delivery-status header block, which triggered an 34117db96d56Sopenharmony_ci # unreadline() of NeedMoreData. 34127db96d56Sopenharmony_ci msg = self._msgobj('msg_43.txt') 34137db96d56Sopenharmony_ci sfp = StringIO() 34147db96d56Sopenharmony_ci iterators._structure(msg, sfp) 34157db96d56Sopenharmony_ci eq(sfp.getvalue(), """\ 34167db96d56Sopenharmony_cimultipart/report 34177db96d56Sopenharmony_ci text/plain 34187db96d56Sopenharmony_ci message/delivery-status 34197db96d56Sopenharmony_ci text/plain 34207db96d56Sopenharmony_ci text/plain 34217db96d56Sopenharmony_ci text/plain 34227db96d56Sopenharmony_ci text/plain 34237db96d56Sopenharmony_ci text/plain 34247db96d56Sopenharmony_ci text/plain 34257db96d56Sopenharmony_ci text/plain 34267db96d56Sopenharmony_ci text/plain 34277db96d56Sopenharmony_ci text/plain 34287db96d56Sopenharmony_ci text/plain 34297db96d56Sopenharmony_ci text/plain 34307db96d56Sopenharmony_ci text/plain 34317db96d56Sopenharmony_ci text/plain 34327db96d56Sopenharmony_ci text/plain 34337db96d56Sopenharmony_ci text/plain 34347db96d56Sopenharmony_ci text/plain 34357db96d56Sopenharmony_ci text/plain 34367db96d56Sopenharmony_ci text/plain 34377db96d56Sopenharmony_ci text/plain 34387db96d56Sopenharmony_ci text/plain 34397db96d56Sopenharmony_ci text/plain 34407db96d56Sopenharmony_ci text/plain 34417db96d56Sopenharmony_ci text/plain 34427db96d56Sopenharmony_ci text/plain 34437db96d56Sopenharmony_ci text/plain 34447db96d56Sopenharmony_ci text/plain 34457db96d56Sopenharmony_ci text/rfc822-headers 34467db96d56Sopenharmony_ci""") 34477db96d56Sopenharmony_ci 34487db96d56Sopenharmony_ci def test_make_msgid_domain(self): 34497db96d56Sopenharmony_ci self.assertEqual( 34507db96d56Sopenharmony_ci email.utils.make_msgid(domain='testdomain-string')[-19:], 34517db96d56Sopenharmony_ci '@testdomain-string>') 34527db96d56Sopenharmony_ci 34537db96d56Sopenharmony_ci def test_make_msgid_idstring(self): 34547db96d56Sopenharmony_ci self.assertEqual( 34557db96d56Sopenharmony_ci email.utils.make_msgid(idstring='test-idstring', 34567db96d56Sopenharmony_ci domain='testdomain-string')[-33:], 34577db96d56Sopenharmony_ci '.test-idstring@testdomain-string>') 34587db96d56Sopenharmony_ci 34597db96d56Sopenharmony_ci def test_make_msgid_default_domain(self): 34607db96d56Sopenharmony_ci with patch('socket.getfqdn') as mock_getfqdn: 34617db96d56Sopenharmony_ci mock_getfqdn.return_value = domain = 'pythontest.example.com' 34627db96d56Sopenharmony_ci self.assertTrue( 34637db96d56Sopenharmony_ci email.utils.make_msgid().endswith( 34647db96d56Sopenharmony_ci '@' + domain + '>')) 34657db96d56Sopenharmony_ci 34667db96d56Sopenharmony_ci def test_Generator_linend(self): 34677db96d56Sopenharmony_ci # Issue 14645. 34687db96d56Sopenharmony_ci with openfile('msg_26.txt', encoding="utf-8", newline='\n') as f: 34697db96d56Sopenharmony_ci msgtxt = f.read() 34707db96d56Sopenharmony_ci msgtxt_nl = msgtxt.replace('\r\n', '\n') 34717db96d56Sopenharmony_ci msg = email.message_from_string(msgtxt) 34727db96d56Sopenharmony_ci s = StringIO() 34737db96d56Sopenharmony_ci g = email.generator.Generator(s) 34747db96d56Sopenharmony_ci g.flatten(msg) 34757db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), msgtxt_nl) 34767db96d56Sopenharmony_ci 34777db96d56Sopenharmony_ci def test_BytesGenerator_linend(self): 34787db96d56Sopenharmony_ci # Issue 14645. 34797db96d56Sopenharmony_ci with openfile('msg_26.txt', encoding="utf-8", newline='\n') as f: 34807db96d56Sopenharmony_ci msgtxt = f.read() 34817db96d56Sopenharmony_ci msgtxt_nl = msgtxt.replace('\r\n', '\n') 34827db96d56Sopenharmony_ci msg = email.message_from_string(msgtxt_nl) 34837db96d56Sopenharmony_ci s = BytesIO() 34847db96d56Sopenharmony_ci g = email.generator.BytesGenerator(s) 34857db96d56Sopenharmony_ci g.flatten(msg, linesep='\r\n') 34867db96d56Sopenharmony_ci self.assertEqual(s.getvalue().decode('ascii'), msgtxt) 34877db96d56Sopenharmony_ci 34887db96d56Sopenharmony_ci def test_BytesGenerator_linend_with_non_ascii(self): 34897db96d56Sopenharmony_ci # Issue 14645. 34907db96d56Sopenharmony_ci with openfile('msg_26.txt', 'rb') as f: 34917db96d56Sopenharmony_ci msgtxt = f.read() 34927db96d56Sopenharmony_ci msgtxt = msgtxt.replace(b'with attachment', b'fo\xf6') 34937db96d56Sopenharmony_ci msgtxt_nl = msgtxt.replace(b'\r\n', b'\n') 34947db96d56Sopenharmony_ci msg = email.message_from_bytes(msgtxt_nl) 34957db96d56Sopenharmony_ci s = BytesIO() 34967db96d56Sopenharmony_ci g = email.generator.BytesGenerator(s) 34977db96d56Sopenharmony_ci g.flatten(msg, linesep='\r\n') 34987db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), msgtxt) 34997db96d56Sopenharmony_ci 35007db96d56Sopenharmony_ci def test_mime_classes_policy_argument(self): 35017db96d56Sopenharmony_ci with openfile('sndhdr.au', 'rb') as fp: 35027db96d56Sopenharmony_ci audiodata = fp.read() 35037db96d56Sopenharmony_ci with openfile('python.gif', 'rb') as fp: 35047db96d56Sopenharmony_ci bindata = fp.read() 35057db96d56Sopenharmony_ci classes = [ 35067db96d56Sopenharmony_ci (MIMEApplication, ('',)), 35077db96d56Sopenharmony_ci (MIMEAudio, (audiodata,)), 35087db96d56Sopenharmony_ci (MIMEImage, (bindata,)), 35097db96d56Sopenharmony_ci (MIMEMessage, (Message(),)), 35107db96d56Sopenharmony_ci (MIMENonMultipart, ('multipart', 'mixed')), 35117db96d56Sopenharmony_ci (MIMEText, ('',)), 35127db96d56Sopenharmony_ci ] 35137db96d56Sopenharmony_ci for cls, constructor in classes: 35147db96d56Sopenharmony_ci with self.subTest(cls=cls.__name__, policy='compat32'): 35157db96d56Sopenharmony_ci m = cls(*constructor) 35167db96d56Sopenharmony_ci self.assertIs(m.policy, email.policy.compat32) 35177db96d56Sopenharmony_ci with self.subTest(cls=cls.__name__, policy='default'): 35187db96d56Sopenharmony_ci m = cls(*constructor, policy=email.policy.default) 35197db96d56Sopenharmony_ci self.assertIs(m.policy, email.policy.default) 35207db96d56Sopenharmony_ci 35217db96d56Sopenharmony_ci 35227db96d56Sopenharmony_ci# Test the iterator/generators 35237db96d56Sopenharmony_ciclass TestIterators(TestEmailBase): 35247db96d56Sopenharmony_ci def test_body_line_iterator(self): 35257db96d56Sopenharmony_ci eq = self.assertEqual 35267db96d56Sopenharmony_ci neq = self.ndiffAssertEqual 35277db96d56Sopenharmony_ci # First a simple non-multipart message 35287db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 35297db96d56Sopenharmony_ci it = iterators.body_line_iterator(msg) 35307db96d56Sopenharmony_ci lines = list(it) 35317db96d56Sopenharmony_ci eq(len(lines), 6) 35327db96d56Sopenharmony_ci neq(EMPTYSTRING.join(lines), msg.get_payload()) 35337db96d56Sopenharmony_ci # Now a more complicated multipart 35347db96d56Sopenharmony_ci msg = self._msgobj('msg_02.txt') 35357db96d56Sopenharmony_ci it = iterators.body_line_iterator(msg) 35367db96d56Sopenharmony_ci lines = list(it) 35377db96d56Sopenharmony_ci eq(len(lines), 43) 35387db96d56Sopenharmony_ci with openfile('msg_19.txt', encoding="utf-8") as fp: 35397db96d56Sopenharmony_ci neq(EMPTYSTRING.join(lines), fp.read()) 35407db96d56Sopenharmony_ci 35417db96d56Sopenharmony_ci def test_typed_subpart_iterator(self): 35427db96d56Sopenharmony_ci eq = self.assertEqual 35437db96d56Sopenharmony_ci msg = self._msgobj('msg_04.txt') 35447db96d56Sopenharmony_ci it = iterators.typed_subpart_iterator(msg, 'text') 35457db96d56Sopenharmony_ci lines = [] 35467db96d56Sopenharmony_ci subparts = 0 35477db96d56Sopenharmony_ci for subpart in it: 35487db96d56Sopenharmony_ci subparts += 1 35497db96d56Sopenharmony_ci lines.append(subpart.get_payload()) 35507db96d56Sopenharmony_ci eq(subparts, 2) 35517db96d56Sopenharmony_ci eq(EMPTYSTRING.join(lines), """\ 35527db96d56Sopenharmony_cia simple kind of mirror 35537db96d56Sopenharmony_cito reflect upon our own 35547db96d56Sopenharmony_cia simple kind of mirror 35557db96d56Sopenharmony_cito reflect upon our own 35567db96d56Sopenharmony_ci""") 35577db96d56Sopenharmony_ci 35587db96d56Sopenharmony_ci def test_typed_subpart_iterator_default_type(self): 35597db96d56Sopenharmony_ci eq = self.assertEqual 35607db96d56Sopenharmony_ci msg = self._msgobj('msg_03.txt') 35617db96d56Sopenharmony_ci it = iterators.typed_subpart_iterator(msg, 'text', 'plain') 35627db96d56Sopenharmony_ci lines = [] 35637db96d56Sopenharmony_ci subparts = 0 35647db96d56Sopenharmony_ci for subpart in it: 35657db96d56Sopenharmony_ci subparts += 1 35667db96d56Sopenharmony_ci lines.append(subpart.get_payload()) 35677db96d56Sopenharmony_ci eq(subparts, 1) 35687db96d56Sopenharmony_ci eq(EMPTYSTRING.join(lines), """\ 35697db96d56Sopenharmony_ci 35707db96d56Sopenharmony_ciHi, 35717db96d56Sopenharmony_ci 35727db96d56Sopenharmony_ciDo you like this message? 35737db96d56Sopenharmony_ci 35747db96d56Sopenharmony_ci-Me 35757db96d56Sopenharmony_ci""") 35767db96d56Sopenharmony_ci 35777db96d56Sopenharmony_ci def test_pushCR_LF(self): 35787db96d56Sopenharmony_ci '''FeedParser BufferedSubFile.push() assumed it received complete 35797db96d56Sopenharmony_ci line endings. A CR ending one push() followed by a LF starting 35807db96d56Sopenharmony_ci the next push() added an empty line. 35817db96d56Sopenharmony_ci ''' 35827db96d56Sopenharmony_ci imt = [ 35837db96d56Sopenharmony_ci ("a\r \n", 2), 35847db96d56Sopenharmony_ci ("b", 0), 35857db96d56Sopenharmony_ci ("c\n", 1), 35867db96d56Sopenharmony_ci ("", 0), 35877db96d56Sopenharmony_ci ("d\r\n", 1), 35887db96d56Sopenharmony_ci ("e\r", 0), 35897db96d56Sopenharmony_ci ("\nf", 1), 35907db96d56Sopenharmony_ci ("\r\n", 1), 35917db96d56Sopenharmony_ci ] 35927db96d56Sopenharmony_ci from email.feedparser import BufferedSubFile, NeedMoreData 35937db96d56Sopenharmony_ci bsf = BufferedSubFile() 35947db96d56Sopenharmony_ci om = [] 35957db96d56Sopenharmony_ci nt = 0 35967db96d56Sopenharmony_ci for il, n in imt: 35977db96d56Sopenharmony_ci bsf.push(il) 35987db96d56Sopenharmony_ci nt += n 35997db96d56Sopenharmony_ci n1 = 0 36007db96d56Sopenharmony_ci for ol in iter(bsf.readline, NeedMoreData): 36017db96d56Sopenharmony_ci om.append(ol) 36027db96d56Sopenharmony_ci n1 += 1 36037db96d56Sopenharmony_ci self.assertEqual(n, n1) 36047db96d56Sopenharmony_ci self.assertEqual(len(om), nt) 36057db96d56Sopenharmony_ci self.assertEqual(''.join([il for il, n in imt]), ''.join(om)) 36067db96d56Sopenharmony_ci 36077db96d56Sopenharmony_ci def test_push_random(self): 36087db96d56Sopenharmony_ci from email.feedparser import BufferedSubFile, NeedMoreData 36097db96d56Sopenharmony_ci 36107db96d56Sopenharmony_ci n = 10000 36117db96d56Sopenharmony_ci chunksize = 5 36127db96d56Sopenharmony_ci chars = 'abcd \t\r\n' 36137db96d56Sopenharmony_ci 36147db96d56Sopenharmony_ci s = ''.join(choice(chars) for i in range(n)) + '\n' 36157db96d56Sopenharmony_ci target = s.splitlines(True) 36167db96d56Sopenharmony_ci 36177db96d56Sopenharmony_ci bsf = BufferedSubFile() 36187db96d56Sopenharmony_ci lines = [] 36197db96d56Sopenharmony_ci for i in range(0, len(s), chunksize): 36207db96d56Sopenharmony_ci chunk = s[i:i+chunksize] 36217db96d56Sopenharmony_ci bsf.push(chunk) 36227db96d56Sopenharmony_ci lines.extend(iter(bsf.readline, NeedMoreData)) 36237db96d56Sopenharmony_ci self.assertEqual(lines, target) 36247db96d56Sopenharmony_ci 36257db96d56Sopenharmony_ci 36267db96d56Sopenharmony_ciclass TestFeedParsers(TestEmailBase): 36277db96d56Sopenharmony_ci 36287db96d56Sopenharmony_ci def parse(self, chunks): 36297db96d56Sopenharmony_ci feedparser = FeedParser() 36307db96d56Sopenharmony_ci for chunk in chunks: 36317db96d56Sopenharmony_ci feedparser.feed(chunk) 36327db96d56Sopenharmony_ci return feedparser.close() 36337db96d56Sopenharmony_ci 36347db96d56Sopenharmony_ci def test_empty_header_name_handled(self): 36357db96d56Sopenharmony_ci # Issue 19996 36367db96d56Sopenharmony_ci msg = self.parse("First: val\n: bad\nSecond: val") 36377db96d56Sopenharmony_ci self.assertEqual(msg['First'], 'val') 36387db96d56Sopenharmony_ci self.assertEqual(msg['Second'], 'val') 36397db96d56Sopenharmony_ci 36407db96d56Sopenharmony_ci def test_newlines(self): 36417db96d56Sopenharmony_ci m = self.parse(['a:\nb:\rc:\r\nd:\n']) 36427db96d56Sopenharmony_ci self.assertEqual(m.keys(), ['a', 'b', 'c', 'd']) 36437db96d56Sopenharmony_ci m = self.parse(['a:\nb:\rc:\r\nd:']) 36447db96d56Sopenharmony_ci self.assertEqual(m.keys(), ['a', 'b', 'c', 'd']) 36457db96d56Sopenharmony_ci m = self.parse(['a:\rb', 'c:\n']) 36467db96d56Sopenharmony_ci self.assertEqual(m.keys(), ['a', 'bc']) 36477db96d56Sopenharmony_ci m = self.parse(['a:\r', 'b:\n']) 36487db96d56Sopenharmony_ci self.assertEqual(m.keys(), ['a', 'b']) 36497db96d56Sopenharmony_ci m = self.parse(['a:\r', '\nb:\n']) 36507db96d56Sopenharmony_ci self.assertEqual(m.keys(), ['a', 'b']) 36517db96d56Sopenharmony_ci 36527db96d56Sopenharmony_ci # Only CR and LF should break header fields 36537db96d56Sopenharmony_ci m = self.parse(['a:\x85b:\u2028c:\n']) 36547db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', '\x85b:\u2028c:')]) 36557db96d56Sopenharmony_ci m = self.parse(['a:\r', 'b:\x85', 'c:\n']) 36567db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', ''), ('b', '\x85c:')]) 36577db96d56Sopenharmony_ci 36587db96d56Sopenharmony_ci def test_long_lines(self): 36597db96d56Sopenharmony_ci # Expected peak memory use on 32-bit platform: 6*N*M bytes. 36607db96d56Sopenharmony_ci M, N = 1000, 20000 36617db96d56Sopenharmony_ci m = self.parse(['a:b\n\n'] + ['x'*M] * N) 36627db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', 'b')]) 36637db96d56Sopenharmony_ci self.assertEqual(m.get_payload(), 'x'*M*N) 36647db96d56Sopenharmony_ci m = self.parse(['a:b\r\r'] + ['x'*M] * N) 36657db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', 'b')]) 36667db96d56Sopenharmony_ci self.assertEqual(m.get_payload(), 'x'*M*N) 36677db96d56Sopenharmony_ci m = self.parse(['a:b\r\r'] + ['x'*M+'\x85'] * N) 36687db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', 'b')]) 36697db96d56Sopenharmony_ci self.assertEqual(m.get_payload(), ('x'*M+'\x85')*N) 36707db96d56Sopenharmony_ci m = self.parse(['a:\r', 'b: '] + ['x'*M] * N) 36717db96d56Sopenharmony_ci self.assertEqual(m.items(), [('a', ''), ('b', 'x'*M*N)]) 36727db96d56Sopenharmony_ci 36737db96d56Sopenharmony_ci 36747db96d56Sopenharmony_ciclass TestParsers(TestEmailBase): 36757db96d56Sopenharmony_ci 36767db96d56Sopenharmony_ci def test_header_parser(self): 36777db96d56Sopenharmony_ci eq = self.assertEqual 36787db96d56Sopenharmony_ci # Parse only the headers of a complex multipart MIME document 36797db96d56Sopenharmony_ci with openfile('msg_02.txt', encoding="utf-8") as fp: 36807db96d56Sopenharmony_ci msg = HeaderParser().parse(fp) 36817db96d56Sopenharmony_ci eq(msg['from'], 'ppp-request@zzz.org') 36827db96d56Sopenharmony_ci eq(msg['to'], 'ppp@zzz.org') 36837db96d56Sopenharmony_ci eq(msg.get_content_type(), 'multipart/mixed') 36847db96d56Sopenharmony_ci self.assertFalse(msg.is_multipart()) 36857db96d56Sopenharmony_ci self.assertIsInstance(msg.get_payload(), str) 36867db96d56Sopenharmony_ci 36877db96d56Sopenharmony_ci def test_bytes_header_parser(self): 36887db96d56Sopenharmony_ci eq = self.assertEqual 36897db96d56Sopenharmony_ci # Parse only the headers of a complex multipart MIME document 36907db96d56Sopenharmony_ci with openfile('msg_02.txt', 'rb') as fp: 36917db96d56Sopenharmony_ci msg = email.parser.BytesHeaderParser().parse(fp) 36927db96d56Sopenharmony_ci eq(msg['from'], 'ppp-request@zzz.org') 36937db96d56Sopenharmony_ci eq(msg['to'], 'ppp@zzz.org') 36947db96d56Sopenharmony_ci eq(msg.get_content_type(), 'multipart/mixed') 36957db96d56Sopenharmony_ci self.assertFalse(msg.is_multipart()) 36967db96d56Sopenharmony_ci self.assertIsInstance(msg.get_payload(), str) 36977db96d56Sopenharmony_ci self.assertIsInstance(msg.get_payload(decode=True), bytes) 36987db96d56Sopenharmony_ci 36997db96d56Sopenharmony_ci def test_bytes_parser_does_not_close_file(self): 37007db96d56Sopenharmony_ci with openfile('msg_02.txt', 'rb') as fp: 37017db96d56Sopenharmony_ci email.parser.BytesParser().parse(fp) 37027db96d56Sopenharmony_ci self.assertFalse(fp.closed) 37037db96d56Sopenharmony_ci 37047db96d56Sopenharmony_ci def test_bytes_parser_on_exception_does_not_close_file(self): 37057db96d56Sopenharmony_ci with openfile('msg_15.txt', 'rb') as fp: 37067db96d56Sopenharmony_ci bytesParser = email.parser.BytesParser 37077db96d56Sopenharmony_ci self.assertRaises(email.errors.StartBoundaryNotFoundDefect, 37087db96d56Sopenharmony_ci bytesParser(policy=email.policy.strict).parse, 37097db96d56Sopenharmony_ci fp) 37107db96d56Sopenharmony_ci self.assertFalse(fp.closed) 37117db96d56Sopenharmony_ci 37127db96d56Sopenharmony_ci def test_parser_does_not_close_file(self): 37137db96d56Sopenharmony_ci with openfile('msg_02.txt', encoding="utf-8") as fp: 37147db96d56Sopenharmony_ci email.parser.Parser().parse(fp) 37157db96d56Sopenharmony_ci self.assertFalse(fp.closed) 37167db96d56Sopenharmony_ci 37177db96d56Sopenharmony_ci def test_parser_on_exception_does_not_close_file(self): 37187db96d56Sopenharmony_ci with openfile('msg_15.txt', encoding="utf-8") as fp: 37197db96d56Sopenharmony_ci parser = email.parser.Parser 37207db96d56Sopenharmony_ci self.assertRaises(email.errors.StartBoundaryNotFoundDefect, 37217db96d56Sopenharmony_ci parser(policy=email.policy.strict).parse, fp) 37227db96d56Sopenharmony_ci self.assertFalse(fp.closed) 37237db96d56Sopenharmony_ci 37247db96d56Sopenharmony_ci def test_whitespace_continuation(self): 37257db96d56Sopenharmony_ci eq = self.assertEqual 37267db96d56Sopenharmony_ci # This message contains a line after the Subject: header that has only 37277db96d56Sopenharmony_ci # whitespace, but it is not empty! 37287db96d56Sopenharmony_ci msg = email.message_from_string("""\ 37297db96d56Sopenharmony_ciFrom: aperson@dom.ain 37307db96d56Sopenharmony_ciTo: bperson@dom.ain 37317db96d56Sopenharmony_ciSubject: the next line has a space on it 37327db96d56Sopenharmony_ci\x20 37337db96d56Sopenharmony_ciDate: Mon, 8 Apr 2002 15:09:19 -0400 37347db96d56Sopenharmony_ciMessage-ID: spam 37357db96d56Sopenharmony_ci 37367db96d56Sopenharmony_ciHere's the message body 37377db96d56Sopenharmony_ci""") 37387db96d56Sopenharmony_ci eq(msg['subject'], 'the next line has a space on it\n ') 37397db96d56Sopenharmony_ci eq(msg['message-id'], 'spam') 37407db96d56Sopenharmony_ci eq(msg.get_payload(), "Here's the message body\n") 37417db96d56Sopenharmony_ci 37427db96d56Sopenharmony_ci def test_whitespace_continuation_last_header(self): 37437db96d56Sopenharmony_ci eq = self.assertEqual 37447db96d56Sopenharmony_ci # Like the previous test, but the subject line is the last 37457db96d56Sopenharmony_ci # header. 37467db96d56Sopenharmony_ci msg = email.message_from_string("""\ 37477db96d56Sopenharmony_ciFrom: aperson@dom.ain 37487db96d56Sopenharmony_ciTo: bperson@dom.ain 37497db96d56Sopenharmony_ciDate: Mon, 8 Apr 2002 15:09:19 -0400 37507db96d56Sopenharmony_ciMessage-ID: spam 37517db96d56Sopenharmony_ciSubject: the next line has a space on it 37527db96d56Sopenharmony_ci\x20 37537db96d56Sopenharmony_ci 37547db96d56Sopenharmony_ciHere's the message body 37557db96d56Sopenharmony_ci""") 37567db96d56Sopenharmony_ci eq(msg['subject'], 'the next line has a space on it\n ') 37577db96d56Sopenharmony_ci eq(msg['message-id'], 'spam') 37587db96d56Sopenharmony_ci eq(msg.get_payload(), "Here's the message body\n") 37597db96d56Sopenharmony_ci 37607db96d56Sopenharmony_ci def test_crlf_separation(self): 37617db96d56Sopenharmony_ci eq = self.assertEqual 37627db96d56Sopenharmony_ci with openfile('msg_26.txt', encoding="utf-8", newline='\n') as fp: 37637db96d56Sopenharmony_ci msg = Parser().parse(fp) 37647db96d56Sopenharmony_ci eq(len(msg.get_payload()), 2) 37657db96d56Sopenharmony_ci part1 = msg.get_payload(0) 37667db96d56Sopenharmony_ci eq(part1.get_content_type(), 'text/plain') 37677db96d56Sopenharmony_ci eq(part1.get_payload(), 'Simple email with attachment.\r\n\r\n') 37687db96d56Sopenharmony_ci part2 = msg.get_payload(1) 37697db96d56Sopenharmony_ci eq(part2.get_content_type(), 'application/riscos') 37707db96d56Sopenharmony_ci 37717db96d56Sopenharmony_ci def test_crlf_flatten(self): 37727db96d56Sopenharmony_ci # Using newline='\n' preserves the crlfs in this input file. 37737db96d56Sopenharmony_ci with openfile('msg_26.txt', encoding="utf-8", newline='\n') as fp: 37747db96d56Sopenharmony_ci text = fp.read() 37757db96d56Sopenharmony_ci msg = email.message_from_string(text) 37767db96d56Sopenharmony_ci s = StringIO() 37777db96d56Sopenharmony_ci g = Generator(s) 37787db96d56Sopenharmony_ci g.flatten(msg, linesep='\r\n') 37797db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), text) 37807db96d56Sopenharmony_ci 37817db96d56Sopenharmony_ci maxDiff = None 37827db96d56Sopenharmony_ci 37837db96d56Sopenharmony_ci def test_multipart_digest_with_extra_mime_headers(self): 37847db96d56Sopenharmony_ci eq = self.assertEqual 37857db96d56Sopenharmony_ci neq = self.ndiffAssertEqual 37867db96d56Sopenharmony_ci with openfile('msg_28.txt', encoding="utf-8") as fp: 37877db96d56Sopenharmony_ci msg = email.message_from_file(fp) 37887db96d56Sopenharmony_ci # Structure is: 37897db96d56Sopenharmony_ci # multipart/digest 37907db96d56Sopenharmony_ci # message/rfc822 37917db96d56Sopenharmony_ci # text/plain 37927db96d56Sopenharmony_ci # message/rfc822 37937db96d56Sopenharmony_ci # text/plain 37947db96d56Sopenharmony_ci eq(msg.is_multipart(), 1) 37957db96d56Sopenharmony_ci eq(len(msg.get_payload()), 2) 37967db96d56Sopenharmony_ci part1 = msg.get_payload(0) 37977db96d56Sopenharmony_ci eq(part1.get_content_type(), 'message/rfc822') 37987db96d56Sopenharmony_ci eq(part1.is_multipart(), 1) 37997db96d56Sopenharmony_ci eq(len(part1.get_payload()), 1) 38007db96d56Sopenharmony_ci part1a = part1.get_payload(0) 38017db96d56Sopenharmony_ci eq(part1a.is_multipart(), 0) 38027db96d56Sopenharmony_ci eq(part1a.get_content_type(), 'text/plain') 38037db96d56Sopenharmony_ci neq(part1a.get_payload(), 'message 1\n') 38047db96d56Sopenharmony_ci # next message/rfc822 38057db96d56Sopenharmony_ci part2 = msg.get_payload(1) 38067db96d56Sopenharmony_ci eq(part2.get_content_type(), 'message/rfc822') 38077db96d56Sopenharmony_ci eq(part2.is_multipart(), 1) 38087db96d56Sopenharmony_ci eq(len(part2.get_payload()), 1) 38097db96d56Sopenharmony_ci part2a = part2.get_payload(0) 38107db96d56Sopenharmony_ci eq(part2a.is_multipart(), 0) 38117db96d56Sopenharmony_ci eq(part2a.get_content_type(), 'text/plain') 38127db96d56Sopenharmony_ci neq(part2a.get_payload(), 'message 2\n') 38137db96d56Sopenharmony_ci 38147db96d56Sopenharmony_ci def test_three_lines(self): 38157db96d56Sopenharmony_ci # A bug report by Andrew McNamara 38167db96d56Sopenharmony_ci lines = ['From: Andrew Person <aperson@dom.ain', 38177db96d56Sopenharmony_ci 'Subject: Test', 38187db96d56Sopenharmony_ci 'Date: Tue, 20 Aug 2002 16:43:45 +1000'] 38197db96d56Sopenharmony_ci msg = email.message_from_string(NL.join(lines)) 38207db96d56Sopenharmony_ci self.assertEqual(msg['date'], 'Tue, 20 Aug 2002 16:43:45 +1000') 38217db96d56Sopenharmony_ci 38227db96d56Sopenharmony_ci def test_strip_line_feed_and_carriage_return_in_headers(self): 38237db96d56Sopenharmony_ci eq = self.assertEqual 38247db96d56Sopenharmony_ci # For [ 1002475 ] email message parser doesn't handle \r\n correctly 38257db96d56Sopenharmony_ci value1 = 'text' 38267db96d56Sopenharmony_ci value2 = 'more text' 38277db96d56Sopenharmony_ci m = 'Header: %s\r\nNext-Header: %s\r\n\r\nBody\r\n\r\n' % ( 38287db96d56Sopenharmony_ci value1, value2) 38297db96d56Sopenharmony_ci msg = email.message_from_string(m) 38307db96d56Sopenharmony_ci eq(msg.get('Header'), value1) 38317db96d56Sopenharmony_ci eq(msg.get('Next-Header'), value2) 38327db96d56Sopenharmony_ci 38337db96d56Sopenharmony_ci def test_rfc2822_header_syntax(self): 38347db96d56Sopenharmony_ci eq = self.assertEqual 38357db96d56Sopenharmony_ci m = '>From: foo\nFrom: bar\n!"#QUX;~: zoo\n\nbody' 38367db96d56Sopenharmony_ci msg = email.message_from_string(m) 38377db96d56Sopenharmony_ci eq(len(msg), 3) 38387db96d56Sopenharmony_ci eq(sorted(field for field in msg), ['!"#QUX;~', '>From', 'From']) 38397db96d56Sopenharmony_ci eq(msg.get_payload(), 'body') 38407db96d56Sopenharmony_ci 38417db96d56Sopenharmony_ci def test_rfc2822_space_not_allowed_in_header(self): 38427db96d56Sopenharmony_ci eq = self.assertEqual 38437db96d56Sopenharmony_ci m = '>From foo@example.com 11:25:53\nFrom: bar\n!"#QUX;~: zoo\n\nbody' 38447db96d56Sopenharmony_ci msg = email.message_from_string(m) 38457db96d56Sopenharmony_ci eq(len(msg.keys()), 0) 38467db96d56Sopenharmony_ci 38477db96d56Sopenharmony_ci def test_rfc2822_one_character_header(self): 38487db96d56Sopenharmony_ci eq = self.assertEqual 38497db96d56Sopenharmony_ci m = 'A: first header\nB: second header\nCC: third header\n\nbody' 38507db96d56Sopenharmony_ci msg = email.message_from_string(m) 38517db96d56Sopenharmony_ci headers = msg.keys() 38527db96d56Sopenharmony_ci headers.sort() 38537db96d56Sopenharmony_ci eq(headers, ['A', 'B', 'CC']) 38547db96d56Sopenharmony_ci eq(msg.get_payload(), 'body') 38557db96d56Sopenharmony_ci 38567db96d56Sopenharmony_ci def test_CRLFLF_at_end_of_part(self): 38577db96d56Sopenharmony_ci # issue 5610: feedparser should not eat two chars from body part ending 38587db96d56Sopenharmony_ci # with "\r\n\n". 38597db96d56Sopenharmony_ci m = ( 38607db96d56Sopenharmony_ci "From: foo@bar.com\n" 38617db96d56Sopenharmony_ci "To: baz\n" 38627db96d56Sopenharmony_ci "Mime-Version: 1.0\n" 38637db96d56Sopenharmony_ci "Content-Type: multipart/mixed; boundary=BOUNDARY\n" 38647db96d56Sopenharmony_ci "\n" 38657db96d56Sopenharmony_ci "--BOUNDARY\n" 38667db96d56Sopenharmony_ci "Content-Type: text/plain\n" 38677db96d56Sopenharmony_ci "\n" 38687db96d56Sopenharmony_ci "body ending with CRLF newline\r\n" 38697db96d56Sopenharmony_ci "\n" 38707db96d56Sopenharmony_ci "--BOUNDARY--\n" 38717db96d56Sopenharmony_ci ) 38727db96d56Sopenharmony_ci msg = email.message_from_string(m) 38737db96d56Sopenharmony_ci self.assertTrue(msg.get_payload(0).get_payload().endswith('\r\n')) 38747db96d56Sopenharmony_ci 38757db96d56Sopenharmony_ci 38767db96d56Sopenharmony_ciclass Test8BitBytesHandling(TestEmailBase): 38777db96d56Sopenharmony_ci # In Python3 all input is string, but that doesn't work if the actual input 38787db96d56Sopenharmony_ci # uses an 8bit transfer encoding. To hack around that, in email 5.1 we 38797db96d56Sopenharmony_ci # decode byte streams using the surrogateescape error handler, and 38807db96d56Sopenharmony_ci # reconvert to binary at appropriate places if we detect surrogates. This 38817db96d56Sopenharmony_ci # doesn't allow us to transform headers with 8bit bytes (they get munged), 38827db96d56Sopenharmony_ci # but it does allow us to parse and preserve them, and to decode body 38837db96d56Sopenharmony_ci # parts that use an 8bit CTE. 38847db96d56Sopenharmony_ci 38857db96d56Sopenharmony_ci bodytest_msg = textwrap.dedent("""\ 38867db96d56Sopenharmony_ci From: foo@bar.com 38877db96d56Sopenharmony_ci To: baz 38887db96d56Sopenharmony_ci Mime-Version: 1.0 38897db96d56Sopenharmony_ci Content-Type: text/plain; charset={charset} 38907db96d56Sopenharmony_ci Content-Transfer-Encoding: {cte} 38917db96d56Sopenharmony_ci 38927db96d56Sopenharmony_ci {bodyline} 38937db96d56Sopenharmony_ci """) 38947db96d56Sopenharmony_ci 38957db96d56Sopenharmony_ci def test_known_8bit_CTE(self): 38967db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='utf-8', 38977db96d56Sopenharmony_ci cte='8bit', 38987db96d56Sopenharmony_ci bodyline='pöstal').encode('utf-8') 38997db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39007db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), "pöstal\n") 39017db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39027db96d56Sopenharmony_ci "pöstal\n".encode('utf-8')) 39037db96d56Sopenharmony_ci 39047db96d56Sopenharmony_ci def test_unknown_8bit_CTE(self): 39057db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='notavalidcharset', 39067db96d56Sopenharmony_ci cte='8bit', 39077db96d56Sopenharmony_ci bodyline='pöstal').encode('utf-8') 39087db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39097db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), "p\uFFFD\uFFFDstal\n") 39107db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39117db96d56Sopenharmony_ci "pöstal\n".encode('utf-8')) 39127db96d56Sopenharmony_ci 39137db96d56Sopenharmony_ci def test_8bit_in_quopri_body(self): 39147db96d56Sopenharmony_ci # This is non-RFC compliant data...without 'decode' the library code 39157db96d56Sopenharmony_ci # decodes the body using the charset from the headers, and because the 39167db96d56Sopenharmony_ci # source byte really is utf-8 this works. This is likely to fail 39177db96d56Sopenharmony_ci # against real dirty data (ie: produce mojibake), but the data is 39187db96d56Sopenharmony_ci # invalid anyway so it is as good a guess as any. But this means that 39197db96d56Sopenharmony_ci # this test just confirms the current behavior; that behavior is not 39207db96d56Sopenharmony_ci # necessarily the best possible behavior. With 'decode' it is 39217db96d56Sopenharmony_ci # returning the raw bytes, so that test should be of correct behavior, 39227db96d56Sopenharmony_ci # or at least produce the same result that email4 did. 39237db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='utf-8', 39247db96d56Sopenharmony_ci cte='quoted-printable', 39257db96d56Sopenharmony_ci bodyline='p=C3=B6stál').encode('utf-8') 39267db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39277db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), 'p=C3=B6stál\n') 39287db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39297db96d56Sopenharmony_ci 'pöstál\n'.encode('utf-8')) 39307db96d56Sopenharmony_ci 39317db96d56Sopenharmony_ci def test_invalid_8bit_in_non_8bit_cte_uses_replace(self): 39327db96d56Sopenharmony_ci # This is similar to the previous test, but proves that if the 8bit 39337db96d56Sopenharmony_ci # byte is undecodeable in the specified charset, it gets replaced 39347db96d56Sopenharmony_ci # by the unicode 'unknown' character. Again, this may or may not 39357db96d56Sopenharmony_ci # be the ideal behavior. Note that if decode=False none of the 39367db96d56Sopenharmony_ci # decoders will get involved, so this is the only test we need 39377db96d56Sopenharmony_ci # for this behavior. 39387db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='ascii', 39397db96d56Sopenharmony_ci cte='quoted-printable', 39407db96d56Sopenharmony_ci bodyline='p=C3=B6stál').encode('utf-8') 39417db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39427db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), 'p=C3=B6st\uFFFD\uFFFDl\n') 39437db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39447db96d56Sopenharmony_ci 'pöstál\n'.encode('utf-8')) 39457db96d56Sopenharmony_ci 39467db96d56Sopenharmony_ci # test_defect_handling:test_invalid_chars_in_base64_payload 39477db96d56Sopenharmony_ci def test_8bit_in_base64_body(self): 39487db96d56Sopenharmony_ci # If we get 8bit bytes in a base64 body, we can just ignore them 39497db96d56Sopenharmony_ci # as being outside the base64 alphabet and decode anyway. But 39507db96d56Sopenharmony_ci # we register a defect. 39517db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='utf-8', 39527db96d56Sopenharmony_ci cte='base64', 39537db96d56Sopenharmony_ci bodyline='cMO2c3RhbAá=').encode('utf-8') 39547db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39557db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39567db96d56Sopenharmony_ci 'pöstal'.encode('utf-8')) 39577db96d56Sopenharmony_ci self.assertIsInstance(msg.defects[0], 39587db96d56Sopenharmony_ci errors.InvalidBase64CharactersDefect) 39597db96d56Sopenharmony_ci 39607db96d56Sopenharmony_ci def test_8bit_in_uuencode_body(self): 39617db96d56Sopenharmony_ci # Sticking an 8bit byte in a uuencode block makes it undecodable by 39627db96d56Sopenharmony_ci # normal means, so the block is returned undecoded, but as bytes. 39637db96d56Sopenharmony_ci m = self.bodytest_msg.format(charset='utf-8', 39647db96d56Sopenharmony_ci cte='uuencode', 39657db96d56Sopenharmony_ci bodyline='<,.V<W1A; á ').encode('utf-8') 39667db96d56Sopenharmony_ci msg = email.message_from_bytes(m) 39677db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), 39687db96d56Sopenharmony_ci '<,.V<W1A; á \n'.encode('utf-8')) 39697db96d56Sopenharmony_ci 39707db96d56Sopenharmony_ci 39717db96d56Sopenharmony_ci headertest_headers = ( 39727db96d56Sopenharmony_ci ('From: foo@bar.com', ('From', 'foo@bar.com')), 39737db96d56Sopenharmony_ci ('To: báz', ('To', '=?unknown-8bit?q?b=C3=A1z?=')), 39747db96d56Sopenharmony_ci ('Subject: Maintenant je vous présente mon collègue, le pouf célèbre\n' 39757db96d56Sopenharmony_ci '\tJean de Baddie', 39767db96d56Sopenharmony_ci ('Subject', '=?unknown-8bit?q?Maintenant_je_vous_pr=C3=A9sente_mon_' 39777db96d56Sopenharmony_ci 'coll=C3=A8gue=2C_le_pouf_c=C3=A9l=C3=A8bre?=\n' 39787db96d56Sopenharmony_ci ' =?unknown-8bit?q?_Jean_de_Baddie?=')), 39797db96d56Sopenharmony_ci ('From: göst', ('From', '=?unknown-8bit?b?Z8O2c3Q=?=')), 39807db96d56Sopenharmony_ci ) 39817db96d56Sopenharmony_ci headertest_msg = ('\n'.join([src for (src, _) in headertest_headers]) + 39827db96d56Sopenharmony_ci '\nYes, they are flying.\n').encode('utf-8') 39837db96d56Sopenharmony_ci 39847db96d56Sopenharmony_ci def test_get_8bit_header(self): 39857db96d56Sopenharmony_ci msg = email.message_from_bytes(self.headertest_msg) 39867db96d56Sopenharmony_ci self.assertEqual(str(msg.get('to')), 'b\uFFFD\uFFFDz') 39877db96d56Sopenharmony_ci self.assertEqual(str(msg['to']), 'b\uFFFD\uFFFDz') 39887db96d56Sopenharmony_ci 39897db96d56Sopenharmony_ci def test_print_8bit_headers(self): 39907db96d56Sopenharmony_ci msg = email.message_from_bytes(self.headertest_msg) 39917db96d56Sopenharmony_ci self.assertEqual(str(msg), 39927db96d56Sopenharmony_ci textwrap.dedent("""\ 39937db96d56Sopenharmony_ci From: {} 39947db96d56Sopenharmony_ci To: {} 39957db96d56Sopenharmony_ci Subject: {} 39967db96d56Sopenharmony_ci From: {} 39977db96d56Sopenharmony_ci 39987db96d56Sopenharmony_ci Yes, they are flying. 39997db96d56Sopenharmony_ci """).format(*[expected[1] for (_, expected) in 40007db96d56Sopenharmony_ci self.headertest_headers])) 40017db96d56Sopenharmony_ci 40027db96d56Sopenharmony_ci def test_values_with_8bit_headers(self): 40037db96d56Sopenharmony_ci msg = email.message_from_bytes(self.headertest_msg) 40047db96d56Sopenharmony_ci self.assertListEqual([str(x) for x in msg.values()], 40057db96d56Sopenharmony_ci ['foo@bar.com', 40067db96d56Sopenharmony_ci 'b\uFFFD\uFFFDz', 40077db96d56Sopenharmony_ci 'Maintenant je vous pr\uFFFD\uFFFDsente mon ' 40087db96d56Sopenharmony_ci 'coll\uFFFD\uFFFDgue, le pouf ' 40097db96d56Sopenharmony_ci 'c\uFFFD\uFFFDl\uFFFD\uFFFDbre\n' 40107db96d56Sopenharmony_ci '\tJean de Baddie', 40117db96d56Sopenharmony_ci "g\uFFFD\uFFFDst"]) 40127db96d56Sopenharmony_ci 40137db96d56Sopenharmony_ci def test_items_with_8bit_headers(self): 40147db96d56Sopenharmony_ci msg = email.message_from_bytes(self.headertest_msg) 40157db96d56Sopenharmony_ci self.assertListEqual([(str(x), str(y)) for (x, y) in msg.items()], 40167db96d56Sopenharmony_ci [('From', 'foo@bar.com'), 40177db96d56Sopenharmony_ci ('To', 'b\uFFFD\uFFFDz'), 40187db96d56Sopenharmony_ci ('Subject', 'Maintenant je vous ' 40197db96d56Sopenharmony_ci 'pr\uFFFD\uFFFDsente ' 40207db96d56Sopenharmony_ci 'mon coll\uFFFD\uFFFDgue, le pouf ' 40217db96d56Sopenharmony_ci 'c\uFFFD\uFFFDl\uFFFD\uFFFDbre\n' 40227db96d56Sopenharmony_ci '\tJean de Baddie'), 40237db96d56Sopenharmony_ci ('From', 'g\uFFFD\uFFFDst')]) 40247db96d56Sopenharmony_ci 40257db96d56Sopenharmony_ci def test_get_all_with_8bit_headers(self): 40267db96d56Sopenharmony_ci msg = email.message_from_bytes(self.headertest_msg) 40277db96d56Sopenharmony_ci self.assertListEqual([str(x) for x in msg.get_all('from')], 40287db96d56Sopenharmony_ci ['foo@bar.com', 40297db96d56Sopenharmony_ci 'g\uFFFD\uFFFDst']) 40307db96d56Sopenharmony_ci 40317db96d56Sopenharmony_ci def test_get_content_type_with_8bit(self): 40327db96d56Sopenharmony_ci msg = email.message_from_bytes(textwrap.dedent("""\ 40337db96d56Sopenharmony_ci Content-Type: text/pl\xA7in; charset=utf-8 40347db96d56Sopenharmony_ci """).encode('latin-1')) 40357db96d56Sopenharmony_ci self.assertEqual(msg.get_content_type(), "text/pl\uFFFDin") 40367db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), "text") 40377db96d56Sopenharmony_ci self.assertEqual(msg.get_content_subtype(), "pl\uFFFDin") 40387db96d56Sopenharmony_ci 40397db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.non_ascii_in_params 40407db96d56Sopenharmony_ci def test_get_params_with_8bit(self): 40417db96d56Sopenharmony_ci msg = email.message_from_bytes( 40427db96d56Sopenharmony_ci 'X-Header: foo=\xa7ne; b\xa7r=two; baz=three\n'.encode('latin-1')) 40437db96d56Sopenharmony_ci self.assertEqual(msg.get_params(header='x-header'), 40447db96d56Sopenharmony_ci [('foo', '\uFFFDne'), ('b\uFFFDr', 'two'), ('baz', 'three')]) 40457db96d56Sopenharmony_ci self.assertEqual(msg.get_param('Foo', header='x-header'), '\uFFFdne') 40467db96d56Sopenharmony_ci # XXX: someday you might be able to get 'b\xa7r', for now you can't. 40477db96d56Sopenharmony_ci self.assertEqual(msg.get_param('b\xa7r', header='x-header'), None) 40487db96d56Sopenharmony_ci 40497db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.non_ascii_in_rfc2231_value 40507db96d56Sopenharmony_ci def test_get_rfc2231_params_with_8bit(self): 40517db96d56Sopenharmony_ci msg = email.message_from_bytes(textwrap.dedent("""\ 40527db96d56Sopenharmony_ci Content-Type: text/plain; charset=us-ascii; 40537db96d56Sopenharmony_ci title*=us-ascii'en'This%20is%20not%20f\xa7n""" 40547db96d56Sopenharmony_ci ).encode('latin-1')) 40557db96d56Sopenharmony_ci self.assertEqual(msg.get_param('title'), 40567db96d56Sopenharmony_ci ('us-ascii', 'en', 'This is not f\uFFFDn')) 40577db96d56Sopenharmony_ci 40587db96d56Sopenharmony_ci def test_set_rfc2231_params_with_8bit(self): 40597db96d56Sopenharmony_ci msg = email.message_from_bytes(textwrap.dedent("""\ 40607db96d56Sopenharmony_ci Content-Type: text/plain; charset=us-ascii; 40617db96d56Sopenharmony_ci title*=us-ascii'en'This%20is%20not%20f\xa7n""" 40627db96d56Sopenharmony_ci ).encode('latin-1')) 40637db96d56Sopenharmony_ci msg.set_param('title', 'test') 40647db96d56Sopenharmony_ci self.assertEqual(msg.get_param('title'), 'test') 40657db96d56Sopenharmony_ci 40667db96d56Sopenharmony_ci def test_del_rfc2231_params_with_8bit(self): 40677db96d56Sopenharmony_ci msg = email.message_from_bytes(textwrap.dedent("""\ 40687db96d56Sopenharmony_ci Content-Type: text/plain; charset=us-ascii; 40697db96d56Sopenharmony_ci title*=us-ascii'en'This%20is%20not%20f\xa7n""" 40707db96d56Sopenharmony_ci ).encode('latin-1')) 40717db96d56Sopenharmony_ci msg.del_param('title') 40727db96d56Sopenharmony_ci self.assertEqual(msg.get_param('title'), None) 40737db96d56Sopenharmony_ci self.assertEqual(msg.get_content_maintype(), 'text') 40747db96d56Sopenharmony_ci 40757db96d56Sopenharmony_ci def test_get_payload_with_8bit_cte_header(self): 40767db96d56Sopenharmony_ci msg = email.message_from_bytes(textwrap.dedent("""\ 40777db96d56Sopenharmony_ci Content-Transfer-Encoding: b\xa7se64 40787db96d56Sopenharmony_ci Content-Type: text/plain; charset=latin-1 40797db96d56Sopenharmony_ci 40807db96d56Sopenharmony_ci payload 40817db96d56Sopenharmony_ci """).encode('latin-1')) 40827db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(), 'payload\n') 40837db96d56Sopenharmony_ci self.assertEqual(msg.get_payload(decode=True), b'payload\n') 40847db96d56Sopenharmony_ci 40857db96d56Sopenharmony_ci non_latin_bin_msg = textwrap.dedent("""\ 40867db96d56Sopenharmony_ci From: foo@bar.com 40877db96d56Sopenharmony_ci To: báz 40887db96d56Sopenharmony_ci Subject: Maintenant je vous présente mon collègue, le pouf célèbre 40897db96d56Sopenharmony_ci \tJean de Baddie 40907db96d56Sopenharmony_ci Mime-Version: 1.0 40917db96d56Sopenharmony_ci Content-Type: text/plain; charset="utf-8" 40927db96d56Sopenharmony_ci Content-Transfer-Encoding: 8bit 40937db96d56Sopenharmony_ci 40947db96d56Sopenharmony_ci Да, они летят. 40957db96d56Sopenharmony_ci """).encode('utf-8') 40967db96d56Sopenharmony_ci 40977db96d56Sopenharmony_ci def test_bytes_generator(self): 40987db96d56Sopenharmony_ci msg = email.message_from_bytes(self.non_latin_bin_msg) 40997db96d56Sopenharmony_ci out = BytesIO() 41007db96d56Sopenharmony_ci email.generator.BytesGenerator(out).flatten(msg) 41017db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), self.non_latin_bin_msg) 41027db96d56Sopenharmony_ci 41037db96d56Sopenharmony_ci def test_bytes_generator_handles_None_body(self): 41047db96d56Sopenharmony_ci #Issue 11019 41057db96d56Sopenharmony_ci msg = email.message.Message() 41067db96d56Sopenharmony_ci out = BytesIO() 41077db96d56Sopenharmony_ci email.generator.BytesGenerator(out).flatten(msg) 41087db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), b"\n") 41097db96d56Sopenharmony_ci 41107db96d56Sopenharmony_ci non_latin_bin_msg_as7bit_wrapped = textwrap.dedent("""\ 41117db96d56Sopenharmony_ci From: foo@bar.com 41127db96d56Sopenharmony_ci To: =?unknown-8bit?q?b=C3=A1z?= 41137db96d56Sopenharmony_ci Subject: =?unknown-8bit?q?Maintenant_je_vous_pr=C3=A9sente_mon_coll=C3=A8gue?= 41147db96d56Sopenharmony_ci =?unknown-8bit?q?=2C_le_pouf_c=C3=A9l=C3=A8bre?= 41157db96d56Sopenharmony_ci =?unknown-8bit?q?_Jean_de_Baddie?= 41167db96d56Sopenharmony_ci Mime-Version: 1.0 41177db96d56Sopenharmony_ci Content-Type: text/plain; charset="utf-8" 41187db96d56Sopenharmony_ci Content-Transfer-Encoding: base64 41197db96d56Sopenharmony_ci 41207db96d56Sopenharmony_ci 0JTQsCwg0L7QvdC4INC70LXRgtGP0YIuCg== 41217db96d56Sopenharmony_ci """) 41227db96d56Sopenharmony_ci 41237db96d56Sopenharmony_ci def test_generator_handles_8bit(self): 41247db96d56Sopenharmony_ci msg = email.message_from_bytes(self.non_latin_bin_msg) 41257db96d56Sopenharmony_ci out = StringIO() 41267db96d56Sopenharmony_ci email.generator.Generator(out).flatten(msg) 41277db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), self.non_latin_bin_msg_as7bit_wrapped) 41287db96d56Sopenharmony_ci 41297db96d56Sopenharmony_ci def test_str_generator_should_not_mutate_msg_when_handling_8bit(self): 41307db96d56Sopenharmony_ci msg = email.message_from_bytes(self.non_latin_bin_msg) 41317db96d56Sopenharmony_ci out = BytesIO() 41327db96d56Sopenharmony_ci BytesGenerator(out).flatten(msg) 41337db96d56Sopenharmony_ci orig_value = out.getvalue() 41347db96d56Sopenharmony_ci Generator(StringIO()).flatten(msg) # Should not mutate msg! 41357db96d56Sopenharmony_ci out = BytesIO() 41367db96d56Sopenharmony_ci BytesGenerator(out).flatten(msg) 41377db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), orig_value) 41387db96d56Sopenharmony_ci 41397db96d56Sopenharmony_ci def test_bytes_generator_with_unix_from(self): 41407db96d56Sopenharmony_ci # The unixfrom contains a current date, so we can't check it 41417db96d56Sopenharmony_ci # literally. Just make sure the first word is 'From' and the 41427db96d56Sopenharmony_ci # rest of the message matches the input. 41437db96d56Sopenharmony_ci msg = email.message_from_bytes(self.non_latin_bin_msg) 41447db96d56Sopenharmony_ci out = BytesIO() 41457db96d56Sopenharmony_ci email.generator.BytesGenerator(out).flatten(msg, unixfrom=True) 41467db96d56Sopenharmony_ci lines = out.getvalue().split(b'\n') 41477db96d56Sopenharmony_ci self.assertEqual(lines[0].split()[0], b'From') 41487db96d56Sopenharmony_ci self.assertEqual(b'\n'.join(lines[1:]), self.non_latin_bin_msg) 41497db96d56Sopenharmony_ci 41507db96d56Sopenharmony_ci non_latin_bin_msg_as7bit = non_latin_bin_msg_as7bit_wrapped.split('\n') 41517db96d56Sopenharmony_ci non_latin_bin_msg_as7bit[2:4] = [ 41527db96d56Sopenharmony_ci 'Subject: =?unknown-8bit?q?Maintenant_je_vous_pr=C3=A9sente_mon_' 41537db96d56Sopenharmony_ci 'coll=C3=A8gue=2C_le_pouf_c=C3=A9l=C3=A8bre?='] 41547db96d56Sopenharmony_ci non_latin_bin_msg_as7bit = '\n'.join(non_latin_bin_msg_as7bit) 41557db96d56Sopenharmony_ci 41567db96d56Sopenharmony_ci def test_message_from_binary_file(self): 41577db96d56Sopenharmony_ci fn = 'test.msg' 41587db96d56Sopenharmony_ci self.addCleanup(unlink, fn) 41597db96d56Sopenharmony_ci with open(fn, 'wb') as testfile: 41607db96d56Sopenharmony_ci testfile.write(self.non_latin_bin_msg) 41617db96d56Sopenharmony_ci with open(fn, 'rb') as testfile: 41627db96d56Sopenharmony_ci m = email.parser.BytesParser().parse(testfile) 41637db96d56Sopenharmony_ci self.assertEqual(str(m), self.non_latin_bin_msg_as7bit) 41647db96d56Sopenharmony_ci 41657db96d56Sopenharmony_ci latin_bin_msg = textwrap.dedent("""\ 41667db96d56Sopenharmony_ci From: foo@bar.com 41677db96d56Sopenharmony_ci To: Dinsdale 41687db96d56Sopenharmony_ci Subject: Nudge nudge, wink, wink 41697db96d56Sopenharmony_ci Mime-Version: 1.0 41707db96d56Sopenharmony_ci Content-Type: text/plain; charset="latin-1" 41717db96d56Sopenharmony_ci Content-Transfer-Encoding: 8bit 41727db96d56Sopenharmony_ci 41737db96d56Sopenharmony_ci oh là là, know what I mean, know what I mean? 41747db96d56Sopenharmony_ci """).encode('latin-1') 41757db96d56Sopenharmony_ci 41767db96d56Sopenharmony_ci latin_bin_msg_as7bit = textwrap.dedent("""\ 41777db96d56Sopenharmony_ci From: foo@bar.com 41787db96d56Sopenharmony_ci To: Dinsdale 41797db96d56Sopenharmony_ci Subject: Nudge nudge, wink, wink 41807db96d56Sopenharmony_ci Mime-Version: 1.0 41817db96d56Sopenharmony_ci Content-Type: text/plain; charset="iso-8859-1" 41827db96d56Sopenharmony_ci Content-Transfer-Encoding: quoted-printable 41837db96d56Sopenharmony_ci 41847db96d56Sopenharmony_ci oh l=E0 l=E0, know what I mean, know what I mean? 41857db96d56Sopenharmony_ci """) 41867db96d56Sopenharmony_ci 41877db96d56Sopenharmony_ci def test_string_generator_reencodes_to_quopri_when_appropriate(self): 41887db96d56Sopenharmony_ci m = email.message_from_bytes(self.latin_bin_msg) 41897db96d56Sopenharmony_ci self.assertEqual(str(m), self.latin_bin_msg_as7bit) 41907db96d56Sopenharmony_ci 41917db96d56Sopenharmony_ci def test_decoded_generator_emits_unicode_body(self): 41927db96d56Sopenharmony_ci m = email.message_from_bytes(self.latin_bin_msg) 41937db96d56Sopenharmony_ci out = StringIO() 41947db96d56Sopenharmony_ci email.generator.DecodedGenerator(out).flatten(m) 41957db96d56Sopenharmony_ci #DecodedHeader output contains an extra blank line compared 41967db96d56Sopenharmony_ci #to the input message. RDM: not sure if this is a bug or not, 41977db96d56Sopenharmony_ci #but it is not specific to the 8bit->7bit conversion. 41987db96d56Sopenharmony_ci self.assertEqual(out.getvalue(), 41997db96d56Sopenharmony_ci self.latin_bin_msg.decode('latin-1')+'\n') 42007db96d56Sopenharmony_ci 42017db96d56Sopenharmony_ci def test_bytes_feedparser(self): 42027db96d56Sopenharmony_ci bfp = email.feedparser.BytesFeedParser() 42037db96d56Sopenharmony_ci for i in range(0, len(self.latin_bin_msg), 10): 42047db96d56Sopenharmony_ci bfp.feed(self.latin_bin_msg[i:i+10]) 42057db96d56Sopenharmony_ci m = bfp.close() 42067db96d56Sopenharmony_ci self.assertEqual(str(m), self.latin_bin_msg_as7bit) 42077db96d56Sopenharmony_ci 42087db96d56Sopenharmony_ci def test_crlf_flatten(self): 42097db96d56Sopenharmony_ci with openfile('msg_26.txt', 'rb') as fp: 42107db96d56Sopenharmony_ci text = fp.read() 42117db96d56Sopenharmony_ci msg = email.message_from_bytes(text) 42127db96d56Sopenharmony_ci s = BytesIO() 42137db96d56Sopenharmony_ci g = email.generator.BytesGenerator(s) 42147db96d56Sopenharmony_ci g.flatten(msg, linesep='\r\n') 42157db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), text) 42167db96d56Sopenharmony_ci 42177db96d56Sopenharmony_ci def test_8bit_multipart(self): 42187db96d56Sopenharmony_ci # Issue 11605 42197db96d56Sopenharmony_ci source = textwrap.dedent("""\ 42207db96d56Sopenharmony_ci Date: Fri, 18 Mar 2011 17:15:43 +0100 42217db96d56Sopenharmony_ci To: foo@example.com 42227db96d56Sopenharmony_ci From: foodwatch-Newsletter <bar@example.com> 42237db96d56Sopenharmony_ci Subject: Aktuelles zu Japan, Klonfleisch und Smiley-System 42247db96d56Sopenharmony_ci Message-ID: <76a486bee62b0d200f33dc2ca08220ad@localhost.localdomain> 42257db96d56Sopenharmony_ci MIME-Version: 1.0 42267db96d56Sopenharmony_ci Content-Type: multipart/alternative; 42277db96d56Sopenharmony_ci boundary="b1_76a486bee62b0d200f33dc2ca08220ad" 42287db96d56Sopenharmony_ci 42297db96d56Sopenharmony_ci --b1_76a486bee62b0d200f33dc2ca08220ad 42307db96d56Sopenharmony_ci Content-Type: text/plain; charset="utf-8" 42317db96d56Sopenharmony_ci Content-Transfer-Encoding: 8bit 42327db96d56Sopenharmony_ci 42337db96d56Sopenharmony_ci Guten Tag, , 42347db96d56Sopenharmony_ci 42357db96d56Sopenharmony_ci mit großer Betroffenheit verfolgen auch wir im foodwatch-Team die 42367db96d56Sopenharmony_ci Nachrichten aus Japan. 42377db96d56Sopenharmony_ci 42387db96d56Sopenharmony_ci 42397db96d56Sopenharmony_ci --b1_76a486bee62b0d200f33dc2ca08220ad 42407db96d56Sopenharmony_ci Content-Type: text/html; charset="utf-8" 42417db96d56Sopenharmony_ci Content-Transfer-Encoding: 8bit 42427db96d56Sopenharmony_ci 42437db96d56Sopenharmony_ci <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 42447db96d56Sopenharmony_ci "http://www.w3.org/TR/html4/loose.dtd"> 42457db96d56Sopenharmony_ci <html lang="de"> 42467db96d56Sopenharmony_ci <head> 42477db96d56Sopenharmony_ci <title>foodwatch - Newsletter</title> 42487db96d56Sopenharmony_ci </head> 42497db96d56Sopenharmony_ci <body> 42507db96d56Sopenharmony_ci <p>mit großer Betroffenheit verfolgen auch wir im foodwatch-Team 42517db96d56Sopenharmony_ci die Nachrichten aus Japan.</p> 42527db96d56Sopenharmony_ci </body> 42537db96d56Sopenharmony_ci </html> 42547db96d56Sopenharmony_ci --b1_76a486bee62b0d200f33dc2ca08220ad-- 42557db96d56Sopenharmony_ci 42567db96d56Sopenharmony_ci """).encode('utf-8') 42577db96d56Sopenharmony_ci msg = email.message_from_bytes(source) 42587db96d56Sopenharmony_ci s = BytesIO() 42597db96d56Sopenharmony_ci g = email.generator.BytesGenerator(s) 42607db96d56Sopenharmony_ci g.flatten(msg) 42617db96d56Sopenharmony_ci self.assertEqual(s.getvalue(), source) 42627db96d56Sopenharmony_ci 42637db96d56Sopenharmony_ci def test_bytes_generator_b_encoding_linesep(self): 42647db96d56Sopenharmony_ci # Issue 14062: b encoding was tacking on an extra \n. 42657db96d56Sopenharmony_ci m = Message() 42667db96d56Sopenharmony_ci # This has enough non-ascii that it should always end up b encoded. 42677db96d56Sopenharmony_ci m['Subject'] = Header('žluťoučký kůň') 42687db96d56Sopenharmony_ci s = BytesIO() 42697db96d56Sopenharmony_ci g = email.generator.BytesGenerator(s) 42707db96d56Sopenharmony_ci g.flatten(m, linesep='\r\n') 42717db96d56Sopenharmony_ci self.assertEqual( 42727db96d56Sopenharmony_ci s.getvalue(), 42737db96d56Sopenharmony_ci b'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') 42747db96d56Sopenharmony_ci 42757db96d56Sopenharmony_ci def test_generator_b_encoding_linesep(self): 42767db96d56Sopenharmony_ci # Since this broke in ByteGenerator, test Generator for completeness. 42777db96d56Sopenharmony_ci m = Message() 42787db96d56Sopenharmony_ci # This has enough non-ascii that it should always end up b encoded. 42797db96d56Sopenharmony_ci m['Subject'] = Header('žluťoučký kůň') 42807db96d56Sopenharmony_ci s = StringIO() 42817db96d56Sopenharmony_ci g = email.generator.Generator(s) 42827db96d56Sopenharmony_ci g.flatten(m, linesep='\r\n') 42837db96d56Sopenharmony_ci self.assertEqual( 42847db96d56Sopenharmony_ci s.getvalue(), 42857db96d56Sopenharmony_ci 'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') 42867db96d56Sopenharmony_ci 42877db96d56Sopenharmony_ci maxDiff = None 42887db96d56Sopenharmony_ci 42897db96d56Sopenharmony_ci 42907db96d56Sopenharmony_ciclass BaseTestBytesGeneratorIdempotent: 42917db96d56Sopenharmony_ci 42927db96d56Sopenharmony_ci maxDiff = None 42937db96d56Sopenharmony_ci 42947db96d56Sopenharmony_ci def _msgobj(self, filename): 42957db96d56Sopenharmony_ci with openfile(filename, 'rb') as fp: 42967db96d56Sopenharmony_ci data = fp.read() 42977db96d56Sopenharmony_ci data = self.normalize_linesep_regex.sub(self.blinesep, data) 42987db96d56Sopenharmony_ci msg = email.message_from_bytes(data) 42997db96d56Sopenharmony_ci return msg, data 43007db96d56Sopenharmony_ci 43017db96d56Sopenharmony_ci def _idempotent(self, msg, data, unixfrom=False): 43027db96d56Sopenharmony_ci b = BytesIO() 43037db96d56Sopenharmony_ci g = email.generator.BytesGenerator(b, maxheaderlen=0) 43047db96d56Sopenharmony_ci g.flatten(msg, unixfrom=unixfrom, linesep=self.linesep) 43057db96d56Sopenharmony_ci self.assertEqual(data, b.getvalue()) 43067db96d56Sopenharmony_ci 43077db96d56Sopenharmony_ci 43087db96d56Sopenharmony_ciclass TestBytesGeneratorIdempotentNL(BaseTestBytesGeneratorIdempotent, 43097db96d56Sopenharmony_ci TestIdempotent): 43107db96d56Sopenharmony_ci linesep = '\n' 43117db96d56Sopenharmony_ci blinesep = b'\n' 43127db96d56Sopenharmony_ci normalize_linesep_regex = re.compile(br'\r\n') 43137db96d56Sopenharmony_ci 43147db96d56Sopenharmony_ci 43157db96d56Sopenharmony_ciclass TestBytesGeneratorIdempotentCRLF(BaseTestBytesGeneratorIdempotent, 43167db96d56Sopenharmony_ci TestIdempotent): 43177db96d56Sopenharmony_ci linesep = '\r\n' 43187db96d56Sopenharmony_ci blinesep = b'\r\n' 43197db96d56Sopenharmony_ci normalize_linesep_regex = re.compile(br'(?<!\r)\n') 43207db96d56Sopenharmony_ci 43217db96d56Sopenharmony_ci 43227db96d56Sopenharmony_ciclass TestBase64(unittest.TestCase): 43237db96d56Sopenharmony_ci def test_len(self): 43247db96d56Sopenharmony_ci eq = self.assertEqual 43257db96d56Sopenharmony_ci eq(base64mime.header_length('hello'), 43267db96d56Sopenharmony_ci len(base64mime.body_encode(b'hello', eol=''))) 43277db96d56Sopenharmony_ci for size in range(15): 43287db96d56Sopenharmony_ci if size == 0 : bsize = 0 43297db96d56Sopenharmony_ci elif size <= 3 : bsize = 4 43307db96d56Sopenharmony_ci elif size <= 6 : bsize = 8 43317db96d56Sopenharmony_ci elif size <= 9 : bsize = 12 43327db96d56Sopenharmony_ci elif size <= 12: bsize = 16 43337db96d56Sopenharmony_ci else : bsize = 20 43347db96d56Sopenharmony_ci eq(base64mime.header_length('x' * size), bsize) 43357db96d56Sopenharmony_ci 43367db96d56Sopenharmony_ci def test_decode(self): 43377db96d56Sopenharmony_ci eq = self.assertEqual 43387db96d56Sopenharmony_ci eq(base64mime.decode(''), b'') 43397db96d56Sopenharmony_ci eq(base64mime.decode('aGVsbG8='), b'hello') 43407db96d56Sopenharmony_ci 43417db96d56Sopenharmony_ci def test_encode(self): 43427db96d56Sopenharmony_ci eq = self.assertEqual 43437db96d56Sopenharmony_ci eq(base64mime.body_encode(b''), '') 43447db96d56Sopenharmony_ci eq(base64mime.body_encode(b'hello'), 'aGVsbG8=\n') 43457db96d56Sopenharmony_ci # Test the binary flag 43467db96d56Sopenharmony_ci eq(base64mime.body_encode(b'hello\n'), 'aGVsbG8K\n') 43477db96d56Sopenharmony_ci # Test the maxlinelen arg 43487db96d56Sopenharmony_ci eq(base64mime.body_encode(b'xxxx ' * 20, maxlinelen=40), """\ 43497db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg 43507db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg 43517db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg 43527db96d56Sopenharmony_cieHh4eCB4eHh4IA== 43537db96d56Sopenharmony_ci""") 43547db96d56Sopenharmony_ci # Test the eol argument 43557db96d56Sopenharmony_ci eq(base64mime.body_encode(b'xxxx ' * 20, maxlinelen=40, eol='\r\n'), 43567db96d56Sopenharmony_ci """\ 43577db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r 43587db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r 43597db96d56Sopenharmony_cieHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r 43607db96d56Sopenharmony_cieHh4eCB4eHh4IA==\r 43617db96d56Sopenharmony_ci""") 43627db96d56Sopenharmony_ci 43637db96d56Sopenharmony_ci def test_header_encode(self): 43647db96d56Sopenharmony_ci eq = self.assertEqual 43657db96d56Sopenharmony_ci he = base64mime.header_encode 43667db96d56Sopenharmony_ci eq(he('hello'), '=?iso-8859-1?b?aGVsbG8=?=') 43677db96d56Sopenharmony_ci eq(he('hello\r\nworld'), '=?iso-8859-1?b?aGVsbG8NCndvcmxk?=') 43687db96d56Sopenharmony_ci eq(he('hello\nworld'), '=?iso-8859-1?b?aGVsbG8Kd29ybGQ=?=') 43697db96d56Sopenharmony_ci # Test the charset option 43707db96d56Sopenharmony_ci eq(he('hello', charset='iso-8859-2'), '=?iso-8859-2?b?aGVsbG8=?=') 43717db96d56Sopenharmony_ci eq(he('hello\nworld'), '=?iso-8859-1?b?aGVsbG8Kd29ybGQ=?=') 43727db96d56Sopenharmony_ci 43737db96d56Sopenharmony_ci 43747db96d56Sopenharmony_ciclass TestQuopri(unittest.TestCase): 43757db96d56Sopenharmony_ci def setUp(self): 43767db96d56Sopenharmony_ci # Set of characters (as byte integers) that don't need to be encoded 43777db96d56Sopenharmony_ci # in headers. 43787db96d56Sopenharmony_ci self.hlit = list(chain( 43797db96d56Sopenharmony_ci range(ord('a'), ord('z') + 1), 43807db96d56Sopenharmony_ci range(ord('A'), ord('Z') + 1), 43817db96d56Sopenharmony_ci range(ord('0'), ord('9') + 1), 43827db96d56Sopenharmony_ci (c for c in b'!*+-/'))) 43837db96d56Sopenharmony_ci # Set of characters (as byte integers) that do need to be encoded in 43847db96d56Sopenharmony_ci # headers. 43857db96d56Sopenharmony_ci self.hnon = [c for c in range(256) if c not in self.hlit] 43867db96d56Sopenharmony_ci assert len(self.hlit) + len(self.hnon) == 256 43877db96d56Sopenharmony_ci # Set of characters (as byte integers) that don't need to be encoded 43887db96d56Sopenharmony_ci # in bodies. 43897db96d56Sopenharmony_ci self.blit = list(range(ord(' '), ord('~') + 1)) 43907db96d56Sopenharmony_ci self.blit.append(ord('\t')) 43917db96d56Sopenharmony_ci self.blit.remove(ord('=')) 43927db96d56Sopenharmony_ci # Set of characters (as byte integers) that do need to be encoded in 43937db96d56Sopenharmony_ci # bodies. 43947db96d56Sopenharmony_ci self.bnon = [c for c in range(256) if c not in self.blit] 43957db96d56Sopenharmony_ci assert len(self.blit) + len(self.bnon) == 256 43967db96d56Sopenharmony_ci 43977db96d56Sopenharmony_ci def test_quopri_header_check(self): 43987db96d56Sopenharmony_ci for c in self.hlit: 43997db96d56Sopenharmony_ci self.assertFalse(quoprimime.header_check(c), 44007db96d56Sopenharmony_ci 'Should not be header quopri encoded: %s' % chr(c)) 44017db96d56Sopenharmony_ci for c in self.hnon: 44027db96d56Sopenharmony_ci self.assertTrue(quoprimime.header_check(c), 44037db96d56Sopenharmony_ci 'Should be header quopri encoded: %s' % chr(c)) 44047db96d56Sopenharmony_ci 44057db96d56Sopenharmony_ci def test_quopri_body_check(self): 44067db96d56Sopenharmony_ci for c in self.blit: 44077db96d56Sopenharmony_ci self.assertFalse(quoprimime.body_check(c), 44087db96d56Sopenharmony_ci 'Should not be body quopri encoded: %s' % chr(c)) 44097db96d56Sopenharmony_ci for c in self.bnon: 44107db96d56Sopenharmony_ci self.assertTrue(quoprimime.body_check(c), 44117db96d56Sopenharmony_ci 'Should be body quopri encoded: %s' % chr(c)) 44127db96d56Sopenharmony_ci 44137db96d56Sopenharmony_ci def test_header_quopri_len(self): 44147db96d56Sopenharmony_ci eq = self.assertEqual 44157db96d56Sopenharmony_ci eq(quoprimime.header_length(b'hello'), 5) 44167db96d56Sopenharmony_ci # RFC 2047 chrome is not included in header_length(). 44177db96d56Sopenharmony_ci eq(len(quoprimime.header_encode(b'hello', charset='xxx')), 44187db96d56Sopenharmony_ci quoprimime.header_length(b'hello') + 44197db96d56Sopenharmony_ci # =?xxx?q?...?= means 10 extra characters 44207db96d56Sopenharmony_ci 10) 44217db96d56Sopenharmony_ci eq(quoprimime.header_length(b'h@e@l@l@o@'), 20) 44227db96d56Sopenharmony_ci # RFC 2047 chrome is not included in header_length(). 44237db96d56Sopenharmony_ci eq(len(quoprimime.header_encode(b'h@e@l@l@o@', charset='xxx')), 44247db96d56Sopenharmony_ci quoprimime.header_length(b'h@e@l@l@o@') + 44257db96d56Sopenharmony_ci # =?xxx?q?...?= means 10 extra characters 44267db96d56Sopenharmony_ci 10) 44277db96d56Sopenharmony_ci for c in self.hlit: 44287db96d56Sopenharmony_ci eq(quoprimime.header_length(bytes([c])), 1, 44297db96d56Sopenharmony_ci 'expected length 1 for %r' % chr(c)) 44307db96d56Sopenharmony_ci for c in self.hnon: 44317db96d56Sopenharmony_ci # Space is special; it's encoded to _ 44327db96d56Sopenharmony_ci if c == ord(' '): 44337db96d56Sopenharmony_ci continue 44347db96d56Sopenharmony_ci eq(quoprimime.header_length(bytes([c])), 3, 44357db96d56Sopenharmony_ci 'expected length 3 for %r' % chr(c)) 44367db96d56Sopenharmony_ci eq(quoprimime.header_length(b' '), 1) 44377db96d56Sopenharmony_ci 44387db96d56Sopenharmony_ci def test_body_quopri_len(self): 44397db96d56Sopenharmony_ci eq = self.assertEqual 44407db96d56Sopenharmony_ci for c in self.blit: 44417db96d56Sopenharmony_ci eq(quoprimime.body_length(bytes([c])), 1) 44427db96d56Sopenharmony_ci for c in self.bnon: 44437db96d56Sopenharmony_ci eq(quoprimime.body_length(bytes([c])), 3) 44447db96d56Sopenharmony_ci 44457db96d56Sopenharmony_ci def test_quote_unquote_idempotent(self): 44467db96d56Sopenharmony_ci for x in range(256): 44477db96d56Sopenharmony_ci c = chr(x) 44487db96d56Sopenharmony_ci self.assertEqual(quoprimime.unquote(quoprimime.quote(c)), c) 44497db96d56Sopenharmony_ci 44507db96d56Sopenharmony_ci def _test_header_encode(self, header, expected_encoded_header, charset=None): 44517db96d56Sopenharmony_ci if charset is None: 44527db96d56Sopenharmony_ci encoded_header = quoprimime.header_encode(header) 44537db96d56Sopenharmony_ci else: 44547db96d56Sopenharmony_ci encoded_header = quoprimime.header_encode(header, charset) 44557db96d56Sopenharmony_ci self.assertEqual(encoded_header, expected_encoded_header) 44567db96d56Sopenharmony_ci 44577db96d56Sopenharmony_ci def test_header_encode_null(self): 44587db96d56Sopenharmony_ci self._test_header_encode(b'', '') 44597db96d56Sopenharmony_ci 44607db96d56Sopenharmony_ci def test_header_encode_one_word(self): 44617db96d56Sopenharmony_ci self._test_header_encode(b'hello', '=?iso-8859-1?q?hello?=') 44627db96d56Sopenharmony_ci 44637db96d56Sopenharmony_ci def test_header_encode_two_lines(self): 44647db96d56Sopenharmony_ci self._test_header_encode(b'hello\nworld', 44657db96d56Sopenharmony_ci '=?iso-8859-1?q?hello=0Aworld?=') 44667db96d56Sopenharmony_ci 44677db96d56Sopenharmony_ci def test_header_encode_non_ascii(self): 44687db96d56Sopenharmony_ci self._test_header_encode(b'hello\xc7there', 44697db96d56Sopenharmony_ci '=?iso-8859-1?q?hello=C7there?=') 44707db96d56Sopenharmony_ci 44717db96d56Sopenharmony_ci def test_header_encode_alt_charset(self): 44727db96d56Sopenharmony_ci self._test_header_encode(b'hello', '=?iso-8859-2?q?hello?=', 44737db96d56Sopenharmony_ci charset='iso-8859-2') 44747db96d56Sopenharmony_ci 44757db96d56Sopenharmony_ci def _test_header_decode(self, encoded_header, expected_decoded_header): 44767db96d56Sopenharmony_ci decoded_header = quoprimime.header_decode(encoded_header) 44777db96d56Sopenharmony_ci self.assertEqual(decoded_header, expected_decoded_header) 44787db96d56Sopenharmony_ci 44797db96d56Sopenharmony_ci def test_header_decode_null(self): 44807db96d56Sopenharmony_ci self._test_header_decode('', '') 44817db96d56Sopenharmony_ci 44827db96d56Sopenharmony_ci def test_header_decode_one_word(self): 44837db96d56Sopenharmony_ci self._test_header_decode('hello', 'hello') 44847db96d56Sopenharmony_ci 44857db96d56Sopenharmony_ci def test_header_decode_two_lines(self): 44867db96d56Sopenharmony_ci self._test_header_decode('hello=0Aworld', 'hello\nworld') 44877db96d56Sopenharmony_ci 44887db96d56Sopenharmony_ci def test_header_decode_non_ascii(self): 44897db96d56Sopenharmony_ci self._test_header_decode('hello=C7there', 'hello\xc7there') 44907db96d56Sopenharmony_ci 44917db96d56Sopenharmony_ci def test_header_decode_re_bug_18380(self): 44927db96d56Sopenharmony_ci # Issue 18380: Call re.sub with a positional argument for flags in the wrong position 44937db96d56Sopenharmony_ci self.assertEqual(quoprimime.header_decode('=30' * 257), '0' * 257) 44947db96d56Sopenharmony_ci 44957db96d56Sopenharmony_ci def _test_decode(self, encoded, expected_decoded, eol=None): 44967db96d56Sopenharmony_ci if eol is None: 44977db96d56Sopenharmony_ci decoded = quoprimime.decode(encoded) 44987db96d56Sopenharmony_ci else: 44997db96d56Sopenharmony_ci decoded = quoprimime.decode(encoded, eol=eol) 45007db96d56Sopenharmony_ci self.assertEqual(decoded, expected_decoded) 45017db96d56Sopenharmony_ci 45027db96d56Sopenharmony_ci def test_decode_null_word(self): 45037db96d56Sopenharmony_ci self._test_decode('', '') 45047db96d56Sopenharmony_ci 45057db96d56Sopenharmony_ci def test_decode_null_line_null_word(self): 45067db96d56Sopenharmony_ci self._test_decode('\r\n', '\n') 45077db96d56Sopenharmony_ci 45087db96d56Sopenharmony_ci def test_decode_one_word(self): 45097db96d56Sopenharmony_ci self._test_decode('hello', 'hello') 45107db96d56Sopenharmony_ci 45117db96d56Sopenharmony_ci def test_decode_one_word_eol(self): 45127db96d56Sopenharmony_ci self._test_decode('hello', 'hello', eol='X') 45137db96d56Sopenharmony_ci 45147db96d56Sopenharmony_ci def test_decode_one_line(self): 45157db96d56Sopenharmony_ci self._test_decode('hello\r\n', 'hello\n') 45167db96d56Sopenharmony_ci 45177db96d56Sopenharmony_ci def test_decode_one_line_lf(self): 45187db96d56Sopenharmony_ci self._test_decode('hello\n', 'hello\n') 45197db96d56Sopenharmony_ci 45207db96d56Sopenharmony_ci def test_decode_one_line_cr(self): 45217db96d56Sopenharmony_ci self._test_decode('hello\r', 'hello\n') 45227db96d56Sopenharmony_ci 45237db96d56Sopenharmony_ci def test_decode_one_line_nl(self): 45247db96d56Sopenharmony_ci self._test_decode('hello\n', 'helloX', eol='X') 45257db96d56Sopenharmony_ci 45267db96d56Sopenharmony_ci def test_decode_one_line_crnl(self): 45277db96d56Sopenharmony_ci self._test_decode('hello\r\n', 'helloX', eol='X') 45287db96d56Sopenharmony_ci 45297db96d56Sopenharmony_ci def test_decode_one_line_one_word(self): 45307db96d56Sopenharmony_ci self._test_decode('hello\r\nworld', 'hello\nworld') 45317db96d56Sopenharmony_ci 45327db96d56Sopenharmony_ci def test_decode_one_line_one_word_eol(self): 45337db96d56Sopenharmony_ci self._test_decode('hello\r\nworld', 'helloXworld', eol='X') 45347db96d56Sopenharmony_ci 45357db96d56Sopenharmony_ci def test_decode_two_lines(self): 45367db96d56Sopenharmony_ci self._test_decode('hello\r\nworld\r\n', 'hello\nworld\n') 45377db96d56Sopenharmony_ci 45387db96d56Sopenharmony_ci def test_decode_two_lines_eol(self): 45397db96d56Sopenharmony_ci self._test_decode('hello\r\nworld\r\n', 'helloXworldX', eol='X') 45407db96d56Sopenharmony_ci 45417db96d56Sopenharmony_ci def test_decode_one_long_line(self): 45427db96d56Sopenharmony_ci self._test_decode('Spam' * 250, 'Spam' * 250) 45437db96d56Sopenharmony_ci 45447db96d56Sopenharmony_ci def test_decode_one_space(self): 45457db96d56Sopenharmony_ci self._test_decode(' ', '') 45467db96d56Sopenharmony_ci 45477db96d56Sopenharmony_ci def test_decode_multiple_spaces(self): 45487db96d56Sopenharmony_ci self._test_decode(' ' * 5, '') 45497db96d56Sopenharmony_ci 45507db96d56Sopenharmony_ci def test_decode_one_line_trailing_spaces(self): 45517db96d56Sopenharmony_ci self._test_decode('hello \r\n', 'hello\n') 45527db96d56Sopenharmony_ci 45537db96d56Sopenharmony_ci def test_decode_two_lines_trailing_spaces(self): 45547db96d56Sopenharmony_ci self._test_decode('hello \r\nworld \r\n', 'hello\nworld\n') 45557db96d56Sopenharmony_ci 45567db96d56Sopenharmony_ci def test_decode_quoted_word(self): 45577db96d56Sopenharmony_ci self._test_decode('=22quoted=20words=22', '"quoted words"') 45587db96d56Sopenharmony_ci 45597db96d56Sopenharmony_ci def test_decode_uppercase_quoting(self): 45607db96d56Sopenharmony_ci self._test_decode('ab=CD=EF', 'ab\xcd\xef') 45617db96d56Sopenharmony_ci 45627db96d56Sopenharmony_ci def test_decode_lowercase_quoting(self): 45637db96d56Sopenharmony_ci self._test_decode('ab=cd=ef', 'ab\xcd\xef') 45647db96d56Sopenharmony_ci 45657db96d56Sopenharmony_ci def test_decode_soft_line_break(self): 45667db96d56Sopenharmony_ci self._test_decode('soft line=\r\nbreak', 'soft linebreak') 45677db96d56Sopenharmony_ci 45687db96d56Sopenharmony_ci def test_decode_false_quoting(self): 45697db96d56Sopenharmony_ci self._test_decode('A=1,B=A ==> A+B==2', 'A=1,B=A ==> A+B==2') 45707db96d56Sopenharmony_ci 45717db96d56Sopenharmony_ci def _test_encode(self, body, expected_encoded_body, maxlinelen=None, eol=None): 45727db96d56Sopenharmony_ci kwargs = {} 45737db96d56Sopenharmony_ci if maxlinelen is None: 45747db96d56Sopenharmony_ci # Use body_encode's default. 45757db96d56Sopenharmony_ci maxlinelen = 76 45767db96d56Sopenharmony_ci else: 45777db96d56Sopenharmony_ci kwargs['maxlinelen'] = maxlinelen 45787db96d56Sopenharmony_ci if eol is None: 45797db96d56Sopenharmony_ci # Use body_encode's default. 45807db96d56Sopenharmony_ci eol = '\n' 45817db96d56Sopenharmony_ci else: 45827db96d56Sopenharmony_ci kwargs['eol'] = eol 45837db96d56Sopenharmony_ci encoded_body = quoprimime.body_encode(body, **kwargs) 45847db96d56Sopenharmony_ci self.assertEqual(encoded_body, expected_encoded_body) 45857db96d56Sopenharmony_ci if eol == '\n' or eol == '\r\n': 45867db96d56Sopenharmony_ci # We know how to split the result back into lines, so maxlinelen 45877db96d56Sopenharmony_ci # can be checked. 45887db96d56Sopenharmony_ci for line in encoded_body.splitlines(): 45897db96d56Sopenharmony_ci self.assertLessEqual(len(line), maxlinelen) 45907db96d56Sopenharmony_ci 45917db96d56Sopenharmony_ci def test_encode_null(self): 45927db96d56Sopenharmony_ci self._test_encode('', '') 45937db96d56Sopenharmony_ci 45947db96d56Sopenharmony_ci def test_encode_null_lines(self): 45957db96d56Sopenharmony_ci self._test_encode('\n\n', '\n\n') 45967db96d56Sopenharmony_ci 45977db96d56Sopenharmony_ci def test_encode_one_line(self): 45987db96d56Sopenharmony_ci self._test_encode('hello\n', 'hello\n') 45997db96d56Sopenharmony_ci 46007db96d56Sopenharmony_ci def test_encode_one_line_crlf(self): 46017db96d56Sopenharmony_ci self._test_encode('hello\r\n', 'hello\n') 46027db96d56Sopenharmony_ci 46037db96d56Sopenharmony_ci def test_encode_one_line_eol(self): 46047db96d56Sopenharmony_ci self._test_encode('hello\n', 'hello\r\n', eol='\r\n') 46057db96d56Sopenharmony_ci 46067db96d56Sopenharmony_ci def test_encode_one_line_eol_after_non_ascii(self): 46077db96d56Sopenharmony_ci # issue 20206; see changeset 0cf700464177 for why the encode/decode. 46087db96d56Sopenharmony_ci self._test_encode('hello\u03c5\n'.encode('utf-8').decode('latin1'), 46097db96d56Sopenharmony_ci 'hello=CF=85\r\n', eol='\r\n') 46107db96d56Sopenharmony_ci 46117db96d56Sopenharmony_ci def test_encode_one_space(self): 46127db96d56Sopenharmony_ci self._test_encode(' ', '=20') 46137db96d56Sopenharmony_ci 46147db96d56Sopenharmony_ci def test_encode_one_line_one_space(self): 46157db96d56Sopenharmony_ci self._test_encode(' \n', '=20\n') 46167db96d56Sopenharmony_ci 46177db96d56Sopenharmony_ci# XXX: body_encode() expect strings, but uses ord(char) from these strings 46187db96d56Sopenharmony_ci# to index into a 256-entry list. For code points above 255, this will fail. 46197db96d56Sopenharmony_ci# Should there be a check for 8-bit only ord() values in body, or at least 46207db96d56Sopenharmony_ci# a comment about the expected input? 46217db96d56Sopenharmony_ci 46227db96d56Sopenharmony_ci def test_encode_two_lines_one_space(self): 46237db96d56Sopenharmony_ci self._test_encode(' \n \n', '=20\n=20\n') 46247db96d56Sopenharmony_ci 46257db96d56Sopenharmony_ci def test_encode_one_word_trailing_spaces(self): 46267db96d56Sopenharmony_ci self._test_encode('hello ', 'hello =20') 46277db96d56Sopenharmony_ci 46287db96d56Sopenharmony_ci def test_encode_one_line_trailing_spaces(self): 46297db96d56Sopenharmony_ci self._test_encode('hello \n', 'hello =20\n') 46307db96d56Sopenharmony_ci 46317db96d56Sopenharmony_ci def test_encode_one_word_trailing_tab(self): 46327db96d56Sopenharmony_ci self._test_encode('hello \t', 'hello =09') 46337db96d56Sopenharmony_ci 46347db96d56Sopenharmony_ci def test_encode_one_line_trailing_tab(self): 46357db96d56Sopenharmony_ci self._test_encode('hello \t\n', 'hello =09\n') 46367db96d56Sopenharmony_ci 46377db96d56Sopenharmony_ci def test_encode_trailing_space_before_maxlinelen(self): 46387db96d56Sopenharmony_ci self._test_encode('abcd \n1234', 'abcd =\n\n1234', maxlinelen=6) 46397db96d56Sopenharmony_ci 46407db96d56Sopenharmony_ci def test_encode_trailing_space_at_maxlinelen(self): 46417db96d56Sopenharmony_ci self._test_encode('abcd \n1234', 'abcd=\n=20\n1234', maxlinelen=5) 46427db96d56Sopenharmony_ci 46437db96d56Sopenharmony_ci def test_encode_trailing_space_beyond_maxlinelen(self): 46447db96d56Sopenharmony_ci self._test_encode('abcd \n1234', 'abc=\nd=20\n1234', maxlinelen=4) 46457db96d56Sopenharmony_ci 46467db96d56Sopenharmony_ci def test_encode_whitespace_lines(self): 46477db96d56Sopenharmony_ci self._test_encode(' \n' * 5, '=20\n' * 5) 46487db96d56Sopenharmony_ci 46497db96d56Sopenharmony_ci def test_encode_quoted_equals(self): 46507db96d56Sopenharmony_ci self._test_encode('a = b', 'a =3D b') 46517db96d56Sopenharmony_ci 46527db96d56Sopenharmony_ci def test_encode_one_long_string(self): 46537db96d56Sopenharmony_ci self._test_encode('x' * 100, 'x' * 75 + '=\n' + 'x' * 25) 46547db96d56Sopenharmony_ci 46557db96d56Sopenharmony_ci def test_encode_one_long_line(self): 46567db96d56Sopenharmony_ci self._test_encode('x' * 100 + '\n', 'x' * 75 + '=\n' + 'x' * 25 + '\n') 46577db96d56Sopenharmony_ci 46587db96d56Sopenharmony_ci def test_encode_one_very_long_line(self): 46597db96d56Sopenharmony_ci self._test_encode('x' * 200 + '\n', 46607db96d56Sopenharmony_ci 2 * ('x' * 75 + '=\n') + 'x' * 50 + '\n') 46617db96d56Sopenharmony_ci 46627db96d56Sopenharmony_ci def test_encode_shortest_maxlinelen(self): 46637db96d56Sopenharmony_ci self._test_encode('=' * 5, '=3D=\n' * 4 + '=3D', maxlinelen=4) 46647db96d56Sopenharmony_ci 46657db96d56Sopenharmony_ci def test_encode_maxlinelen_too_small(self): 46667db96d56Sopenharmony_ci self.assertRaises(ValueError, self._test_encode, '', '', maxlinelen=3) 46677db96d56Sopenharmony_ci 46687db96d56Sopenharmony_ci def test_encode(self): 46697db96d56Sopenharmony_ci eq = self.assertEqual 46707db96d56Sopenharmony_ci eq(quoprimime.body_encode(''), '') 46717db96d56Sopenharmony_ci eq(quoprimime.body_encode('hello'), 'hello') 46727db96d56Sopenharmony_ci # Test the binary flag 46737db96d56Sopenharmony_ci eq(quoprimime.body_encode('hello\r\nworld'), 'hello\nworld') 46747db96d56Sopenharmony_ci # Test the maxlinelen arg 46757db96d56Sopenharmony_ci eq(quoprimime.body_encode('xxxx ' * 20, maxlinelen=40), """\ 46767db96d56Sopenharmony_cixxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx= 46777db96d56Sopenharmony_ci xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx= 46787db96d56Sopenharmony_cix xxxx xxxx xxxx xxxx=20""") 46797db96d56Sopenharmony_ci # Test the eol argument 46807db96d56Sopenharmony_ci eq(quoprimime.body_encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'), 46817db96d56Sopenharmony_ci """\ 46827db96d56Sopenharmony_cixxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx=\r 46837db96d56Sopenharmony_ci xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx=\r 46847db96d56Sopenharmony_cix xxxx xxxx xxxx xxxx=20""") 46857db96d56Sopenharmony_ci eq(quoprimime.body_encode("""\ 46867db96d56Sopenharmony_cione line 46877db96d56Sopenharmony_ci 46887db96d56Sopenharmony_citwo line"""), """\ 46897db96d56Sopenharmony_cione line 46907db96d56Sopenharmony_ci 46917db96d56Sopenharmony_citwo line""") 46927db96d56Sopenharmony_ci 46937db96d56Sopenharmony_ci 46947db96d56Sopenharmony_ci 46957db96d56Sopenharmony_ci# Test the Charset class 46967db96d56Sopenharmony_ciclass TestCharset(unittest.TestCase): 46977db96d56Sopenharmony_ci def tearDown(self): 46987db96d56Sopenharmony_ci from email import charset as CharsetModule 46997db96d56Sopenharmony_ci try: 47007db96d56Sopenharmony_ci del CharsetModule.CHARSETS['fake'] 47017db96d56Sopenharmony_ci except KeyError: 47027db96d56Sopenharmony_ci pass 47037db96d56Sopenharmony_ci 47047db96d56Sopenharmony_ci def test_codec_encodeable(self): 47057db96d56Sopenharmony_ci eq = self.assertEqual 47067db96d56Sopenharmony_ci # Make sure us-ascii = no Unicode conversion 47077db96d56Sopenharmony_ci c = Charset('us-ascii') 47087db96d56Sopenharmony_ci eq(c.header_encode('Hello World!'), 'Hello World!') 47097db96d56Sopenharmony_ci # Test 8-bit idempotency with us-ascii 47107db96d56Sopenharmony_ci s = '\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa' 47117db96d56Sopenharmony_ci self.assertRaises(UnicodeError, c.header_encode, s) 47127db96d56Sopenharmony_ci c = Charset('utf-8') 47137db96d56Sopenharmony_ci eq(c.header_encode(s), '=?utf-8?b?wqTCosKkwqTCpMKmwqTCqMKkwqo=?=') 47147db96d56Sopenharmony_ci 47157db96d56Sopenharmony_ci def test_body_encode(self): 47167db96d56Sopenharmony_ci eq = self.assertEqual 47177db96d56Sopenharmony_ci # Try a charset with QP body encoding 47187db96d56Sopenharmony_ci c = Charset('iso-8859-1') 47197db96d56Sopenharmony_ci eq('hello w=F6rld', c.body_encode('hello w\xf6rld')) 47207db96d56Sopenharmony_ci # Try a charset with Base64 body encoding 47217db96d56Sopenharmony_ci c = Charset('utf-8') 47227db96d56Sopenharmony_ci eq('aGVsbG8gd29ybGQ=\n', c.body_encode(b'hello world')) 47237db96d56Sopenharmony_ci # Try a charset with None body encoding 47247db96d56Sopenharmony_ci c = Charset('us-ascii') 47257db96d56Sopenharmony_ci eq('hello world', c.body_encode('hello world')) 47267db96d56Sopenharmony_ci # Try the convert argument, where input codec != output codec 47277db96d56Sopenharmony_ci c = Charset('euc-jp') 47287db96d56Sopenharmony_ci # With apologies to Tokio Kikuchi ;) 47297db96d56Sopenharmony_ci # XXX FIXME 47307db96d56Sopenharmony_ci## try: 47317db96d56Sopenharmony_ci## eq('\x1b$B5FCO;~IW\x1b(B', 47327db96d56Sopenharmony_ci## c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7')) 47337db96d56Sopenharmony_ci## eq('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', 47347db96d56Sopenharmony_ci## c.body_encode('\xb5\xc6\xc3\xcf\xbb\xfe\xc9\xd7', False)) 47357db96d56Sopenharmony_ci## except LookupError: 47367db96d56Sopenharmony_ci## # We probably don't have the Japanese codecs installed 47377db96d56Sopenharmony_ci## pass 47387db96d56Sopenharmony_ci # Testing SF bug #625509, which we have to fake, since there are no 47397db96d56Sopenharmony_ci # built-in encodings where the header encoding is QP but the body 47407db96d56Sopenharmony_ci # encoding is not. 47417db96d56Sopenharmony_ci from email import charset as CharsetModule 47427db96d56Sopenharmony_ci CharsetModule.add_charset('fake', CharsetModule.QP, None, 'utf-8') 47437db96d56Sopenharmony_ci c = Charset('fake') 47447db96d56Sopenharmony_ci eq('hello world', c.body_encode('hello world')) 47457db96d56Sopenharmony_ci 47467db96d56Sopenharmony_ci def test_unicode_charset_name(self): 47477db96d56Sopenharmony_ci charset = Charset('us-ascii') 47487db96d56Sopenharmony_ci self.assertEqual(str(charset), 'us-ascii') 47497db96d56Sopenharmony_ci self.assertRaises(errors.CharsetError, Charset, 'asc\xffii') 47507db96d56Sopenharmony_ci 47517db96d56Sopenharmony_ci 47527db96d56Sopenharmony_ci 47537db96d56Sopenharmony_ci# Test multilingual MIME headers. 47547db96d56Sopenharmony_ciclass TestHeader(TestEmailBase): 47557db96d56Sopenharmony_ci def test_simple(self): 47567db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 47577db96d56Sopenharmony_ci h = Header('Hello World!') 47587db96d56Sopenharmony_ci eq(h.encode(), 'Hello World!') 47597db96d56Sopenharmony_ci h.append(' Goodbye World!') 47607db96d56Sopenharmony_ci eq(h.encode(), 'Hello World! Goodbye World!') 47617db96d56Sopenharmony_ci 47627db96d56Sopenharmony_ci def test_simple_surprise(self): 47637db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 47647db96d56Sopenharmony_ci h = Header('Hello World!') 47657db96d56Sopenharmony_ci eq(h.encode(), 'Hello World!') 47667db96d56Sopenharmony_ci h.append('Goodbye World!') 47677db96d56Sopenharmony_ci eq(h.encode(), 'Hello World! Goodbye World!') 47687db96d56Sopenharmony_ci 47697db96d56Sopenharmony_ci def test_header_needs_no_decoding(self): 47707db96d56Sopenharmony_ci h = 'no decoding needed' 47717db96d56Sopenharmony_ci self.assertEqual(decode_header(h), [(h, None)]) 47727db96d56Sopenharmony_ci 47737db96d56Sopenharmony_ci def test_long(self): 47747db96d56Sopenharmony_ci 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.", 47757db96d56Sopenharmony_ci maxlinelen=76) 47767db96d56Sopenharmony_ci for l in h.encode(splitchars=' ').split('\n '): 47777db96d56Sopenharmony_ci self.assertLessEqual(len(l), 76) 47787db96d56Sopenharmony_ci 47797db96d56Sopenharmony_ci def test_multilingual(self): 47807db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 47817db96d56Sopenharmony_ci g = Charset("iso-8859-1") 47827db96d56Sopenharmony_ci cz = Charset("iso-8859-2") 47837db96d56Sopenharmony_ci utf8 = Charset("utf-8") 47847db96d56Sopenharmony_ci g_head = (b'Die Mieter treten hier ein werden mit einem ' 47857db96d56Sopenharmony_ci b'Foerderband komfortabel den Korridor entlang, ' 47867db96d56Sopenharmony_ci b'an s\xfcdl\xfcndischen Wandgem\xe4lden vorbei, ' 47877db96d56Sopenharmony_ci b'gegen die rotierenden Klingen bef\xf6rdert. ') 47887db96d56Sopenharmony_ci cz_head = (b'Finan\xe8ni metropole se hroutily pod tlakem jejich ' 47897db96d56Sopenharmony_ci b'd\xf9vtipu.. ') 47907db96d56Sopenharmony_ci utf8_head = ('\u6b63\u78ba\u306b\u8a00\u3046\u3068\u7ffb\u8a33\u306f' 47917db96d56Sopenharmony_ci '\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4e00' 47927db96d56Sopenharmony_ci '\u90e8\u306f\u30c9\u30a4\u30c4\u8a9e\u3067\u3059\u304c' 47937db96d56Sopenharmony_ci '\u3001\u3042\u3068\u306f\u3067\u305f\u3089\u3081\u3067' 47947db96d56Sopenharmony_ci '\u3059\u3002\u5b9f\u969b\u306b\u306f\u300cWenn ist das ' 47957db96d56Sopenharmony_ci 'Nunstuck git und Slotermeyer? Ja! Beiherhund das Oder ' 47967db96d56Sopenharmony_ci 'die Flipperwaldt gersput.\u300d\u3068\u8a00\u3063\u3066' 47977db96d56Sopenharmony_ci '\u3044\u307e\u3059\u3002') 47987db96d56Sopenharmony_ci h = Header(g_head, g) 47997db96d56Sopenharmony_ci h.append(cz_head, cz) 48007db96d56Sopenharmony_ci h.append(utf8_head, utf8) 48017db96d56Sopenharmony_ci enc = h.encode(maxlinelen=76) 48027db96d56Sopenharmony_ci eq(enc, """\ 48037db96d56Sopenharmony_ci=?iso-8859-1?q?Die_Mieter_treten_hier_ein_werden_mit_einem_Foerderband_kom?= 48047db96d56Sopenharmony_ci =?iso-8859-1?q?fortabel_den_Korridor_entlang=2C_an_s=FCdl=FCndischen_Wand?= 48057db96d56Sopenharmony_ci =?iso-8859-1?q?gem=E4lden_vorbei=2C_gegen_die_rotierenden_Klingen_bef=F6r?= 48067db96d56Sopenharmony_ci =?iso-8859-1?q?dert=2E_?= =?iso-8859-2?q?Finan=E8ni_metropole_se_hroutily?= 48077db96d56Sopenharmony_ci =?iso-8859-2?q?_pod_tlakem_jejich_d=F9vtipu=2E=2E_?= =?utf-8?b?5q2j56K6?= 48087db96d56Sopenharmony_ci =?utf-8?b?44Gr6KiA44GG44Go57+76Kiz44Gv44GV44KM44Gm44GE44G+44Gb44KT44CC?= 48097db96d56Sopenharmony_ci =?utf-8?b?5LiA6YOo44Gv44OJ44Kk44OE6Kqe44Gn44GZ44GM44CB44GC44Go44Gv44Gn?= 48107db96d56Sopenharmony_ci =?utf-8?b?44Gf44KJ44KB44Gn44GZ44CC5a6f6Zqb44Gr44Gv44CMV2VubiBpc3QgZGFz?= 48117db96d56Sopenharmony_ci =?utf-8?b?IE51bnN0dWNrIGdpdCB1bmQgU2xvdGVybWV5ZXI/IEphISBCZWloZXJodW5k?= 48127db96d56Sopenharmony_ci =?utf-8?b?IGRhcyBPZGVyIGRpZSBGbGlwcGVyd2FsZHQgZ2Vyc3B1dC7jgI3jgajoqIA=?= 48137db96d56Sopenharmony_ci =?utf-8?b?44Gj44Gm44GE44G+44GZ44CC?=""") 48147db96d56Sopenharmony_ci decoded = decode_header(enc) 48157db96d56Sopenharmony_ci eq(len(decoded), 3) 48167db96d56Sopenharmony_ci eq(decoded[0], (g_head, 'iso-8859-1')) 48177db96d56Sopenharmony_ci eq(decoded[1], (cz_head, 'iso-8859-2')) 48187db96d56Sopenharmony_ci eq(decoded[2], (utf8_head.encode('utf-8'), 'utf-8')) 48197db96d56Sopenharmony_ci ustr = str(h) 48207db96d56Sopenharmony_ci eq(ustr, 48217db96d56Sopenharmony_ci (b'Die Mieter treten hier ein werden mit einem Foerderband ' 48227db96d56Sopenharmony_ci b'komfortabel den Korridor entlang, an s\xc3\xbcdl\xc3\xbcndischen ' 48237db96d56Sopenharmony_ci b'Wandgem\xc3\xa4lden vorbei, gegen die rotierenden Klingen ' 48247db96d56Sopenharmony_ci b'bef\xc3\xb6rdert. Finan\xc4\x8dni metropole se hroutily pod ' 48257db96d56Sopenharmony_ci b'tlakem jejich d\xc5\xafvtipu.. \xe6\xad\xa3\xe7\xa2\xba\xe3\x81' 48267db96d56Sopenharmony_ci b'\xab\xe8\xa8\x80\xe3\x81\x86\xe3\x81\xa8\xe7\xbf\xbb\xe8\xa8\xb3' 48277db96d56Sopenharmony_ci b'\xe3\x81\xaf\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3' 48287db96d56Sopenharmony_ci b'\x81\xbe\xe3\x81\x9b\xe3\x82\x93\xe3\x80\x82\xe4\xb8\x80\xe9\x83' 48297db96d56Sopenharmony_ci b'\xa8\xe3\x81\xaf\xe3\x83\x89\xe3\x82\xa4\xe3\x83\x84\xe8\xaa\x9e' 48307db96d56Sopenharmony_ci b'\xe3\x81\xa7\xe3\x81\x99\xe3\x81\x8c\xe3\x80\x81\xe3\x81\x82\xe3' 48317db96d56Sopenharmony_ci b'\x81\xa8\xe3\x81\xaf\xe3\x81\xa7\xe3\x81\x9f\xe3\x82\x89\xe3\x82' 48327db96d56Sopenharmony_ci b'\x81\xe3\x81\xa7\xe3\x81\x99\xe3\x80\x82\xe5\xae\x9f\xe9\x9a\x9b' 48337db96d56Sopenharmony_ci b'\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x8cWenn ist das Nunstuck git ' 48347db96d56Sopenharmony_ci b'und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt ' 48357db96d56Sopenharmony_ci b'gersput.\xe3\x80\x8d\xe3\x81\xa8\xe8\xa8\x80\xe3\x81\xa3\xe3\x81' 48367db96d56Sopenharmony_ci b'\xa6\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82' 48377db96d56Sopenharmony_ci ).decode('utf-8')) 48387db96d56Sopenharmony_ci # Test make_header() 48397db96d56Sopenharmony_ci newh = make_header(decode_header(enc)) 48407db96d56Sopenharmony_ci eq(newh, h) 48417db96d56Sopenharmony_ci 48427db96d56Sopenharmony_ci def test_empty_header_encode(self): 48437db96d56Sopenharmony_ci h = Header() 48447db96d56Sopenharmony_ci self.assertEqual(h.encode(), '') 48457db96d56Sopenharmony_ci 48467db96d56Sopenharmony_ci def test_header_ctor_default_args(self): 48477db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 48487db96d56Sopenharmony_ci h = Header() 48497db96d56Sopenharmony_ci eq(h, '') 48507db96d56Sopenharmony_ci h.append('foo', Charset('iso-8859-1')) 48517db96d56Sopenharmony_ci eq(h, 'foo') 48527db96d56Sopenharmony_ci 48537db96d56Sopenharmony_ci def test_explicit_maxlinelen(self): 48547db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 48557db96d56Sopenharmony_ci hstr = ('A very long line that must get split to something other ' 48567db96d56Sopenharmony_ci 'than at the 76th character boundary to test the non-default ' 48577db96d56Sopenharmony_ci 'behavior') 48587db96d56Sopenharmony_ci h = Header(hstr) 48597db96d56Sopenharmony_ci eq(h.encode(), '''\ 48607db96d56Sopenharmony_ciA very long line that must get split to something other than at the 76th 48617db96d56Sopenharmony_ci character boundary to test the non-default behavior''') 48627db96d56Sopenharmony_ci eq(str(h), hstr) 48637db96d56Sopenharmony_ci h = Header(hstr, header_name='Subject') 48647db96d56Sopenharmony_ci eq(h.encode(), '''\ 48657db96d56Sopenharmony_ciA very long line that must get split to something other than at the 48667db96d56Sopenharmony_ci 76th character boundary to test the non-default behavior''') 48677db96d56Sopenharmony_ci eq(str(h), hstr) 48687db96d56Sopenharmony_ci h = Header(hstr, maxlinelen=1024, header_name='Subject') 48697db96d56Sopenharmony_ci eq(h.encode(), hstr) 48707db96d56Sopenharmony_ci eq(str(h), hstr) 48717db96d56Sopenharmony_ci 48727db96d56Sopenharmony_ci def test_quopri_splittable(self): 48737db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 48747db96d56Sopenharmony_ci h = Header(charset='iso-8859-1', maxlinelen=20) 48757db96d56Sopenharmony_ci x = 'xxxx ' * 20 48767db96d56Sopenharmony_ci h.append(x) 48777db96d56Sopenharmony_ci s = h.encode() 48787db96d56Sopenharmony_ci eq(s, """\ 48797db96d56Sopenharmony_ci=?iso-8859-1?q?xxx?= 48807db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 48817db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48827db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48837db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 48847db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48857db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 48867db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48877db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48887db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 48897db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48907db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 48917db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48927db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48937db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 48947db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48957db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 48967db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48977db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 48987db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 48997db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49007db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49017db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49027db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49037db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 49047db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49057db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49067db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49077db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49087db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 49097db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49107db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49117db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49127db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49137db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 49147db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49157db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49167db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49177db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49187db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 49197db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49207db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49217db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49227db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49237db96d56Sopenharmony_ci =?iso-8859-1?q?_x?= 49247db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49257db96d56Sopenharmony_ci =?iso-8859-1?q?x_?= 49267db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49277db96d56Sopenharmony_ci =?iso-8859-1?q?xx?= 49287db96d56Sopenharmony_ci =?iso-8859-1?q?_?=""") 49297db96d56Sopenharmony_ci eq(x, str(make_header(decode_header(s)))) 49307db96d56Sopenharmony_ci h = Header(charset='iso-8859-1', maxlinelen=40) 49317db96d56Sopenharmony_ci h.append('xxxx ' * 20) 49327db96d56Sopenharmony_ci s = h.encode() 49337db96d56Sopenharmony_ci eq(s, """\ 49347db96d56Sopenharmony_ci=?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xxx?= 49357db96d56Sopenharmony_ci =?iso-8859-1?q?x_xxxx_xxxx_xxxx_xxxx_?= 49367db96d56Sopenharmony_ci =?iso-8859-1?q?xxxx_xxxx_xxxx_xxxx_xx?= 49377db96d56Sopenharmony_ci =?iso-8859-1?q?xx_xxxx_xxxx_xxxx_xxxx?= 49387db96d56Sopenharmony_ci =?iso-8859-1?q?_xxxx_xxxx_?=""") 49397db96d56Sopenharmony_ci eq(x, str(make_header(decode_header(s)))) 49407db96d56Sopenharmony_ci 49417db96d56Sopenharmony_ci def test_base64_splittable(self): 49427db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 49437db96d56Sopenharmony_ci h = Header(charset='koi8-r', maxlinelen=20) 49447db96d56Sopenharmony_ci x = 'xxxx ' * 20 49457db96d56Sopenharmony_ci h.append(x) 49467db96d56Sopenharmony_ci s = h.encode() 49477db96d56Sopenharmony_ci eq(s, """\ 49487db96d56Sopenharmony_ci=?koi8-r?b?eHh4?= 49497db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49507db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49517db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49527db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49537db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49547db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49557db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49567db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49577db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49587db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49597db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49607db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49617db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49627db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49637db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49647db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49657db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49667db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49677db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49687db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49697db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49707db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49717db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49727db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49737db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49747db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49757db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49767db96d56Sopenharmony_ci =?koi8-r?b?IHh4?= 49777db96d56Sopenharmony_ci =?koi8-r?b?eHgg?= 49787db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49797db96d56Sopenharmony_ci =?koi8-r?b?eCB4?= 49807db96d56Sopenharmony_ci =?koi8-r?b?eHh4?= 49817db96d56Sopenharmony_ci =?koi8-r?b?IA==?=""") 49827db96d56Sopenharmony_ci eq(x, str(make_header(decode_header(s)))) 49837db96d56Sopenharmony_ci h = Header(charset='koi8-r', maxlinelen=40) 49847db96d56Sopenharmony_ci h.append(x) 49857db96d56Sopenharmony_ci s = h.encode() 49867db96d56Sopenharmony_ci eq(s, """\ 49877db96d56Sopenharmony_ci=?koi8-r?b?eHh4eCB4eHh4IHh4eHggeHh4?= 49887db96d56Sopenharmony_ci =?koi8-r?b?eCB4eHh4IHh4eHggeHh4eCB4?= 49897db96d56Sopenharmony_ci =?koi8-r?b?eHh4IHh4eHggeHh4eCB4eHh4?= 49907db96d56Sopenharmony_ci =?koi8-r?b?IHh4eHggeHh4eCB4eHh4IHh4?= 49917db96d56Sopenharmony_ci =?koi8-r?b?eHggeHh4eCB4eHh4IHh4eHgg?= 49927db96d56Sopenharmony_ci =?koi8-r?b?eHh4eCB4eHh4IA==?=""") 49937db96d56Sopenharmony_ci eq(x, str(make_header(decode_header(s)))) 49947db96d56Sopenharmony_ci 49957db96d56Sopenharmony_ci def test_us_ascii_header(self): 49967db96d56Sopenharmony_ci eq = self.assertEqual 49977db96d56Sopenharmony_ci s = 'hello' 49987db96d56Sopenharmony_ci x = decode_header(s) 49997db96d56Sopenharmony_ci eq(x, [('hello', None)]) 50007db96d56Sopenharmony_ci h = make_header(x) 50017db96d56Sopenharmony_ci eq(s, h.encode()) 50027db96d56Sopenharmony_ci 50037db96d56Sopenharmony_ci def test_string_charset(self): 50047db96d56Sopenharmony_ci eq = self.assertEqual 50057db96d56Sopenharmony_ci h = Header() 50067db96d56Sopenharmony_ci h.append('hello', 'iso-8859-1') 50077db96d56Sopenharmony_ci eq(h, 'hello') 50087db96d56Sopenharmony_ci 50097db96d56Sopenharmony_ci## def test_unicode_error(self): 50107db96d56Sopenharmony_ci## raises = self.assertRaises 50117db96d56Sopenharmony_ci## raises(UnicodeError, Header, u'[P\xf6stal]', 'us-ascii') 50127db96d56Sopenharmony_ci## raises(UnicodeError, Header, '[P\xf6stal]', 'us-ascii') 50137db96d56Sopenharmony_ci## h = Header() 50147db96d56Sopenharmony_ci## raises(UnicodeError, h.append, u'[P\xf6stal]', 'us-ascii') 50157db96d56Sopenharmony_ci## raises(UnicodeError, h.append, '[P\xf6stal]', 'us-ascii') 50167db96d56Sopenharmony_ci## raises(UnicodeError, Header, u'\u83ca\u5730\u6642\u592b', 'iso-8859-1') 50177db96d56Sopenharmony_ci 50187db96d56Sopenharmony_ci def test_utf8_shortest(self): 50197db96d56Sopenharmony_ci eq = self.assertEqual 50207db96d56Sopenharmony_ci h = Header('p\xf6stal', 'utf-8') 50217db96d56Sopenharmony_ci eq(h.encode(), '=?utf-8?q?p=C3=B6stal?=') 50227db96d56Sopenharmony_ci h = Header('\u83ca\u5730\u6642\u592b', 'utf-8') 50237db96d56Sopenharmony_ci eq(h.encode(), '=?utf-8?b?6I+K5Zyw5pmC5aSr?=') 50247db96d56Sopenharmony_ci 50257db96d56Sopenharmony_ci def test_bad_8bit_header(self): 50267db96d56Sopenharmony_ci raises = self.assertRaises 50277db96d56Sopenharmony_ci eq = self.assertEqual 50287db96d56Sopenharmony_ci x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big' 50297db96d56Sopenharmony_ci raises(UnicodeError, Header, x) 50307db96d56Sopenharmony_ci h = Header() 50317db96d56Sopenharmony_ci raises(UnicodeError, h.append, x) 50327db96d56Sopenharmony_ci e = x.decode('utf-8', 'replace') 50337db96d56Sopenharmony_ci eq(str(Header(x, errors='replace')), e) 50347db96d56Sopenharmony_ci h.append(x, errors='replace') 50357db96d56Sopenharmony_ci eq(str(h), e) 50367db96d56Sopenharmony_ci 50377db96d56Sopenharmony_ci def test_escaped_8bit_header(self): 50387db96d56Sopenharmony_ci x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big' 50397db96d56Sopenharmony_ci e = x.decode('ascii', 'surrogateescape') 50407db96d56Sopenharmony_ci h = Header(e, charset=email.charset.UNKNOWN8BIT) 50417db96d56Sopenharmony_ci self.assertEqual(str(h), 50427db96d56Sopenharmony_ci 'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big') 50437db96d56Sopenharmony_ci self.assertEqual(email.header.decode_header(h), [(x, 'unknown-8bit')]) 50447db96d56Sopenharmony_ci 50457db96d56Sopenharmony_ci def test_header_handles_binary_unknown8bit(self): 50467db96d56Sopenharmony_ci x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big' 50477db96d56Sopenharmony_ci h = Header(x, charset=email.charset.UNKNOWN8BIT) 50487db96d56Sopenharmony_ci self.assertEqual(str(h), 50497db96d56Sopenharmony_ci 'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big') 50507db96d56Sopenharmony_ci self.assertEqual(email.header.decode_header(h), [(x, 'unknown-8bit')]) 50517db96d56Sopenharmony_ci 50527db96d56Sopenharmony_ci def test_make_header_handles_binary_unknown8bit(self): 50537db96d56Sopenharmony_ci x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big' 50547db96d56Sopenharmony_ci h = Header(x, charset=email.charset.UNKNOWN8BIT) 50557db96d56Sopenharmony_ci h2 = email.header.make_header(email.header.decode_header(h)) 50567db96d56Sopenharmony_ci self.assertEqual(str(h2), 50577db96d56Sopenharmony_ci 'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big') 50587db96d56Sopenharmony_ci self.assertEqual(email.header.decode_header(h2), [(x, 'unknown-8bit')]) 50597db96d56Sopenharmony_ci 50607db96d56Sopenharmony_ci def test_modify_returned_list_does_not_change_header(self): 50617db96d56Sopenharmony_ci h = Header('test') 50627db96d56Sopenharmony_ci chunks = email.header.decode_header(h) 50637db96d56Sopenharmony_ci chunks.append(('ascii', 'test2')) 50647db96d56Sopenharmony_ci self.assertEqual(str(h), 'test') 50657db96d56Sopenharmony_ci 50667db96d56Sopenharmony_ci def test_encoded_adjacent_nonencoded(self): 50677db96d56Sopenharmony_ci eq = self.assertEqual 50687db96d56Sopenharmony_ci h = Header() 50697db96d56Sopenharmony_ci h.append('hello', 'iso-8859-1') 50707db96d56Sopenharmony_ci h.append('world') 50717db96d56Sopenharmony_ci s = h.encode() 50727db96d56Sopenharmony_ci eq(s, '=?iso-8859-1?q?hello?= world') 50737db96d56Sopenharmony_ci h = make_header(decode_header(s)) 50747db96d56Sopenharmony_ci eq(h.encode(), s) 50757db96d56Sopenharmony_ci 50767db96d56Sopenharmony_ci def test_whitespace_keeper(self): 50777db96d56Sopenharmony_ci eq = self.assertEqual 50787db96d56Sopenharmony_ci s = 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztk=?= =?koi8-r?q?=CA?= zz.' 50797db96d56Sopenharmony_ci parts = decode_header(s) 50807db96d56Sopenharmony_ci eq(parts, [(b'Subject: ', None), (b'\xf0\xd2\xcf\xd7\xc5\xd2\xcb\xc1 \xce\xc1 \xc6\xc9\xce\xc1\xcc\xd8\xce\xd9\xca', 'koi8-r'), (b' zz.', None)]) 50817db96d56Sopenharmony_ci hdr = make_header(parts) 50827db96d56Sopenharmony_ci eq(hdr.encode(), 50837db96d56Sopenharmony_ci 'Subject: =?koi8-r?b?8NLP18XSy8EgzsEgxsnOwczYztnK?= zz.') 50847db96d56Sopenharmony_ci 50857db96d56Sopenharmony_ci def test_broken_base64_header(self): 50867db96d56Sopenharmony_ci raises = self.assertRaises 50877db96d56Sopenharmony_ci s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3I ?=' 50887db96d56Sopenharmony_ci raises(errors.HeaderParseError, decode_header, s) 50897db96d56Sopenharmony_ci 50907db96d56Sopenharmony_ci def test_shift_jis_charset(self): 50917db96d56Sopenharmony_ci h = Header('文', charset='shift_jis') 50927db96d56Sopenharmony_ci self.assertEqual(h.encode(), '=?iso-2022-jp?b?GyRCSjgbKEI=?=') 50937db96d56Sopenharmony_ci 50947db96d56Sopenharmony_ci def test_flatten_header_with_no_value(self): 50957db96d56Sopenharmony_ci # Issue 11401 (regression from email 4.x) Note that the space after 50967db96d56Sopenharmony_ci # the header doesn't reflect the input, but this is also the way 50977db96d56Sopenharmony_ci # email 4.x behaved. At some point it would be nice to fix that. 50987db96d56Sopenharmony_ci msg = email.message_from_string("EmptyHeader:") 50997db96d56Sopenharmony_ci self.assertEqual(str(msg), "EmptyHeader: \n\n") 51007db96d56Sopenharmony_ci 51017db96d56Sopenharmony_ci def test_encode_preserves_leading_ws_on_value(self): 51027db96d56Sopenharmony_ci msg = Message() 51037db96d56Sopenharmony_ci msg['SomeHeader'] = ' value with leading ws' 51047db96d56Sopenharmony_ci self.assertEqual(str(msg), "SomeHeader: value with leading ws\n\n") 51057db96d56Sopenharmony_ci 51067db96d56Sopenharmony_ci def test_whitespace_header(self): 51077db96d56Sopenharmony_ci self.assertEqual(Header(' ').encode(), ' ') 51087db96d56Sopenharmony_ci 51097db96d56Sopenharmony_ci 51107db96d56Sopenharmony_ci 51117db96d56Sopenharmony_ci# Test RFC 2231 header parameters (en/de)coding 51127db96d56Sopenharmony_ciclass TestRFC2231(TestEmailBase): 51137db96d56Sopenharmony_ci 51147db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_with_double_quotes 51157db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_single_quote_inside_double_quotes 51167db96d56Sopenharmony_ci def test_get_param(self): 51177db96d56Sopenharmony_ci eq = self.assertEqual 51187db96d56Sopenharmony_ci msg = self._msgobj('msg_29.txt') 51197db96d56Sopenharmony_ci eq(msg.get_param('title'), 51207db96d56Sopenharmony_ci ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!')) 51217db96d56Sopenharmony_ci eq(msg.get_param('title', unquote=False), 51227db96d56Sopenharmony_ci ('us-ascii', 'en', '"This is even more ***fun*** isn\'t it!"')) 51237db96d56Sopenharmony_ci 51247db96d56Sopenharmony_ci def test_set_param(self): 51257db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 51267db96d56Sopenharmony_ci msg = Message() 51277db96d56Sopenharmony_ci msg.set_param('title', 'This is even more ***fun*** isn\'t it!', 51287db96d56Sopenharmony_ci charset='us-ascii') 51297db96d56Sopenharmony_ci eq(msg.get_param('title'), 51307db96d56Sopenharmony_ci ('us-ascii', '', 'This is even more ***fun*** isn\'t it!')) 51317db96d56Sopenharmony_ci msg.set_param('title', 'This is even more ***fun*** isn\'t it!', 51327db96d56Sopenharmony_ci charset='us-ascii', language='en') 51337db96d56Sopenharmony_ci eq(msg.get_param('title'), 51347db96d56Sopenharmony_ci ('us-ascii', 'en', 'This is even more ***fun*** isn\'t it!')) 51357db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 51367db96d56Sopenharmony_ci msg.set_param('title', 'This is even more ***fun*** isn\'t it!', 51377db96d56Sopenharmony_ci charset='us-ascii', language='en') 51387db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 51397db96d56Sopenharmony_ciReturn-Path: <bbb@zzz.org> 51407db96d56Sopenharmony_ciDelivered-To: bbb@zzz.org 51417db96d56Sopenharmony_ciReceived: by mail.zzz.org (Postfix, from userid 889) 51427db96d56Sopenharmony_ci\tid 27CEAD38CC; Fri, 4 May 2001 14:05:44 -0400 (EDT) 51437db96d56Sopenharmony_ciMIME-Version: 1.0 51447db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 51457db96d56Sopenharmony_ciMessage-ID: <15090.61304.110929.45684@aaa.zzz.org> 51467db96d56Sopenharmony_ciFrom: bbb@ddd.com (John X. Doe) 51477db96d56Sopenharmony_ciTo: bbb@zzz.org 51487db96d56Sopenharmony_ciSubject: This is a test message 51497db96d56Sopenharmony_ciDate: Fri, 4 May 2001 14:05:44 -0400 51507db96d56Sopenharmony_ciContent-Type: text/plain; charset=us-ascii; 51517db96d56Sopenharmony_ci title*=us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21 51527db96d56Sopenharmony_ci 51537db96d56Sopenharmony_ci 51547db96d56Sopenharmony_ciHi, 51557db96d56Sopenharmony_ci 51567db96d56Sopenharmony_ciDo you like this message? 51577db96d56Sopenharmony_ci 51587db96d56Sopenharmony_ci-Me 51597db96d56Sopenharmony_ci""") 51607db96d56Sopenharmony_ci 51617db96d56Sopenharmony_ci def test_set_param_requote(self): 51627db96d56Sopenharmony_ci msg = Message() 51637db96d56Sopenharmony_ci msg.set_param('title', 'foo') 51647db96d56Sopenharmony_ci self.assertEqual(msg['content-type'], 'text/plain; title="foo"') 51657db96d56Sopenharmony_ci msg.set_param('title', 'bar', requote=False) 51667db96d56Sopenharmony_ci self.assertEqual(msg['content-type'], 'text/plain; title=bar') 51677db96d56Sopenharmony_ci # tspecial is still quoted. 51687db96d56Sopenharmony_ci msg.set_param('title', "(bar)bell", requote=False) 51697db96d56Sopenharmony_ci self.assertEqual(msg['content-type'], 'text/plain; title="(bar)bell"') 51707db96d56Sopenharmony_ci 51717db96d56Sopenharmony_ci def test_del_param(self): 51727db96d56Sopenharmony_ci eq = self.ndiffAssertEqual 51737db96d56Sopenharmony_ci msg = self._msgobj('msg_01.txt') 51747db96d56Sopenharmony_ci msg.set_param('foo', 'bar', charset='us-ascii', language='en') 51757db96d56Sopenharmony_ci msg.set_param('title', 'This is even more ***fun*** isn\'t it!', 51767db96d56Sopenharmony_ci charset='us-ascii', language='en') 51777db96d56Sopenharmony_ci msg.del_param('foo', header='Content-Type') 51787db96d56Sopenharmony_ci eq(msg.as_string(maxheaderlen=78), """\ 51797db96d56Sopenharmony_ciReturn-Path: <bbb@zzz.org> 51807db96d56Sopenharmony_ciDelivered-To: bbb@zzz.org 51817db96d56Sopenharmony_ciReceived: by mail.zzz.org (Postfix, from userid 889) 51827db96d56Sopenharmony_ci\tid 27CEAD38CC; Fri, 4 May 2001 14:05:44 -0400 (EDT) 51837db96d56Sopenharmony_ciMIME-Version: 1.0 51847db96d56Sopenharmony_ciContent-Transfer-Encoding: 7bit 51857db96d56Sopenharmony_ciMessage-ID: <15090.61304.110929.45684@aaa.zzz.org> 51867db96d56Sopenharmony_ciFrom: bbb@ddd.com (John X. Doe) 51877db96d56Sopenharmony_ciTo: bbb@zzz.org 51887db96d56Sopenharmony_ciSubject: This is a test message 51897db96d56Sopenharmony_ciDate: Fri, 4 May 2001 14:05:44 -0400 51907db96d56Sopenharmony_ciContent-Type: text/plain; charset="us-ascii"; 51917db96d56Sopenharmony_ci title*=us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21 51927db96d56Sopenharmony_ci 51937db96d56Sopenharmony_ci 51947db96d56Sopenharmony_ciHi, 51957db96d56Sopenharmony_ci 51967db96d56Sopenharmony_ciDo you like this message? 51977db96d56Sopenharmony_ci 51987db96d56Sopenharmony_ci-Me 51997db96d56Sopenharmony_ci""") 52007db96d56Sopenharmony_ci 52017db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_charset 52027db96d56Sopenharmony_ci # I changed the charset name, though, because the one in the file isn't 52037db96d56Sopenharmony_ci # a legal charset name. Should add a test for an illegal charset. 52047db96d56Sopenharmony_ci def test_rfc2231_get_content_charset(self): 52057db96d56Sopenharmony_ci eq = self.assertEqual 52067db96d56Sopenharmony_ci msg = self._msgobj('msg_32.txt') 52077db96d56Sopenharmony_ci eq(msg.get_content_charset(), 'us-ascii') 52087db96d56Sopenharmony_ci 52097db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_no_double_quotes 52107db96d56Sopenharmony_ci def test_rfc2231_parse_rfc_quoting(self): 52117db96d56Sopenharmony_ci m = textwrap.dedent('''\ 52127db96d56Sopenharmony_ci Content-Disposition: inline; 52137db96d56Sopenharmony_ci \tfilename*0*=''This%20is%20even%20more%20; 52147db96d56Sopenharmony_ci \tfilename*1*=%2A%2A%2Afun%2A%2A%2A%20; 52157db96d56Sopenharmony_ci \tfilename*2="is it not.pdf" 52167db96d56Sopenharmony_ci 52177db96d56Sopenharmony_ci ''') 52187db96d56Sopenharmony_ci msg = email.message_from_string(m) 52197db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 52207db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 52217db96d56Sopenharmony_ci self.assertEqual(m, msg.as_string()) 52227db96d56Sopenharmony_ci 52237db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_with_double_quotes 52247db96d56Sopenharmony_ci def test_rfc2231_parse_extra_quoting(self): 52257db96d56Sopenharmony_ci m = textwrap.dedent('''\ 52267db96d56Sopenharmony_ci Content-Disposition: inline; 52277db96d56Sopenharmony_ci \tfilename*0*="''This%20is%20even%20more%20"; 52287db96d56Sopenharmony_ci \tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 52297db96d56Sopenharmony_ci \tfilename*2="is it not.pdf" 52307db96d56Sopenharmony_ci 52317db96d56Sopenharmony_ci ''') 52327db96d56Sopenharmony_ci msg = email.message_from_string(m) 52337db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 52347db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 52357db96d56Sopenharmony_ci self.assertEqual(m, msg.as_string()) 52367db96d56Sopenharmony_ci 52377db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_no_language_or_charset 52387db96d56Sopenharmony_ci # but new test uses *0* because otherwise lang/charset is not valid. 52397db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_segmented_normal_values 52407db96d56Sopenharmony_ci def test_rfc2231_no_language_or_charset(self): 52417db96d56Sopenharmony_ci m = '''\ 52427db96d56Sopenharmony_ciContent-Transfer-Encoding: 8bit 52437db96d56Sopenharmony_ciContent-Disposition: inline; filename="file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm" 52447db96d56Sopenharmony_ciContent-Type: text/html; NAME*0=file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEM; NAME*1=P_nsmail.htm 52457db96d56Sopenharmony_ci 52467db96d56Sopenharmony_ci''' 52477db96d56Sopenharmony_ci msg = email.message_from_string(m) 52487db96d56Sopenharmony_ci param = msg.get_param('NAME') 52497db96d56Sopenharmony_ci self.assertNotIsInstance(param, tuple) 52507db96d56Sopenharmony_ci self.assertEqual( 52517db96d56Sopenharmony_ci param, 52527db96d56Sopenharmony_ci 'file____C__DOCUMENTS_20AND_20SETTINGS_FABIEN_LOCAL_20SETTINGS_TEMP_nsmail.htm') 52537db96d56Sopenharmony_ci 52547db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_no_charset 52557db96d56Sopenharmony_ci def test_rfc2231_no_language_or_charset_in_filename(self): 52567db96d56Sopenharmony_ci m = '''\ 52577db96d56Sopenharmony_ciContent-Disposition: inline; 52587db96d56Sopenharmony_ci\tfilename*0*="''This%20is%20even%20more%20"; 52597db96d56Sopenharmony_ci\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 52607db96d56Sopenharmony_ci\tfilename*2="is it not.pdf" 52617db96d56Sopenharmony_ci 52627db96d56Sopenharmony_ci''' 52637db96d56Sopenharmony_ci msg = email.message_from_string(m) 52647db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 52657db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 52667db96d56Sopenharmony_ci 52677db96d56Sopenharmony_ci # Duplicate of previous test? 52687db96d56Sopenharmony_ci def test_rfc2231_no_language_or_charset_in_filename_encoded(self): 52697db96d56Sopenharmony_ci m = '''\ 52707db96d56Sopenharmony_ciContent-Disposition: inline; 52717db96d56Sopenharmony_ci\tfilename*0*="''This%20is%20even%20more%20"; 52727db96d56Sopenharmony_ci\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 52737db96d56Sopenharmony_ci\tfilename*2="is it not.pdf" 52747db96d56Sopenharmony_ci 52757db96d56Sopenharmony_ci''' 52767db96d56Sopenharmony_ci msg = email.message_from_string(m) 52777db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 52787db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 52797db96d56Sopenharmony_ci 52807db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_partly_encoded, 52817db96d56Sopenharmony_ci # but the test below is wrong (the first part should be decoded). 52827db96d56Sopenharmony_ci def test_rfc2231_partly_encoded(self): 52837db96d56Sopenharmony_ci m = '''\ 52847db96d56Sopenharmony_ciContent-Disposition: inline; 52857db96d56Sopenharmony_ci\tfilename*0="''This%20is%20even%20more%20"; 52867db96d56Sopenharmony_ci\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 52877db96d56Sopenharmony_ci\tfilename*2="is it not.pdf" 52887db96d56Sopenharmony_ci 52897db96d56Sopenharmony_ci''' 52907db96d56Sopenharmony_ci msg = email.message_from_string(m) 52917db96d56Sopenharmony_ci self.assertEqual( 52927db96d56Sopenharmony_ci msg.get_filename(), 52937db96d56Sopenharmony_ci 'This%20is%20even%20more%20***fun*** is it not.pdf') 52947db96d56Sopenharmony_ci 52957db96d56Sopenharmony_ci def test_rfc2231_partly_nonencoded(self): 52967db96d56Sopenharmony_ci m = '''\ 52977db96d56Sopenharmony_ciContent-Disposition: inline; 52987db96d56Sopenharmony_ci\tfilename*0="This%20is%20even%20more%20"; 52997db96d56Sopenharmony_ci\tfilename*1="%2A%2A%2Afun%2A%2A%2A%20"; 53007db96d56Sopenharmony_ci\tfilename*2="is it not.pdf" 53017db96d56Sopenharmony_ci 53027db96d56Sopenharmony_ci''' 53037db96d56Sopenharmony_ci msg = email.message_from_string(m) 53047db96d56Sopenharmony_ci self.assertEqual( 53057db96d56Sopenharmony_ci msg.get_filename(), 53067db96d56Sopenharmony_ci 'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20is it not.pdf') 53077db96d56Sopenharmony_ci 53087db96d56Sopenharmony_ci def test_rfc2231_no_language_or_charset_in_boundary(self): 53097db96d56Sopenharmony_ci m = '''\ 53107db96d56Sopenharmony_ciContent-Type: multipart/alternative; 53117db96d56Sopenharmony_ci\tboundary*0*="''This%20is%20even%20more%20"; 53127db96d56Sopenharmony_ci\tboundary*1*="%2A%2A%2Afun%2A%2A%2A%20"; 53137db96d56Sopenharmony_ci\tboundary*2="is it not.pdf" 53147db96d56Sopenharmony_ci 53157db96d56Sopenharmony_ci''' 53167db96d56Sopenharmony_ci msg = email.message_from_string(m) 53177db96d56Sopenharmony_ci self.assertEqual(msg.get_boundary(), 53187db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 53197db96d56Sopenharmony_ci 53207db96d56Sopenharmony_ci def test_rfc2231_no_language_or_charset_in_charset(self): 53217db96d56Sopenharmony_ci # This is a nonsensical charset value, but tests the code anyway 53227db96d56Sopenharmony_ci m = '''\ 53237db96d56Sopenharmony_ciContent-Type: text/plain; 53247db96d56Sopenharmony_ci\tcharset*0*="This%20is%20even%20more%20"; 53257db96d56Sopenharmony_ci\tcharset*1*="%2A%2A%2Afun%2A%2A%2A%20"; 53267db96d56Sopenharmony_ci\tcharset*2="is it not.pdf" 53277db96d56Sopenharmony_ci 53287db96d56Sopenharmony_ci''' 53297db96d56Sopenharmony_ci msg = email.message_from_string(m) 53307db96d56Sopenharmony_ci self.assertEqual(msg.get_content_charset(), 53317db96d56Sopenharmony_ci 'this is even more ***fun*** is it not.pdf') 53327db96d56Sopenharmony_ci 53337db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_unknown_charset_treated_as_ascii 53347db96d56Sopenharmony_ci def test_rfc2231_bad_encoding_in_filename(self): 53357db96d56Sopenharmony_ci m = '''\ 53367db96d56Sopenharmony_ciContent-Disposition: inline; 53377db96d56Sopenharmony_ci\tfilename*0*="bogus'xx'This%20is%20even%20more%20"; 53387db96d56Sopenharmony_ci\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 53397db96d56Sopenharmony_ci\tfilename*2="is it not.pdf" 53407db96d56Sopenharmony_ci 53417db96d56Sopenharmony_ci''' 53427db96d56Sopenharmony_ci msg = email.message_from_string(m) 53437db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 53447db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf') 53457db96d56Sopenharmony_ci 53467db96d56Sopenharmony_ci def test_rfc2231_bad_encoding_in_charset(self): 53477db96d56Sopenharmony_ci m = """\ 53487db96d56Sopenharmony_ciContent-Type: text/plain; charset*=bogus''utf-8%E2%80%9D 53497db96d56Sopenharmony_ci 53507db96d56Sopenharmony_ci""" 53517db96d56Sopenharmony_ci msg = email.message_from_string(m) 53527db96d56Sopenharmony_ci # This should return None because non-ascii characters in the charset 53537db96d56Sopenharmony_ci # are not allowed. 53547db96d56Sopenharmony_ci self.assertEqual(msg.get_content_charset(), None) 53557db96d56Sopenharmony_ci 53567db96d56Sopenharmony_ci def test_rfc2231_bad_character_in_charset(self): 53577db96d56Sopenharmony_ci m = """\ 53587db96d56Sopenharmony_ciContent-Type: text/plain; charset*=ascii''utf-8%E2%80%9D 53597db96d56Sopenharmony_ci 53607db96d56Sopenharmony_ci""" 53617db96d56Sopenharmony_ci msg = email.message_from_string(m) 53627db96d56Sopenharmony_ci # This should return None because non-ascii characters in the charset 53637db96d56Sopenharmony_ci # are not allowed. 53647db96d56Sopenharmony_ci self.assertEqual(msg.get_content_charset(), None) 53657db96d56Sopenharmony_ci 53667db96d56Sopenharmony_ci def test_rfc2231_bad_character_in_filename(self): 53677db96d56Sopenharmony_ci m = '''\ 53687db96d56Sopenharmony_ciContent-Disposition: inline; 53697db96d56Sopenharmony_ci\tfilename*0*="ascii'xx'This%20is%20even%20more%20"; 53707db96d56Sopenharmony_ci\tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; 53717db96d56Sopenharmony_ci\tfilename*2*="is it not.pdf%E2" 53727db96d56Sopenharmony_ci 53737db96d56Sopenharmony_ci''' 53747db96d56Sopenharmony_ci msg = email.message_from_string(m) 53757db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 53767db96d56Sopenharmony_ci 'This is even more ***fun*** is it not.pdf\ufffd') 53777db96d56Sopenharmony_ci 53787db96d56Sopenharmony_ci def test_rfc2231_unknown_encoding(self): 53797db96d56Sopenharmony_ci m = """\ 53807db96d56Sopenharmony_ciContent-Transfer-Encoding: 8bit 53817db96d56Sopenharmony_ciContent-Disposition: inline; filename*=X-UNKNOWN''myfile.txt 53827db96d56Sopenharmony_ci 53837db96d56Sopenharmony_ci""" 53847db96d56Sopenharmony_ci msg = email.message_from_string(m) 53857db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 'myfile.txt') 53867db96d56Sopenharmony_ci 53877db96d56Sopenharmony_ci def test_rfc2231_bad_character_in_encoding(self): 53887db96d56Sopenharmony_ci m = """\ 53897db96d56Sopenharmony_ciContent-Transfer-Encoding: 8bit 53907db96d56Sopenharmony_ciContent-Disposition: inline; filename*=utf-8\udce2\udc80\udc9d''myfile.txt 53917db96d56Sopenharmony_ci 53927db96d56Sopenharmony_ci""" 53937db96d56Sopenharmony_ci msg = email.message_from_string(m) 53947db96d56Sopenharmony_ci self.assertEqual(msg.get_filename(), 'myfile.txt') 53957db96d56Sopenharmony_ci 53967db96d56Sopenharmony_ci def test_rfc2231_single_tick_in_filename_extended(self): 53977db96d56Sopenharmony_ci eq = self.assertEqual 53987db96d56Sopenharmony_ci m = """\ 53997db96d56Sopenharmony_ciContent-Type: application/x-foo; 54007db96d56Sopenharmony_ci\tname*0*=\"Frank's\"; name*1*=\" Document\" 54017db96d56Sopenharmony_ci 54027db96d56Sopenharmony_ci""" 54037db96d56Sopenharmony_ci msg = email.message_from_string(m) 54047db96d56Sopenharmony_ci charset, language, s = msg.get_param('name') 54057db96d56Sopenharmony_ci eq(charset, None) 54067db96d56Sopenharmony_ci eq(language, None) 54077db96d56Sopenharmony_ci eq(s, "Frank's Document") 54087db96d56Sopenharmony_ci 54097db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_single_quote_inside_double_quotes 54107db96d56Sopenharmony_ci def test_rfc2231_single_tick_in_filename(self): 54117db96d56Sopenharmony_ci m = """\ 54127db96d56Sopenharmony_ciContent-Type: application/x-foo; name*0=\"Frank's\"; name*1=\" Document\" 54137db96d56Sopenharmony_ci 54147db96d56Sopenharmony_ci""" 54157db96d56Sopenharmony_ci msg = email.message_from_string(m) 54167db96d56Sopenharmony_ci param = msg.get_param('name') 54177db96d56Sopenharmony_ci self.assertNotIsInstance(param, tuple) 54187db96d56Sopenharmony_ci self.assertEqual(param, "Frank's Document") 54197db96d56Sopenharmony_ci 54207db96d56Sopenharmony_ci def test_rfc2231_missing_tick(self): 54217db96d56Sopenharmony_ci m = '''\ 54227db96d56Sopenharmony_ciContent-Disposition: inline; 54237db96d56Sopenharmony_ci\tfilename*0*="'This%20is%20broken"; 54247db96d56Sopenharmony_ci''' 54257db96d56Sopenharmony_ci msg = email.message_from_string(m) 54267db96d56Sopenharmony_ci self.assertEqual( 54277db96d56Sopenharmony_ci msg.get_filename(), 54287db96d56Sopenharmony_ci "'This is broken") 54297db96d56Sopenharmony_ci 54307db96d56Sopenharmony_ci def test_rfc2231_missing_tick_with_encoded_non_ascii(self): 54317db96d56Sopenharmony_ci m = '''\ 54327db96d56Sopenharmony_ciContent-Disposition: inline; 54337db96d56Sopenharmony_ci\tfilename*0*="'This%20is%E2broken"; 54347db96d56Sopenharmony_ci''' 54357db96d56Sopenharmony_ci msg = email.message_from_string(m) 54367db96d56Sopenharmony_ci self.assertEqual( 54377db96d56Sopenharmony_ci msg.get_filename(), 54387db96d56Sopenharmony_ci "'This is\ufffdbroken") 54397db96d56Sopenharmony_ci 54407db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_single_quote_in_value_with_charset_and_lang 54417db96d56Sopenharmony_ci def test_rfc2231_tick_attack_extended(self): 54427db96d56Sopenharmony_ci eq = self.assertEqual 54437db96d56Sopenharmony_ci m = """\ 54447db96d56Sopenharmony_ciContent-Type: application/x-foo; 54457db96d56Sopenharmony_ci\tname*0*=\"us-ascii'en-us'Frank's\"; name*1*=\" Document\" 54467db96d56Sopenharmony_ci 54477db96d56Sopenharmony_ci""" 54487db96d56Sopenharmony_ci msg = email.message_from_string(m) 54497db96d56Sopenharmony_ci charset, language, s = msg.get_param('name') 54507db96d56Sopenharmony_ci eq(charset, 'us-ascii') 54517db96d56Sopenharmony_ci eq(language, 'en-us') 54527db96d56Sopenharmony_ci eq(s, "Frank's Document") 54537db96d56Sopenharmony_ci 54547db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_single_quote_in_non_encoded_value 54557db96d56Sopenharmony_ci def test_rfc2231_tick_attack(self): 54567db96d56Sopenharmony_ci m = """\ 54577db96d56Sopenharmony_ciContent-Type: application/x-foo; 54587db96d56Sopenharmony_ci\tname*0=\"us-ascii'en-us'Frank's\"; name*1=\" Document\" 54597db96d56Sopenharmony_ci 54607db96d56Sopenharmony_ci""" 54617db96d56Sopenharmony_ci msg = email.message_from_string(m) 54627db96d56Sopenharmony_ci param = msg.get_param('name') 54637db96d56Sopenharmony_ci self.assertNotIsInstance(param, tuple) 54647db96d56Sopenharmony_ci self.assertEqual(param, "us-ascii'en-us'Frank's Document") 54657db96d56Sopenharmony_ci 54667db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_single_quotes_inside_quotes 54677db96d56Sopenharmony_ci def test_rfc2231_no_extended_values(self): 54687db96d56Sopenharmony_ci eq = self.assertEqual 54697db96d56Sopenharmony_ci m = """\ 54707db96d56Sopenharmony_ciContent-Type: application/x-foo; name=\"Frank's Document\" 54717db96d56Sopenharmony_ci 54727db96d56Sopenharmony_ci""" 54737db96d56Sopenharmony_ci msg = email.message_from_string(m) 54747db96d56Sopenharmony_ci eq(msg.get_param('name'), "Frank's Document") 54757db96d56Sopenharmony_ci 54767db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_then_unencoded_segments 54777db96d56Sopenharmony_ci def test_rfc2231_encoded_then_unencoded_segments(self): 54787db96d56Sopenharmony_ci eq = self.assertEqual 54797db96d56Sopenharmony_ci m = """\ 54807db96d56Sopenharmony_ciContent-Type: application/x-foo; 54817db96d56Sopenharmony_ci\tname*0*=\"us-ascii'en-us'My\"; 54827db96d56Sopenharmony_ci\tname*1=\" Document\"; 54837db96d56Sopenharmony_ci\tname*2*=\" For You\" 54847db96d56Sopenharmony_ci 54857db96d56Sopenharmony_ci""" 54867db96d56Sopenharmony_ci msg = email.message_from_string(m) 54877db96d56Sopenharmony_ci charset, language, s = msg.get_param('name') 54887db96d56Sopenharmony_ci eq(charset, 'us-ascii') 54897db96d56Sopenharmony_ci eq(language, 'en-us') 54907db96d56Sopenharmony_ci eq(s, 'My Document For You') 54917db96d56Sopenharmony_ci 54927db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_unencoded_then_encoded_segments 54937db96d56Sopenharmony_ci # test_headerregistry.TestContentTypeHeader.rfc2231_quoted_unencoded_then_encoded_segments 54947db96d56Sopenharmony_ci def test_rfc2231_unencoded_then_encoded_segments(self): 54957db96d56Sopenharmony_ci eq = self.assertEqual 54967db96d56Sopenharmony_ci m = """\ 54977db96d56Sopenharmony_ciContent-Type: application/x-foo; 54987db96d56Sopenharmony_ci\tname*0=\"us-ascii'en-us'My\"; 54997db96d56Sopenharmony_ci\tname*1*=\" Document\"; 55007db96d56Sopenharmony_ci\tname*2*=\" For You\" 55017db96d56Sopenharmony_ci 55027db96d56Sopenharmony_ci""" 55037db96d56Sopenharmony_ci msg = email.message_from_string(m) 55047db96d56Sopenharmony_ci charset, language, s = msg.get_param('name') 55057db96d56Sopenharmony_ci eq(charset, 'us-ascii') 55067db96d56Sopenharmony_ci eq(language, 'en-us') 55077db96d56Sopenharmony_ci eq(s, 'My Document For You') 55087db96d56Sopenharmony_ci 55097db96d56Sopenharmony_ci def test_should_not_hang_on_invalid_ew_messages(self): 55107db96d56Sopenharmony_ci messages = ["""From: user@host.com 55117db96d56Sopenharmony_ciTo: user@host.com 55127db96d56Sopenharmony_ciBad-Header: 55137db96d56Sopenharmony_ci =?us-ascii?Q?LCSwrV11+IB0rSbSker+M9vWR7wEDSuGqmHD89Gt=ea0nJFSaiz4vX3XMJPT4vrE?= 55147db96d56Sopenharmony_ci =?us-ascii?Q?xGUZeOnp0o22pLBB7CYLH74Js=wOlK6Tfru2U47qR?= 55157db96d56Sopenharmony_ci =?us-ascii?Q?72OfyEY2p2=2FrA9xNFyvH+fBTCmazxwzF8nGkK6D?= 55167db96d56Sopenharmony_ci 55177db96d56Sopenharmony_ciHello! 55187db96d56Sopenharmony_ci""", """From: ����� �������� <xxx@xxx> 55197db96d56Sopenharmony_ciTo: "xxx" <xxx@xxx> 55207db96d56Sopenharmony_ciSubject: ��� ���������� ����� ����� � ��������� �� ���� 55217db96d56Sopenharmony_ciMIME-Version: 1.0 55227db96d56Sopenharmony_ciContent-Type: text/plain; charset="windows-1251"; 55237db96d56Sopenharmony_ciContent-Transfer-Encoding: 8bit 55247db96d56Sopenharmony_ci 55257db96d56Sopenharmony_ci�� ����� � ���� ������ ��� �������� 55267db96d56Sopenharmony_ci"""] 55277db96d56Sopenharmony_ci for m in messages: 55287db96d56Sopenharmony_ci with self.subTest(m=m): 55297db96d56Sopenharmony_ci msg = email.message_from_string(m) 55307db96d56Sopenharmony_ci 55317db96d56Sopenharmony_ci 55327db96d56Sopenharmony_ci# Tests to ensure that signed parts of an email are completely preserved, as 55337db96d56Sopenharmony_ci# required by RFC1847 section 2.1. Note that these are incomplete, because the 55347db96d56Sopenharmony_ci# email package does not currently always preserve the body. See issue 1670765. 55357db96d56Sopenharmony_ciclass TestSigned(TestEmailBase): 55367db96d56Sopenharmony_ci 55377db96d56Sopenharmony_ci def _msg_and_obj(self, filename): 55387db96d56Sopenharmony_ci with openfile(filename, encoding="utf-8") as fp: 55397db96d56Sopenharmony_ci original = fp.read() 55407db96d56Sopenharmony_ci msg = email.message_from_string(original) 55417db96d56Sopenharmony_ci return original, msg 55427db96d56Sopenharmony_ci 55437db96d56Sopenharmony_ci def _signed_parts_eq(self, original, result): 55447db96d56Sopenharmony_ci # Extract the first mime part of each message 55457db96d56Sopenharmony_ci import re 55467db96d56Sopenharmony_ci repart = re.compile(r'^--([^\n]+)\n(.*?)\n--\1$', re.S | re.M) 55477db96d56Sopenharmony_ci inpart = repart.search(original).group(2) 55487db96d56Sopenharmony_ci outpart = repart.search(result).group(2) 55497db96d56Sopenharmony_ci self.assertEqual(outpart, inpart) 55507db96d56Sopenharmony_ci 55517db96d56Sopenharmony_ci def test_long_headers_as_string(self): 55527db96d56Sopenharmony_ci original, msg = self._msg_and_obj('msg_45.txt') 55537db96d56Sopenharmony_ci result = msg.as_string() 55547db96d56Sopenharmony_ci self._signed_parts_eq(original, result) 55557db96d56Sopenharmony_ci 55567db96d56Sopenharmony_ci def test_long_headers_as_string_maxheaderlen(self): 55577db96d56Sopenharmony_ci original, msg = self._msg_and_obj('msg_45.txt') 55587db96d56Sopenharmony_ci result = msg.as_string(maxheaderlen=60) 55597db96d56Sopenharmony_ci self._signed_parts_eq(original, result) 55607db96d56Sopenharmony_ci 55617db96d56Sopenharmony_ci def test_long_headers_flatten(self): 55627db96d56Sopenharmony_ci original, msg = self._msg_and_obj('msg_45.txt') 55637db96d56Sopenharmony_ci fp = StringIO() 55647db96d56Sopenharmony_ci Generator(fp).flatten(msg) 55657db96d56Sopenharmony_ci result = fp.getvalue() 55667db96d56Sopenharmony_ci self._signed_parts_eq(original, result) 55677db96d56Sopenharmony_ci 55687db96d56Sopenharmony_ciclass TestHeaderRegistry(TestEmailBase): 55697db96d56Sopenharmony_ci # See issue gh-93010. 55707db96d56Sopenharmony_ci def test_HeaderRegistry(self): 55717db96d56Sopenharmony_ci reg = HeaderRegistry() 55727db96d56Sopenharmony_ci a = reg('Content-Disposition', 'attachment; 0*00="foo"') 55737db96d56Sopenharmony_ci self.assertIsInstance(a.defects[0], errors.InvalidHeaderDefect) 55747db96d56Sopenharmony_ci 55757db96d56Sopenharmony_ciif __name__ == '__main__': 55767db96d56Sopenharmony_ci unittest.main() 5577