2021-06-08 13:24:20 +03:00
|
|
|
/* 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/. */
|
|
|
|
|
2024-03-12 18:01:01 +03:00
|
|
|
import { LDAPListenerBase } from "resource:///modules/LDAPListenerBase.sys.mjs";
|
2021-06-08 13:24:20 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a nsIAbBooleanExpression to a filter string.
|
2022-11-23 07:43:25 +03:00
|
|
|
*
|
2021-06-08 13:24:20 +03:00
|
|
|
* @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) {
|
2023-10-26 12:32:05 +03:00
|
|
|
for (const childExp of exp.expressions) {
|
2021-06-08 13:24:20 +03:00
|
|
|
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.
|
2022-11-23 07:43:25 +03:00
|
|
|
*
|
2021-06-08 13:24:20 +03:00
|
|
|
* @param {nsIAbLDAPAttributeMap} attrMap - A mapping between addressbook
|
|
|
|
* properties and ldap attributes.
|
|
|
|
* @param {nsIAbBooleanConditionString} exp - The expression to convert.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function boolConditionToFilter(attrMap, exp) {
|
2023-10-26 12:32:05 +03:00
|
|
|
const attr = attrMap.getFirstAttribute(exp.name);
|
2021-09-07 08:34:37 +03:00
|
|
|
if (!attr) {
|
|
|
|
return "";
|
|
|
|
}
|
2021-06-08 13:24:20 +03:00
|
|
|
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}
|
2021-06-16 12:59:42 +03:00
|
|
|
* @implements {nsILDAPMessageListener}
|
2021-06-08 13:24:20 +03:00
|
|
|
*/
|
2024-02-23 15:50:48 +03:00
|
|
|
export class LDAPDirectoryQuery extends LDAPListenerBase {
|
2021-06-16 12:59:42 +03:00
|
|
|
QueryInterface = ChromeUtils.generateQI([
|
|
|
|
"nsIAbDirectoryQuery",
|
|
|
|
"nsILDAPMessageListener",
|
|
|
|
]);
|
2021-06-08 13:24:20 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-07-23 03:35:20 +03:00
|
|
|
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})`;
|
|
|
|
}
|
|
|
|
|
2021-06-08 13:24:20 +03:00
|
|
|
this._connection = Cc[
|
|
|
|
"@mozilla.org/network/ldap-connection;1"
|
|
|
|
].createInstance(Ci.nsILDAPConnection);
|
|
|
|
this._operation = Cc[
|
|
|
|
"@mozilla.org/network/ldap-operation;1"
|
|
|
|
].createInstance(Ci.nsILDAPOperation);
|
|
|
|
|
2024-05-08 12:05:30 +03:00
|
|
|
this._connection.init(directory.lDAPURL, directory.authDn, this);
|
2021-06-08 13:24:20 +03:00
|
|
|
return this.i++;
|
|
|
|
}
|
|
|
|
|
2024-03-22 22:12:04 +03:00
|
|
|
stopQuery() {
|
2021-06-08 13:24:20 +03:00
|
|
|
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() {
|
2023-10-26 12:32:05 +03:00
|
|
|
const ldapUrl = this._directory.lDAPURL;
|
2021-06-08 13:24:20 +03:00
|
|
|
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.
|
2022-11-23 07:43:25 +03:00
|
|
|
*
|
2021-06-08 13:24:20 +03:00
|
|
|
* @param {nsILDAPMessage} msg - The received LDAP message.
|
|
|
|
*/
|
|
|
|
_onLDAPSearchEntry(msg) {
|
2023-10-26 12:32:05 +03:00
|
|
|
const newCard = Cc[
|
|
|
|
"@mozilla.org/addressbook/cardproperty;1"
|
|
|
|
].createInstance(Ci.nsIAbCard);
|
2021-06-08 13:24:20 +03:00
|
|
|
this._attrMap.setCardPropertiesFromLDAPMessage(msg, newCard);
|
2021-06-16 13:00:10 +03:00
|
|
|
newCard.directoryUID = this._directory.UID;
|
2021-06-08 13:24:20 +03:00
|
|
|
this._listener.onSearchFoundCard(newCard);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler of nsILDAPMessage.RES_SEARCH_RESULT message.
|
2022-11-23 07:43:25 +03:00
|
|
|
*
|
2021-06-08 13:24:20 +03:00
|
|
|
* @param {nsILDAPMessage} msg - The received LDAP message.
|
|
|
|
*/
|
|
|
|
_onLDAPSearchResult(msg) {
|
|
|
|
this._onSearchFinished(
|
2021-07-23 05:32:33 +03:00
|
|
|
[Ci.nsILDAPErrors.SUCCESS, Ci.nsILDAPErrors.SIZELIMIT_EXCEEDED].includes(
|
|
|
|
msg.errorCode
|
|
|
|
)
|
|
|
|
? Cr.NS_OK
|
|
|
|
: Cr.NS_ERROR_FAILURE
|
2021-06-08 13:24:20 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-06-28 01:58:32 +03:00
|
|
|
_onSearchFinished(status, secInfo, location) {
|
|
|
|
this._listener.onSearchFinished(status, false, secInfo, location);
|
2021-06-08 13:24:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LDAPDirectoryQuery.prototype.classID = Components.ID(
|
|
|
|
"{5ad5d311-1a50-43db-a03c-63d45f443903}"
|
|
|
|
);
|