From 302bf1b523012e11b60425d6eee1221ebc2724eb Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 3 Nov 2019 00:17:46 -0400 Subject: Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1 --- mailnews/jsaccount/modules/JSAccountUtils.jsm | 285 +++++++++++++++++++++++++ mailnews/jsaccount/modules/JaBaseUrl.jsm | 81 +++++++ mailnews/jsaccount/moz.build | 15 ++ mailnews/jsaccount/public/moz.build | 17 ++ mailnews/jsaccount/public/msgIDelegateList.idl | 19 ++ mailnews/jsaccount/public/msgIOverride.idl | 42 ++++ mailnews/jsaccount/public/msgJsAccountCID.h | 35 +++ mailnews/jsaccount/readme.html | 56 +++++ mailnews/jsaccount/src/DelegateList.cpp | 33 +++ mailnews/jsaccount/src/DelegateList.h | 52 +++++ mailnews/jsaccount/src/JaAbDirectory.cpp | 98 +++++++++ mailnews/jsaccount/src/JaAbDirectory.h | 89 ++++++++ mailnews/jsaccount/src/JaCompose.cpp | 103 +++++++++ mailnews/jsaccount/src/JaCompose.h | 92 ++++++++ mailnews/jsaccount/src/JaIncomingServer.cpp | 109 ++++++++++ mailnews/jsaccount/src/JaIncomingServer.h | 94 ++++++++ mailnews/jsaccount/src/JaMsgFolder.cpp | 207 ++++++++++++++++++ mailnews/jsaccount/src/JaMsgFolder.h | 126 +++++++++++ mailnews/jsaccount/src/JaSend.cpp | 102 +++++++++ mailnews/jsaccount/src/JaSend.h | 96 +++++++++ mailnews/jsaccount/src/JaUrl.cpp | 230 ++++++++++++++++++++ mailnews/jsaccount/src/JaUrl.h | 121 +++++++++++ mailnews/jsaccount/src/moz.build | 28 +++ 23 files changed, 2130 insertions(+) create mode 100644 mailnews/jsaccount/modules/JSAccountUtils.jsm create mode 100644 mailnews/jsaccount/modules/JaBaseUrl.jsm create mode 100644 mailnews/jsaccount/moz.build create mode 100644 mailnews/jsaccount/public/moz.build create mode 100644 mailnews/jsaccount/public/msgIDelegateList.idl create mode 100644 mailnews/jsaccount/public/msgIOverride.idl create mode 100644 mailnews/jsaccount/public/msgJsAccountCID.h create mode 100644 mailnews/jsaccount/readme.html create mode 100644 mailnews/jsaccount/src/DelegateList.cpp create mode 100644 mailnews/jsaccount/src/DelegateList.h create mode 100644 mailnews/jsaccount/src/JaAbDirectory.cpp create mode 100644 mailnews/jsaccount/src/JaAbDirectory.h create mode 100644 mailnews/jsaccount/src/JaCompose.cpp create mode 100644 mailnews/jsaccount/src/JaCompose.h create mode 100644 mailnews/jsaccount/src/JaIncomingServer.cpp create mode 100644 mailnews/jsaccount/src/JaIncomingServer.h create mode 100644 mailnews/jsaccount/src/JaMsgFolder.cpp create mode 100644 mailnews/jsaccount/src/JaMsgFolder.h create mode 100644 mailnews/jsaccount/src/JaSend.cpp create mode 100644 mailnews/jsaccount/src/JaSend.h create mode 100644 mailnews/jsaccount/src/JaUrl.cpp create mode 100644 mailnews/jsaccount/src/JaUrl.h create mode 100644 mailnews/jsaccount/src/moz.build (limited to 'mailnews/jsaccount') 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 @@ + + + + + JsAccount Usage and Architecture + + +

Overview

+

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.

+

Existing C++-based architecture of mailnews accounts

+

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:

+

@mozilla.org/messenger/server;1?type=imap

+

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.

+

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.

+

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.

+

Role of JsAccount

+

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.

+


+

+ + 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 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 (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 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 mJsIAbDirectory; + nsCOMPtr mJsIAbCollection; + nsCOMPtr mJsIAbItem; + nsCOMPtr mJsIInterfaceRequestor; + + nsCOMPtr mJsISupports; + + // Class to bypass JS delegates. nsCOMPtr for when we do cycle collection. + nsCOMPtr mCppBase; + + RefPtr mDelegateList; + nsDataHashtable* 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 (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 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 mJsIMsgCompose; + nsCOMPtr mJsIMsgSendListener; + nsCOMPtr mJsIInterfaceRequestor; + + nsCOMPtr mJsISupports; + + // Class to bypass JS delegates. + nsCOMPtr mCppBase; + + RefPtr mDelegateList; + nsDataHashtable* 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 (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 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 mJsIMsgIncomingServer; + nsCOMPtr mJsIInterfaceRequestor; + + nsCOMPtr mJsISupports; + + // Class to bypass JS delegates. + nsCOMPtr mCppBase; + + RefPtr mDelegateList; + nsDataHashtable* 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 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 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 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 (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 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 mJsIMsgFolder; + nsCOMPtr mJsIDBChangeListener; + nsCOMPtr mJsIUrlListener; + nsCOMPtr mJsIJunkMailClassificationListener; + nsCOMPtr mJsIMsgTraitClassificationListener; + nsCOMPtr mJsIInterfaceRequestor; + + nsCOMPtr mJsISupports; + + nsCOMPtr mCppBase; + RefPtr mDelegateList; + nsDataHashtable* 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 (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 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 mJsIMsgSend; + nsCOMPtr mJsIMsgOperationListener; + nsCOMPtr mJsIInterfaceRequestor; + + nsCOMPtr mJsISupports; + + // Class to bypass JS delegates. + nsCOMPtr mCppBase; + + RefPtr mDelegateList; + nsDataHashtable* 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 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 messenger(do_CreateInstance(NS_MESSENGER_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr 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 (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 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 mFolder; + + // nsIMsgMessageUrl variables. + + // the uri for the original message, like ews-message://server/folder#123 + nsCString mUri; + nsCOMPtr 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 mJsIMsgMailNewsUrl; + nsCOMPtr mJsIURI; + nsCOMPtr mJsIURIWithQuery; + nsCOMPtr mJsIURL; + nsCOMPtr mJsIMsgMessageUrl; + nsCOMPtr mJsIInterfaceRequestor; + + // Owning reference to the JS override. + nsCOMPtr mJsISupports; + + // Class to bypass JS delegates. nsCOMPtr for when we do cycle collection. + nsCOMPtr mCppBase; + + RefPtr mDelegateList; + nsDataHashtable *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' -- cgit v1.2.3