Bug 759422 - Remove all uses of e4x from comm-central to reopen a CLOSED TREE, r=BenB.
--- a/mail/app/profile/all-thunderbird.js
+++ b/mail/app/profile/all-thunderbird.js
@@ -6,18 +6,16 @@
#filter substitution
#ifdef XP_UNIX
#ifndef XP_MACOSX
#define UNIX_BUT_NOT_MAC
#endif
#endif
-pref("javascript.options.xml.chrome", true);
-
pref("general.useragent.locale", "@AB_CD@");
pref("general.skins.selectedSkin", "classic/1.0");
#ifdef XP_MACOSX
pref("browser.chromeURL", "chrome://messenger/content/messengercompose/messengercompose.xul");
pref("mail.biff.animate_dock_icon", false);
#endif
@@ -381,18 +379,16 @@ pref("browser.download.manager.showAlert
pref("browser.download.manager.retention", 1);
pref("browser.download.manager.showWhenStarting", true);
pref("browser.download.manager.closeWhenDone", true);
pref("browser.download.manager.openDelay", 100);
pref("browser.download.manager.focusWhenStarting", false);
pref("browser.download.manager.flashCount", 0);
pref("browser.download.manager.addToRecentDocs", true);
-pref("javascript.options.showInConsole", true);
-
pref("spellchecker.dictionary", "");
// Dictionary download preference
pref("spellchecker.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/%APP%/dictionaries/");
// profile.force.migration can be used to bypass the migration wizard, forcing migration from a particular
// mail application without any user intervention. Possible values are:
// seamonkey (mozilla suite), eudora, oexpress, outlook.
pref("profile.force.migration", "");
--- a/mail/components/cloudfile/nsYouSendIt.js
+++ b/mail/components/cloudfile/nsYouSendIt.js
@@ -975,27 +975,17 @@ nsYouSendItFileUploader.prototype = {
let curDate = Date.now().toString();
this.log.info("upload url = " + this._urlInfo.uploadUrl[0]);
this.request = req;
req.open("POST", this._urlInfo.uploadUrl[0] + "?" + kUrlTail, true);
req.onload = function() {
this.cleanupTempFile();
if (req.status >= 200 && req.status < 400) {
try {
- let response = req.responseText.replace(/<\?xml[^>]*\?>/, "");
- this.log.info("upload response = " + response);
- let docResponse = new XML(response);
- this.log.info("docResponse = " + docResponse);
- this._uploadResponse = docResponse;
- let ysiError = docResponse['ysi-error'];
- let uploadStatus = docResponse['upload-status'];
- this.log.info("upload status = " + uploadStatus);
- this.log.info("ysi error = " + ysiError);
- let errorCode = docResponse['error-code'];
- this.log.info("error code = " + errorCode);
+ this.log.info("upload response = " + req.responseText);
this._commitSend();
} catch (ex) {
this.log.error(ex);
}
}
else
this.callback(this.requestObserver,
Ci.nsIMsgCloudFileProvider.uploadErr);
--- a/mail/components/newmailaccount/content/uriListener.js
+++ b/mail/components/newmailaccount/content/uriListener.js
@@ -11,16 +11,17 @@
let Cu = Components.utils;
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/JXON.js");
/**
* This is an observer that watches all HTTP requests for one where the
* response contentType contains text/xml. Once that observation is
* made, we ensure that the associated window for that request matches
* the window belonging to the content tab for the account order form.
* If so, we attach an nsITraceableListener to read the contents of the
* request response, and react accordingly if the contents can be turned
@@ -170,20 +171,19 @@ TracingListener.prototype = {
let tabmail = document.getElementById('tabmail');
let success = false;
let account;
try {
// Attempt to construct the downloaded data into XML
let data = this.chunks.join("");
- let xml = new XML(data);
// Attempt to derive email account information
- let accountConfig = accountCreationFuncs.readFromXML(xml);
+ let accountConfig = accountCreationFuncs.readFromXML(JXON.build(data));
accountCreationFuncs.replaceVariables(accountConfig,
this.params.realName,
this.params.email);
account = accountCreationFuncs.createAccountInBackend(accountConfig);
success = true;
} catch (e) {
// Something went wrong with account set up. Dump the error out to the
// error console. The tab will be closed, and the Account Provisioner
--- a/mailnews/base/prefs/content/accountcreation/fetchConfig.js
+++ b/mailnews/base/prefs/content/accountcreation/fetchConfig.js
@@ -5,32 +5,35 @@
/**
* Tries to find a configuration for this ISP on the local harddisk, in the
* application install directory's "isp" subdirectory.
* Params @see fetchConfigFromISP()
*/
Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/JXON.js");
+
function fetchConfigFromDisk(domain, successCallback, errorCallback)
{
return new TimeoutAbortable(runAsync(function()
{
try {
// <TB installdir>/isp/example.com.xml
var configLocation = Services.dirsvc.get("CurProcD", Ci.nsIFile);
configLocation.append("isp");
configLocation.append(sanitize.hostname(domain) + ".xml");
var contents =
readURLasUTF8(Services.io.newFileURI(configLocation));
- // Bug 336551 trips over <?xml ... >
- contents = contents.replace(/<\?xml[^>]*\?>/, "");
- successCallback(readFromXML(new XML(contents)));
+ let domParser = Cc["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Ci.nsIDOMParser);
+ successCallback(readFromXML(JXON.build(
+ domParser.parseFromString(contents, "text/xml"))));
} catch (e) { errorCallback(e); }
}));
}
/**
* Tries to get a configuration from the ISP / mail provider directly.
*
* Disclaimers:
--- a/mailnews/base/prefs/content/accountcreation/fetchhttp.js
+++ b/mailnews/base/prefs/content/accountcreation/fetchhttp.js
@@ -10,16 +10,18 @@
*
* It does not provide download progress, but assumes that the
* fetched resource is so small (<1 10 KB) that the roundtrip and
* response generation is far more significant than the
* download time of the response. In other words, it's fine for RPC,
* but not for bigger file downloads.
*/
+Components.utils.import("resource://gre/modules/JXON.js");
+
/**
* Set up a fetch.
*
* @param url {String} URL of the server function.
* ATTENTION: The caller needs to make sure that the URL is secure to call.
* @param urlArgs {Object, associative array} Parameters to add
* to the end of the URL as query string. E.g.
* { foo: "bla", bar: "blub blub" } will add "?foo=bla&bar=blub%20blub"
@@ -130,21 +132,18 @@ FetchHTTP.prototype =
var mimetype = this._request.getResponseHeader("Content-Type");
if (!mimetype)
mimetype = "";
mimetype = mimetype.split(";")[0];
if (mimetype == "text/xml" ||
mimetype == "application/xml" ||
mimetype == "text/rdf")
{
- // Bug 270553 prevents usage of .responseXML
- var text = this._request.responseText;
- // Bug 336551 trips over <?xml ... >
- text = text.replace(/<\?xml[^>]*\?>/, "");
- this.result = new XML(text);
+ this._request.overrideMimeType("text/xml");
+ this.result = JXON.build(this._request.responseXML);
}
else
{
//ddump("mimetype: " + mimetype + " only supported as text");
this.result = this._request.responseText;
}
//ddump("result:\n" + this.result);
}
--- a/mailnews/base/prefs/content/accountcreation/readFromXML.js
+++ b/mailnews/base/prefs/content/accountcreation/readFromXML.js
@@ -1,88 +1,92 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
- * Takes an XML snipplet (as E4X) and reads the values into
+ * Takes an XML snipplet (as JXON) and reads the values into
* a new AccountConfig object.
* It does so securely (or tries to), by trying to avoid remote execution
* and similar holes which can appear when reading too naively.
* Of course it cannot tell whether the actual values are correct,
* e.g. it can't tell whether the host name is a good server.
*
* The XML format is documented at
* <https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat>
*
- * @param clientConfigXML {E4X} The <clientConfig> node.
+ * @param clientConfigXML {JXON} The <clientConfig> node.
* @return AccountConfig object filled with the data from XML
*/
function readFromXML(clientConfigXML)
{
+ function array_or_undef(value) {
+ return value === undefined ? [] : value;
+ }
var exception;
- if (typeof(clientConfigXML) != "xml" ||
- !("emailProvider" in clientConfigXML))
+ if (typeof(clientConfigXML) != "object" ||
+ !("clientConfig" in clientConfigXML) ||
+ !("emailProvider" in clientConfigXML.clientConfig))
{
- dump("client config xml = " + clientConfigXML + "\n");
+ dump("client config xml = " + JSON.stringify(clientConfigXML) + "\n");
var stringBundle = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties");
throw stringBundle.GetStringFromName("no_emailProvider.error");
}
- var xml = clientConfigXML.emailProvider;
+ var xml = clientConfigXML.clientConfig.emailProvider;
var d = new AccountConfig();
d.source = AccountConfig.kSourceXML;
- d.id = sanitize.hostname(xml.@id);
+ d.id = sanitize.hostname(xml["@id"]);
d.displayName = d.id;
try {
- d.displayName = sanitize.label(xml.displayName[0]);
+ d.displayName = sanitize.label(xml.displayName);
} catch (e) { logException(e); }
- for each (var domain in xml.domain)
+ for (var domain of xml.$domain)
{
try {
d.domains.push(sanitize.hostname(domain));
} catch (e) { logException(e); exception = e; }
}
if (domain.length == 0)
throw exception ? exception : "need proper <domain> in XML";
exception = null;
// incoming server
- for each (let iX in xml.incomingServer) // input (XML)
+ for (let iX of array_or_undef(xml.$incomingServer)) // input (XML)
{
let iO = d.createNewIncoming(); // output (object)
try {
// throws if not supported
- iO.type = sanitize.enum(iX.@type, ["pop3", "imap", "nntp"]);
- iO.hostname = sanitize.hostname(iX.hostname[0]);
- iO.port = sanitize.integerRange(iX.port[0], 1, 65535);
+ iO.type = sanitize.enum(iX["@type"], ["pop3", "imap", "nntp"]);
+ iO.hostname = sanitize.hostname(iX.hostname);
+ iO.port = sanitize.integerRange(iX.port, 1, 65535);
// We need a username even for Kerberos, need it even internally.
- iO.username = sanitize.string(iX.username[0]); // may be a %VARIABLE%
+ iO.username = sanitize.string(iX.username); // may be a %VARIABLE%
if ("password" in iX) {
d.rememberPassword = true;
- iO.password = sanitize.string(iX.password[0]);
+ iO.password = sanitize.string(iX.password);
}
- for each (let iXsocketType in iX.socketType)
+ for (let iXsocketType of array_or_undef(iX.$socketType))
{
try {
iO.socketType = sanitize.translate(iXsocketType,
{ plain : 1, SSL: 2, STARTTLS: 3 });
break; // take first that we support
} catch (e) { exception = e; }
}
if (!iO.socketType)
throw exception ? exception : "need proper <socketType> in XML";
exception = null;
- for each (let iXauth in iX.authentication)
+ for (let iXauth of array_or_undef(iX.$authentication))
{
try {
iO.auth = sanitize.translate(iXauth,
{ "password-cleartext" : Ci.nsMsgAuthMethod.passwordCleartext,
// @deprecated TODO remove
"plain" : Ci.nsMsgAuthMethod.passwordCleartext,
"password-encrypted" : Ci.nsMsgAuthMethod.passwordEncrypted,
// @deprecated TODO remove
@@ -95,25 +99,25 @@ function readFromXML(clientConfigXML)
if (!iO.auth)
throw exception ? exception : "need proper <authentication> in XML";
exception = null;
// defaults are in accountConfig.js
if (iO.type == "pop3" && "pop3" in iX)
{
try {
- if ("leaveMessagesOnServer" in iX.pop3[0])
+ if ("leaveMessagesOnServer" in iX.pop3)
iO.leaveMessagesOnServer =
sanitize.boolean(iX.pop3.leaveMessagesOnServer);
- if ("daysToLeaveMessagesOnServer" in iX.pop3[0])
+ if ("daysToLeaveMessagesOnServer" in iX.pop3)
iO.daysToLeaveMessagesOnServer =
sanitize.integer(iX.pop3.daysToLeaveMessagesOnServer);
} catch (e) { logException(e); }
try {
- if ("downloadOnBiff" in iX.pop3[0])
+ if ("downloadOnBiff" in iX.pop3)
iO.downloadOnBiff = sanitize.boolean(iX.pop3.downloadOnBiff);
} catch (e) { logException(e); }
}
// processed successfully, now add to result object
if (!d.incoming.hostname) // first valid
d.incoming = iO;
else
@@ -121,42 +125,42 @@ function readFromXML(clientConfigXML)
} catch (e) { exception = e; }
}
if (!d.incoming.hostname)
// throw exception for last server
throw exception ? exception : "Need proper <incomingServer> in XML file";
exception = null;
// outgoing server
- for each (let oX in xml.outgoingServer) // input (XML)
+ for (let oX of array_or_undef(xml.$outgoingServer)) // input (XML)
{
let oO = d.createNewOutgoing(); // output (object)
try {
- if (oX.@type != "smtp")
+ if (oX["@type"] != "smtp")
{
var stringBundle = getStringBundle(
"chrome://messenger/locale/accountCreationModel.properties");
throw stringBundle.GetStringFromName("outgoing_not_smtp.error");
}
- oO.hostname = sanitize.hostname(oX.hostname[0]);
- oO.port = sanitize.integerRange(oX.port[0], 1, 65535);
+ oO.hostname = sanitize.hostname(oX.hostname);
+ oO.port = sanitize.integerRange(oX.port, 1, 65535);
- for each (let oXsocketType in oX.socketType)
+ for (let oXsocketType of array_or_undef(oX.$socketType))
{
try {
oO.socketType = sanitize.translate(oXsocketType,
{ plain : 1, SSL: 2, STARTTLS: 3 });
break; // take first that we support
} catch (e) { exception = e; }
}
if (!oO.socketType)
throw exception ? exception : "need proper <socketType> in XML";
exception = null;
- for each (let oXauth in oX.authentication)
+ for (let oXauth of array_or_undef(oX.$authentication))
{
try {
oO.auth = sanitize.translate(oXauth,
{ // open relay
"none" : Ci.nsMsgAuthMethod.none,
// inside ISP or corp network
"client-IP-address" : Ci.nsMsgAuthMethod.none,
// hope for the best
@@ -177,21 +181,21 @@ function readFromXML(clientConfigXML)
throw exception ? exception : "need proper <authentication> in XML";
exception = null;
if ("username" in oX ||
// if password-based auth, we need a username,
// so go there anyways and throw.
oO.auth == Ci.nsMsgAuthMethod.passwordCleartext ||
oO.auth == Ci.nsMsgAuthMethod.passwordEncrypted)
- oO.username = sanitize.string(oX.username[0]);
+ oO.username = sanitize.string(oX.username);
if ("password" in oX) {
d.rememberPassword = true;
- oO.password = sanitize.string(oX.password[0]);
+ oO.password = sanitize.string(oX.password);
}
try {
// defaults are in accountConfig.js
if ("addThisServer" in oX)
oO.addThisServer = sanitize.boolean(oX.addThisServer);
if ("useGlobalPreferredServer" in oX)
oO.useGlobalPreferredServer =
@@ -206,24 +210,24 @@ function readFromXML(clientConfigXML)
} catch (e) { logException(e); exception = e; }
}
if (!d.outgoing.hostname)
// throw exception for last server
throw exception ? exception : "Need proper <outgoingServer> in XML file";
exception = null;
d.inputFields = new Array();
- for each (let inputField in xml.inputField)
+ for (let inputField of array_or_undef(xml.$inputField))
{
try {
var fieldset =
{
- varname : sanitize.alphanumdash(inputField.@key).toUpperCase(),
- displayName : sanitize.label(inputField.@label),
- exampleValue : sanitize.label(inputField.text())
+ varname : sanitize.alphanumdash(inputField["@key"]).toUpperCase(),
+ displayName : sanitize.label(inputField["@label"]),
+ exampleValue : sanitize.label(inputField.value)
};
d.inputFields.push(fieldset);
} catch (e) { logException(e); } // for now, don't throw,
// because we don't support custom fields yet anyways.
}
return d;
}
--- a/mailnews/base/test/unit/test_autoconfigXML.js
+++ b/mailnews/base/test/unit/test_autoconfigXML.js
@@ -12,16 +12,19 @@
* reading and allow fallback mechanisms. This test checks whether that works,
* and of course also whether we can read a normal config and get the proper
* values.
*/
// Globals
Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/JXON.js");
+
+var DOMParser = Components.Constructor("@mozilla.org/xmlextras/domparser;1");
var xmlReader = {};
try {
Services.scriptloader.loadSubScript(
"chrome://messenger/content/accountcreation/util.js", xmlReader);
Services.scriptloader.loadSubScript(
"chrome://messenger/content/accountcreation/accountConfig.js",
xmlReader);
@@ -60,114 +63,115 @@ function assert_equal_config(aA, aB, fie
/**
* Test that the xml reader returns a proper config and
* is also forwards-compatible to new additions to the data format.
*/
function test_readFromXML_config1()
{
var clientConfigXML =
- <clientConfig>
- <emailProvider id="example.com">
- <domain>example.com</domain>
- <domain>example.net</domain>
- <displayName>Example</displayName>
- <displayShortName>Example Mail</displayShortName>
+ '<clientConfig>' +
+ '<emailProvider id="example.com">' +
+ '<domain>example.com</domain>' +
+ '<domain>example.net</domain>' +
+ '<displayName>Example</displayName>' +
+ '<displayShortName>Example Mail</displayShortName>' +
- <!-- 1. - protocol not supported -->
- <incomingServer type="imap5">
- <hostname>badprotocol.example.com</hostname>
- <port>993</port>
- <socketType>SSL</socketType>
- <username>%EMAILLOCALPART%</username>
- <authentication>ssl-client-cert</authentication>
- </incomingServer>
- <!-- 2. - socket type not supported -->
- <incomingServer type="imap">
- <hostname>badsocket.example.com</hostname>
- <port>993</port>
- <socketType>key-from-DNSSEC</socketType>
- <username>%EMAILLOCALPART%</username>
- <authentication>password-cleartext</authentication>
- </incomingServer>
- <!-- 3. - first supported incoming server -->
- <incomingServer type="imap">
- <hostname>imapmail.example.com</hostname>
- <port>993</port>
- <socketType>SSL</socketType>
- <username>%EMAILLOCALPART%</username>
- <authentication>password-cleartext</authentication>
- </incomingServer>
- <!-- 4. - auth method not supported -->
- <incomingServer type="imap">
- <hostname>badauth.example.com</hostname>
- <port>993</port>
- <socketType>SSL</socketType>
- <username>%EMAILLOCALPART%</username>
- <authentication>ssl-client-cert</authentication>
- <!-- Throw in some elements we don't support yet -->
- <imap>
- <rootFolder path="INBOX." />
- <specialFolder id="sent" path="INBOX.Sent Mail" />
- </imap>
- </incomingServer>
- <!-- 5. - second supported incoming server -->
- <incomingServer type="pop3">
- <hostname>popmail.example.com</hostname>
- <!-- alternative hostname, not yet supported, should be ignored -->
- <hostname>popbackup.example.com</hostname>
- <port>110</port>
- <port>7878</port>
- <!-- unsupported socket type -->
- <socketType>GSSAPI2</socketType>
- <!-- but fall back -->
- <socketType>plain</socketType>
- <username>%EMAILLOCALPART%</username>
- <username>%EMAILADDRESS%</username>
- <!-- unsupported auth method -->
- <authentication>GSSAPI2</authentication>
- <!-- but fall back -->
- <authentication>password-encrypted</authentication>
- <pop3>
- <leaveMessagesOnServer>true</leaveMessagesOnServer>
- <daysToLeaveMessagesOnServer>999</daysToLeaveMessagesOnServer>
- </pop3>
- </incomingServer>
+ // 1. - protocol not supported
+ '<incomingServer type="imap5">' +
+ '<hostname>badprotocol.example.com</hostname>' +
+ '<port>993</port>' +
+ '<socketType>SSL</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>ssl-client-cert</authentication>' +
+ '</incomingServer>' +
+ // 2. - socket type not supported
+ '<incomingServer type="imap">' +
+ '<hostname>badsocket.example.com</hostname>' +
+ '<port>993</port>' +
+ '<socketType>key-from-DNSSEC</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>password-cleartext</authentication>' +
+ '</incomingServer>' +
+ // 3. - first supported incoming server
+ '<incomingServer type="imap">' +
+ '<hostname>imapmail.example.com</hostname>' +
+ '<port>993</port>' +
+ '<socketType>SSL</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>password-cleartext</authentication>' +
+ '</incomingServer>' +
+ // 4. - auth method not supported
+ '<incomingServer type="imap">' +
+ '<hostname>badauth.example.com</hostname>' +
+ '<port>993</port>' +
+ '<socketType>SSL</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>ssl-client-cert</authentication>' +
+ // Throw in some elements we don't support yet
+ '<imap>' +
+ '<rootFolder path="INBOX." />' +
+ '<specialFolder id="sent" path="INBOX.Sent Mail" />' +
+ '</imap>' +
+ '</incomingServer>' +
+ // 5. - second supported incoming server
+ '<incomingServer type="pop3">' +
+ '<hostname>popmail.example.com</hostname>' +
+ // alternative hostname, not yet supported, should be ignored
+ '<hostname>popbackup.example.com</hostname>' +
+ '<port>110</port>' +
+ '<port>7878</port>' +
+ // unsupported socket type
+ '<socketType>GSSAPI2</socketType>' +
+ // but fall back
+ '<socketType>plain</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<username>%EMAILADDRESS%</username>' +
+ // unsupported auth method
+ '<authentication>GSSAPI2</authentication>' +
+ // but fall back
+ '<authentication>password-encrypted</authentication>' +
+ '<pop3>' +
+ '<leaveMessagesOnServer>true</leaveMessagesOnServer>' +
+ '<daysToLeaveMessagesOnServer>999</daysToLeaveMessagesOnServer>' +
+ '</pop3>' +
+ '</incomingServer>' +
- <!-- outgoing server with invalid auth method -->
- <outgoingServer type="smtp">
- <hostname>badauth.example.com</hostname>
- <port>587</port>
- <socketType>STARTTLS</socketType>
- <username>%EMAILADDRESS%</username>
- <authentication>smtp-after-imap</authentication>
- </outgoingServer>
- <!-- outgoing server - supported -->
- <outgoingServer type="smtp">
- <hostname>smtpout.example.com</hostname>
- <hostname>smtpfallback.example.com</hostname>
- <port>587</port>
- <port>7878</port>
- <socketType>GSSAPI2</socketType>
- <socketType>STARTTLS</socketType>
- <username>%EMAILADDRESS%</username>
- <username>%EMAILLOCALPART%</username>
- <authentication>GSSAPI2</authentication>
- <authentication>client-IP-address</authentication>
- <smtp/>
- </outgoingServer>
+ // outgoing server with invalid auth method
+ '<outgoingServer type="smtp">' +
+ '<hostname>badauth.example.com</hostname>' +
+ '<port>587</port>' +
+ '<socketType>STARTTLS</socketType>' +
+ '<username>%EMAILADDRESS%</username>' +
+ '<authentication>smtp-after-imap</authentication>' +
+ '</outgoingServer>' +
+ // outgoing server - supported
+ '<outgoingServer type="smtp">' +
+ '<hostname>smtpout.example.com</hostname>' +
+ '<hostname>smtpfallback.example.com</hostname>' +
+ '<port>587</port>' +
+ '<port>7878</port>' +
+ '<socketType>GSSAPI2</socketType>' +
+ '<socketType>STARTTLS</socketType>' +
+ '<username>%EMAILADDRESS%</username>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>GSSAPI2</authentication>' +
+ '<authentication>client-IP-address</authentication>' +
+ '<smtp/>' +
+ '</outgoingServer>' +
+ // Throw in some more elements we don't support yet
+ '<enableURL url="http://foobar" />' +
+ '<instructionsURL url="http://foobar" />' +
- <!-- Throw in some more elements we don't support yet -->
- <enableURL url="http://foobar" />
- <instructionsURL url="http://foobar" />
+ '</emailProvider>' +
+ '</clientConfig>';
- </emailProvider>
- </clientConfig>;
-
- var config = xmlReader.readFromXML(clientConfigXML);
+ var domParser = new DOMParser();
+ var config = xmlReader.readFromXML(JXON.build(
+ domParser.parseFromString(clientConfigXML, "text/xml")));
do_check_eq(config instanceof xmlReader.AccountConfig, true);
do_check_eq("example.com", config.id);
do_check_eq("Example", config.displayName);
do_check_neq(-1, config.domains.indexOf("example.com"));
// 1. incoming server skipped because of an unsupported protocol
// 2. incoming server skipped because of an so-far unknown auth method
// 3. incoming server is fine for us: IMAP, SSL, cleartext password
@@ -197,45 +201,47 @@ function test_readFromXML_config1()
}
/**
* Test the replaceVariables method.
*/
function test_replaceVariables()
{
var clientConfigXML =
- <clientConfig>
- <emailProvider id="example.com">
- <domain>example.com</domain>
- <displayName>example.com</displayName>
- <displayShortName>example.com</displayShortName>
- <incomingServer type="pop3">
- <hostname>pop.%EMAILDOMAIN%</hostname>
- <port>995</port>
- <socketType>SSL</socketType>
- <username>%EMAILLOCALPART%</username>
- <authentication>plain</authentication>
- <pop3>
- <leaveMessagesOnServer>true</leaveMessagesOnServer>
- <daysToLeaveMessagesOnServer>999</daysToLeaveMessagesOnServer>
- </pop3>
- </incomingServer>
- <outgoingServer type="smtp">
- <hostname>smtp.example.com</hostname>
- <port>587</port>
- <socketType>STARTTLS</socketType>
- <username>%EMAILADDRESS%</username>
- <authentication>plain</authentication>
- <addThisServer>true</addThisServer>
- <useGlobalPreferredServer>false</useGlobalPreferredServer>
- </outgoingServer>
- </emailProvider>
- </clientConfig>;
+ '<clientConfig>' +
+ '<emailProvider id="example.com">' +
+ '<domain>example.com</domain>' +
+ '<displayName>example.com</displayName>' +
+ '<displayShortName>example.com</displayShortName>' +
+ '<incomingServer type="pop3">' +
+ '<hostname>pop.%EMAILDOMAIN%</hostname>' +
+ '<port>995</port>' +
+ '<socketType>SSL</socketType>' +
+ '<username>%EMAILLOCALPART%</username>' +
+ '<authentication>plain</authentication>' +
+ '<pop3>' +
+ '<leaveMessagesOnServer>true</leaveMessagesOnServer>' +
+ '<daysToLeaveMessagesOnServer>999</daysToLeaveMessagesOnServer>' +
+ '</pop3>' +
+ '</incomingServer>' +
+ '<outgoingServer type="smtp">' +
+ '<hostname>smtp.example.com</hostname>' +
+ '<port>587</port>' +
+ '<socketType>STARTTLS</socketType>' +
+ '<username>%EMAILADDRESS%</username>' +
+ '<authentication>plain</authentication>' +
+ '<addThisServer>true</addThisServer>' +
+ '<useGlobalPreferredServer>false</useGlobalPreferredServer>' +
+ '</outgoingServer>' +
+ '</emailProvider>' +
+ '</clientConfig>';
- var config = xmlReader.readFromXML(clientConfigXML);
+ var domParser = new DOMParser();
+ var config = xmlReader.readFromXML(JXON.build(
+ domParser.parseFromString(clientConfigXML, "text/xml")));
xmlReader.replaceVariables(config,
"Yamato Nadeshiko",
"yamato.nadeshiko@example.com",
"abc12345");
assert_equal_config(config.incoming.username,
"yamato.nadeshiko",
--- a/mailnews/base/test/unit/test_searchCustomTerm.js
+++ b/mailnews/base/test/unit/test_searchCustomTerm.js
@@ -29,22 +29,22 @@ var Tests =
// nsIMsgSearchCustomTerm object
var customTerm =
{
id: kCustomId,
name: "term name",
getEnabled: function(scope, op)
{
return scope == Ci.nsMsgSearchScope.offlineMail &&
- op == Ci.nsMsgSearchOp::Is
+ op == Ci.nsMsgSearchOp.Is
},
getAvailable: function(scope, op)
{
return scope == Ci.nsMsgSearchScope.offlineMail &&
- op == Ci.nsMsgSearchOp::Is
+ op == Ci.nsMsgSearchOp.Is
},
getAvailableOperators: function(scope, length)
{
length.value = 1;
return [Ci.nsMsgSearchOp.Is];
},
match: function(msgHdr, searchValue, searchOp)
{
new file mode 100644
--- /dev/null
+++ b/mailnews/base/util/JXON.js
@@ -0,0 +1,181 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This is a modification of the JXON parsers found on the page
+// <https://developer.mozilla.org/en-US/docs/JXON>
+
+var EXPORTED_SYMBOLS = ["JXON"];
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+
+const JXON = new (function() {
+ const sValueProp = "value"; /* you can customize these values */
+ const sAttributesProp = "attr";
+ const sAttrPref = "@";
+ const sElementListPrefix = "$";
+ const sConflictSuffix = "_"; // used when there's a name conflict with special JXON properties
+ const aCache = [];
+ const rIsNull = /^\s*$/;
+ const rIsBool = /^(?:true|false)$/i;
+
+ function parseText(sValue) {
+ //if (rIsNull.test(sValue))
+ // return null;
+ if (rIsBool.test(sValue))
+ return sValue.toLowerCase() === "true";
+ if (isFinite(sValue))
+ return parseFloat(sValue);
+ if (isFinite(Date.parse(sValue)))
+ return new Date(sValue);
+ return sValue;
+ };
+
+ function EmptyTree() {
+ }
+ EmptyTree.prototype = {
+ toString : function () {
+ return "null";
+ },
+ valueOf : function () {
+ return null;
+ },
+ };
+
+ function objectify(vValue) {
+ if (vValue === null)
+ return new EmptyTree();
+ else if (vValue instanceof Object)
+ return vValue;
+ else
+ return new vValue.constructor(vValue); // What does this? copy?
+ };
+
+ function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
+ const nLevelStart = aCache.length;
+ const bChildren = oParentNode.hasChildNodes();
+ const bAttributes = oParentNode.hasAttributes();
+ const bHighVerb = Boolean(nVerb & 2);
+
+ var sProp = 0;
+ var vContent = 0;
+ var nLength = 0;
+ var sCollectedTxt = "";
+ var vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
+
+ if (bChildren) {
+ for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
+ oNode = oParentNode.childNodes.item(nItem);
+ if (oNode.nodeType === 4) // CDATASection
+ sCollectedTxt += oNode.nodeValue;
+ else if (oNode.nodeType === 3) // Text
+ sCollectedTxt += oNode.nodeValue;
+ else if (oNode.nodeType === 1) // Element
+ aCache.push(oNode);
+ }
+ }
+
+ const nLevelEnd = aCache.length;
+ const vBuiltVal = parseText(sCollectedTxt);
+
+ if (!bHighVerb && (bChildren || bAttributes))
+ vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
+
+ for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
+ sProp = aCache[nElId].nodeName;
+ if (sProp == sValueProp || sProp == sAttributesProp)
+ sProp = sProp + sConflictSuffix;
+ vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
+ if (!vResult.hasOwnProperty(sProp)) {
+ vResult[sProp] = vContent;
+ vResult[sElementListPrefix + sProp] = [];
+ }
+ vResult[sElementListPrefix + sProp].push(vContent);
+ nLength++;
+ }
+
+ if (bAttributes) {
+ const nAttrLen = oParentNode.attributes.length;
+ const sAPrefix = bNesteAttr ? "" : sAttrPref;
+ const oAttrParent = bNesteAttr ? {} : vResult;
+
+ for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
+ oAttrib = oParentNode.attributes.item(nAttrib);
+ oAttrParent[sAPrefix + oAttrib.name] = parseText(oAttrib.value);
+ }
+
+ if (bNesteAttr) {
+ if (bFreeze)
+ Object.freeze(oAttrParent);
+ vResult[sAttributesProp] = oAttrParent;
+ nLength -= nAttrLen - 1;
+ }
+ }
+
+ if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt)
+ vResult[sValueProp] = vBuiltVal;
+ else if (!bHighVerb && nLength === 0 && sCollectedTxt)
+ vResult = vBuiltVal;
+
+ if (bFreeze && (bHighVerb || nLength > 0))
+ Object.freeze(vResult);
+
+ aCache.length = nLevelStart;
+
+ return vResult;
+ };
+
+ function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
+ var vValue, oChild;
+
+ if (oParentObj instanceof String || oParentObj instanceof Number ||
+ oParentObj instanceof Boolean)
+ oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
+ else if (oParentObj.constructor === Date)
+ oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
+
+ for (var sName in oParentObj) {
+ vValue = oParentObj[sName];
+ if (isFinite(sName) || vValue instanceof Function)
+ continue; /* verbosity level is 0 */
+ if (sName === sValueProp) {
+ if (vValue !== null && vValue !== true) {
+ oParentEl.appendChild(oXMLDoc.createTextNode(
+ vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
+ }
+ } else if (sName === sAttributesProp) { /* verbosity level is 3 */
+ for (var sAttrib in vValue)
+ oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
+ } else if (sName.charAt(0) === sAttrPref) {
+ oParentEl.setAttribute(sName.slice(1), vValue);
+ } else if (vValue.constructor === Array) {
+ for (var nItem = 0; nItem < vValue.length; nItem++) {
+ oChild = oXMLDoc.createElement(sName);
+ loadObjTree(oXMLDoc, oChild, vValue[nItem]);
+ oParentEl.appendChild(oChild);
+ }
+ } else {
+ oChild = oXMLDoc.createElement(sName);
+ if (vValue instanceof Object)
+ loadObjTree(oXMLDoc, oChild, vValue);
+ else if (vValue !== null && vValue !== true)
+ oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
+ oParentEl.appendChild(oChild);
+ }
+ }
+ };
+
+ this.build = function(oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
+ const _nVerb = arguments.length > 1 &&
+ typeof nVerbosity === "number" ? nVerbosity & 3 :
+ /* put here the default verbosity level: */ 1;
+ return createObjTree(oXMLParent, _nVerb, bFreeze || false,
+ arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
+ };
+
+ this.unbuild = function(oObjTree) {
+ const oNewDoc = document.implementation.createDocument("", "", null);
+ loadObjTree(oNewDoc, oNewDoc, oObjTree);
+ return oNewDoc;
+ };
+})();
--- a/mailnews/base/util/Makefile.in
+++ b/mailnews/base/util/Makefile.in
@@ -66,16 +66,20 @@ EXTRA_JS_MODULES = \
templateUtils.js \
IOUtils.js \
mailnewsMigrator.js \
mailServices.js \
msgDBCacheManager.js \
hostnameUtils.jsm \
$(NULL)
+ifdef MOZ_THUNDERBIRD
+EXTRA_JS_MODULES += JXON.js
+endif
+
# we don't want the shared lib, but we want to force the creation of a static lib.
FORCE_STATIC_LIB = 1
DEFINES += -D_IMPL_NS_MSG_BASE
ifeq ($(OS_ARCH),WINNT)
DEFINES += -DZLIB_DLL
OS_CXXFLAGS += -DNOMINMAX