/* * Test ensuring that messages with "long lines" are transmitted correctly. * Most of this test was copied from test_messageHeaders.js. */ const { MimeParser } = ChromeUtils.import("resource:///modules/mimeParser.jsm"); var CompFields = CC( "@mozilla.org/messengercompose/composefields;1", Ci.nsIMsgCompFields ); // Copied from jsmime.js. function stringToTypedArray(buffer) { var typedarray = new Uint8Array(buffer.length); for (var i = 0; i < buffer.length; i++) { typedarray[i] = buffer.charCodeAt(i); } return typedarray; } function checkDraftHeadersAndBody( expectedHeaders, expectedBody, charset = "UTF-8" ) { let msgData = mailTestUtils.loadMessageToString( gDraftFolder, mailTestUtils.firstMsgHdr(gDraftFolder) ); checkMessageHeaders(msgData, expectedHeaders); // Get the message body, decode from base64 and check. let endOfHeaders = msgData.indexOf("\r\n\r\n"); let body = msgData.slice(endOfHeaders + 4); let endOfBody = body.indexOf("\r\n\r\n"); if (endOfBody > 0) { body = body.slice(0, endOfBody); } else { body = body.slice(0, body.length); } // Remove line breaks and decode from base64 if required. if (expectedHeaders["Content-Transfer-Encoding"] == "base64") { body = atob(body.replace(/\r\n/g, "")); } if (charset == "UTF-8") { let expectedBinary = String.fromCharCode.apply( undefined, new TextEncoder("UTF-8").encode(expectedBody) ); Assert.equal(body, expectedBinary); } else { let strView = stringToTypedArray(body); let decodedBody = new TextDecoder(charset).decode(strView); Assert.equal(decodedBody, expectedBody); } } function checkMessageHeaders(msgData, expectedHeaders, partNum = "") { let seen = false; let handler = { startPart(part, headers) { if (part != partNum) { return; } seen = true; for (let header in expectedHeaders) { let expected = expectedHeaders[header]; if (expected === undefined) { Assert.ok(!headers.has(header)); } else { let value = headers.getRawHeader(header); Assert.equal(value.length, 1); value[0] = value[0].replace(/boundary=[^;]*(;|$)/, "boundary=."); Assert.equal(value[0], expected); } } }, }; MimeParser.parseSync(msgData, handler, { onerror(e) { throw e; }, }); Assert.ok(seen); } // Create a line with 600 letters 'a' with acute accent, encoded as // two bytes c3a1 in UTF-8. let longMultibyteLine = "\u00E1".repeat(600); // And here a line with a Korean character, encoded as three bytes // ec9588 in UTF-8. let longMultibyteLineCJK = "안".repeat(400); // And some Japanese. let longMultibyteLineJapanese = "語".repeat(450); async function testBodyWithLongLine() { // Lines in the message body are split by CRLF according to RFC 5322, should // be independent of the system. let newline = "\r\n"; let fields = new CompFields(); let identity = getSmtpIdentity( "from@tinderbox.invalid", getBasicSmtpServer() ); identity.fullName = "Me"; identity.organization = "World Destruction Committee"; fields.from = "Nobody "; fields.to = "Nobody "; fields.subject = "Message with 1200 byte line in body"; let htmlMessage = "" + '' + "" + longMultibyteLine + "\r\n\r\n"; fields.body = htmlMessage; await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/html; charset=UTF-8", "Content-Transfer-Encoding": "base64", }, htmlMessage ); // Again, but this time as plain text. fields.body = htmlMessage; fields.forcePlainText = true; fields.useMultipartAlternative = false; await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/plain; charset=UTF-8; format=flowed", "Content-Transfer-Encoding": "base64", }, longMultibyteLine + " " + newline + newline // Expected body: The message without the tags. ); // Now CJK. fields.forcePlainText = false; htmlMessage = "" + '' + "" + longMultibyteLineCJK + "\r\n\r\n"; fields.body = htmlMessage; await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/html; charset=UTF-8", "Content-Transfer-Encoding": "base64", }, htmlMessage ); // Again, but this time as plain text. fields.body = htmlMessage; fields.forcePlainText = true; fields.useMultipartAlternative = false; await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/plain; charset=UTF-8; format=flowed", "Content-Transfer-Encoding": "base64", }, longMultibyteLineCJK + " " + newline + newline // Expected body: The message without the tags. ); // Now a test for ISO-2022-JP. fields.forcePlainText = false; htmlMessage = "" + '' + "" + longMultibyteLineJapanese + "\r\n\r\n"; fields.body = htmlMessage; await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/html; charset=UTF-8", "Content-Transfer-Encoding": "base64", }, htmlMessage ); // Again, but this time as plain text. fields.body = htmlMessage; fields.forcePlainText = true; fields.useMultipartAlternative = false; await richCreateMessage(fields, [], identity); let expectedBody = longMultibyteLineJapanese + " " + newline + newline; checkDraftHeadersAndBody( { "Content-Type": "text/plain; charset=UTF-8; format=flowed", "Content-Transfer-Encoding": "base64", }, expectedBody ); // Again, but this time not flowed. fields.body = htmlMessage; Services.prefs.setBoolPref("mailnews.send_plaintext_flowed", false); await richCreateMessage(fields, [], identity); checkDraftHeadersAndBody( { "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "base64", }, expectedBody.replace(/ /g, "") // No spaces expected this time. ); } var tests = [testBodyWithLongLine]; function run_test() { // Ensure we have at least one mail account localAccountUtils.loadLocalMailAccount(); tests.forEach(x => add_task(x)); run_next_test(); }