diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/addrbook/modules/LDAPDirectoryQuery.jsm | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/comm/mailnews/addrbook/modules/LDAPDirectoryQuery.jsm b/comm/mailnews/addrbook/modules/LDAPDirectoryQuery.jsm new file mode 100644 index 0000000000..88291cbaed --- /dev/null +++ b/comm/mailnews/addrbook/modules/LDAPDirectoryQuery.jsm @@ -0,0 +1,218 @@ +/* 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 = ["LDAPDirectoryQuery"]; + +const { LDAPListenerBase } = ChromeUtils.import( + "resource:///modules/LDAPListenerBase.jsm" +); + +/** + * Convert a nsIAbBooleanExpression to a filter string. + * + * @param {nsIAbLDAPAttributeMap} attrMap - A mapping between address book + * properties and ldap attributes. + * @param {nsIAbBooleanExpression} exp - The expression to convert. + * @returns {string} + */ +function boolExpressionToFilter(attrMap, exp) { + let filter = "("; + filter += + { + [Ci.nsIAbBooleanOperationTypes.AND]: "&", + [Ci.nsIAbBooleanOperationTypes.OR]: "|", + [Ci.nsIAbBooleanOperationTypes.NOT]: "!", + }[exp.operation] || ""; + + if (exp.expressions) { + for (let childExp of exp.expressions) { + if (childExp instanceof Ci.nsIAbBooleanExpression) { + filter += boolExpressionToFilter(attrMap, childExp); + } else if (childExp instanceof Ci.nsIAbBooleanConditionString) { + filter += boolConditionToFilter(attrMap, childExp); + } + } + } + + filter += ")"; + return filter; +} + +/** + * Convert a nsIAbBooleanConditionString to a filter string. + * + * @param {nsIAbLDAPAttributeMap} attrMap - A mapping between addressbook + * properties and ldap attributes. + * @param {nsIAbBooleanConditionString} exp - The expression to convert. + * @returns {string} + */ +function boolConditionToFilter(attrMap, exp) { + let attr = attrMap.getFirstAttribute(exp.name); + if (!attr) { + return ""; + } + switch (exp.condition) { + case Ci.nsIAbBooleanConditionTypes.DoesNotExist: + return `(!(${attr}=*))`; + case Ci.nsIAbBooleanConditionTypes.Exists: + return `(${attr}=*)`; + case Ci.nsIAbBooleanConditionTypes.Contains: + return `(${attr}=*${exp.value}*)`; + case Ci.nsIAbBooleanConditionTypes.DoesNotContain: + return `(!(${attr}=*${exp.value}*))`; + case Ci.nsIAbBooleanConditionTypes.Is: + return `(${attr}=${exp.value})`; + case Ci.nsIAbBooleanConditionTypes.IsNot: + return `(!(${attr}=${exp.value}))`; + case Ci.nsIAbBooleanConditionTypes.BeginsWith: + return `(${attr}=${exp.value}*)`; + case Ci.nsIAbBooleanConditionTypes.EndsWith: + return `(${attr}=*${exp.value})`; + case Ci.nsIAbBooleanConditionTypes.LessThan: + return `(${attr}<=${exp.value})`; + case Ci.nsIAbBooleanConditionTypes.GreaterThan: + return `(${attr}>=${exp.value})`; + case Ci.nsIAbBooleanConditionTypes.SoundsLike: + return `(${attr}~=${exp.value})`; + default: + return ""; + } +} + +/** + * @implements {nsIAbDirectoryQuery} + * @implements {nsILDAPMessageListener} + */ +class LDAPDirectoryQuery extends LDAPListenerBase { + QueryInterface = ChromeUtils.generateQI([ + "nsIAbDirectoryQuery", + "nsILDAPMessageListener", + ]); + + i = 0; + + doQuery(directory, args, listener, limit, timeout) { + this._directory = directory.QueryInterface(Ci.nsIAbLDAPDirectory); + this._listener = listener; + this._attrMap = args.typeSpecificArg; + this._filter = + args.filter || boolExpressionToFilter(this._attrMap, args.expression); + this._limit = limit; + this._timeout = timeout; + + let urlFilter = this._directory.lDAPURL.filter; + // If urlFilter is empty or the default "(objectclass=*)", do nothing. + if (urlFilter && urlFilter != "(objectclass=*)") { + if (!urlFilter.startsWith("(")) { + urlFilter = `(${urlFilter})`; + } + this._filter = `(&${urlFilter}${this._filter})`; + } + + this._connection = Cc[ + "@mozilla.org/network/ldap-connection;1" + ].createInstance(Ci.nsILDAPConnection); + this._operation = Cc[ + "@mozilla.org/network/ldap-operation;1" + ].createInstance(Ci.nsILDAPOperation); + + this._connection.init( + directory.lDAPURL, + directory.authDn, + this, + null, + directory.protocolVersion + ); + return this.i++; + } + + stopQuery(contextId) { + this._operation?.abandonExt(); + } + + /** + * @see nsILDAPMessageListener + */ + onLDAPMessage(msg) { + switch (msg.type) { + case Ci.nsILDAPMessage.RES_BIND: + this._onLDAPBind(msg); + break; + case Ci.nsILDAPMessage.RES_SEARCH_ENTRY: + this._onLDAPSearchEntry(msg); + break; + case Ci.nsILDAPMessage.RES_SEARCH_RESULT: + this._onLDAPSearchResult(msg); + break; + default: + break; + } + } + + /** + * @see nsILDAPMessageListener + */ + onLDAPError(status, secInfo, location) { + this._onSearchFinished(status, secInfo, location); + } + + /** + * @see LDAPListenerBase + */ + _actionOnBindSuccess() { + let ldapUrl = this._directory.lDAPURL; + this._operation.searchExt( + ldapUrl.dn, + ldapUrl.scope, + this._filter, + ldapUrl.attributes, + this._timeout, + this._limit + ); + } + + /** + * @see LDAPListenerBase + */ + _actionOnBindFailure() { + this._onSearchFinished(Cr.NS_ERROR_FAILURE); + } + + /** + * Handler of nsILDAPMessage.RES_SEARCH_ENTRY message. + * + * @param {nsILDAPMessage} msg - The received LDAP message. + */ + _onLDAPSearchEntry(msg) { + let newCard = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance( + Ci.nsIAbCard + ); + this._attrMap.setCardPropertiesFromLDAPMessage(msg, newCard); + newCard.directoryUID = this._directory.UID; + this._listener.onSearchFoundCard(newCard); + } + + /** + * Handler of nsILDAPMessage.RES_SEARCH_RESULT message. + * + * @param {nsILDAPMessage} msg - The received LDAP message. + */ + _onLDAPSearchResult(msg) { + this._onSearchFinished( + [Ci.nsILDAPErrors.SUCCESS, Ci.nsILDAPErrors.SIZELIMIT_EXCEEDED].includes( + msg.errorCode + ) + ? Cr.NS_OK + : Cr.NS_ERROR_FAILURE + ); + } + + _onSearchFinished(status, secInfo, location) { + this._listener.onSearchFinished(status, false, secInfo, location); + } +} + +LDAPDirectoryQuery.prototype.classID = Components.ID( + "{5ad5d311-1a50-43db-a03c-63d45f443903}" +); |