mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-26 02:17:34 +09:00
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
This commit is contained in:
parent
23e0d82436
commit
e400f4130a
1564 changed files with 510348 additions and 0 deletions
285
mailnews/jsaccount/modules/JSAccountUtils.jsm
Normal file
285
mailnews/jsaccount/modules/JSAccountUtils.jsm
Normal file
|
|
@ -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;
|
||||
}
|
||||
81
mailnews/jsaccount/modules/JaBaseUrl.jsm
Normal file
81
mailnews/jsaccount/modules/JaBaseUrl.jsm
Normal file
|
|
@ -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.
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue