/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * General testing of the byte-counting libmime facility, to make sure that what * is streamed to us is actually labeled with the right size. */ /* * Do not include glodaTestHelper because we do not want gloda loaded and it * adds a lot of runtime overhead which makes certain debugging strategies like * using chronicle-recorder impractical. */ var { MsgHdrToMimeMessage } = ChromeUtils.import( "resource:///modules/gloda/MimeMessage.jsm" ); var { MessageGenerator, SyntheticPartLeaf, SyntheticPartMultiMixed, SyntheticPartMultiRelated, SyntheticMessageSet, } = ChromeUtils.import( "resource://testing-common/mailnews/MessageGenerator.jsm" ); var { MessageInjection } = ChromeUtils.import( "resource://testing-common/mailnews/MessageInjection.jsm" ); var msgGen = new MessageGenerator(); var messageInjection; add_setup(function () { // Sanity check: figure out how many bytes the original text occupies in UTF-8 encoding Assert.equal( new TextEncoder().encode(originalText).length, originalTextByteCount ); messageInjection = new MessageInjection({ mode: "local" }, msgGen); }); var htmlText = "I am HTML! Woo! "; var partHtml = new SyntheticPartLeaf(htmlText, { contentType: "text/html", }); // This text is 168 characters long, and occupies 173 bytes when encoded in // UTF-8. (We make sure it occupies 173 bytes in run_test below). Note that // you cannot use this text directly because it isn't pure ASCII. You must use // one of the encoded forms below. var originalText = "Longtemps, je me suis couché de bonne heure. Parfois, à " + "peine ma bougie éteinte, mes yeux se fermaient si vite que je n'avais pas le " + "temps de me dire : « Je m'endors. »"; var originalTextByteCount = 173; var b64Text = "TG9uZ3RlbXBzLCBqZSBtZSBzdWlzIGNvdWNow6kgZGUgYm9ubmUgaGV1cmUuIFBhcmZvaXMs\n" + "IMOgIHBlaW5lIG1hIGJvdWdpZSDDqXRlaW50ZSwgbWVzIHlldXggc2UgZmVybWFpZW50IHNp\n" + "IHZpdGUgcXVlIGplIG4nYXZhaXMgcGFzIGxlIHRlbXBzIGRlIG1lIGRpcmUgOiDCqyBKZSBt\n" + "J2VuZG9ycy4gwrsK"; var qpText = "Longtemps,=20je=20me=20suis=20couch=C3=A9=20de=20bonne=20heure.=20Parfois,=\n" + "=20=C3=A0=20peine=20ma=20bougie=20=C3=A9teinte,=20mes=20yeux=20se=20fermaie=\n" + "nt=20si=20vite=20que=20je=20n'avais=20pas=20le=20temps=20de=20me=20dire=20:=\n" + "=20=C2=AB=20Je=20m'endors.=20=C2=BB"; var uuText = "begin 666 -\n" + 'M3&]N9W1E;7!S+"!J92!M92!S=6ES(&-O=6-HPZD@9&4@8F]N;F4@:&5U { promiseResolve = resolve; }); MsgHdrToMimeMessage(msgHdr, null, function (aMsgHdr, aMimeMsg) { try { Assert.equal(aMimeMsg.allUserAttachments.length, number); promiseResolve(); } catch (e) { do_throw(e); } }); await promise; }); async function message_attachments(info) { let synMsg = msgGen.makeMessage(info); let synSet = new SyntheticMessageSet([synMsg]); await messageInjection.addSetsToFolders( [messageInjection.getInboxFolder()], [synSet] ); let msgHdr = synSet.getMsgHdr(0); let promiseResolve; let promise = new Promise(resolve => { promiseResolve = resolve; }); MsgHdrToMimeMessage(msgHdr, null, function (aMsgHdr, aMimeMsg) { try { check_attachments( aMimeMsg, info.epsilon, "checkTotalSize" in info ? info.checkTotalSize : undefined ); promiseResolve(); } catch (e) { do_throw(e); } }); await promise; } function check_attachments(aMimeMsg, epsilon, checkTotalSize) { if (aMimeMsg == null) { do_throw("We really should have gotten a result!"); } /* It is hard to get a byte count that's perfectly accurate. When composing * the message, the MIME structure goes like this (for an encoded attachment): * * XXXXXXXXXX * XXXXXXXXXX <-- encoded block * XXXXXXXXXX * <-- newline * --chopchop <-- MIME separator * * libmime counts bytes all the way up to the separator, which means it counts * the bytes for the extra line. Since newlines in emails are \n, most of the * time we get att.size = 174 instead of 173. * * The good news is, it's just a fixed extra cost. There no issues with the * inner contents of the attachment, you can add as many newlines as you want * in it, Unix or Windows, the count won't get past the bounds. */ Assert.ok(aMimeMsg.allUserAttachments.length > 0); let totalSize = htmlText.length; for (let att of aMimeMsg.allUserAttachments) { dump("*** Attachment now is " + att.name + " " + att.size + "\n"); Assert.ok(Math.abs(att.size - originalTextByteCount) <= epsilon); totalSize += att.size; } // Undefined means true. if (checkTotalSize !== false) { dump( "*** Total size comparison: " + totalSize + " vs " + aMimeMsg.size + "\n" ); Assert.ok(Math.abs(aMimeMsg.size - totalSize) <= epsilon); } } function check_bogus_parts(aMimeMsg, { epsilon, checkSize }) { if (aMimeMsg == null) { do_throw("We really should have gotten a result!"); } // First make sure the size is computed properly let x = parseInt(aMimeMsg.size); Assert.ok(!isNaN(x)); let sep = "@mozilla.org/windows-registry-key;1" in Cc ? "\r\n" : "\n"; if (checkSize) { let partSize = 0; // The attachment, although a MimeUnknown part, is actually plain/text that // contains the whole attached message, including headers. Count them. for (let k in bogusMessage.headers) { let v = bogusMessage.headers[k]; partSize += (k + ": " + v + sep).length; } // That's the newline between the headers and the message body. partSize += sep.length; // That's the message body. partSize += originalTextByteCount; // That's the total length that's to be returned by the MimeMessage abstraction. let totalSize = htmlText.length + partSize; dump(totalSize + " vs " + aMimeMsg.size + "\n"); Assert.ok(Math.abs(aMimeMsg.size - totalSize) <= epsilon); } } async function bogus_messages(info) { let synMsg = msgGen.makeMessage(info); let synSet = new SyntheticMessageSet([synMsg]); await messageInjection.addSetsToFolders( [messageInjection.getInboxFolder()], [synSet] ); let msgHdr = synSet.getMsgHdr(0); let promiseResolve; let promise = new Promise(resolve => { promiseResolve = resolve; }); MsgHdrToMimeMessage(msgHdr, null, function (aMsgHdr, aMimeMsg) { try { check_bogus_parts(aMimeMsg, info); promiseResolve(); } catch (e) { do_throw(e); } }); await promise; }