/* 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;
}