mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 07:17:32 +09:00
155 lines
6.1 KiB
JavaScript
155 lines
6.1 KiB
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.EXPORTED_SYMBOLS = ['GlodaUtils'];
|
|
|
|
var Cc = Components.classes;
|
|
var Ci = Components.interfaces;
|
|
var Cr = Components.results;
|
|
var Cu = Components.utils;
|
|
|
|
Cu.import("resource:///modules/mailServices.js");
|
|
|
|
/**
|
|
* @namespace A holding place for logic that is not gloda-specific and should
|
|
* reside elsewhere.
|
|
*/
|
|
var GlodaUtils = {
|
|
|
|
/**
|
|
* This Regexp is super-complicated and used at least in two different parts of
|
|
* the code, so let's expose it from one single location.
|
|
*/
|
|
PART_RE: new RegExp("^[^?]+\\?(?:/;section=\\d+\\?)?(?:[^&]+&)*part=([^&]+)(?:&[^&]+)*$"),
|
|
|
|
deMime: function gloda_utils_deMime(aString) {
|
|
return MailServices.mimeConverter.decodeMimeHeader(aString, null, false, true);
|
|
},
|
|
|
|
_headerParser: MailServices.headerParser,
|
|
|
|
/**
|
|
* Parses an RFC 2822 list of e-mail addresses and returns an object with
|
|
* 4 attributes, as described below. We will use the example of the user
|
|
* passing an argument of '"Bob Smith" <bob@example.com>'.
|
|
*
|
|
* This method (by way of nsIMsgHeaderParser) takes care of decoding mime
|
|
* headers, but is not aware of folder-level character set overrides.
|
|
*
|
|
* count: the number of addresses parsed. (ex: 1)
|
|
* addresses: a list of e-mail addresses (ex: ["bob@example.com"])
|
|
* names: a list of names (ex: ["Bob Smith"])
|
|
* fullAddresses: aka the list of name and e-mail together (ex: ['"Bob Smith"
|
|
* <bob@example.com>']).
|
|
*
|
|
* This method is a convenience wrapper around nsIMsgHeaderParser.
|
|
*/
|
|
parseMailAddresses: function gloda_utils_parseMailAddresses(aMailAddresses) {
|
|
let addresses = {}, names = {}, fullAddresses = {};
|
|
this._headerParser.parseHeadersWithArray(aMailAddresses, addresses,
|
|
names, fullAddresses);
|
|
return {names: names.value, addresses: addresses.value,
|
|
fullAddresses: fullAddresses.value,
|
|
count: names.value.length};
|
|
},
|
|
|
|
/**
|
|
* MD5 hash a string and return the hex-string result. Impl from nsICryptoHash
|
|
* docs.
|
|
*/
|
|
md5HashString: function gloda_utils_md5hash(aString) {
|
|
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
|
createInstance(Ci.nsIScriptableUnicodeConverter);
|
|
let trash = {};
|
|
converter.charset = "UTF-8";
|
|
let data = converter.convertToByteArray(aString, trash);
|
|
|
|
let hasher = Cc['@mozilla.org/security/hash;1'].
|
|
createInstance(Ci.nsICryptoHash);
|
|
hasher.init(Ci.nsICryptoHash.MD5);
|
|
hasher.update(data, data.length);
|
|
let hash = hasher.finish(false);
|
|
|
|
// return the two-digit hexadecimal code for a byte
|
|
function toHexString(charCode) {
|
|
return ("0" + charCode.toString(16)).slice(-2);
|
|
}
|
|
|
|
// convert the binary hash data to a hex string.
|
|
let hex = Object.keys(hash).map(i => toHexString(hash.charCodeAt(i)));
|
|
return hex.join("");
|
|
},
|
|
|
|
getCardForEmail: function gloda_utils_getCardForEmail(aAddress) {
|
|
// search through all of our local address books looking for a match.
|
|
let enumerator = MailServices.ab.directories;
|
|
let cardForEmailAddress;
|
|
let addrbook;
|
|
while (!cardForEmailAddress && enumerator.hasMoreElements())
|
|
{
|
|
addrbook = enumerator.getNext().QueryInterface(Ci.nsIAbDirectory);
|
|
try
|
|
{
|
|
cardForEmailAddress = addrbook.cardForEmailAddress(aAddress);
|
|
if (cardForEmailAddress)
|
|
return cardForEmailAddress;
|
|
} catch (ex) {}
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
_FORCE_GC_AFTER_NUM_HEADERS: 4096,
|
|
_headersSeen: 0,
|
|
/**
|
|
* As |forceGarbageCollection| says, once XPConnect sees a header, it likes
|
|
* to hold onto that reference. This method is used to track the number of
|
|
* headers we have seen and force a GC when we have to.
|
|
*
|
|
* Ideally the indexer's idle-biased GC mechanism would take care of all the
|
|
* GC; we are just a failsafe to make sure that our memory usage is bounded
|
|
* based on the number of headers we have seen rather than just time.
|
|
* Since holding onto headers can keep databases around too, this also
|
|
* helps avoid keeping file handles open, etc.
|
|
*
|
|
* |forceGarbageCollection| will zero our tracking variable when a GC happens
|
|
* so we are informed by the indexer's GC triggering.
|
|
*
|
|
* And of course, we don't want to trigger collections willy nilly because
|
|
* they have a cost even if there is no garbage.
|
|
*
|
|
* @param aNumHeadersSeen The number of headers code has seen. A granularity
|
|
* of hundreds of messages should be fine.
|
|
*/
|
|
considerHeaderBasedGC: function(aNumHeadersSeen) {
|
|
this._headersSeen += aNumHeadersSeen;
|
|
if (this._headersSeen >= this._FORCE_GC_AFTER_NUM_HEADERS)
|
|
this.forceGarbageCollection();
|
|
},
|
|
|
|
/**
|
|
* Force a garbage-collection sweep. Gloda has to force garbage collection
|
|
* periodically because XPConnect's XPCJSRuntime::DeferredRelease mechanism
|
|
* can end up holding onto a ridiculously high number of XPConnect objects in
|
|
* between normal garbage collections. This has mainly posed a problem
|
|
* because nsAutolock is a jerk in DEBUG builds in 1.9.1, but in theory this
|
|
* also helps us even out our memory usage.
|
|
* We also are starting to do this more to try and keep the garbage collection
|
|
* durations acceptable. We intentionally avoid triggering the cycle
|
|
* collector in those cases, as we do presume a non-trivial fixed cost for
|
|
* cycle collection. (And really all we want is XPConnect to not be a jerk.)
|
|
* This method exists mainly to centralize our GC activities and because if
|
|
* we do start involving the cycle collector, that is a non-trivial block of
|
|
* code to copy-and-paste all over the place (at least in a module).
|
|
*
|
|
* @param aCycleCollecting Do we need the cycle collector to run? Currently
|
|
* unused / unimplemented, but we would use
|
|
* nsIDOMWindowUtils.garbageCollect() to do so.
|
|
*/
|
|
forceGarbageCollection:
|
|
function gloda_utils_garbageCollection(aCycleCollecting) {
|
|
Cu.forceGC();
|
|
this._headersSeen = 0;
|
|
}
|
|
};
|