Revision control

Copy as Markdown

Other Tools

/* 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/. */
/*
* Tests that every mailbox the server lists is selected under the name the
* server gave it. AllocateCanonicalPath() maps that name into the folder
* tree and AllocateServerPath() maps it back; each keeps its own rules about
* namespace prefixes and the server directory, and nothing else checks that
* they agree (bug 2005701).
*/
add_task(async function testNamespaces() {
// Like Dovecot or Cyrus, advertise the prefixes with their trailing
// delimiter.
await checkRoundTrip({
// "sha" and "other" only start the prefixes; the other users' namespace
// has no root of its own, as when the namespace above it is hidden.
mailboxes: ["shared", "shared/sub", "folder", "sha", "other"],
namespaces: '(("" "/")) (("other/user/" "/")) (("shared/" "/"))',
});
});
add_task(async function testServerDirectory() {
await checkRoundTrip({
mailboxes: ["Mail", "Mail/Mail", "Mail/folder"],
serverDirectory: "Mail",
});
});
/**
* Lets Thunderbird discover the mailboxes, selects every folder it shows, and
* compares the selected names with the selectable mailboxes on the server.
*
* @param {object} options
* @param {string[]} options.mailboxes - Mailboxes to create on the server.
* @param {string} [options.namespaces] - The NAMESPACE response, if any.
* @param {string} [options.serverDirectory] - The server directory to set.
*/
async function checkRoundTrip({ mailboxes, namespaces, serverDirectory }) {
const daemon = new ImapDaemon();
for (const name of mailboxes) {
daemon.createMailbox(name, { subscribed: true });
}
const server = makeServer(
daemon,
"RFC2342",
namespaces && {
NAMESPACE() {
return `* NAMESPACE ${namespaces}\0OK NAMESPACE completed`;
},
}
);
const incomingServer = createLocalIMAPServer(server.port);
incomingServer.maximumConnectionsNumber = 1;
if (serverDirectory) {
incomingServer.serverDirectory = serverDirectory;
}
const account = MailServices.accounts.createAccount();
const identity = MailServices.accounts.createIdentity();
account.addIdentity(identity);
account.defaultIdentity = identity;
account.incomingServer = incomingServer;
const root = incomingServer.rootFolder;
await updateFolder(root.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox));
const selected = [];
for (const folder of root.descendants) {
if (folder.getFlag(Ci.nsMsgFolderFlags.ImapNoselect)) {
continue;
}
await updateFolder(folder).catch(() => {});
const commands = server.playTransaction().them;
const select = commands.findLast(line => line.includes(" select "));
selected.push(
select.substring(select.indexOf(" select ") + 9, select.length - 1)
);
}
const listed = serverMailboxes(daemon.root).filter(
name =>
!serverDirectory ||
name == "INBOX" ||
name.startsWith(serverDirectory + "/")
);
Assert.deepEqual(selected.sort(), listed.sort());
incomingServer.closeCachedConnections();
server.stop();
MailServices.accounts.removeAccount(account, false);
}
function serverMailboxes(parent) {
return parent._children.flatMap(mailbox => [
...(mailbox.flags.includes("\\Noselect") ? [] : [mailbox.fullName]),
...serverMailboxes(mailbox),
]);
}
async function updateFolder(folder) {
const listener = new PromiseTestUtils.PromiseUrlListener();
folder
.QueryInterface(Ci.nsIMsgImapMailFolder)
.updateFolderWithListener(null, listener);
await listener.promise;
}