diff options
Diffstat (limited to 'comm/mailnews/mapi/test')
-rw-r--r-- | comm/mailnews/mapi/test/moz.build | 6 | ||||
-rw-r--r-- | comm/mailnews/mapi/test/unit/head_mapi.js | 243 | ||||
-rw-r--r-- | comm/mailnews/mapi/test/unit/tail_mapi.js | 1 | ||||
-rw-r--r-- | comm/mailnews/mapi/test/unit/test_mapisendmail.js | 97 | ||||
-rw-r--r-- | comm/mailnews/mapi/test/unit/xpcshell.ini | 7 |
5 files changed, 354 insertions, 0 deletions
diff --git a/comm/mailnews/mapi/test/moz.build b/comm/mailnews/mapi/test/moz.build new file mode 100644 index 0000000000..6b37fdbe09 --- /dev/null +++ b/comm/mailnews/mapi/test/moz.build @@ -0,0 +1,6 @@ +# vim: set filetype=python: +# 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/. + +XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell.ini"] diff --git a/comm/mailnews/mapi/test/unit/head_mapi.js b/comm/mailnews/mapi/test/unit/head_mapi.js new file mode 100644 index 0000000000..d80b7da173 --- /dev/null +++ b/comm/mailnews/mapi/test/unit/head_mapi.js @@ -0,0 +1,243 @@ +/* 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/. */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +var { ctypes } = ChromeUtils.importESModule( + "resource://gre/modules/ctypes.sys.mjs" +); +var { localAccountUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/LocalAccountUtils.jsm" +); + +// Ensure the profile directory is set up. +do_get_profile(); + +// Import fakeserver +var { nsMailServer } = ChromeUtils.import( + "resource://testing-common/mailnews/Maild.jsm" +); +var { SmtpDaemon, SMTP_RFC2821_handler } = ChromeUtils.import( + "resource://testing-common/mailnews/Smtpd.jsm" +); + +var SMTP_PORT = 1024 + 120; +var POP3_PORT = 1024 + 121; + +// Setup the daemon and server +function setupServerDaemon(handler) { + if (!handler) { + handler = function (d) { + return new SMTP_RFC2821_handler(d); + }; + } + let daemon = new SmtpDaemon(); + let server = new nsMailServer(handler, daemon); + return [daemon, server]; +} + +function getBasicSmtpServer() { + // We need to have a default account for MAPI. + localAccountUtils.loadLocalMailAccount(); + let incoming = localAccountUtils.create_incoming_server( + "pop3", + POP3_PORT, + "user", + "password" + ); + let server = localAccountUtils.create_outgoing_server( + SMTP_PORT, + "user", + "password" + ); + // We also need to have a working identity, including an email address. + let account = MailServices.accounts.FindAccountForServer(incoming); + localAccountUtils.associate_servers(account, server, true); + let identity = account.defaultIdentity; + identity.email = "tinderbox@tinderbox.invalid"; + MailServices.accounts.defaultAccount = account; + + return server; +} + +/** + * Returns a structure allowing access to all of the Simple MAPI functions. + * The functions do not have the MAPI prefix on the variables. Also added are + * the three structures needed for MAPI. + */ +function loadMAPILibrary() { + // This is a hack to load the MAPI support in the current environment, as the + // profile-after-change event is never sent out. + var gMapiSupport = Cc["@mozilla.org/mapisupport;1"].getService( + Ci.nsIObserver + ); + gMapiSupport.observe(null, "profile-after-change", null); + // Set some preferences to make MAPI (particularly blind MAPI, aka work + // without a dialog box) work properly. + Services.prefs.setBoolPref("mapi.blind-send.enabled", true); + Services.prefs.setBoolPref("mapi.blind-send.warn", false); + + // The macros that are used in the definitions + let WINAPI = ctypes.winapi_abi; + let ULONG = ctypes.unsigned_long; + let LHANDLE = ULONG.ptr; + let LPSTR = ctypes.char.ptr; + let LPVOID = ctypes.voidptr_t; + let FLAGS = ctypes.unsigned_long; + + // Define all of the MAPI structs we need to use. + let functionData = {}; + functionData.MapiRecipDesc = new ctypes.StructType("gMapi.MapiRecipDesc", [ + { ulReserved: ULONG }, + { ulRecipClass: ULONG }, + { lpszName: LPSTR }, + { lpszAddress: LPSTR }, + { ulEIDSize: ULONG }, + { lpEntryID: LPVOID }, + ]); + let lpMapiRecipDesc = functionData.MapiRecipDesc.ptr; + + functionData.MapiFileDesc = new ctypes.StructType("gMapi.MapiFileDesc", [ + { ulReserved: ULONG }, + { flFlags: ULONG }, + { nPosition: ULONG }, + { lpszPathName: LPSTR }, + { lpszFileName: LPSTR }, + { lpFileType: LPVOID }, + ]); + let lpMapiFileDesc = functionData.MapiFileDesc.ptr; + + functionData.MapiMessage = new ctypes.StructType("gMapi.MapiMessage", [ + { ulReserved: ULONG }, + { lpszSubject: LPSTR }, + { lpszNoteText: LPSTR }, + { lpszMessageType: LPSTR }, + { lpszDateReceived: LPSTR }, + { lpszConversationID: LPSTR }, + { flFlags: FLAGS }, + { lpOriginator: lpMapiRecipDesc }, + { nRecipCount: ULONG }, + { lpRecips: lpMapiRecipDesc }, + { nFileCount: ULONG }, + { lpFiles: lpMapiFileDesc }, + ]); + let lpMapiMessage = functionData.MapiMessage.ptr; + + // Load the MAPI library. We're using our definition instead of the global + // MAPI definition. + let mapi = ctypes.open("mozMapi32.dll"); + + // Load the MAPI functions, + // see https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_types + // for details. The first three parameters of the declaration are name, API flag and output value. + // This is followed by input parameters. + + // MAPIAddress is not supported. + + functionData.DeleteMail = mapi.declare( + "MAPIDeleteMail", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + LPSTR, // lpszMessageID + FLAGS, // flFlags + ULONG + ); // ulReserved + + // MAPIDetails is not supported. + + functionData.FindNext = mapi.declare( + "MAPIFindNext", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + LPSTR, // lpszMessageType + LPSTR, // lpszSeedMessageID + FLAGS, // flFlags + ULONG, // ulReserved + LPSTR + ); // lpszMessageID + + functionData.FreeBuffer = mapi.declare( + "MAPIFreeBuffer", + WINAPI, + ULONG, + LPVOID + ); // pv + + functionData.Logoff = mapi.declare( + "MAPILogoff", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + FLAGS, // flFlags + ULONG + ); // ulReserved + + functionData.Logon = mapi.declare( + "MAPILogon", + WINAPI, + ULONG, + ULONG.ptr, // ulUIParam + LPSTR, // lpszProfileName + LPSTR, // lpszPassword + FLAGS, // flFlags + ULONG, // ulReserved + LHANDLE.ptr + ); // lplhSession + + functionData.ReadMail = mapi.declare( + "MAPIReadMail", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + LPSTR, // lpszMessageID + FLAGS, // flFlags + ULONG, // ulReserved + lpMapiMessage.ptr + ); // *lppMessage + + functionData.ResolveName = mapi.declare( + "MAPIResolveName", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + LPSTR, // lpszName + FLAGS, // flFlags + ULONG, // ulReserved + lpMapiRecipDesc.ptr + ); // *lppRecip + + // MAPISaveMail is not supported. + + functionData.SendDocuments = mapi.declare( + "MAPISendDocuments", + WINAPI, + ULONG, + ULONG.ptr, // ulUIParam + LPSTR, // lpszDelimChar + LPSTR, // lpszFilePaths + LPSTR, // lpszFileNames + ULONG + ); // ulReserved + + functionData.SendMail = mapi.declare( + "MAPISendMail", + WINAPI, + ULONG, + LHANDLE, // lhSession + ULONG.ptr, // ulUIParam + lpMapiMessage, // lpMessage + FLAGS, // flFlags + ULONG + ); // ulReserved + + return functionData; +} diff --git a/comm/mailnews/mapi/test/unit/tail_mapi.js b/comm/mailnews/mapi/test/unit/tail_mapi.js new file mode 100644 index 0000000000..f64ae61317 --- /dev/null +++ b/comm/mailnews/mapi/test/unit/tail_mapi.js @@ -0,0 +1 @@ +load("../../../resources/mailShutdown.js"); diff --git a/comm/mailnews/mapi/test/unit/test_mapisendmail.js b/comm/mailnews/mapi/test/unit/test_mapisendmail.js new file mode 100644 index 0000000000..5dc480af9e --- /dev/null +++ b/comm/mailnews/mapi/test/unit/test_mapisendmail.js @@ -0,0 +1,97 @@ +/* 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/. */ + +var { ctypes } = ChromeUtils.importESModule( + "resource://gre/modules/ctypes.sys.mjs" +); +var { MimeParser } = ChromeUtils.import("resource:///modules/mimeParser.jsm"); +var { mailTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/MailTestUtils.jsm" +); + +// Set up an SMTP server and the MAPI daemon. +getBasicSmtpServer(); +let [daemon, server] = setupServerDaemon(); +server.start(SMTP_PORT); +let mapi = loadMAPILibrary(); + +registerCleanupFunction(() => { + server.stop(); +}); + +/** + * Construct a MapiMessage, then send through MAPI. + * + * @param {boolean} offline - Switch to offline mode if true. + */ +function testMapiSendMail(offline) { + Services.io.offline = offline; + + // Build a message using the MAPI interface. + let message = new mapi.MapiMessage(); + message.lpszSubject = ctypes.char.array()(`Hello, MAPI offline=${offline}!`); + message.lpszNoteText = ctypes.char.array()("I successfully sent a message!"); + message.lpszMessageType = ctypes.char.array()(""); + + let file = do_get_file("../../../compose/test/unit/data/message1.eml"); + let attachment = new mapi.MapiFileDesc(); + attachment.lpszFileName = ctypes.char.array()(file.leafName); + attachment.lpszPathName = ctypes.char.array()(file.path); + message.nFileCount = 1; + message.lpFiles = attachment.address(); + + let recipient = new mapi.MapiRecipDesc(); + recipient.ulRecipClass = 1; /* MAPI_TO */ + recipient.lpszName = ctypes.char.array()("John Doe"); + recipient.lpszAddress = ctypes.char.array()("SMTP:john.doe@example.com"); + message.nRecipCount = 1; + message.lpRecips = recipient.address(); + + // Use MAPISendMail to send this message. + mapi.SendMail( + null /* No session */, + null /* No HWND */, + message.address(), + 0x2 /* MAPI_NEW_SESSION */, + 0 + ); +} + +/** + * Test that when we're online, the message can be sent correctly to the SMTP + * server. + */ +add_task(function mapiSendMailOnline() { + server.resetTest(); + testMapiSendMail(false); + + // Check that the post has the correct information. + let [headers, body] = MimeParser.extractHeadersAndBody(daemon.post); + Assert.equal(headers.get("from")[0].email, "tinderbox@tinderbox.invalid"); + Assert.equal(headers.get("to")[0].email, "john.doe@example.com"); + Assert.equal(headers.get("subject"), "Hello, MAPI offline=false!"); + Assert.ok(body.includes("I successfully sent a message!")); + Assert.ok(body.includes("this email is in dos format")); +}); + +/** + * Test that when we're offline, the message can be saved correctly to the Outbox. + */ +add_task(function mapiSendMailOffline() { + server.resetTest(); + testMapiSendMail(true); + + let outbox = localAccountUtils.rootFolder.getChildNamed("Outbox"); + let msgData = mailTestUtils.loadMessageToString( + outbox, + mailTestUtils.firstMsgHdr(outbox) + ); + // Check that the post has the correct information. + let [headers, body] = MimeParser.extractHeadersAndBody(msgData); + Assert.equal(headers.get("from")[0].email, "tinderbox@tinderbox.invalid"); + Assert.equal(headers.get("to")[0].email, "john.doe@example.com"); + Assert.equal(headers.get("subject"), "Hello, MAPI offline=true!"); + Assert.ok(body.includes("I successfully sent a message!")); + Assert.ok(body.includes("this email is in dos format")); +}); diff --git a/comm/mailnews/mapi/test/unit/xpcshell.ini b/comm/mailnews/mapi/test/unit/xpcshell.ini new file mode 100644 index 0000000000..8d4fe504ab --- /dev/null +++ b/comm/mailnews/mapi/test/unit/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = head_mapi.js +tail = tail_mapi.js +run-sequentially = Need to use well-known port for SMTP. + +[test_mapisendmail.js] +skip-if = true # Not yet enabled, see bug 1526807. |