summaryrefslogtreecommitdiffstats
path: root/mailnews/jsaccount
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/jsaccount')
-rw-r--r--mailnews/jsaccount/modules/JSAccountUtils.jsm285
-rw-r--r--mailnews/jsaccount/modules/JaBaseUrl.jsm81
-rw-r--r--mailnews/jsaccount/moz.build15
-rw-r--r--mailnews/jsaccount/public/moz.build17
-rw-r--r--mailnews/jsaccount/public/msgIDelegateList.idl19
-rw-r--r--mailnews/jsaccount/public/msgIOverride.idl42
-rw-r--r--mailnews/jsaccount/public/msgJsAccountCID.h35
-rw-r--r--mailnews/jsaccount/readme.html56
-rw-r--r--mailnews/jsaccount/src/DelegateList.cpp33
-rw-r--r--mailnews/jsaccount/src/DelegateList.h52
-rw-r--r--mailnews/jsaccount/src/JaAbDirectory.cpp98
-rw-r--r--mailnews/jsaccount/src/JaAbDirectory.h89
-rw-r--r--mailnews/jsaccount/src/JaCompose.cpp103
-rw-r--r--mailnews/jsaccount/src/JaCompose.h92
-rw-r--r--mailnews/jsaccount/src/JaIncomingServer.cpp109
-rw-r--r--mailnews/jsaccount/src/JaIncomingServer.h94
-rw-r--r--mailnews/jsaccount/src/JaMsgFolder.cpp207
-rw-r--r--mailnews/jsaccount/src/JaMsgFolder.h126
-rw-r--r--mailnews/jsaccount/src/JaSend.cpp102
-rw-r--r--mailnews/jsaccount/src/JaSend.h96
-rw-r--r--mailnews/jsaccount/src/JaUrl.cpp230
-rw-r--r--mailnews/jsaccount/src/JaUrl.h121
-rw-r--r--mailnews/jsaccount/src/moz.build28
23 files changed, 2130 insertions, 0 deletions
diff --git a/mailnews/jsaccount/modules/JSAccountUtils.jsm b/mailnews/jsaccount/modules/JSAccountUtils.jsm
new file mode 100644
index 000000000..b5ce34682
--- /dev/null
+++ b/mailnews/jsaccount/modules/JSAccountUtils.jsm
@@ -0,0 +1,285 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* 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/. */
+
+/**
+ * This file implements helper methods to make the transition of base mailnews
+ * objects from JS to C++ easier, and also to allow creating specialized
+ * versions of those accounts using only JS XPCOM implementations.
+ *
+ * In C++ land, the XPCOM component is a generic C++ class that does nothing
+ * but delegate any calls to interfaces known in C++ to either the generic
+ * C++ implementation (such as nsMsgIncomingServer.cpp) or a JavaScript
+ * implementation of those methods. Those delegations could be used for either
+ * method-by-method replacement of the generic C++ methods with JavaScript
+ * versions, or for specialization of the generic class using JavaScript to
+ * implement a particular class type. We use a C++ class as the main XPCOM
+ * version for two related reasons: First, we do not want to go through a
+ * C++->js->C++ XPCOM transition just to execute a C++ method. Second, C++
+ * inheritance is different from JS inheritance, and sometimes the C++ code
+ * will ignore the XPCOM parts of the JS, and just execute using C++
+ * inheritance.
+ *
+ * In JavaScript land, the implementation currently uses the XPCOM object for
+ * JavaScript calls, with the last object in the prototype chain defaulting
+ * to calling using the CPP object, specified in an instance-specific
+ * this.cppBase object.
+ *
+ * Examples of use can be found in the test files for jsaccount stuff.
+ */
+
+const EXPORTED_SYMBOLS = ["JSAccountUtils"];
+var JSAccountUtils = {};
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+var Cr = Components.results;
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// Logger definitions.
+const LOGGER_NAME = "JsAccount";
+const PREF_BRANCH_LOG = "mailnews.jsaccount.log.";
+const PREF_LOG_LEVEL = PREF_BRANCH_LOG + "level";
+const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
+
+// Set default logging levels.
+const LOG_LEVEL_DEFAULT = "Info"
+const LOG_DUMP_DEFAULT = true;
+
+// Logging usage: set mailnews.jsaccount.log.level to the word "Debug" to
+// increase logging level.
+
+var log = configureLogging();
+
+/**
+ *
+ * Generic factory to create XPCOM components under JsAccount.
+ *
+ * @param aProperties This a a const JS object that describes the specific
+ * details of a particular JsAccount XPCOM object:
+ * {
+ * baseContractID: string contractID used to create the base generic C++
+ * object. This object must implement the interfaces in
+ * baseInterfaces, plus msgIOverride.
+ *
+ * baseInterfaces: JS array of interfaces implemented by the base, generic
+ * C++ object.
+ *
+ * extraInterfaces: JS array of additional interfaces implemented by the
+ * component (accessed using getInterface())
+ *
+ * contractID: string contract ID for the JS object that will be
+ * created by the factory.
+ *
+ * classID: Components.ID(CID) for the JS object that will be
+ * created by the factory, where CID is a string uuid.
+ * }
+ *
+ * @param aJsDelegateConstructor: a JS contructor class, called using new,
+ * that will create the JS object to which
+ * XPCOM methods calls will be delegated.
+ */
+
+JSAccountUtils.jaFactory = function (aProperties, aJsDelegateConstructor)
+{
+ let factory = {};
+ factory.QueryInterface = XPCOMUtils.generateQI([Ci.nsIFactory]);
+ factory.lockFactory = function() {};
+
+ factory.createInstance = function(outer, iid)
+ {
+ if (outer != null)
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+
+ // C++ delegator class.
+ let delegator = Cc[aProperties.baseContractID]
+ .createInstance(Ci.msgIOverride);
+
+ // Make sure the delegator JS wrapper knows its interfaces.
+ aProperties.baseInterfaces.forEach(iface => delegator instanceof iface);
+
+ // JavaScript overrides of base class functions.
+ let jsDelegate = new aJsDelegateConstructor(delegator, aProperties.baseInterfaces);
+ delegator.jsDelegate = jsDelegate;
+
+ // Get the delegate list for this current class. Use OwnProperty in case it
+ // inherits from another JsAccount class.
+
+ let delegateList = null;
+ if (Object.getPrototypeOf(jsDelegate).hasOwnProperty("delegateList")) {
+ delegateList = Object.getPrototypeOf(jsDelegate).delegateList;
+ }
+ if (delegateList instanceof Ci.msgIDelegateList) {
+ delegator.methodsToDelegate = delegateList;
+ } else {
+ // Lazily create and populate the list of methods to delegate.
+ log.info("creating delegate list for contractID " + aProperties.contractID);
+ let delegateList = delegator.methodsToDelegate;
+ Object.keys(delegator).forEach(name => {log.debug("delegator has key " + name);});
+
+ // jsMethods contains the methods that may be targets of the C++ delegation to JS.
+ let jsMethods = Object.getPrototypeOf(delegator.jsDelegate.wrappedJSObject);
+ for (let name in jsMethods)
+ {
+ log.debug("processing jsDelegate method: " + name);
+ if (name[0] == '_') { // don't bother with methods explicitly marked as internal.
+ log.debug("skipping " + name);
+ continue;
+ }
+ // Other methods to skip.
+ if (["QueryInterface", // nsISupports
+ "methodsToDelegate", "jsDelegate", "cppBase", // msgIOverride
+ "delegateList", "wrappedJSObject", // non-XPCOM methods to skip
+ ].includes(name)) {
+ log.debug("skipping " + name);
+ continue;
+ }
+
+ let jsDescriptor = getPropertyDescriptor(jsMethods, name);
+ if (!jsDescriptor) {
+ log.debug("no jsDescriptor for " + name);
+ continue;
+ }
+ let cppDescriptor = Object.getOwnPropertyDescriptor(delegator, name);
+ if (!cppDescriptor) {
+ log.debug("no cppDescriptor found for " + name);
+ // It is OK for jsMethods to have methods that are not used in override of C++.
+ continue;
+ }
+
+ let upperCaseName = name[0].toUpperCase() + name.substr(1);
+ if ('value' in jsDescriptor) {
+ log.info("delegating " + upperCaseName);
+ delegateList.add(upperCaseName);
+ }
+ else {
+ if (jsDescriptor.set) {
+ log.info("delegating Set" + upperCaseName);
+ delegateList.add("Set" + upperCaseName);
+ }
+ if (jsDescriptor.get) {
+ log.info("delegating Get" + upperCaseName);
+ delegateList.add("Get" + upperCaseName);
+ }
+ }
+ }
+
+ // Save the delegate list for reuse, statically for all instances.
+ Object.getPrototypeOf(jsDelegate).delegateList = delegateList;
+ }
+
+ for (let iface of aProperties.baseInterfaces)
+ if (iid.equals(iface)) {
+ log.debug("Successfully returning delegator " + delegator);
+ return delegator;
+ }
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ };
+
+ return factory;
+}
+
+/**
+ * Create a JS object that contains calls to each of the methods in a CPP
+ * base class, that will reference the cpp object defined on a particular
+ * instance of the object. This is intended to be the last item in the
+ * prototype chain for a JsAccount implementation.
+ *
+ * @param aProperties see definition in jsFactory above
+ *
+ * @returns a JS object suitable as the prototype of a JsAccount implementation.
+ */
+JSAccountUtils.makeCppDelegator = function(aProperties)
+{
+ log.info("Making cppDelegator for contractID " + aProperties.contractID);
+ let cppDelegator = {};
+ let cppDummy = Cc[aProperties.baseContractID].createInstance(Ci.nsISupports);
+ // Add methods from all interfaces.
+ for (let iface of aProperties.baseInterfaces)
+ cppDummy instanceof Ci[iface];
+
+ for (let method in cppDummy) {
+ // skip nsISupports and msgIOverride methods
+ if (["QueryInterface", "methodsToDelegate", "jsDelegate", "cppBase", "getInterface"].includes(method)) {
+ log.config("Skipping " + method + "\n");
+ continue;
+ }
+ log.config("processing " + method + "\n");
+ let descriptor = Object.getOwnPropertyDescriptor(cppDummy, method);
+ let property = { enumerable: true };
+ // We must use Immediately Invoked Function Expressions to pass method, otherwise it is
+ // a closure containing just the last value it was set to.
+ if ('value' in descriptor) {
+ log.debug("Adding value for " + method);
+ property.value = function(aMethod) {
+ return function(...args) {
+ return Reflect.apply(this.cppBase[aMethod], undefined, args);
+ };
+ }(method);
+ }
+ if (descriptor.set) {
+ log.debug("Adding setter for " + method);
+ property.set = function(aMethod) {
+ return function(aVal) {
+ this.cppBase[aMethod] = aVal;
+ };
+ }(method);
+ }
+ if (descriptor.get) {
+ log.debug("Adding getter for " + method);
+ property.get = function(aMethod) {
+ return function() {
+ return this.cppBase[aMethod];
+ };
+ }(method);
+ }
+ Object.defineProperty(cppDelegator, method, property);
+ }
+ return cppDelegator;
+}
+
+// Utility functions.
+
+// Iterate over an object and its prototypes to get a property descriptor.
+function getPropertyDescriptor(obj, name)
+{
+ let descriptor = null;
+
+ // Eventually we will hit an object that will delegate JS calls to a CPP
+ // object, which are not JS overrides of CPP methods. Locate this item, and
+ // skip, because it will not have _JsPrototypeToDelegate defined.
+ while (obj && ("_JsPrototypeToDelegate" in obj)) {
+ descriptor = Object.getOwnPropertyDescriptor(obj, name);
+ if (descriptor)
+ break;
+ obj = Object.getPrototypeOf(obj);
+ }
+ return descriptor;
+}
+
+// Configure the logger based on the preferences.
+function configureLogging()
+{
+ let log = Log.repository.getLogger(LOGGER_NAME);
+
+ // Log messages need to go to the browser console.
+ let consoleAppender = new Log.ConsoleAppender(new Log.BasicFormatter());
+ log.addAppender(consoleAppender);
+
+ // Make sure the logger keeps up with the logging level preference.
+ log.level = Log.Level[Preferences.get(PREF_LOG_LEVEL, LOG_LEVEL_DEFAULT)];
+
+ // If enabled in the preferences, add a dump appender.
+ let logDumping = Preferences.get(PREF_LOG_DUMP, LOG_DUMP_DEFAULT);
+ if (logDumping) {
+ let dumpAppender = new Log.DumpAppender(new Log.BasicFormatter());
+ log.addAppender(dumpAppender);
+ }
+ return log;
+}
diff --git a/mailnews/jsaccount/modules/JaBaseUrl.jsm b/mailnews/jsaccount/modules/JaBaseUrl.jsm
new file mode 100644
index 000000000..21a10847a
--- /dev/null
+++ b/mailnews/jsaccount/modules/JaBaseUrl.jsm
@@ -0,0 +1,81 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* 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/. */
+
+const EXPORTED_SYMBOLS = ["JaBaseUrlProperties", "JaBaseUrl"];
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/jsaccount/JSAccountUtils.jsm");
+
+// A partial JavaScript implementation of the base server methods.
+
+const JaBaseUrlProperties = {
+
+ // The CPP object that delgates to CPP or JS.
+ baseContractID: "@mozilla.org/jacppurldelegator;1",
+
+ // Interfaces implemented by the base CPP version of this object.
+ baseInterfaces: [ Ci.nsIURI,
+ Ci.nsIURL,
+ Ci.nsIMsgMailNewsUrl,
+ Ci.nsIMsgMessageUrl,
+ Ci.msgIOverride,
+ Ci.nsISupports,
+ Ci.nsIInterfaceRequestor,
+ ],
+
+ // We don't typically define this as a creatable component, but if we do use
+ // these. Subclasses for particular account types require these defined for
+ // that type.
+ contractID: "@mozilla.org/jsaccount/jaurl;1",
+ classID: Components.ID("{1E7B42CA-E6D9-408F-A4E4-8D2F82AECBBD}"),
+};
+
+function JaBaseUrl(aDelegator, aBaseInterfaces) {
+
+// Typical boilerplate to include in all implementations.
+
+ // Object delegating method calls to the appropriate XPCOM object.
+ // Weak because it owns us.
+ this._delegatorWeak = Cu.getWeakReference(aDelegator);
+
+ // Base implementation of methods with no overrides.
+ this.cppBase = aDelegator.cppBase;
+
+ // cppBase class sees all interfaces
+ aBaseInterfaces.forEach(iface => this.cppBase instanceof iface);
+}
+
+JaBaseUrl.prototype = {
+// Typical boilerplate to include in all implementations.
+ __proto__: JSAccountUtils.makeCppDelegator(JaBaseUrlProperties),
+
+ // Flag this item as CPP needs to delegate to JS.
+ _JsPrototypeToDelegate: true,
+
+ // QI to the interfaces.
+ QueryInterface: XPCOMUtils.generateQI(JaBaseUrlProperties.baseInterfaces),
+
+ // Used to access an instance as JS, bypassing XPCOM.
+ get wrappedJSObject() {
+ return this;
+ },
+
+ // Accessor to the weak cpp delegator.
+ get delegator() {
+ return this._delegatorWeak.get();
+ },
+
+ // Dynamically-generated list of delegate methods.
+ delegateList: null,
+
+ // Implementation in JS (if any) of methods in XPCOM interfaces.
+
+};
diff --git a/mailnews/jsaccount/moz.build b/mailnews/jsaccount/moz.build
new file mode 100644
index 000000000..6e080b863
--- /dev/null
+++ b/mailnews/jsaccount/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+DIRS += [
+ 'public',
+ 'src'
+]
+
+EXTRA_JS_MODULES.jsaccount += [
+ 'modules/JaBaseUrl.jsm',
+ 'modules/JSAccountUtils.jsm',
+]
diff --git a/mailnews/jsaccount/public/moz.build b/mailnews/jsaccount/public/moz.build
new file mode 100644
index 000000000..a635ffca9
--- /dev/null
+++ b/mailnews/jsaccount/public/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+XPIDL_SOURCES += [
+ 'msgIDelegateList.idl',
+ 'msgIOverride.idl',
+]
+
+EXPORTS += [
+ 'msgJsAccountCID.h',
+]
+
+XPIDL_MODULE = 'msgjsaccount'
+
diff --git a/mailnews/jsaccount/public/msgIDelegateList.idl b/mailnews/jsaccount/public/msgIDelegateList.idl
new file mode 100644
index 000000000..dce1b0bb6
--- /dev/null
+++ b/mailnews/jsaccount/public/msgIDelegateList.idl
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+/**
+ * This interface provides a list of methods that should be delegated to
+ * a JsObject rather than a C++ XPCOM base object in JsAccount classes.
+ */
+
+[scriptable, builtinclass, uuid(627D3A34-F8A3-40eb-91FE-E413D6638D27)]
+interface msgIDelegateList : nsISupports
+{
+ /// Method name to delegate to JavaScript.
+ void add(in string aMethod);
+};
diff --git a/mailnews/jsaccount/public/msgIOverride.idl b/mailnews/jsaccount/public/msgIOverride.idl
new file mode 100644
index 000000000..cad1bf415
--- /dev/null
+++ b/mailnews/jsaccount/public/msgIOverride.idl
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#include "nsISupports.idl"
+#include "msgIDelegateList.idl"
+
+/**
+ * Mailnews code typically has a C++ base class for objects, which is then
+ * specialized for each account type with a C++ subclass of the base class.
+ *
+ * This interface provides the ability of JavaScript-based account
+ * implementations to use the same C++ base classes as core objects, but
+ * use JavaScript to override methods instead of C++.
+ */
+
+[scriptable, uuid(68075269-8BBD-4a09-AC04-3241BF44F633)]
+interface msgIOverride : nsISupports
+{
+ /**
+ *
+ * A list of methods in the C++ base class that will be delegated to the JS
+ * delegate. This is calculated once, and then a fixed value is set to
+ * all subsequent instances so that it does not need to be recalculated each
+ * time. If the value has not yet been set, this will return a new instance.
+ */
+ attribute msgIDelegateList methodsToDelegate;
+
+ /**
+ * JavaScript-based xpcom object that overrides C++ methods.
+ */
+ attribute nsISupports jsDelegate;
+
+ /**
+ * C++ class used to implement default functionality. This is used when
+ * JavaScript methods want to call the base class default action, bypassing a
+ * possible JS override.
+ */
+ readonly attribute nsISupports cppBase;
+};
diff --git a/mailnews/jsaccount/public/msgJsAccountCID.h b/mailnews/jsaccount/public/msgJsAccountCID.h
new file mode 100644
index 000000000..330569312
--- /dev/null
+++ b/mailnews/jsaccount/public/msgJsAccountCID.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// Contains the definitions of contract IDs for modules in JsAccounts.
+
+#ifndef _msgJsAccountCID_H_
+#define _msgJsAccountCID_H_
+
+#define JACPPURLDELEGATOR_CID \
+{ 0x1a0b778c, 0x2fe6, 0x4012, { 0xb4, 0xf3, 0xe8, 0x1c, 0xc, 0x11, 0x64, 0x9 } }
+#define JACPPURLDELEGATOR_CONTRACTID "@mozilla.org/jacppurldelegator;1"
+
+#define JACPPABDIRECTORYDELEGATOR_CID \
+{ 0x77b5592c, 0x5018, 0x436d, { 0xa4, 0x66, 0xc4, 0xe5, 0x44, 0x3a, 0x16, 0x69 } }
+#define JACPPABDIRECTORYDELEGATOR_CONTRACTID "@mozilla.org/jacppabdirectorydelegator;1"
+
+#define JACPPINCOMINGSERVERDELEGATOR_CID \
+{ 0x7aa11dd3, 0x5590, 0x4e01, { 0xbd, 0x87, 0x91, 0xf6, 0x02, 0x72, 0xd0, 0x1a } }
+#define JACPPINCOMINGSERVERDELEGATOR_CONTRACTID "@mozilla.org/jacppincomingserverdelegator;1"
+
+#define JACPPCOMPOSEDELEGATOR_CID \
+{ 0xcfcd1caa, 0x00d9, 0x40d0, { 0x83, 0x1e, 0x67, 0x38, 0x20, 0xe0, 0x4f, 0xc6 } }
+#define JACPPCOMPOSEDELEGATOR_CONTRACTID "@mozilla.org/jacppcomposedelegator;1"
+
+#define JACPPMSGFOLDERDELEGATOR_CID \
+{ 0xd6bd81fa, 0xb1d4, 0x424a, { 0x88, 0xea, 0xbb, 0x3e, 0xa8, 0x38, 0x1d, 0x50 } }
+#define JACPPMSGFOLDERDELEGATOR_CONTRACTID "@mozilla.org/jacppmsgfolderdelegator;1"
+
+#define JACPPSENDDELEGATOR_CID \
+{ 0x36fcb887, 0x2b04, 0x42d4, { 0x92, 0xc9, 0xae, 0xd2, 0xac, 0xa1, 0xd4, 0x5b } }
+#define JACPPSENDDELEGATOR_CONTRACTID "@mozilla.org/jacppsenddelegator;1"
+#endif
diff --git a/mailnews/jsaccount/readme.html b/mailnews/jsaccount/readme.html
new file mode 100644
index 000000000..317b3c227
--- /dev/null
+++ b/mailnews/jsaccount/readme.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>JsAccount Usage and Architecture</title>
+ </head>
+ <body>
+ <h1>Overview</h1>
+ <p>JsAccount is a technology that allows message account types to be created
+ in Mozilla Mailnews code using JavaScript. Although this is primarily
+ targeted at allowing extensions to create new accounts, it might also be
+ useful as a bridge to convert existing account types from being C++ based
+ to JavaScript based.</p>
+ <h2>Existing C++-based architecture of mailnews accounts</h2>
+ <p>In mailnews code, an account type is a set of classes that allow
+ implementation of a messaging particular protocol. The account type is
+ given a short string identifier ("imap", "news", "pop3") and is then used
+ to create objects of the appropriate type by appending that string to the
+ end of a base XPCOM contractID. So, for example, to create an imap server,
+ you generate a contractID using a base ID,
+ NS_MSGINCOMINGSERVER_CONTRACTID_PREFIX
+ "@mozilla.org/messenger/server;1?type=", then append "imap" to get:</p>
+ <p>@mozilla.org/messenger/server;1?type=imap</p>
+ <p>In the C++ code, there is a base object implementing shared
+ functionality. An account-specific class inherits that base functionality,
+ then extends it to represent the account-specific behavior that is needed.
+ This same basic concept is used to represent a whole series of classes
+ that are necessary to implement a specific mailnews account type.</p>
+ <p>For the server example, there is a base class named
+ nsMsgIncomingServer.cpp that implements that base interface
+ nsIMsgIncomingServer.idl. For imap, there is a specific class
+ nsImapIncomingServer.cpp that inherits from nsMsgIncomingServer.cpp,
+ overrides some of the methods in nsIMsgIncomingServer.idl, and also
+ implements an imap-specific interface nsIImapIncomingServer.idl. All of
+ this works fine using C++ inheritance and polymorphism.</p>
+ <p>Although JsAccount is intended mostly for mailnews accounts, the same
+ basic method of using a base class extended for specific types is also used
+ in other ways in mailnews code, including for addressbook types and views.
+ The technology may also be applied to those other object types as well.</p>
+ <h2>Role of JsAccount</h2>
+ <p>The JavaScript class system works very differently than the C++ system,
+ and you cannot use normal language constructs to override a C++ class with
+ a JavaScript class. What JsAccount allows you to do is to create XPCOM
+ objects in JavaScript, and use those objects to override or extend the
+ methods from the C++ base class in a way that will function correctly
+ whether those objects are executed from within C++ code or JavaScript
+ code. This allows you to create a new account using JavaScript code, while
+ using the same base class functionality that is used by the core C++
+ account types. Thus a new account type may be created in JavaScript-based
+ extension. The technology may also be used to create JavaScript
+ versions of existing account types in an incremental manner, slowly
+ converting methods from C++ to JavaScript.</p>
+ <p><br>
+ </p>
+ </body>
+</html>
diff --git a/mailnews/jsaccount/src/DelegateList.cpp b/mailnews/jsaccount/src/DelegateList.cpp
new file mode 100644
index 000000000..7d2bae30c
--- /dev/null
+++ b/mailnews/jsaccount/src/DelegateList.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "DelegateList.h"
+
+// This class is used within JsAccount to allow static storage of a list
+// of methods to be overridden by JS implementations, in a way that can
+// be stored and manipulated in JS, but used efficiently in C++.
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS(DelegateList, msgIDelegateList)
+
+NS_IMETHODIMP DelegateList::Add(const char *aMethodName)
+{
+ // __FUNCTION__ is the undecorated function name in gcc, but decorated in
+ // Windows. __func__ will resolve this when supported in VS 2015.
+ nsCString prettyFunction;
+#if defined (_MSC_VER)
+ prettyFunction.Append(mPrefix);
+#endif
+ prettyFunction.Append(nsDependentCString(aMethodName));
+
+ mMethods.Put(prettyFunction, true);
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/DelegateList.h b/mailnews/jsaccount/src/DelegateList.h
new file mode 100644
index 000000000..943b3e726
--- /dev/null
+++ b/mailnews/jsaccount/src/DelegateList.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _DelegateList_H_
+#define _DelegateList_H_
+
+#include "nsISupports.h"
+#include "msgIDelegateList.h"
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+namespace mailnews {
+
+// This class provides a list of method names to delegate to another object.
+class DelegateList : public msgIDelegateList
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_MSGIDELEGATELIST
+ DelegateList(const char *aWindowsPrefix) :
+ mPrefix(aWindowsPrefix)
+ { }
+ nsDataHashtable<nsCStringHashKey, bool> mMethods;
+
+protected:
+ virtual ~DelegateList() { }
+ nsCString mPrefix; // Windows decorated method prefix.
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+/*
+ * This macro is used in forwarding functions.
+ * _interface: the interface being forwarded.
+ * _jsdelegate: the name of the JS pointer that implements a particular
+ * interface.
+ *
+ * You must follow the naming convention:
+ * 1) use mCppBase as the name of the C++ base class instance.
+ * 2) use mMethod as the name of the DelegateList object.
+ **/
+
+#define DELEGATE_JS(_interface, _jsdelegate) (\
+ _jsdelegate && mMethods && \
+ mMethods->Contains(nsLiteralCString(__FUNCTION__)) ? \
+ _jsdelegate : nsCOMPtr<_interface>(do_QueryInterface(mCppBase)))
+
+#endif
diff --git a/mailnews/jsaccount/src/JaAbDirectory.cpp b/mailnews/jsaccount/src/JaAbDirectory.cpp
new file mode 100644
index 000000000..7d9c16d78
--- /dev/null
+++ b/mailnews/jsaccount/src/JaAbDirectory.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaAbDirectory.h"
+#include "nsISupportsUtils.h"
+#include "nsIFile.h"
+#include "nsIMsgHdr.h"
+#include "nsIMessenger.h"
+#include "nsMsgBaseCID.h"
+#include "nsComponentManagerUtils.h"
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppAbDirectory, nsAbDirProperty,
+ nsIInterfaceRequestor)
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP JaBaseCppAbDirectory::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Delegator
+NS_IMPL_ISUPPORTS_INHERITED(JaCppAbDirectoryDelegator,
+ JaBaseCppAbDirectory,
+ msgIOverride)
+
+// Delegator object to bypass JS method override.
+NS_IMPL_ISUPPORTS(JaCppAbDirectoryDelegator::Super,
+ nsIAbDirectory,
+ nsIAbCollection,
+ nsIAbItem,
+ nsIInterfaceRequestor)
+
+JaCppAbDirectoryDelegator::JaCppAbDirectoryDelegator() :
+ mCppBase(new Super(this)),
+ mMethods(nullptr)
+{ }
+
+NS_IMETHODIMP JaCppAbDirectoryDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP JaCppAbDirectoryDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppAbDirectoryDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaCppAbDirectoryDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIAbDirectory = do_QueryInterface(aJsDelegate);
+ mJsIAbCollection = do_QueryInterface(aJsDelegate);
+ mJsIAbItem = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP JaCppAbDirectoryDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP JaCppAbDirectoryDelegator::GetCppBase(nsISupports** aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIAbDirectory*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaAbDirectory.h b/mailnews/jsaccount/src/JaAbDirectory.h
new file mode 100644
index 000000000..4ada7c761
--- /dev/null
+++ b/mailnews/jsaccount/src/JaAbDirectory.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaAbDirectory_H_
+#define _JaAbDirectory_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsAbDirProperty.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppAbDirectory : public nsAbDirProperty,
+ public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppAbDirectory() { }
+
+protected:
+ virtual ~JaBaseCppAbDirectory() { }
+
+};
+
+class JaCppAbDirectoryDelegator : public JaBaseCppAbDirectory,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ NS_FORWARD_NSIABDIRECTORY(DELEGATE_JS(nsIAbDirectory, mJsIAbDirectory)->)
+ NS_FORWARD_NSIABCOLLECTION(DELEGATE_JS(nsIAbCollection, mJsIAbCollection)->)
+ NS_FORWARD_NSIABITEM(DELEGATE_JS(nsIAbItem, mJsIAbItem)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppAbDirectoryDelegator();
+
+private:
+ virtual ~JaCppAbDirectoryDelegator() {
+ }
+
+ class Super : public nsIAbDirectory,
+ public nsIInterfaceRequestor
+ {
+ public:
+ Super(JaCppAbDirectoryDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_NSIABDIRECTORY(mFakeThis->JaBaseCppAbDirectory::)
+ NS_FORWARD_NSIABCOLLECTION(mFakeThis->JaBaseCppAbDirectory::)
+ NS_FORWARD_NSIABITEM(mFakeThis->JaBaseCppAbDirectory::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppAbDirectory::)
+ private:
+ virtual ~Super() {}
+ JaCppAbDirectoryDelegator* mFakeThis;
+ };
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIAbDirectory> mJsIAbDirectory;
+ nsCOMPtr<nsIAbCollection> mJsIAbCollection;
+ nsCOMPtr<nsIAbItem> mJsIAbItem;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ // Class to bypass JS delegates. nsCOMPtr for when we do cycle collection.
+ nsCOMPtr<nsIAbDirectory> mCppBase;
+
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/JaCompose.cpp b/mailnews/jsaccount/src/JaCompose.cpp
new file mode 100644
index 000000000..a6c1d59f3
--- /dev/null
+++ b/mailnews/jsaccount/src/JaCompose.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaCompose.h"
+#include "nsISupportsUtils.h"
+#include "nsComponentManagerUtils.h"
+
+// This file specifies the implementation of nsIMsgCompose.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppCompose,
+ nsMsgCompose,
+ nsIInterfaceRequestor)
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP
+JaBaseCppCompose::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Delegator object to bypass JS method override.
+
+JaCppComposeDelegator::JaCppComposeDelegator() {
+ mCppBase = do_QueryInterface(
+ NS_ISUPPORTS_CAST(nsIMsgCompose*, new Super(this)));
+ mMethods = nullptr;
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(JaCppComposeDelegator,
+ JaBaseCppCompose,
+ msgIOverride)
+
+NS_IMPL_ISUPPORTS(JaCppComposeDelegator::Super,
+ nsIMsgCompose,
+ nsIMsgSendListener,
+ nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+JaCppComposeDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppComposeDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppComposeDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+JaCppComposeDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIMsgCompose = do_QueryInterface(aJsDelegate);
+ mJsIMsgSendListener = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppComposeDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP
+JaCppComposeDelegator::GetCppBase(nsISupports** aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgCompose*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaCompose.h b/mailnews/jsaccount/src/JaCompose.h
new file mode 100644
index 000000000..b81adda5c
--- /dev/null
+++ b/mailnews/jsaccount/src/JaCompose.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaCompose_H_
+#define _JaCompose_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsMsgCompose.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+
+// This file specifies the definition of nsIMsgCompose.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppCompose : public nsMsgCompose,
+ public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppCompose() { }
+
+protected:
+ virtual ~JaBaseCppCompose() { }
+
+};
+
+class JaCppComposeDelegator : public JaBaseCppCompose,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ NS_FORWARD_NSIMSGCOMPOSE(DELEGATE_JS(nsIMsgCompose, mJsIMsgCompose)->)
+ NS_FORWARD_NSIMSGSENDLISTENER(DELEGATE_JS(nsIMsgSendListener, mJsIMsgSendListener)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppComposeDelegator();
+
+private:
+ virtual ~JaCppComposeDelegator() {
+ }
+
+ // This class will call a method on the delegator, but force the use of the
+ // C++ cppBase class, bypassing any JS Delegate.
+ class Super : public nsIMsgCompose,
+ public nsIInterfaceRequestor
+ {
+ public:
+ Super(JaCppComposeDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ // Forward all overridable methods, bypassing JS override.
+ NS_FORWARD_NSIMSGCOMPOSE(mFakeThis->JaBaseCppCompose::)
+ NS_FORWARD_NSIMSGSENDLISTENER(mFakeThis->JaBaseCppCompose::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppCompose::)
+ private:
+ virtual ~Super() {};
+ JaCppComposeDelegator* mFakeThis;
+ };
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIMsgCompose> mJsIMsgCompose;
+ nsCOMPtr<nsIMsgSendListener> mJsIMsgSendListener;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ // Class to bypass JS delegates.
+ nsCOMPtr<nsIMsgCompose> mCppBase;
+
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/JaIncomingServer.cpp b/mailnews/jsaccount/src/JaIncomingServer.cpp
new file mode 100644
index 000000000..74296ac06
--- /dev/null
+++ b/mailnews/jsaccount/src/JaIncomingServer.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaIncomingServer.h"
+#include "nsISupportsUtils.h"
+#include "nsComponentManagerUtils.h"
+
+// This file specifies the implementation of nsIMsgIncomingServer.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppIncomingServer,
+ nsMsgIncomingServer,
+ nsIInterfaceRequestor)
+
+// nsMsgIncomingServer overrides
+nsresult
+JaBaseCppIncomingServer::CreateRootFolderFromUri(const nsCString &serverUri,
+ nsIMsgFolder **rootFolder)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP
+JaBaseCppIncomingServer::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Delegator object to bypass JS method override.
+
+JaCppIncomingServerDelegator::JaCppIncomingServerDelegator() {
+ mCppBase = do_QueryInterface(
+ NS_ISUPPORTS_CAST(nsIMsgIncomingServer*, new Super(this)));
+ mMethods = nullptr;
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(JaCppIncomingServerDelegator,
+ JaBaseCppIncomingServer,
+ msgIOverride)
+
+NS_IMPL_ISUPPORTS(JaCppIncomingServerDelegator::Super,
+ nsIMsgIncomingServer,
+ nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+JaCppIncomingServerDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppIncomingServerDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppIncomingServerDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+JaCppIncomingServerDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIMsgIncomingServer = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppIncomingServerDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP
+JaCppIncomingServerDelegator::GetCppBase(nsISupports** aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgIncomingServer*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaIncomingServer.h b/mailnews/jsaccount/src/JaIncomingServer.h
new file mode 100644
index 000000000..5b0362324
--- /dev/null
+++ b/mailnews/jsaccount/src/JaIncomingServer.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaIncomingServer_H_
+#define _JaIncomingServer_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsMsgIncomingServer.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+
+// This file specifies the definition of nsIMsgIncomingServer.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppIncomingServer : public nsMsgIncomingServer,
+ public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppIncomingServer() { }
+
+ // nsMsgIncomingServer overrides
+ nsresult CreateRootFolderFromUri(const nsCString &serverUri,
+ nsIMsgFolder **rootFolder) override;
+
+protected:
+ virtual ~JaBaseCppIncomingServer() { }
+
+};
+
+class JaCppIncomingServerDelegator : public JaBaseCppIncomingServer,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ NS_FORWARD_NSIMSGINCOMINGSERVER(DELEGATE_JS(nsIMsgIncomingServer, mJsIMsgIncomingServer)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppIncomingServerDelegator();
+
+private:
+ virtual ~JaCppIncomingServerDelegator() {
+ }
+
+ // This class will call a method on the delegator, but force the use of the
+ // C++ parent class, bypassing any JS Delegate.
+ class Super : public nsIMsgIncomingServer,
+ public nsIInterfaceRequestor
+ {
+ public:
+ Super(JaCppIncomingServerDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ // Forward all overridable methods, bypassing JS override.
+ NS_FORWARD_NSIMSGINCOMINGSERVER(mFakeThis->JaBaseCppIncomingServer::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppIncomingServer::)
+ private:
+ virtual ~Super() {};
+ JaCppIncomingServerDelegator* mFakeThis;
+ };
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIMsgIncomingServer> mJsIMsgIncomingServer;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ // Class to bypass JS delegates.
+ nsCOMPtr<nsIMsgIncomingServer> mCppBase;
+
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/JaMsgFolder.cpp b/mailnews/jsaccount/src/JaMsgFolder.cpp
new file mode 100644
index 000000000..e51528e11
--- /dev/null
+++ b/mailnews/jsaccount/src/JaMsgFolder.cpp
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaMsgFolder.h"
+#include "nsISupportsUtils.h"
+#include "nsMsgBaseCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIUUIDGenerator.h"
+#include "nsIComponentRegistrar.h"
+#include "nsMsgDBCID.h"
+
+#define MAILDATABASE_CONTRACTID_BASE "@mozilla.org/nsMsgDatabase/msgDB-"
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppMsgFolder, nsMsgDBFolder,
+ nsIInterfaceRequestor)
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP
+JaBaseCppMsgFolder::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Definition of abstract nsMsgDBFolder methods.
+nsresult
+JaBaseCppMsgFolder::GetDatabase()
+{
+ nsresult rv = NS_OK;
+ if (!mDatabase)
+ {
+
+ nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Create the database, keeping it if it is "out of date"
+ rv = msgDBService->OpenFolderDB(this, true, getter_AddRefs(mDatabase));
+ if (rv == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
+ {
+ rv = msgDBService->CreateNewDB(this, getter_AddRefs(mDatabase));
+ NS_ENSURE_STATE(mDatabase);
+ // not sure about this ... the issue is that if the summary is not valid, then
+ // the db does not get added to the cache in the future, and reindexes
+ // do not show all of the messages.
+ //mDatabase->SetSummaryValid(true);
+ mDatabase->SetSummaryValid(false);
+ CreateDummyFile(this);
+ }
+
+ if (rv != NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE)
+ NS_ENSURE_SUCCESS(rv, rv);
+ else if (mDatabase)
+ {
+ // Not going to warn here, because on initialization we set all
+ // databases as invalid.
+ //NS_WARNING("Mail Summary database is out of date");
+ // Grrr, the only way to get this into the cache is to set the db as valid,
+ // close, reopen, then set as invalid.
+ mDatabase->SetSummaryValid(true);
+ msgDBService->ForceFolderDBClosed(this);
+ rv = msgDBService->OpenFolderDB(this, true, getter_AddRefs(mDatabase));
+ if (mDatabase)
+ mDatabase->SetSummaryValid(false);
+ }
+
+ if (mDatabase)
+ {
+ //
+ // When I inadvertently deleted the out-of-date database, I hit this code with
+ // the db's m_dbFolderInfo as null from the delete, yet the local mDatabase
+ // reference kept the database alive. So I hit an assert when I tried to open
+ // the database. Be careful if you try to fix the out-of-date issues!
+ //
+ //UpdateNewMessages();
+ if(mAddListener)
+ mDatabase->AddListener(this);
+ // UpdateSummaryTotals can null mDatabase during initialization, so we save a local copy
+ nsCOMPtr<nsIMsgDatabase> database(mDatabase);
+ UpdateSummaryTotals(true);
+ mDatabase = database;
+
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * The utility function GetSummaryFileLocation takes a folder file,
+ * then appends .msf to come up with the name of the database file. So
+ * we need a placeholder file with simply the folder name. This method
+ * creates an appropriate file as a placeholder, or you may use the file if
+ * appropriate.
+ */
+nsresult
+JaBaseCppMsgFolder::CreateDummyFile(nsIMsgFolder* aMailFolder)
+{
+ nsresult rv;
+ if (!aMailFolder)
+ return NS_OK;
+ nsCOMPtr <nsIFile> path;
+ // need to make sure folder exists...
+ aMailFolder->GetFilePath(getter_AddRefs(path));
+ if (path)
+ {
+ bool exists;
+ rv = path->Exists(&exists);
+ if (!exists)
+ {
+ rv = path->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+ return NS_OK;
+}
+
+// AFAICT this is unused in mailnews code.
+nsresult
+JaBaseCppMsgFolder::CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// Delegator object to bypass JS method override.
+
+JaCppMsgFolderDelegator::JaCppMsgFolderDelegator() :
+ mCppBase(new Super(this)),
+ mMethods(nullptr)
+{ }
+
+NS_IMPL_ISUPPORTS_INHERITED(JaCppMsgFolderDelegator, JaBaseCppMsgFolder,
+ msgIOverride)
+
+NS_IMPL_ISUPPORTS(JaCppMsgFolderDelegator::Super,
+ nsIMsgFolder,
+ nsIRDFResource,
+ nsIRDFNode,
+ nsIDBChangeListener,
+ nsIUrlListener,
+ nsIJunkMailClassificationListener,
+ nsIMsgTraitClassificationListener,
+ nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+JaCppMsgFolderDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppMsgFolderDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppMsgFolderDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaCppMsgFolderDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIMsgFolder = do_QueryInterface(aJsDelegate);
+ mJsIDBChangeListener = do_QueryInterface(aJsDelegate);
+ mJsIUrlListener = do_QueryInterface(aJsDelegate);
+ mJsIJunkMailClassificationListener = do_QueryInterface(aJsDelegate);
+ mJsIMsgTraitClassificationListener = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP JaCppMsgFolderDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP JaCppMsgFolderDelegator::GetCppBase(nsISupports** aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgFolder*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaMsgFolder.h b/mailnews/jsaccount/src/JaMsgFolder.h
new file mode 100644
index 000000000..514d6e07f
--- /dev/null
+++ b/mailnews/jsaccount/src/JaMsgFolder.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaMsgFolder_H_
+#define _JaMsgFolder_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsMsgDBFolder.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsWeakReference.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppMsgFolder : public nsMsgDBFolder,
+ public nsIInterfaceRequestor
+
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppMsgFolder() { }
+
+ // nsMsgDBFolder overrides
+
+ nsresult CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder) override;
+ nsresult GetDatabase() override;
+
+ // Local Utility Functions
+
+ // Create a placeholder file to represent a folder.
+ nsresult CreateDummyFile(nsIMsgFolder* aMailFolder);
+
+protected:
+ virtual ~JaBaseCppMsgFolder() { }
+
+};
+
+class JaCppMsgFolderDelegator : public JaBaseCppMsgFolder,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ // Note that we do not support override of RDF methods.
+ NS_FORWARD_NSIRDFRESOURCE(JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIRDFNODE(JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIMSGFOLDER(DELEGATE_JS(nsIMsgFolder, mJsIMsgFolder)->)
+ NS_FORWARD_NSIDBCHANGELISTENER(
+ DELEGATE_JS(nsIDBChangeListener, mJsIDBChangeListener)->)
+ NS_FORWARD_NSIURLLISTENER(DELEGATE_JS(nsIUrlListener, mJsIUrlListener)->)
+ NS_FORWARD_NSIJUNKMAILCLASSIFICATIONLISTENER(
+ DELEGATE_JS(nsIJunkMailClassificationListener,
+ mJsIJunkMailClassificationListener)->)
+ NS_FORWARD_NSIMSGTRAITCLASSIFICATIONLISTENER(
+ DELEGATE_JS(nsIMsgTraitClassificationListener,
+ mJsIMsgTraitClassificationListener)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(
+ DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppMsgFolderDelegator();
+
+private:
+ virtual ~JaCppMsgFolderDelegator() {
+ }
+
+ class Super : public nsIMsgFolder,
+ public nsIRDFResource,
+ public nsIDBChangeListener,
+ public nsIUrlListener,
+ public nsIJunkMailClassificationListener,
+ public nsIMsgTraitClassificationListener,
+ public nsIInterfaceRequestor
+ {
+ public:
+ // Why fake this? Because this method is fully owned by
+ // JaCppMsgFolderDelegator, and this reference is to the "this" of the
+ // main method. But it is not really the local "this".
+ Super(JaCppMsgFolderDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_NSIMSGFOLDER(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIRDFRESOURCE(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIRDFNODE(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIDBCHANGELISTENER(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIURLLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIJUNKMAILCLASSIFICATIONLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIMSGTRAITCLASSIFICATIONLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppMsgFolder::)
+ private:
+ virtual ~Super() {}
+ JaCppMsgFolderDelegator* mFakeThis;
+ };
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIMsgFolder> mJsIMsgFolder;
+ nsCOMPtr<nsIDBChangeListener> mJsIDBChangeListener;
+ nsCOMPtr<nsIUrlListener> mJsIUrlListener;
+ nsCOMPtr<nsIJunkMailClassificationListener> mJsIJunkMailClassificationListener;
+ nsCOMPtr<nsIMsgTraitClassificationListener> mJsIMsgTraitClassificationListener;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ nsCOMPtr<nsIMsgFolder> mCppBase;
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/JaSend.cpp b/mailnews/jsaccount/src/JaSend.cpp
new file mode 100644
index 000000000..5a473d2f8
--- /dev/null
+++ b/mailnews/jsaccount/src/JaSend.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaSend.h"
+#include "nsISupportsUtils.h"
+#include "nsComponentManagerUtils.h"
+
+// This file specifies the implementation of nsIMsgSend.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppSend,
+ nsMsgComposeAndSend,
+ nsIInterfaceRequestor)
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP
+JaBaseCppSend::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Delegator object to bypass JS method override.
+
+JaCppSendDelegator::JaCppSendDelegator() {
+ mCppBase = do_QueryInterface(
+ NS_ISUPPORTS_CAST(nsIMsgSend*, new Super(this)));
+ mMethods = nullptr;
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(JaCppSendDelegator,
+ JaBaseCppSend,
+ msgIOverride)
+
+NS_IMPL_ISUPPORTS(JaCppSendDelegator::Super,
+ nsIMsgSend,
+ nsIMsgOperationListener,
+ nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+JaCppSendDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppSendDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppSendDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+JaCppSendDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIMsgSend = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP
+JaCppSendDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP
+JaCppSendDelegator::GetCppBase(nsISupports** aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgSend*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaSend.h b/mailnews/jsaccount/src/JaSend.h
new file mode 100644
index 000000000..c4d8ac3b8
--- /dev/null
+++ b/mailnews/jsaccount/src/JaSend.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaSend_H_
+#define _JaSend_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsMsgSend.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+
+// This file specifies the definition of nsIMsgSend.idl objects
+// in the JsAccount system.
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppSend : public nsMsgComposeAndSend,
+ public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppSend() { }
+
+protected:
+ virtual ~JaBaseCppSend() { }
+
+};
+
+class JaCppSendDelegator : public JaBaseCppSend,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ NS_FORWARD_NSIMSGSEND(DELEGATE_JS(nsIMsgSend, mJsIMsgSend)->)
+ NS_FORWARD_NSIMSGOPERATIONLISTENER(
+ DELEGATE_JS(nsIMsgOperationListener, mJsIMsgOperationListener)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(
+ DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppSendDelegator();
+
+private:
+ virtual ~JaCppSendDelegator() {
+ }
+
+ // This class will call a method on the delegator, but force the use of the
+ // C++ parent class, bypassing any JS Delegate.
+ class Super : public nsIMsgSend,
+ public nsIMsgOperationListener,
+ public nsIInterfaceRequestor
+ {
+ public:
+ Super(JaCppSendDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ // Forward all overridable methods, bypassing JS override.
+ NS_FORWARD_NSIMSGSEND(mFakeThis->JaBaseCppSend::)
+ NS_FORWARD_NSIMSGOPERATIONLISTENER(mFakeThis->JaBaseCppSend::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppSend::)
+ private:
+ virtual ~Super() {};
+ JaCppSendDelegator* mFakeThis;
+ };
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIMsgSend> mJsIMsgSend;
+ nsCOMPtr<nsIMsgOperationListener> mJsIMsgOperationListener;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ // Class to bypass JS delegates.
+ nsCOMPtr<nsIMsgSend> mCppBase;
+
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/JaUrl.cpp b/mailnews/jsaccount/src/JaUrl.cpp
new file mode 100644
index 000000000..70b19329c
--- /dev/null
+++ b/mailnews/jsaccount/src/JaUrl.cpp
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "JaUrl.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIFile.h"
+#include "nsIMessenger.h"
+#include "nsIMsgHdr.h"
+#include "nsISupportsUtils.h"
+#include "nsMsgBaseCID.h"
+#include "nsMsgUtils.h"
+
+// This file contains an implementation of mailnews URLs in JsAccount.
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppUrl, nsMsgMailNewsUrl,
+ nsIMsgMessageUrl,
+ nsIInterfaceRequestor,
+ nsISupportsWeakReference)
+
+// nsIMsgMailNewsUrl overrides
+NS_IMETHODIMP JaBaseCppUrl::GetFolder(nsIMsgFolder **aFolder)
+{
+ NS_ENSURE_ARG_POINTER(aFolder);
+ NS_IF_ADDREF(*aFolder = mFolder);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::SetFolder(nsIMsgFolder *aFolder)
+{
+ mFolder = aFolder;
+ return NS_OK;
+}
+
+// nsIMsgMessageUrl implementation
+NS_IMETHODIMP JaBaseCppUrl::GetUri(char **aUri)
+{
+ if (!mUri.IsEmpty())
+ *aUri = ToNewCString(mUri);
+ else
+ return NS_ERROR_NOT_INITIALIZED;
+ return NS_OK;
+}
+NS_IMETHODIMP JaBaseCppUrl::SetUri(const char *aUri)
+{
+ mUri = aUri;
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetMessageFile(nsIFile **aMessageFile)
+{
+ NS_ENSURE_ARG_POINTER(aMessageFile);
+ NS_IF_ADDREF(*aMessageFile = mMessageFile);
+ return NS_OK;
+}
+NS_IMETHODIMP JaBaseCppUrl::SetMessageFile(nsIFile *aMessageFile)
+{
+ mMessageFile = aMessageFile;
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetAddDummyEnvelope(bool *aAddDummyEnvelope)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP JaBaseCppUrl::SetAddDummyEnvelope(bool aAddDummyEnvelope)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetCanonicalLineEnding(bool *aCanonicalLineEnding)
+{
+ NS_ENSURE_ARG_POINTER(aCanonicalLineEnding);
+ *aCanonicalLineEnding = mCanonicalLineEnding;
+ return NS_OK;
+}
+NS_IMETHODIMP JaBaseCppUrl::SetCanonicalLineEnding(bool aCanonicalLineEnding)
+{
+ mCanonicalLineEnding = aCanonicalLineEnding;
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetOriginalSpec(char **aOriginalSpec)
+{
+ if (!aOriginalSpec || mOriginalSpec.IsEmpty())
+ return NS_ERROR_NULL_POINTER;
+ *aOriginalSpec = ToNewCString(mOriginalSpec);
+ return NS_OK;
+}
+NS_IMETHODIMP JaBaseCppUrl::SetOriginalSpec(const char *aOriginalSpec)
+{
+ mOriginalSpec = aOriginalSpec;
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetPrincipalSpec(nsACString& aPrincipalSpec)
+{
+ // URLs contain a lot of query parts. We want need a normalised form:
+ // scheme://server/folder?number=123
+ nsCOMPtr<nsIMsgMailNewsUrl> mailnewsURL;
+ QueryInterface(NS_GET_IID(nsIMsgMailNewsUrl), getter_AddRefs(mailnewsURL));
+
+ nsAutoCString spec;
+ mailnewsURL->GetSpecIgnoringRef(spec);
+
+ nsAutoCString queryPart = MsgExtractQueryPart(spec, "number=");
+
+ // Strip any query part beginning with ? or /;
+ int32_t ind = spec.Find("/;");
+ if (ind != kNotFound)
+ spec.SetLength(ind);
+
+ ind = spec.FindChar('?');
+ if (ind != kNotFound)
+ spec.SetLength(ind);
+
+ if (!queryPart.IsEmpty())
+ spec += NS_LITERAL_CSTRING("?") + queryPart;
+
+ aPrincipalSpec.Assign(spec);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::GetMessageHeader(nsIMsgDBHdr **aMessageHeader)
+{
+ // This routine does a lookup using messenger, assumming that the message URI
+ // has been set in mUri.
+ NS_ENSURE_TRUE(!mUri.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
+ nsresult rv;
+ nsCOMPtr<nsIMessenger> messenger(do_CreateInstance(NS_MESSENGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIMsgDBHdr> msgHdr;
+ rv = messenger->MsgHdrFromURI(mUri, getter_AddRefs(msgHdr));
+ NS_ENSURE_SUCCESS(rv, rv);
+ msgHdr.forget(aMessageHeader);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaBaseCppUrl::SetMessageHeader(nsIMsgDBHdr *aMsgHdr)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP JaBaseCppUrl::GetInterface(const nsIID & aIID, void **aSink)
+{
+ return QueryInterface(aIID, aSink);
+}
+
+// Delegator
+NS_IMPL_ISUPPORTS_INHERITED(JaCppUrlDelegator,
+ JaBaseCppUrl,
+ msgIOverride)
+
+// Delegator object to bypass JS method override.
+NS_IMPL_ISUPPORTS(JaCppUrlDelegator::Super,
+ nsIMsgMailNewsUrl,
+ nsIMsgMessageUrl,
+ nsIURI,
+ nsIURIWithQuery,
+ nsIURL,
+ nsIInterfaceRequestor)
+
+JaCppUrlDelegator::JaCppUrlDelegator() :
+ mCppBase(new Super(this)),
+ mMethods(nullptr)
+{ }
+
+NS_IMETHODIMP JaCppUrlDelegator::SetMethodsToDelegate(msgIDelegateList *aDelegateList)
+{
+ if (!aDelegateList)
+ {
+ NS_WARNING("Null delegate list");
+ return NS_ERROR_NULL_POINTER;
+ }
+ // We static_cast since we want to use the hash object directly.
+ mDelegateList = static_cast<DelegateList*> (aDelegateList);
+ mMethods = &(mDelegateList->mMethods);
+ return NS_OK;
+}
+NS_IMETHODIMP JaCppUrlDelegator::GetMethodsToDelegate(msgIDelegateList **aDelegateList)
+{
+ if (!mDelegateList)
+ mDelegateList = new DelegateList("mozilla::mailnews::JaCppUrlDelegator::");
+ mMethods = &(mDelegateList->mMethods);
+ NS_ADDREF(*aDelegateList = mDelegateList);
+ return NS_OK;
+}
+
+NS_IMETHODIMP JaCppUrlDelegator::SetJsDelegate(nsISupports *aJsDelegate)
+{
+ // If these QIs fail, then overrides are not provided for methods in that
+ // interface, which is OK.
+ mJsISupports = aJsDelegate;
+ mJsIMsgMailNewsUrl = do_QueryInterface(aJsDelegate);
+ mJsIURI = do_QueryInterface(aJsDelegate);
+ mJsIURIWithQuery = do_QueryInterface(aJsDelegate);
+ mJsIURL = do_QueryInterface(aJsDelegate);
+ mJsIMsgMessageUrl = do_QueryInterface(aJsDelegate);
+ mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+ return NS_OK;
+}
+NS_IMETHODIMP JaCppUrlDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+ NS_ENSURE_ARG_POINTER(aJsDelegate);
+ if (mJsISupports)
+ {
+ NS_ADDREF(*aJsDelegate = mJsISupports);
+ return NS_OK;
+ }
+ return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP JaCppUrlDelegator::GetCppBase(nsISupports **aCppBase)
+{
+ nsCOMPtr<nsISupports> cppBaseSupports;
+ cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgMailNewsUrl*, mCppBase);
+ NS_ENSURE_STATE(cppBaseSupports);
+ cppBaseSupports.forget(aCppBase);
+
+ return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
diff --git a/mailnews/jsaccount/src/JaUrl.h b/mailnews/jsaccount/src/JaUrl.h
new file mode 100644
index 000000000..57c902eee
--- /dev/null
+++ b/mailnews/jsaccount/src/JaUrl.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef _JaUrl_H_
+#define _JaUrl_H_
+
+#include "DelegateList.h"
+#include "msgCore.h"
+#include "msgIOverride.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDataHashtable.h"
+#include "nsIFile.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIMsgFolder.h"
+#include "nsISupports.h"
+#include "nsMsgMailNewsUrl.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppUrl : public nsMsgMailNewsUrl,
+ public nsIMsgMessageUrl,
+ public nsIInterfaceRequestor,
+ public nsSupportsWeakReference
+
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIMSGMESSAGEURL
+ NS_DECL_NSIINTERFACEREQUESTOR
+ JaBaseCppUrl() { }
+
+ // nsIMsgMailNewsUrl overrides
+ NS_IMETHOD GetFolder(nsIMsgFolder **aFolder) override;
+ NS_IMETHOD SetFolder(nsIMsgFolder *aFolder) override;
+
+protected:
+ virtual ~JaBaseCppUrl() { }
+
+ // nsIMsgMailUrl variables.
+
+ nsCOMPtr<nsIMsgFolder> mFolder;
+
+ // nsIMsgMessageUrl variables.
+
+ // the uri for the original message, like ews-message://server/folder#123
+ nsCString mUri;
+ nsCOMPtr<nsIFile> mMessageFile;
+ bool mCanonicalLineEnding;
+ nsCString mOriginalSpec;
+};
+
+class JaCppUrlDelegator : public JaBaseCppUrl,
+ public msgIOverride
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MSGIOVERRIDE
+
+ NS_FORWARD_NSIMSGMAILNEWSURL(DELEGATE_JS(nsIMsgMailNewsUrl, mJsIMsgMailNewsUrl)->)
+ NS_FORWARD_NSIURI(DELEGATE_JS(nsIURI, mJsIURI)->)
+ NS_FORWARD_NSIURIWITHQUERY(DELEGATE_JS(nsIURIWithQuery, mJsIURIWithQuery)->)
+ NS_FORWARD_NSIURL(DELEGATE_JS(nsIURL, mJsIURL)->)
+ NS_FORWARD_NSIMSGMESSAGEURL(DELEGATE_JS(nsIMsgMessageUrl, mJsIMsgMessageUrl)->)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+ JaCppUrlDelegator();
+
+ class Super : public nsIMsgMailNewsUrl,
+ public nsIMsgMessageUrl,
+ public nsIInterfaceRequestor
+ {
+ public:
+ Super(JaCppUrlDelegator *aFakeThis) {mFakeThis = aFakeThis;}
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_NSIMSGMAILNEWSURL(mFakeThis->JaBaseCppUrl::)
+ NS_FORWARD_NSIURI(mFakeThis->JaBaseCppUrl::)
+ NS_FORWARD_NSIURIWITHQUERY(mFakeThis->JaBaseCppUrl::)
+ NS_FORWARD_NSIURL(mFakeThis->JaBaseCppUrl::)
+ NS_FORWARD_NSIMSGMESSAGEURL(mFakeThis->JaBaseCppUrl::)
+ NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppUrl::)
+ private:
+ virtual ~Super() {}
+ JaCppUrlDelegator *mFakeThis;
+ };
+
+private:
+ virtual ~JaCppUrlDelegator() {
+ }
+
+ // Interfaces that may be overridden by JS.
+ nsCOMPtr<nsIMsgMailNewsUrl> mJsIMsgMailNewsUrl;
+ nsCOMPtr<nsIURI> mJsIURI;
+ nsCOMPtr<nsIURIWithQuery> mJsIURIWithQuery;
+ nsCOMPtr<nsIURL> mJsIURL;
+ nsCOMPtr<nsIMsgMessageUrl> mJsIMsgMessageUrl;
+ nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+ // Owning reference to the JS override.
+ nsCOMPtr<nsISupports> mJsISupports;
+
+ // Class to bypass JS delegates. nsCOMPtr for when we do cycle collection.
+ nsCOMPtr<nsIMsgMailNewsUrl> mCppBase;
+
+ RefPtr<DelegateList> mDelegateList;
+ nsDataHashtable<nsCStringHashKey, bool> *mMethods;
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
diff --git a/mailnews/jsaccount/src/moz.build b/mailnews/jsaccount/src/moz.build
new file mode 100644
index 000000000..761bb04ca
--- /dev/null
+++ b/mailnews/jsaccount/src/moz.build
@@ -0,0 +1,28 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+SOURCES += [
+ 'DelegateList.cpp',
+ 'JaAbDirectory.cpp',
+ 'JaCompose.cpp',
+ 'JaIncomingServer.cpp',
+ 'JaMsgFolder.cpp',
+ 'JaSend.cpp',
+ 'JaUrl.cpp',
+]
+
+EXPORTS += [
+ 'DelegateList.h',
+ 'JaAbDirectory.h',
+ 'JaCompose.h',
+ 'JaIncomingServer.h',
+ 'JaMsgFolder.h',
+ 'JaSend.h',
+ 'JaUrl.h',
+]
+
+Library('JsAccount')
+FINAL_LIBRARY = 'mail'