Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,72 @@
/* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
var gOkButton;
var gNameInput;
var gDirectory = null;
var kPersonalAddressbookURI = "moz-abmdbdirectory://abook.mab";
var kCollectedAddressbookURI = "moz-abmdbdirectory://history.mab";
var kAllDirectoryRoot = "moz-abdirectory://";
var kPABDirectory = 2; // defined in nsDirPrefs.h
function abNameOnLoad()
{
// Get the document elements.
gOkButton = document.documentElement.getButton('accept');
gNameInput = document.getElementById('name');
// look in arguments[0] for parameters to see if we have a directory or not
if ("arguments" in window && window.arguments[0] &&
"selectedDirectory" in window.arguments[0]) {
gDirectory = window.arguments[0].selectedDirectory;
gNameInput.value = gDirectory.dirName;
}
// Work out the window title (if we have a directory specified, then it's a
// rename).
var bundle = document.getElementById("bundle_addressBook");
if (gDirectory) {
let oldListName = gDirectory.dirName;
document.title = bundle.getFormattedString("addressBookTitleEdit", [oldListName]);
} else {
document.title = bundle.getString("addressBookTitleNew");
}
if (gDirectory &&
(gDirectory.URI == kCollectedAddressbookURI ||
gDirectory.URI == kPersonalAddressbookURI ||
gDirectory.URI == kAllDirectoryRoot + "?")) {
// Address book name is not editable, therefore disable the field and
// only have an ok button that doesn't do anything.
gNameInput.readOnly = true;
document.documentElement.buttons = "accept";
document.documentElement.removeAttribute("ondialogaccept");
} else {
gNameInput.focus();
abNameDoOkEnabling();
}
}
function abNameOKButton()
{
var newName = gNameInput.value.trim();
// Either create a new directory or update an existing one depending on what
// we were given when we started.
if (gDirectory)
gDirectory.dirName = newName;
else
MailServices.ab.newAddressBook(newName, "", kPABDirectory);
return true;
}
function abNameDoOkEnabling()
{
gOkButton.disabled = gNameInput.value.trim() == "";
}

View file

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/abAddressBookNameDialog.dtd">
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
style="width: 36em;"
onload="abNameOnLoad();"
ondialogaccept="return abNameOKButton();">
<stringbundleset id="stringbundleset">
<stringbundle id="bundle_addressBook"
src="chrome://messenger/locale/addressbook/addressBook.properties"/>
</stringbundleset>
<script type="application/javascript" src="chrome://messenger/content/addressbook/abAddressBookNameDialog.js"/>
<hbox align="center">
<label control="name" value="&name.label;" accesskey="&name.accesskey;"/>
<textbox id="name" oninput="abNameDoOkEnabling();" flex="1"/>
</hbox>
</dialog>

View file

@ -0,0 +1,424 @@
/* -*- 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/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/PluralForm.jsm");
// Returns the load context for the current window
function getLoadContext() {
return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsILoadContext);
}
var abFlavorDataProvider = {
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIFlavorDataProvider]),
getFlavorData: function(aTransferable, aFlavor, aData, aDataLen)
{
if (aFlavor == "application/x-moz-file-promise")
{
var primitive = {};
aTransferable.getTransferData("text/vcard", primitive, {});
var vCard = primitive.value.QueryInterface(Components.interfaces.nsISupportsString).data;
aTransferable.getTransferData("application/x-moz-file-promise-dest-filename", primitive, {});
var leafName = primitive.value.QueryInterface(Components.interfaces.nsISupportsString).data;
aTransferable.getTransferData("application/x-moz-file-promise-dir", primitive, {});
var localFile = primitive.value.QueryInterface(Components.interfaces.nsIFile).clone();
localFile.append(leafName);
var ofStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
ofStream.init(localFile, -1, -1, 0);
var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream);
converter.init(ofStream, null, 0, 0);
converter.writeString(vCard);
converter.close();
aData.value = localFile;
}
}
};
var abResultsPaneObserver = {
onDragStart: function (aEvent, aXferData, aDragAction)
{
var selectedRows = GetSelectedRows();
if (!selectedRows)
return;
var selectedAddresses = GetSelectedAddresses();
aXferData.data = new TransferData();
aXferData.data.addDataForFlavour("moz/abcard", selectedRows);
aXferData.data.addDataForFlavour("text/x-moz-address", selectedAddresses);
aXferData.data.addDataForFlavour("text/unicode", selectedAddresses);
let srcDirectory = getSelectedDirectory();
// The default allowable actions are copy, move and link, so we need
// to restrict them here.
if (!srcDirectory.readOnly)
// Only allow copy & move from read-write directories.
aDragAction.action = Components.interfaces.
nsIDragService.DRAGDROP_ACTION_COPY |
Components.interfaces.
nsIDragService.DRAGDROP_ACTION_MOVE;
else
// Only allow copy from read-only directories.
aDragAction.action = Components.interfaces.
nsIDragService.DRAGDROP_ACTION_COPY;
var card = GetSelectedCard();
if (card && card.displayName) {
let vCard = card.translateTo("vcard");
aXferData.data.addDataForFlavour("text/vcard", decodeURIComponent(vCard));
aXferData.data.addDataForFlavour("application/x-moz-file-promise-dest-filename", card.displayName + ".vcf");
aXferData.data.addDataForFlavour("application/x-moz-file-promise-url", "data:text/vcard," + vCard);
aXferData.data.addDataForFlavour("application/x-moz-file-promise", abFlavorDataProvider);
}
},
onDrop: function (aEvent, aXferData, aDragSession)
{
},
onDragExit: function (aEvent, aDragSession)
{
},
onDragOver: function (aEvent, aFlavour, aDragSession)
{
},
getSupportedFlavours: function ()
{
return null;
}
};
var dragService = Components.classes["@mozilla.org/widget/dragservice;1"]
.getService(Components.interfaces.nsIDragService);
var abDirTreeObserver = {
/**
* canDrop - determine if the tree will accept the dropping of a item
* onto it.
*
* Note 1: We don't allow duplicate mailing list names, therefore copy
* is not allowed for mailing lists.
* Note 2: Mailing lists currently really need a card in the parent
* address book, therefore only moving to an address book is allowed.
*
* The possibilities:
*
* anything -> same place = Not allowed
* anything -> read only directory = Not allowed
* mailing list -> mailing list = Not allowed
* (we currently do not support recursive lists)
* address book card -> different address book = MOVE or COPY
* address book card -> mailing list = COPY only
* (cards currently have to exist outside list for list to work correctly)
* mailing list -> different address book = MOVE only
* (lists currently need to have unique names)
* card in mailing list -> parent mailing list = Not allowed
* card in mailing list -> other mailing list = MOVE or COPY
* card in mailing list -> other address book = MOVE or COPY
* read only directory item -> anywhere = COPY only
*/
canDrop: function(index, orientation, dataTransfer)
{
if (orientation != Components.interfaces.nsITreeView.DROP_ON)
return false;
if (!dataTransfer.types.includes("moz/abcard")) {
return false;
}
let targetURI = gDirectoryTreeView.getDirectoryAtIndex(index).URI;
let srcURI = getSelectedDirectoryURI();
// We cannot allow copy/move to "All Address Books".
if (targetURI == kAllDirectoryRoot + "?")
return false;
// The same place case
if (targetURI == srcURI)
return false;
// determine if we dragging from a mailing list on a directory x to the parent (directory x).
// if so, don't allow the drop
if (srcURI.startsWith(targetURI))
return false;
// check if we can write to the target directory
// e.g. LDAP is readonly currently
var targetDirectory = GetDirectoryFromURI(targetURI);
if (targetDirectory.readOnly)
return false;
var dragSession = dragService.getCurrentSession();
if (!dragSession)
return false;
// XXX Due to bug 373125/bug 349044 we can't specify a default action,
// so we default to move and this means that the user would have to press
// ctrl to copy which most users don't realise.
//
// If target directory is a mailing list, then only allow copies.
// if (targetDirectory.isMailList &&
// dragSession.dragAction != Components.interfaces.
// nsIDragService.DRAGDROP_ACTION_COPY)
//return false;
var srcDirectory = GetDirectoryFromURI(srcURI);
// Only allow copy from read-only directories.
if (srcDirectory.readOnly &&
dragSession.dragAction != Components.interfaces.
nsIDragService.DRAGDROP_ACTION_COPY)
return false;
// Go through the cards checking to see if one of them is a mailing list
// (if we are attempting a copy) - we can't copy mailing lists as
// that would give us duplicate names which isn't allowed at the
// moment.
var draggingMailList = false;
// The data contains the a string of "selected rows", eg.: "1,2".
var rows = dataTransfer.getData("moz/abcard").split(",").map(j => parseInt(j, 10));
for (var j = 0; j < rows.length; j++)
{
if (gAbView.getCardFromRow(rows[j]).isMailList)
{
draggingMailList = true;
break;
}
}
// The rest of the cases - allow cards for copy or move, but only allow
// move of mailing lists if we're not going into another mailing list.
if (draggingMailList &&
(targetDirectory.isMailList ||
dragSession.dragAction == Components.interfaces.
nsIDragService.DRAGDROP_ACTION_COPY))
{
return false;
}
dragSession.canDrop = true;
return true;
},
/**
* onDrop - we don't need to check again for correctness as the
* tree view calls canDrop just before calling onDrop.
*
*/
onDrop: function(index, orientation, dataTransfer)
{
var dragSession = dragService.getCurrentSession();
if (!dragSession)
return;
if (!dataTransfer.types.includes("moz/abcard")) {
return;
}
let targetURI = gDirectoryTreeView.getDirectoryAtIndex(index).URI;
let srcURI = getSelectedDirectoryURI();
// The data contains the a string of "selected rows", eg.: "1,2".
var rows = dataTransfer.getData("moz/abcard").split(",").map(j => parseInt(j, 10));
var numrows = rows.length;
var result;
// needToCopyCard is used for whether or not we should be creating
// copies of the cards in a mailing list in a different address book
// - it's not for if we are moving or not.
var needToCopyCard = true;
if (srcURI.length > targetURI.length) {
result = srcURI.split(targetURI);
if (result[0] != srcURI) {
// src directory is a mailing list on target directory, no need to copy card
needToCopyCard = false;
}
}
else {
result = targetURI.split(srcURI);
if (result[0] != targetURI) {
// target directory is a mailing list on src directory, no need to copy card
needToCopyCard = false;
}
}
// if we still think we have to copy the card,
// check if srcURI and targetURI are mailing lists on same directory
// if so, we don't have to copy the card
if (needToCopyCard) {
var targetParentURI = GetParentDirectoryFromMailingListURI(targetURI);
if (targetParentURI && (targetParentURI == GetParentDirectoryFromMailingListURI(srcURI)))
needToCopyCard = false;
}
var directory = GetDirectoryFromURI(targetURI);
// Only move if we are not transferring to a mail list
var actionIsMoving = (dragSession.dragAction & dragSession.DRAGDROP_ACTION_MOVE) && !directory.isMailList;
let cardsToCopy = [];
for (let j = 0; j < numrows; j++) {
cardsToCopy.push(gAbView.getCardFromRow(rows[j]));
}
for (let card of cardsToCopy) {
if (card.isMailList) {
// This check ensures we haven't slipped through by mistake
if (needToCopyCard && actionIsMoving) {
directory.addMailList(GetDirectoryFromURI(card.mailListURI));
}
} else {
let srcDirectory = null;
if (srcURI == (kAllDirectoryRoot + "?") && actionIsMoving) {
let dirId = card.directoryId.substring(0, card.directoryId.indexOf("&"));
srcDirectory = MailServices.ab.getDirectoryFromId(dirId);
}
directory.dropCard(card, needToCopyCard);
// This is true only if srcURI is "All ABs" and action is moving.
if (srcDirectory) {
let cardArray =
Components.classes["@mozilla.org/array;1"]
.createInstance(Components.interfaces.nsIMutableArray);
cardArray.appendElement(card, false);
srcDirectory.deleteCards(cardArray);
}
}
}
var cardsTransferredText;
// If we are moving, but not moving to a directory, then delete the
// selected cards and display the appropriate text
if (actionIsMoving && srcURI != (kAllDirectoryRoot + "?")) {
// If we have moved the cards, then delete them as well.
gAbView.deleteSelectedCards();
}
if (actionIsMoving) {
cardsTransferredText = PluralForm.get(numrows,
gAddressBookBundle.getFormattedString("contactsMoved", [numrows]));
} else {
cardsTransferredText = PluralForm.get(numrows,
gAddressBookBundle.getFormattedString("contactsCopied", [numrows]));
}
if (srcURI == kAllDirectoryRoot + "?") {
SetAbView(srcURI);
}
document.getElementById("statusText").label = cardsTransferredText;
},
onToggleOpenState: function()
{
},
onCycleHeader: function(colID, elt)
{
},
onCycleCell: function(row, colID)
{
},
onSelectionChanged: function()
{
},
onPerformAction: function(action)
{
},
onPerformActionOnRow: function(action, row)
{
},
onPerformActionOnCell: function(action, row, colID)
{
}
}
function DragAddressOverTargetControl(event)
{
var dragSession = gDragService.getCurrentSession();
if (!dragSession.isDataFlavorSupported("text/x-moz-address"))
return;
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
trans.init(getLoadContext());
trans.addDataFlavor("text/x-moz-address");
var canDrop = true;
for ( var i = 0; i < dragSession.numDropItems; ++i )
{
dragSession.getData ( trans, i );
var dataObj = new Object();
var bestFlavor = new Object();
var len = new Object();
try
{
trans.getAnyTransferData ( bestFlavor, dataObj, len );
}
catch (ex)
{
canDrop = false;
break;
}
}
dragSession.canDrop = canDrop;
}
function DropAddressOverTargetControl(event)
{
var dragSession = gDragService.getCurrentSession();
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/x-moz-address");
for ( var i = 0; i < dragSession.numDropItems; ++i )
{
dragSession.getData ( trans, i );
var dataObj = new Object();
var bestFlavor = new Object();
var len = new Object();
// Ensure we catch any empty data that may have slipped through
try
{
trans.getAnyTransferData ( bestFlavor, dataObj, len);
}
catch (ex)
{
continue;
}
if ( dataObj )
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
if ( !dataObj )
continue;
// pull the address out of the data object
var address = dataObj.data.substring(0, len.value);
if (!address)
continue;
DropRecipient(address);
}
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xul-overlay href="chrome://messenger/content/addressbook/abCardOverlay.xul"?>
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="abcardWindow"
onload="OnLoadEditCard()"
ondialogaccept="return EditCardOKButton();">
<stringbundleset id="stringbundleset"/>
<vbox id="editcard"/>
</dialog>

View file

@ -0,0 +1,613 @@
/* 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/. */
top.MAX_RECIPIENTS = 1;
var inputElementType = "";
var gListCard;
var gEditList;
var oldListName = "";
var gLoadListeners = [];
var gSaveListeners = [];
try
{
var gDragService = Components.classes["@mozilla.org/widget/dragservice;1"]
.getService(Components.interfaces.nsIDragService);
}
catch (e)
{
}
// Returns the load context for the current window
function getLoadContext() {
return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsILoadContext);
}
function awHandleKeyPress(element, event)
{
// allow dialog to close on enter if focused textbox has no value
if (element.value != "" && event.keyCode == KeyEvent.DOM_VK_RETURN) {
event.stopPropagation();
event.preventDefault();
}
}
function mailingListExists(listname)
{
if (MailServices.ab.mailListNameExists(listname))
{
Services.prompt.alert(window,
gAddressBookBundle.getString("mailListNameExistsTitle"),
gAddressBookBundle.getString("mailListNameExistsMessage"));
return true;
}
return false;
}
function GetListValue(mailList, doAdd)
{
var listname = document.getElementById("ListName").value.trim();
if (listname.length == 0)
{
var alertText = gAddressBookBundle.getString("emptyListName");
alert(alertText);
return false;
}
else
{
var canonicalNewListName = listname.toLowerCase();
var canonicalOldListName = oldListName.toLowerCase();
if (doAdd)
{
if (mailingListExists(canonicalNewListName))
return false;
}
else if (canonicalOldListName != canonicalNewListName)
{
if (mailingListExists(canonicalNewListName))
return false;
}
}
mailList.isMailList = true;
mailList.dirName = listname;
mailList.listNickName = document.getElementById('ListNickName').value;
mailList.description = document.getElementById('ListDescription').value;
var oldTotal = mailList.addressLists.length;
var i = 1;
var pos = 0;
var inputField, fieldValue, cardproperty;
while ((inputField = awGetInputElement(i)))
{
fieldValue = inputField.value;
if (doAdd || (!doAdd && pos >= oldTotal))
cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
else
cardproperty = mailList.addressLists.queryElementAt(pos, Components.interfaces.nsIAbCard);
if (fieldValue == "")
{
if (!doAdd && cardproperty)
try
{
mailList.addressLists.removeElementAt(pos);
--oldTotal;
}
catch(ex)
{
// Ignore attempting to remove an item
// at a position greater than the number
// of elements in the addressLists attribute
}
}
else if (cardproperty)
{
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
if (cardproperty)
{
let addrObjects = MailServices.headerParser
.makeFromDisplayAddress(fieldValue, {});
for (let j = 0; j < addrObjects.length; j++)
{
if (j > 0)
{
cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
}
cardproperty.primaryEmail = addrObjects[j].email;
cardproperty.displayName = addrObjects[j].name || addrObjects[j].email;
if (doAdd || (doAdd == false && pos >= oldTotal))
mailList.addressLists.appendElement(cardproperty, false);
}
pos++;
}
}
i++;
}
--i;
if (doAdd == false && i < oldTotal)
{
for (var j = i; j < oldTotal; j++)
mailList.addressLists.removeElementAt(j);
}
return true;
}
function MailListOKButton()
{
var popup = document.getElementById('abPopup');
if (popup)
{
var uri = popup.getAttribute('value');
// FIX ME - hack to avoid crashing if no ab selected because of blank option bug from template
// should be able to just remove this if we are not seeing blank lines in the ab popup
if (!uri)
return false; // don't close window
// -----
//Add mailing list to database
var mailList = Components.classes["@mozilla.org/addressbook/directoryproperty;1"].createInstance();
mailList = mailList.QueryInterface(Components.interfaces.nsIAbDirectory);
if (GetListValue(mailList, true))
{
var parentDirectory = GetDirectoryFromURI(uri);
mailList = parentDirectory.addMailList(mailList);
NotifySaveListeners(mailList);
}
else
return false;
}
return true; // close the window
}
function OnLoadNewMailList()
{
var selectedAB = null;
InitCommonJS();
if ("arguments" in window && window.arguments[0])
{
var abURI = window.arguments[0].selectedAB;
if (abURI && abURI != kAllDirectoryRoot + "?") {
var directory = GetDirectoryFromURI(abURI);
if (directory.isMailList) {
var parentURI = GetParentDirectoryFromMailingListURI(abURI);
if (parentURI) {
selectedAB = parentURI;
}
}
else if (directory.readOnly) {
selectedAB = kPersonalAddressbookURI;
}
else {
selectedAB = abURI;
}
}
}
if (!selectedAB)
selectedAB = kPersonalAddressbookURI;
// set popup with address book names
var abPopup = document.getElementById('abPopup');
abPopup.value = selectedAB;
AppendNewRowAndSetFocus();
awFitDummyRows(1);
document.addEventListener("keypress", awDocumentKeyPress, true);
// focus on first name
var listName = document.getElementById('ListName');
if (listName)
setTimeout( function(firstTextBox) { firstTextBox.focus(); }, 0, listName );
NotifyLoadListeners(directory);
}
function EditListOKButton()
{
//edit mailing list in database
if (GetListValue(gEditList, false))
{
if (gListCard) {
// modify the list card (for the results pane) from the mailing list
gListCard.displayName = gEditList.dirName;
gListCard.lastName = gEditList.dirName;
gListCard.setProperty("NickName", gEditList.listNickName);
gListCard.setProperty("Notes", gEditList.description);
}
NotifySaveListeners(gEditList);
gEditList.editMailListToDatabase(gListCard);
window.arguments[0].refresh = true;
return true; // close the window
}
return false;
}
function OnLoadEditList()
{
InitCommonJS();
gListCard = window.arguments[0].abCard;
var listUri = window.arguments[0].listURI;
gEditList = GetDirectoryFromURI(listUri);
document.getElementById('ListName').value = gEditList.dirName;
document.getElementById('ListNickName').value = gEditList.listNickName;
document.getElementById('ListDescription').value = gEditList.description;
oldListName = gEditList.dirName;
document.title = gAddressBookBundle.getFormattedString("mailingListTitleEdit", [oldListName]);
if (gEditList.addressLists)
{
let total = gEditList.addressLists.length;
if (total)
{
let listbox = document.getElementById('addressingWidget');
let newListBoxNode = listbox.cloneNode(false);
let templateNode = listbox.querySelector("listitem");
top.MAX_RECIPIENTS = 0;
for (let i = 0; i < total; i++)
{
let card = gEditList.addressLists.queryElementAt(i, Components.interfaces.nsIAbCard);
let address = MailServices.headerParser.makeMailboxObject(
card.displayName, card.primaryEmail).toString();
SetInputValue(address, newListBoxNode, templateNode);
}
listbox.parentNode.replaceChild(newListBoxNode, listbox);
}
}
// Is this directory read-only? If so, we now need to set all the fields to
// read-only.
if (gEditList.readOnly) {
const kMailListFields = [ 'ListName', 'ListNickName', 'ListDescription' ];
for (let i = 0; i < kMailListFields.length; ++i)
document.getElementById(kMailListFields[i]).readOnly = true;
document.documentElement.buttons = "accept";
document.documentElement.removeAttribute("ondialogaccept");
// Getting a sane read-only implementation for the addressing widget would
// basically need a separate dialog. Given I'm not sure about the future of
// the mailing list dialog in its current state, let's just disable it
// completely.
document.getElementById("addressingWidget").disabled = true;
}
document.addEventListener("keypress", awDocumentKeyPress, true);
// workaround for bug 118337 - for mailing lists that have more rows than fits inside
// the display, the value of the textbox inside the new row isn't inherited into the input -
// the first row then appears to be duplicated at the end although it is actually empty.
// see awAppendNewRow which copies first row and clears it
setTimeout(AppendLastRow, 0);
NotifyLoadListeners(gEditList);
}
function AppendLastRow()
{
AppendNewRowAndSetFocus();
awFitDummyRows(1);
// focus on first name
var listName = document.getElementById('ListName');
if (listName)
listName.focus();
}
function AppendNewRowAndSetFocus()
{
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(true);
else
awSetFocus(top.MAX_RECIPIENTS, lastInput);
}
function SetInputValue(inputValue, parentNode, templateNode)
{
top.MAX_RECIPIENTS++;
var newNode = templateNode.cloneNode(true);
parentNode.appendChild(newNode); // we need to insert the new node before we set the value of the select element!
var input = newNode.getElementsByTagName(awInputElementName());
if (input && input.length == 1)
{
//We need to set the value using both setAttribute and .value else we will
// lose the content when the field is not visible. See bug 37435
input[0].setAttribute("value", inputValue);
input[0].value = inputValue;
input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);
}
}
function awNotAnEmptyArea(event)
{
//This is temporary until i figure out how to ensure to always having an empty space after the last row
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(false);
event.stopPropagation();
}
function awClickEmptySpace(target, setFocus)
{
if (target == null ||
(target.localName != "listboxbody" &&
target.localName != "listcell" &&
target.localName != "listitem"))
return;
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value)
awAppendNewRow(setFocus);
else
if (setFocus)
awSetFocus(top.MAX_RECIPIENTS, lastInput);
}
function awReturnHit(inputElement)
{
var row = awGetRowByInputElement(inputElement);
if (inputElement.value)
{
var nextInput = awGetInputElement(row+1);
if (!nextInput)
awAppendNewRow(true);
else
awSetFocus(row+1, nextInput);
}
}
function awDeleteRow(rowToDelete)
{
/* When we delete a row, we must reset the id of others row in order to not break the sequence */
var maxRecipients = top.MAX_RECIPIENTS;
awRemoveRow(rowToDelete);
var numberOfCols = awGetNumberOfCols();
for (var row = rowToDelete + 1; row <= maxRecipients; row ++)
for (var col = 1; col <= numberOfCols; col++)
awGetElementByCol(row, col).setAttribute("id", "addressCol" + (col) + "#" + (row-1));
awTestRowSequence();
}
function awInputChanged(inputElement)
{
// AutoCompleteAddress(inputElement);
//Do we need to add a new row?
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
if (lastInput && lastInput.value && !top.doNotCreateANewRow)
awAppendNewRow(false);
top.doNotCreateANewRow = false;
}
function awInputElementName()
{
if (inputElementType == "")
inputElementType = document.getElementById("addressCol1#1").localName;
return inputElementType;
}
function awAppendNewRow(setFocus)
{
var body = document.getElementById("addressingWidget");
var listitem1 = awGetListItem(1);
if (body && listitem1)
{
var nextDummy = awGetNextDummyRow();
var newNode = listitem1.cloneNode(true);
if (nextDummy)
body.replaceChild(newNode, nextDummy);
else
body.appendChild(newNode);
top.MAX_RECIPIENTS++;
var input = newNode.getElementsByTagName(awInputElementName());
if (input && input.length == 1)
{
input[0].setAttribute("value", "");
input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);
if (input[0].getAttribute('focused') != '')
input[0].removeAttribute('focused');
}
// focus on new input widget
if (setFocus && input )
awSetFocus(top.MAX_RECIPIENTS, input[0]);
}
}
// functions for accessing the elements in the addressing widget
function awGetInputElement(row)
{
return document.getElementById("addressCol1#" + row);
}
function _awSetFocus()
{
var listbox = document.getElementById('addressingWidget');
try
{
var theNewRow = awGetListItem(top.awRow);
listbox.ensureElementIsVisible(theNewRow);
top.awInputElement.focus();
}
catch(ex)
{
top.awFocusRetry ++;
if (top.awFocusRetry < 8)
{
dump("_awSetFocus failed, try it again...\n");
setTimeout(_awSetFocus, 0);
}
else
dump("_awSetFocus failed, forget about it!\n");
}
}
function awTabFromRecipient(element, event)
{
//If we are the last element in the listbox, we don't want to create a new row.
if (element == awGetInputElement(top.MAX_RECIPIENTS))
top.doNotCreateANewRow = true;
}
function DragOverAddressListTree(event)
{
var validFlavor = false;
var dragSession = gDragService.getCurrentSession();
// XXX add support for other flavors here
if (dragSession.isDataFlavorSupported("text/x-moz-address")) {
dragSession.canDrop = true;
}
}
function DropOnAddressListTree(event)
{
let dragSession = gDragService.getCurrentSession();
let trans;
try {
trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.init(getLoadContext());
trans.addDataFlavor("text/x-moz-address");
}
catch (ex) {
return;
}
for (let i = 0; i < dragSession.numDropItems; ++i)
{
dragSession.getData(trans, i);
let dataObj = new Object();
let bestFlavor = new Object();
let len = new Object();
trans.getAnyTransferData(bestFlavor, dataObj, len);
if (dataObj)
dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
if (!dataObj)
continue;
// pull the URL out of the data object
let address = dataObj.data.substring(0, len.value);
if (!address)
continue;
DropListAddress(event.target, address);
}
}
function DropListAddress(target, address)
{
// Set focus on a new available, visible row.
awClickEmptySpace(target, true);
if (top.MAX_RECIPIENTS == 0)
top.MAX_RECIPIENTS = 1;
// Break apart the MIME-ready header address into individual addressees to
// add to the dialog.
let addresses = {}, names = {}, fullNames = {};
MailServices.headerParser.parseHeadersWithArray(address, addresses, names,
fullNames);
for (let full of fullNames.value)
{
let lastInput = awGetInputElement(top.MAX_RECIPIENTS);
lastInput.value = full;
awAppendNewRow(true);
}
}
/* Allows extensions to register a listener function for
* when a mailing list is loaded. The listener function
* should take two parameters - the first being the
* mailing list being loaded, the second one being the
* current window document.
*/
function RegisterLoadListener(aListener)
{
gLoadListeners.push(aListener);
}
/* Allows extensions to unload a load listener function.
*/
function UnregisterLoadListener(aListener)
{
var fIndex = gLoadListeners.indexOf(aListener);
if (fIndex != -1)
gLoadListeners.splice(fIndex, 1);
}
/* Allows extensions to register a listener function for
* when a mailing list is saved. Like a load listener,
* the save listener should take two parameters: the first
* being a copy of the mailing list that is being saved,
* and the second being the current window document.
*/
function RegisterSaveListener(aListener)
{
gSaveListeners.push(aListener);
}
/* Allows extensions to unload a save listener function.
*/
function UnregisterSaveListener(aListener)
{
var fIndex = gSaveListeners.indexOf(aListener);
if (fIndex != -1)
gSaveListeners.splice(fIndex, 1);
}
/* Notifies all load listeners.
*/
function NotifyLoadListeners(aMailingList)
{
for (let i = 0; i < gLoadListeners.length; i++)
gLoadListeners[i](aMailingList, document);
}
/* Notifies all save listeners.
*/
function NotifySaveListeners(aMailingList)
{
for (let i = 0; i < gSaveListeners.length; i++)
gSaveListeners[i](aMailingList, document);
}

View file

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xul-overlay href="chrome://messenger/content/addressbook/abCardOverlay.xul"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/abNewCardDialog.dtd">
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="abcardWindow"
onload="OnLoadNewCard()"
ondialogaccept="return NewCardOKButton();">
<stringbundleset id="stringbundleset"/>
<hbox align="center">
<label id="abPopupLabel" control="abPopup" value="&chooseAddressBook.label;" accesskey="&chooseAddressBook.accesskey;"/>
<menulist id="abPopup">
<menupopup id="abPopup-menupopup" class="addrbooksPopup" writable="true"/>
</menulist>
</hbox>
<spacer style="height:1em"/>
<vbox id="editcard"/>
</dialog>

View file

@ -0,0 +1,502 @@
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/**
* Use of items in this file require:
*
* getSelectedDirectoryURI()
* returns the URI of the selected directory
* AbResultsPaneDoubleClick(card)
* Is called when the results pane is double-clicked, with the clicked card.
* AbEditCard(card)
* Is called when a card is to be edited, with the card as the parameter.
*
* The following function is only required if ResultsPaneController is used:
*
* goSetMenuValue()
* Core function in globalOverlay.js
*/
// List/card selections in the results pane.
var kNothingSelected = 0;
var kListsAndCards = 1;
var kMultipleListsOnly = 2;
var kSingleListOnly = 3;
var kCardsOnly = 4;
// Global Variables
// gAbView holds an object with an nsIAbView interface
var gAbView = null;
// Holds a reference to the "abResultsTree" document element. Initially
// set up by SetAbView.
var gAbResultsTree = null;
function SetAbView(aURI)
{
// If we don't have a URI, just clear the view and leave everything else
// alone.
if (!aURI) {
gAbView.clearView();
return;
}
// If we do have a URI, we want to allow updating the review even if the
// URI is the same, as the search results may be different.
var sortColumn = kDefaultSortColumn;
var sortDirection = kDefaultAscending;
if (!gAbResultsTree) {
gAbResultsTree = document.getElementById("abResultsTree");
gAbResultsTree.controllers.appendController(ResultsPaneController);
}
if (gAbView) {
sortColumn = gAbView.sortColumn;
sortDirection = gAbView.sortDirection;
}
else {
if (gAbResultsTree.hasAttribute("sortCol"))
sortColumn = gAbResultsTree.getAttribute("sortCol");
var sortColumnNode = document.getElementById(sortColumn);
if (sortColumnNode && sortColumnNode.hasAttribute("sortDirection"))
sortDirection = sortColumnNode.getAttribute("sortDirection");
}
var directory = GetDirectoryFromURI(aURI);
if (!gAbView)
gAbView = Components.classes["@mozilla.org/addressbook/abview;1"]
.createInstance(Components.interfaces.nsIAbView);
var actualSortColumn = gAbView.setView(directory, GetAbViewListener(),
sortColumn, sortDirection);
gAbResultsTree.treeBoxObject.view =
gAbView.QueryInterface(Components.interfaces.nsITreeView);
UpdateSortIndicators(actualSortColumn, sortDirection);
// If the selected address book is LDAP and the search box is empty,
// inform the user of the empty results pane.
let abResultsTree = document.getElementById("abResultsTree");
let cardViewOuterBox = document.getElementById("CardViewOuterBox");
let blankResultsPaneMessageBox = document.getElementById("blankResultsPaneMessageBox");
if (aURI.startsWith("moz-abldapdirectory://") && !aURI.includes("?")) {
if (abResultsTree)
abResultsTree.hidden = true;
if (cardViewOuterBox)
cardViewOuterBox.hidden = true;
if (blankResultsPaneMessageBox)
blankResultsPaneMessageBox.hidden = false;
} else {
if (abResultsTree)
abResultsTree.hidden = false;
if (cardViewOuterBox)
cardViewOuterBox.hidden = false;
if (blankResultsPaneMessageBox)
blankResultsPaneMessageBox.hidden = true;
}
}
function CloseAbView()
{
if (gAbView)
gAbView.clearView();
}
function GetOneOrMoreCardsSelected()
{
return (gAbView && (gAbView.selection.getRangeCount() > 0));
}
function GetSelectedAddresses()
{
return GetAddressesForCards(GetSelectedAbCards());
}
function GetNumSelectedCards()
{
try {
return gAbView.selection.count;
}
catch (ex) {
}
// if something went wrong, return 0 for the count.
return 0;
}
function GetSelectedCardTypes()
{
var cards = GetSelectedAbCards();
if (!cards) {
Components.utils.reportError("ERROR: GetSelectedCardTypes: |cards| is null.");
return kNothingSelected; // no view
}
var count = cards.length;
if (count == 0)
return kNothingSelected; // nothing selected
var mailingListCnt = 0;
var cardCnt = 0;
for (let i = 0; i < count; i++) {
// We can assume no values from GetSelectedAbCards will be null.
if (cards[i].isMailList)
mailingListCnt++;
else
cardCnt++;
}
return (mailingListCnt == 0) ? kCardsOnly :
(cardCnt > 0) ? kListsAndCards :
(mailingListCnt == 1) ? kSingleListOnly :
kMultipleListsOnly;
}
// NOTE, will return -1 if more than one card selected, or no cards selected.
function GetSelectedCardIndex()
{
if (!gAbView)
return -1;
var treeSelection = gAbView.selection;
if (treeSelection.getRangeCount() == 1) {
var start = new Object;
var end = new Object;
treeSelection.getRangeAt(0, start, end);
if (start.value == end.value)
return start.value;
}
return -1;
}
// NOTE, returns the card if exactly one card is selected, null otherwise
function GetSelectedCard()
{
var index = GetSelectedCardIndex();
return (index == -1) ? null : gAbView.getCardFromRow(index);
}
/**
* Return a (possibly empty) list of cards
*
* It pushes only non-null/empty element, if any, into the returned list.
*/
function GetSelectedAbCards()
{
var abView = gAbView;
// if sidebar is open, and addressbook panel is open and focused,
// then use the ab view from sidebar (gCurFrame is from sidebarOverlay.js)
if (document.getElementById("sidebar-box")) {
const abPanelUrl =
"chrome://messenger/content/addressbook/addressbook-panel.xul";
if (gCurFrame &&
gCurFrame.getAttribute("src") == abPanelUrl &&
document.commandDispatcher.focusedWindow == gCurFrame.contentDocument.defaultView)
abView = gCurFrame.contentDocument.defaultView.gAbView;
}
if (!abView)
return [];
let cards = [];
var count = abView.selection.getRangeCount();
var current = 0;
for (let i = 0; i < count; ++i) {
let start = {};
let end = {};
abView.selection.getRangeAt(i, start, end);
for (let j = start.value; j <= end.value; ++j) {
// avoid inserting null element into the list. GetRangeAt() may be buggy.
let tmp = abView.getCardFromRow(j);
if (tmp) {
cards.push(tmp);
}
}
}
return cards;
}
// XXX todo
// an optimization might be to make this return
// the selected ranges, which would be faster
// when the user does large selections, but for now, let's keep it simple.
function GetSelectedRows()
{
var selectedRows = "";
if (!gAbView)
return selectedRows;
var rangeCount = gAbView.selection.getRangeCount();
for (let i = 0; i < rangeCount; ++i) {
var start = new Object;
var end = new Object;
gAbView.selection.getRangeAt(i, start, end);
for (let j = start.value;j <= end.value; ++j) {
if (selectedRows)
selectedRows += ",";
selectedRows += j;
}
}
return selectedRows;
}
function AbSwapFirstNameLastName()
{
if (gAbView)
gAbView.swapFirstNameLastName();
}
function AbEditSelectedCard()
{
AbEditCard(GetSelectedCard());
}
function AbResultsPaneOnClick(event)
{
// we only care about button 0 (left click) events
if (event.button != 0) return;
// all we need to worry about here is double clicks
// and column header clicks.
//
// we get in here for clicks on the "treecol" (headers)
// and the "scrollbarbutton" (scrollbar buttons)
// we don't want those events to cause a "double click"
var t = event.originalTarget;
if (t.localName == "treecol") {
var sortDirection;
var currentDirection = t.getAttribute("sortDirection");
// Revert the sort order. If none is set, use Ascending.
sortDirection = currentDirection == kDefaultAscending ?
kDefaultDescending : kDefaultAscending;
SortAndUpdateIndicators(t.id, sortDirection);
}
else if (t.localName == "treechildren") {
// figure out what row the click was in
var row = gAbResultsTree.treeBoxObject.getRowAt(event.clientX,
event.clientY);
if (row == -1)
return;
if (event.detail == 2)
AbResultsPaneDoubleClick(gAbView.getCardFromRow(row));
}
}
function AbSortAscending()
{
var sortColumn = gAbResultsTree.getAttribute("sortCol");
SortAndUpdateIndicators(sortColumn, kDefaultAscending);
}
function AbSortDescending()
{
var sortColumn = gAbResultsTree.getAttribute("sortCol");
SortAndUpdateIndicators(sortColumn, kDefaultDescending);
}
function SortResultPane(sortColumn)
{
var sortDirection = kDefaultAscending;
if (gAbView)
sortDirection = gAbView.sortDirection;
SortAndUpdateIndicators(sortColumn, sortDirection);
}
function SortAndUpdateIndicators(sortColumn, sortDirection)
{
UpdateSortIndicators(sortColumn, sortDirection);
if (gAbView)
gAbView.sortBy(sortColumn, sortDirection);
}
function UpdateSortIndicators(colID, sortDirection)
{
var sortedColumn = null;
// set the sort indicator on the column we are sorted by
if (colID) {
sortedColumn = document.getElementById(colID);
if (sortedColumn) {
sortedColumn.setAttribute("sortDirection",sortDirection);
gAbResultsTree.setAttribute("sortCol", colID);
}
}
// remove the sort indicator from all the columns
// except the one we are sorted by
var currCol = gAbResultsTree.firstChild.firstChild;
while (currCol) {
if (currCol != sortedColumn && currCol.localName == "treecol")
currCol.removeAttribute("sortDirection");
currCol = currCol.nextSibling;
}
}
function InvalidateResultsPane()
{
if (gAbResultsTree)
gAbResultsTree.treeBoxObject.invalidate();
}
// Controller object for Results Pane
var ResultsPaneController =
{
supportsCommand: function(command)
{
switch (command) {
case "cmd_selectAll":
case "cmd_delete":
case "button_delete":
case "cmd_properties":
case "cmd_newlist":
case "cmd_newCard":
return true;
default:
return false;
}
},
isCommandEnabled: function(command)
{
switch (command) {
case "cmd_selectAll":
return true;
case "cmd_delete":
case "button_delete":
var numSelected;
var enabled = false;
if (gAbView && gAbView.selection) {
if (gAbView.directory)
enabled = !gAbView.directory.readOnly;
numSelected = gAbView.selection.count;
}
else
numSelected = 0;
// fix me, don't update on isCommandEnabled
if (command == "cmd_delete") {
switch (GetSelectedCardTypes()) {
case kSingleListOnly:
goSetMenuValue(command, "valueList");
break;
case kMultipleListsOnly:
goSetMenuValue(command, "valueLists");
break;
case kListsAndCards:
goSetMenuValue(command, "valueItems");
break;
case kCardsOnly:
default:
if (numSelected < 2)
goSetMenuValue(command, "valueCard");
else
goSetMenuValue(command, "valueCards");
break;
}
}
return (enabled && (numSelected > 0));
case "cmd_properties":
// Temporary fix for SeaMonkey (see bug 1318852).
// goSetLabelAccesskeyTooltiptext() is only defined in mail/.
// This will be removed in due course and therefore the
// block wasn't indented.
if (typeof goSetLabelAccesskeyTooltiptext == "function") {
let labelAttr = "valueGeneric";
let accKeyAttr = "valueGenericAccessKey";
let tooltipTextAttr = "valueGenericTooltipText";
switch (GetSelectedCardTypes()) {
// Set cmd_properties UI according to the type of the selected item(s),
// even with multiple selections for which cmd_properties is
// not yet available and hence disabled.
case kMultipleListsOnly:
case kSingleListOnly:
labelAttr = "valueMailingList";
accKeyAttr = "valueMailingListAccessKey";
tooltipTextAttr = "valueMailingListTooltipText";
break;
case kCardsOnly:
labelAttr = "valueContact";
accKeyAttr = "valueContactAccessKey";
tooltipTextAttr = "valueContactTooltipText";
break;
case kListsAndCards:
default:
//use generic set of attributes declared above
break;
}
// This code is shared between main AB and composition's contacts sidebar.
// Note that in composition, there's no cmd_properties-button (yet);
// the resulting dump() should be ignored.
goSetLabelAccesskeyTooltiptext("cmd_properties-button", null, null,
tooltipTextAttr);
goSetLabelAccesskeyTooltiptext("cmd_properties-contextMenu",
labelAttr, accKeyAttr);
goSetLabelAccesskeyTooltiptext("cmd_properties-menu",
labelAttr, accKeyAttr);
}
// While "Edit Contact" dialogue is still modal (bug 115904, bug 135126),
// only enable "Properties" button for single selection; then fix bug 119999.
return (GetNumSelectedCards() == 1);
case "cmd_newlist":
case "cmd_newCard":
return true;
default:
return false;
}
},
doCommand: function(command)
{
switch (command) {
case "cmd_selectAll":
if (gAbView)
gAbView.selectAll();
break;
case "cmd_delete":
case "button_delete":
AbDelete();
break;
case "cmd_properties":
AbEditSelectedCard();
break;
case "cmd_newlist":
AbNewList();
break;
case "cmd_newCard":
AbNewCard();
break;
}
},
onEvent: function(event)
{
// on blur events set the menu item texts back to the normal values
if (event == "blur")
goSetMenuValue("cmd_delete", "valueDefault");
}
};
function SelectFirstCard()
{
if (gAbView && gAbView.selection && (gAbView.selection.count > 0))
gAbView.selection.select(0);
}

View file

@ -0,0 +1,90 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/addressbook/abResultsPane.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://messenger/locale/addressbook/abResultsPaneOverlay.dtd">
<overlay
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://messenger/content/addressbook/abResultsPane.js"/>
<script type="application/javascript" src="chrome://global/content/nsDragAndDrop.js"/>
<script type="application/javascript" src="chrome://messenger/content/addressbook/abDragDrop.js"/>
<tree id="abResultsTree" flex="1" enableColumnDrag="true" class="plain focusring"
onclick="AbResultsPaneOnClick(event);"
onselect="this.view.selectionChanged(); document.commandDispatcher.updateCommands('addrbook-select');"
sortCol="GeneratedName"
persist="sortCol height">
<treecols id="abResultsTreeCols">
<!-- these column ids must match up to the mork column names, except for GeneratedName, see nsIAddrDatabase.idl -->
<treecol id="GeneratedName"
persist="hidden ordinal width sortDirection" flex="1"
label="&GeneratedName.label;" primary="true"/>
<splitter class="tree-splitter"/>
<treecol id="PrimaryEmail"
persist="hidden ordinal width sortDirection" flex="1"
label="&PrimaryEmail.label;"/>
<splitter class="tree-splitter"/>
<treecol id="_AimScreenName"
persist="hidden ordinal width sortDirection" flex="1"
label="&ScreenName.label;"/>
<splitter class="tree-splitter"/>
<treecol id="Company"
persist="hidden ordinal width sortDirection" flex="1"
label="&Company.label;"/>
<splitter class="tree-splitter"/>
<treecol id="NickName"
persist="hidden ordinal width sortDirection" flex="1"
label="&NickName.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="SecondEmail"
persist="hidden ordinal width sortDirection" flex="1"
label="&SecondEmail.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="Department"
persist="hidden ordinal width sortDirection" flex="1"
label="&Department.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="JobTitle"
persist="hidden ordinal width sortDirection" flex="1"
label="&JobTitle.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="CellularNumber"
persist="hidden ordinal width sortDirection" flex="1"
label="&CellularNumber.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="PagerNumber"
persist="hidden ordinal width sortDirection" flex="1"
label="&PagerNumber.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="FaxNumber"
persist="hidden ordinal width sortDirection" flex="1"
label="&FaxNumber.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="HomePhone"
persist="hidden ordinal width sortDirection" flex="1"
label="&HomePhone.label;" hidden="true"/>
<splitter class="tree-splitter"/>
<treecol id="WorkPhone"
persist="hidden ordinal width sortDirection" flex="1"
label="&WorkPhone.label;"/>
<!-- LOCALIZATION NOTE: _PhoneticName may be enabled for Japanese builds. -->
<!--
<splitter class="tree-splitter"/>
<treecol id="_PhoneticName"
persist="hidden ordinal width sortDirection" flex="1"
label="&_PhoneticName.label;" hidden="true"/>
-->
</treecols>
<treechildren ondragstart="nsDragAndDrop.startDrag(event, abResultsPaneObserver);"/>
</tree>
</overlay>

View file

@ -0,0 +1,439 @@
<?xml version="1.0"?>
<!-- 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/. -->
<bindings id="addrbookBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="addrbooks-menupopup"
extends="chrome://global/content/bindings/popup.xml#popup">
<implementation implements="nsIAbListener">
<!-- A cache of nsIAbDirectory objects. -->
<field name="_directories">[]</field>
<!-- Represents the nsIAbDirectory attribute used as the value of the
parent menulist. Defaults to URI but can be e.g. dirPrefId -->
<field name="_value">this.getAttribute("value") || "URI"</field>
<constructor>
<![CDATA[
Components.utils.import("resource:///modules/mailServices.js");
// Init the address book cache.
const nsIAbDirectory = Components.interfaces.nsIAbDirectory;
let directories = MailServices.ab.directories;
while (directories && directories.hasMoreElements()) {
var ab = directories.getNext();
if (ab instanceof nsIAbDirectory && this._matches(ab))
this._directories.push(ab);
}
this._directories.sort(this._compare);
// Now create menuitems for all displayed directories.
var menulist = this.parentNode;
var value = this._value;
this._directories.forEach(function (ab) {
menulist.appendItem(ab.dirName, ab[value]);
});
if (this.hasAttribute("none")) {
// Create a dummy menuitem representing no selection.
this._directories.unshift(null);
menulist.insertItemAt(0, this.getAttribute("none"), "");
}
// Attempt to select the persisted or otherwise first directory.
menulist.value = menulist.value;
if (!menulist.selectedItem && this.hasChildNodes())
menulist.selectedIndex = 0;
const nsIAbListener = Components.interfaces.nsIAbListener;
// Add a listener so we can update correctly if the list should change
MailServices.ab.addAddressBookListener(this,
nsIAbListener.itemAdded |
nsIAbListener.directoryRemoved |
nsIAbListener.itemChanged);
]]>
</constructor>
<destructor>
<![CDATA[
Components.utils.import("resource:///modules/mailServices.js");
MailServices.ab.removeAddressBookListener(this);
// Empty out anything in the list.
while (this.hasChildNodes())
this.lastChild.remove();
]]>
</destructor>
<!-- nsIAbListener methods -->
<method name="onItemAdded">
<parameter name="aParentDir"/>
<parameter name="aItem"/>
<body><![CDATA[
// Are we interested in this new directory?
if (aItem instanceof Components.interfaces.nsIAbDirectory &&
!aItem.isMailList && this._matches(aItem)) {
this._directories.push(aItem);
this._directories.sort(this._compare);
// Insert the new menuitem at the position to which it was sorted.
this.parentNode.insertItemAt(this._directories.indexOf(aItem),
aItem.dirName, aItem[this._value]);
}
]]></body>
</method>
<method name="onItemRemoved">
<parameter name="aParentDir"/>
<parameter name="aItem"/>
<body><![CDATA[
if (aItem instanceof Components.interfaces.nsIAbDirectory &&
!aItem.isMailList) {
// Find the item in the list to remove
// We can't use indexOf here because we need loose equality
for (var index = this._directories.length; --index >= 0; )
if (this._directories[index] == aItem)
break;
if (index != -1)
// Are we removing the selected directory?
if (this.parentNode.selectedItem ==
this.removeChild(this.childNodes[index]))
// If so, try to select the first directory, if available.
if (this.hasChildNodes())
this.firstChild.doCommand();
else
this.parentNode.selectedItem = null;
}
]]></body>
</method>
<method name="onItemPropertyChanged">
<parameter name="aItem"/>
<parameter name="aProperty"/>
<parameter name="aOldValue"/>
<parameter name="aNewValue"/>
<body><![CDATA[
if (aItem instanceof Components.interfaces.nsIAbDirectory &&
!aItem.isMailList) {
// Find the item in the list to rename.
// We can't use indexOf here because we need loose equality
for (var oldIndex = this._directories.length; --oldIndex >= 0; )
if (this._directories[oldIndex] == aItem)
break;
if (oldIndex != -1) {
// Cache the matching item so that we can use indexOf next time.
aItem = this._directories[oldIndex];
var child = this.childNodes[oldIndex];
child.label = aItem.dirName;
this._directories.sort(this._compare);
// Reorder the menuitems if renaming changed the directory index.
var newIndex = this._directories.indexOf(aItem);
if (newIndex < oldIndex)
this.insertBefore(child, this.childNodes[newIndex]);
else if (newIndex > oldIndex)
this.insertBefore(child, this.childNodes[newIndex].nextSibling);
}
}
]]></body>
</method>
<!-- Private methods -->
<!-- Tests to see whether this directory should display in the list. -->
<method name="_matches">
<parameter name="ab"/>
<body><![CDATA[
// This condition is used for instance when creating cards
if (this.getAttribute("writable") == "true" && ab.readOnly)
return false;
// This condition is used for instance when creating mailing lists
if (this.getAttribute("supportsmaillists") == "true" &&
!ab.supportsMailingLists)
return false;
return this.getAttribute(ab.isRemote ? "localonly" : "remoteonly") != "true";
]]></body>
</method>
<!-- Used to sort directories in order -->
<method name="_compare">
<parameter name="a"/>
<parameter name="b"/>
<body><![CDATA[
// Null at the very top.
if (!a)
return -1;
if (!b)
return 1;
// Personal at the top.
const kPersonalAddressbookURI = "moz-abmdbdirectory://abook.mab";
if (a.URI == kPersonalAddressbookURI)
return -1;
if (b.URI == kPersonalAddressbookURI)
return 1;
// Collected at the bottom.
const kCollectedAddressbookURI = "moz-abmdbdirectory://history.mab";
if (a.URI == kCollectedAddressbookURI)
return 1;
if (b.URI == kCollectedAddressbookURI)
return -1;
// Sort books of the same type by name.
if (a.dirType == b.dirType)
return a.dirName.localeCompare(b.dirName);
// If one of the dirTypes is PAB and the other is something else,
// then the other will go below the one of type PAB.
const PABDirectory = 2;
if (a.dirType == PABDirectory)
return -1;
if (b.dirType == PABDirectory)
return 1;
// Sort anything else by the dir type.
return a.dirType - b.dirType;
]]></body>
</method>
</implementation>
</binding>
<binding id="map-list"
extends="chrome://global/content/bindings/popup.xml#popup">
<implementation>
<property name="mapURL" readonly="true">
<getter><![CDATA[
return this._createMapItURL();
]]></getter>
</property>
<constructor>
<![CDATA[
this._setWidgetDisabled(true);
]]>
</constructor>
<!--
Initializes the necessary address data from an addressbook card.
@param aCard A nsIAbCard to get the address data from.
@param aAddrPrefix A prefix of the card properties to use. Use "Home" or "Work".
-->
<method name="initMapAddressFromCard">
<parameter name="aCard"/>
<parameter name="aAddrPrefix"/>
<body><![CDATA[
let mapItURLFormat = this._getMapURLPref(0);
let doNotShowMap = !mapItURLFormat || !aAddrPrefix || !aCard;
this._setWidgetDisabled(doNotShowMap);
if (doNotShowMap)
return;
this.setAttribute("map_address1", aCard.getProperty(aAddrPrefix + "Address"));
this.setAttribute("map_address2", aCard.getProperty(aAddrPrefix + "Address2"));
this.setAttribute("map_city" , aCard.getProperty(aAddrPrefix + "City"));
this.setAttribute("map_state" , aCard.getProperty(aAddrPrefix + "State"));
this.setAttribute("map_zip" , aCard.getProperty(aAddrPrefix + "ZipCode"));
this.setAttribute("map_country" , aCard.getProperty(aAddrPrefix + "Country"));
]]></body>
</method>
<!--
Initializes the necessary address data from passed in values.
-->
<method name="initMapAddress">
<parameter name="aAddr1"/>
<parameter name="aAddr2"/>
<parameter name="aCity"/>
<parameter name="aState"/>
<parameter name="aZip"/>
<parameter name="aCountry"/>
<body><![CDATA[
let mapItURLFormat = this._getMapURLPref(0);
let doNotShowMap = !mapItURLFormat || !(aAddr1 + aAddr2 + aCity + aState + aZip + aCountry);
this._setWidgetDisabled(doNotShowMap);
if (doNotShowMap)
return;
this.setAttribute("map_address1", aAddr1);
this.setAttribute("map_address2", aAddr2);
this.setAttribute("map_city" , aCity);
this.setAttribute("map_state" , aState);
this.setAttribute("map_zip" , aZip);
this.setAttribute("map_country" , aCountry);
]]></body>
</method>
<!--
Sets the disabled/enabled state of the parent widget (e.g. a button).
-->
<method name="_setWidgetDisabled">
<parameter name="aDisabled"/>
<body><![CDATA[
this.parentNode.disabled = aDisabled;
]]></body>
</method>
<!--
Returns the Map service URL from localized pref. Returns null if there
is none at the given index.
@param aIndex The index of the service to return. 0 is the default service.
-->
<method name="_getMapURLPref">
<parameter name="aIndex"/>
<body><![CDATA[
let url = null;
if (!aIndex) {
url = Services.prefs.getComplexValue("mail.addr_book.mapit_url.format",
Components.interfaces.nsIPrefLocalizedString).data;
} else {
try {
url = Services.prefs.getComplexValue("mail.addr_book.mapit_url." + aIndex + ".format",
Components.interfaces.nsIPrefLocalizedString).data;
} catch (e) { }
}
return url;
]]></body>
</method>
<!--
Builds menuitem elements representing map services defined in prefs
and attaches them to the specified button.
-->
<method name="_listMapServices">
<body><![CDATA[
let index = 1;
let itemFound = true;
let defaultFound = false;
const kUserIndex = 100;
let aMapList = this;
while (aMapList.hasChildNodes()) {
aMapList.lastChild.remove();
}
let defaultUrl = this._getMapURLPref(0);
// Creates the menuitem with supplied data.
function addMapService(aUrl, aName) {
let item = document.createElement("menuitem");
item.setAttribute("url", aUrl);
item.setAttribute("label", aName);
item.setAttribute("type", "radio");
item.setAttribute("name", "mapit_service");
if (aUrl == defaultUrl)
item.setAttribute("checked", "true");
aMapList.appendChild(item);
}
// Generates a useful generic name by cutting out only the host address.
function generateName(aUrl) {
return new URL(aUrl).hostname;
}
// Add all defined map services as menuitems.
while (itemFound) {
let urlName;
let urlTemplate = this._getMapURLPref(index);
if (!urlTemplate) {
itemFound = false;
} else {
// Name is not mandatory, generate one if not found.
try {
urlName = Services.prefs.getComplexValue("mail.addr_book.mapit_url." + index + ".name",
Components.interfaces.nsIPrefLocalizedString).data;
} catch (e) {
urlName = generateName(urlTemplate);
}
}
if (itemFound) {
addMapService(urlTemplate, urlName);
index++;
if (urlTemplate == defaultUrl)
defaultFound = true;
} else if (index < kUserIndex) {
// After iterating the base region provided urls, check for user defined ones.
index = kUserIndex;
itemFound = true;
}
}
if (!defaultFound) {
// If user had put a customized map URL into mail.addr_book.mapit_url.format
// preserve it as a new map service named with the URL.
// 'index' now points to the first unused entry in prefs.
let defaultName = generateName(defaultUrl);
addMapService(defaultUrl, defaultName);
Services.prefs.setCharPref("mail.addr_book.mapit_url." + index + ".format",
defaultUrl);
Services.prefs.setCharPref("mail.addr_book.mapit_url." + index + ".name",
defaultName);
}
]]></body>
</method>
<!--
Save user selected mapping service.
@param aItem The chosen menuitem with map service.
-->
<method name="_chooseMapService">
<parameter name="aItem"/>
<body><![CDATA[
// Save selected URL as the default.
let defaultUrl = Components.classes["@mozilla.org/pref-localizedstring;1"]
.createInstance(Components.interfaces.nsIPrefLocalizedString);
defaultUrl.data = aItem.getAttribute("url");
Services.prefs.setComplexValue("mail.addr_book.mapit_url.format",
Components.interfaces.nsIPrefLocalizedString, defaultUrl);
]]></body>
</method>
<!--
Generate map URL in the href attribute.
-->
<method name="_createMapItURL">
<body><![CDATA[
let urlFormat = this._getMapURLPref(0);
if (!urlFormat)
return null;
let address1 = this.getAttribute("map_address1");
let address2 = this.getAttribute("map_address2");
let city = this.getAttribute("map_city");
let state = this.getAttribute("map_state");
let zip = this.getAttribute("map_zip");
let country = this.getAttribute("map_country");
urlFormat = urlFormat.replace("@A1", encodeURIComponent(address1));
urlFormat = urlFormat.replace("@A2", encodeURIComponent(address2));
urlFormat = urlFormat.replace("@CI", encodeURIComponent(city));
urlFormat = urlFormat.replace("@ST", encodeURIComponent(state));
urlFormat = urlFormat.replace("@ZI", encodeURIComponent(zip));
urlFormat = urlFormat.replace("@CO", encodeURIComponent(country));
return urlFormat;
]]></body>
</method>
</implementation>
<handlers>
<handler event="command">
<![CDATA[
this._chooseMapService(event.target);
event.stopPropagation();
]]>
</handler>
<handler event="popupshowing">
<![CDATA[
this._listMapServices();
]]>
</handler>
</handlers>
</binding>
</bindings>

View file

@ -0,0 +1,94 @@
/* 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/. */
directory {
display: block;
}
section {
display:block;
margin: 15px 20px;
}
sectiontitle {
display:block;
font-weight:bold;
font-family:verdana;
font-size:small;
}
labelrow {
display:block;
}
label {
display:inline;
font-family:verdana;
font-size:small;
}
GeneratedName {
display:block;
font-weight:bold;
font-family:verdana;
margin-top: 20px;
margin-bottom: 3px;
margin-inline-end: 10px;
margin-inline-start: 10px;
}
FirstName, LastName,
HomeAddress, HomeAddress2, HomeCountry,
WorkAddress, WorkAddress2, WorkCountry,
JobTitle, Department, Company, Notes {
display: block;
font-family: verdana;
font-size: small;
}
DisplayName, NickName,
WorkPhone, HomePhone, FaxNumber, PagerNumber, CellularNumber,
HomeCity, HomeState, HomeZipCode,
WorkCity, WorkState, WorkZipCode,
Custom1, Custom2, Custom3, Custom4 {
display: inline;
font-family: verdana;
font-size: small;
}
PrimaryEmail, SecondEmail,
WebPage1, WebPage2 {
display: block;
font-family: verdana;
font-size: small;
text-decoration: underline;
color: #666666;
}
separator {
display: block;
border-bottom: 1px solid #000000;
margin-top: 0px;
margin-bottom: 0px;
margin-inline-end: 0px;
margin-inline-start: 10px;
}
table {
display: table;
}
tr {
display: table-row;
}
td {
display: table-cell;
vertical-align: top;
}
PreferMailFormat {
display: none;
}

View file

@ -0,0 +1,9 @@
# vim: set filetype=python:
# 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/.
DIRS += [
'public',
'src',
]

View file

@ -0,0 +1,394 @@
/* -*- Mode: Java; 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/hostnameUtils.jsm");
var gCurrentDirectory = null;
var gReplicationBundle = null;
var gReplicationService =
Components.classes["@mozilla.org/addressbook/ldap-replication-service;1"].
getService(Components.interfaces.nsIAbLDAPReplicationService);
var gReplicationCancelled = false;
var gProgressText;
var gProgressMeter;
var gDownloadInProgress = false;
var kDefaultMaxHits = 100;
var kDefaultLDAPPort = 389;
var kDefaultSecureLDAPPort = 636;
var kLDAPDirectory = 0; // defined in nsDirPrefs.h
var ldapOfflineObserver = {
observe: function(subject, topic, state)
{
// sanity checks
if (topic != "network:offline-status-changed") return;
setDownloadOfflineOnlineState(state == "offline");
}
}
function Startup()
{
gReplicationBundle = document.getElementById("bundle_replication");
document.getElementById("download").label =
gReplicationBundle.getString("downloadButton");
document.getElementById("download").accessKey =
gReplicationBundle.getString("downloadButton.accesskey");
if ("arguments" in window && window.arguments[0]) {
gCurrentDirectory = window.arguments[0].selectedDirectory;
try {
fillSettings();
} catch (ex) {
dump("pref-directory-add.js:Startup(): fillSettings() exception: "
+ ex + "\n");
}
let oldListName = gCurrentDirectory.dirName;
document.title = gReplicationBundle.getFormattedString("directoryTitleEdit", [oldListName]);
// Only set up the download button for online/offline status toggling
// if the pref isn't locked to disable the button.
if (!Services.prefs.prefIsLocked(gCurrentDirectory.dirPrefId +
".disable_button_download")) {
// Now connect to the offline/online observer
Services.obs.addObserver(ldapOfflineObserver,
"network:offline-status-changed", false);
// Now set the initial offline/online state and update the state
setDownloadOfflineOnlineState(Services.io.offline);
}
} else {
document.title = gReplicationBundle.getString("directoryTitleNew");
fillDefaultSettings();
// Don't add observer here as it doesn't make any sense.
}
}
function onUnload()
{
if ("arguments" in window &&
window.arguments[0] &&
!Services.prefs.prefIsLocked(gCurrentDirectory.dirPrefId +
".disable_button_download")) {
// Remove the observer that we put in on dialog startup
Services.obs.removeObserver(ldapOfflineObserver,
"network:offline-status-changed");
}
}
var progressListener = {
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
{
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START) {
// start the spinning
gProgressMeter.setAttribute("mode", "undetermined");
gProgressText.value = gReplicationBundle.getString(aStatus ?
"replicationStarted" :
"changesStarted");
gDownloadInProgress = true;
document.getElementById("download").label =
gReplicationBundle.getString("cancelDownloadButton");
document.getElementById("download").accessKey =
gReplicationBundle.getString("cancelDownloadButton.accesskey");
}
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP) {
EndDownload(aStatus);
}
},
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
{
gProgressText.value = gReplicationBundle.getFormattedString("currentCount",
[aCurSelfProgress]);
},
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags)
{
},
onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
{
},
onSecurityChange: function(aWebProgress, aRequest, state)
{
},
QueryInterface : function(iid)
{
if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
iid.equals(Components.interfaces.nsISupportsWeakReference) ||
iid.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
}
};
function DownloadNow()
{
if (!gDownloadInProgress) {
gProgressText = document.getElementById("replicationProgressText");
gProgressMeter = document.getElementById("replicationProgressMeter");
gProgressText.hidden = false;
gProgressMeter.hidden = false;
gReplicationCancelled = false;
try {
if (gCurrentDirectory instanceof Components.interfaces.nsIAbLDAPDirectory)
gReplicationService.startReplication(gCurrentDirectory,
progressListener);
else
EndDownload(false);
}
catch (ex) {
EndDownload(false);
}
} else {
gReplicationCancelled = true;
try {
gReplicationService.cancelReplication(gCurrentDirectory.dirPrefId);
}
catch (ex) {
// XXX todo
// perhaps replication hasn't started yet? This can happen if you hit cancel after attempting to replication when offline
dump("unexpected failure while cancelling. ex=" + ex + "\n");
}
}
}
function EndDownload(aStatus)
{
document.getElementById("download").label =
gReplicationBundle.getString("downloadButton");
document.getElementById("download").accessKey =
gReplicationBundle.getString("downloadButton.accesskey");
// stop the spinning
gProgressMeter.setAttribute("mode", "normal");
gProgressMeter.setAttribute("value", "100");
gProgressMeter.hidden = true;
gDownloadInProgress = false;
gProgressText.value =
gReplicationBundle.getString(aStatus ? "replicationSucceeded" :
gReplicationCancelled ? "replicationCancelled" :
"replicationFailed");
}
// fill the settings panel with the data from the preferences.
//
function fillSettings()
{
document.getElementById("description").value = gCurrentDirectory.dirName;
if (gCurrentDirectory instanceof Components.interfaces.nsIAbLDAPDirectory) {
var ldapUrl = gCurrentDirectory.lDAPURL;
document.getElementById("results").value = gCurrentDirectory.maxHits;
document.getElementById("login").value = gCurrentDirectory.authDn;
document.getElementById("hostname").value = ldapUrl.host;
document.getElementById("basedn").value = ldapUrl.dn;
document.getElementById("search").value = ldapUrl.filter;
var sub = document.getElementById("sub");
switch(ldapUrl.scope) {
case Components.interfaces.nsILDAPURL.SCOPE_ONELEVEL:
sub.radioGroup.selectedItem = document.getElementById("one");
break;
default:
sub.radioGroup.selectedItem = sub;
break;
}
var sasl = document.getElementById("saslMechanism");
switch (gCurrentDirectory.saslMechanism) {
case "GSSAPI":
sasl.selectedItem = document.getElementById("GSSAPI");
break;
default:
sasl.selectedItem = document.getElementById("Simple");
break;
}
var secure = ldapUrl.options & ldapUrl.OPT_SECURE
if (secure)
document.getElementById("secure").setAttribute("checked", "true");
if (ldapUrl.port == -1)
document.getElementById("port").value =
(secure ? kDefaultSecureLDAPPort : kDefaultLDAPPort);
else
document.getElementById("port").value = ldapUrl.port;
}
// check if any of the preferences for this server are locked.
//If they are locked disable them
DisableUriFields(gCurrentDirectory.dirPrefId + ".uri");
DisableElementIfPrefIsLocked(gCurrentDirectory.dirPrefId + ".description", "description");
DisableElementIfPrefIsLocked(gCurrentDirectory.dirPrefId + ".disable_button_download", "download");
DisableElementIfPrefIsLocked(gCurrentDirectory.dirPrefId + ".maxHits", "results");
DisableElementIfPrefIsLocked(gCurrentDirectory.dirPrefId + ".auth.dn", "login");
}
function DisableElementIfPrefIsLocked(aPrefName, aElementId)
{
if (Services.prefs.prefIsLocked(aPrefName))
document.getElementById(aElementId).setAttribute('disabled', true);
}
// disables all the text fields corresponding to the .uri pref.
function DisableUriFields(aPrefName)
{
if (Services.prefs.prefIsLocked(aPrefName)) {
let lockedElements = document.querySelectorAll('[disableiflocked="true"]');
for (let i = 0; i < lockedElements.length; i++)
lockedElements[i].setAttribute('disabled', 'true');
}
}
function onSecure()
{
document.getElementById("port").value =
document.getElementById("secure").checked ? kDefaultSecureLDAPPort :
kDefaultLDAPPort;
}
function fillDefaultSettings()
{
document.getElementById("port").value = kDefaultLDAPPort;
document.getElementById("results").value = kDefaultMaxHits;
var sub = document.getElementById("sub");
sub.radioGroup.selectedItem = sub;
// Disable the download button and add some text indicating why.
document.getElementById("download").disabled = true;
document.getElementById("downloadWarningMsg").hidden = false;
document.getElementById("downloadWarningMsg").textContent = document.
getElementById("bundle_addressBook").
getString("abReplicationSaveSettings");
}
function hasCharacters(number)
{
var re = /[0-9]/g;
var num = number.match(re);
if(num && (num.length == number.length))
return false;
else
return true;
}
function onAccept()
{
try {
var pref_string_content = "";
var pref_string_title = "";
var description = document.getElementById("description").value;
var hostname = cleanUpHostName(document.getElementById("hostname").value);
var port = document.getElementById("port").value;
var secure = document.getElementById("secure");
var results = document.getElementById("results").value;
var errorValue = null;
var saslMechanism = "";
if ((!description) || (description.trim() == ""))
errorValue = "invalidName";
else if (!isLegalHostNameOrIP(hostname))
errorValue = "invalidHostname";
// XXX write isValidDn and call it on the dn string here?
else if (port && hasCharacters(port))
errorValue = "invalidPortNumber";
else if (results && hasCharacters(results))
errorValue = "invalidResults";
if (!errorValue) {
// XXX Due to the LDAP c-sdk pass a dummy url to the IO service, then
// update the parts (bug 473351).
let ldapUrl = Services.io.newURI(
(secure.checked ? "ldaps://" : "ldap://") + "localhost/dc=???", null, null)
.QueryInterface(Components.interfaces.nsILDAPURL);
ldapUrl.host = hostname;
ldapUrl.port = port ? port :
(secure.checked ? kDefaultSecureLDAPPort :
kDefaultLDAPPort);
ldapUrl.dn = document.getElementById("basedn").value;
ldapUrl.scope = document.getElementById("one").selected ?
Components.interfaces.nsILDAPURL.SCOPE_ONELEVEL :
Components.interfaces.nsILDAPURL.SCOPE_SUBTREE;
ldapUrl.filter = document.getElementById("search").value;
if (document.getElementById("GSSAPI").selected) {
saslMechanism = "GSSAPI";
}
// check if we are modifying an existing directory or adding a new directory
if (gCurrentDirectory) {
gCurrentDirectory.dirName = description;
gCurrentDirectory.lDAPURL = ldapUrl.QueryInterface(Components.interfaces.nsILDAPURL);
window.opener.gNewServerString = gCurrentDirectory.dirPrefId;
}
else { // adding a new directory
window.opener.gNewServerString =
MailServices.ab.newAddressBook(description, ldapUrl.spec, kLDAPDirectory);
}
// XXX This is really annoying - both new/modify Address Book don't
// give us back the new directory we just created - so go find it from
// rdf so we can set a few final things up on it.
var targetURI = "moz-abldapdirectory://" + window.opener.gNewServerString;
var theDirectory =
MailServices.ab.getDirectory(targetURI)
.QueryInterface(Components.interfaces.nsIAbLDAPDirectory);
theDirectory.maxHits = results;
theDirectory.authDn = document.getElementById("login").value;
theDirectory.saslMechanism = saslMechanism;
window.opener.gNewServer = description;
// set window.opener.gUpdate to true so that LDAP Directory Servers
// dialog gets updated
window.opener.gUpdate = true;
} else {
var addressBookBundle = document.getElementById("bundle_addressBook");
Services.prompt.alert(window,
document.title,
addressBookBundle.getString(errorValue));
return false;
}
} catch (outer) {
dump("Internal error in pref-directory-add.js:onAccept() " + outer + "\n");
}
return true;
}
function onCancel()
{
window.opener.gUpdate = false;
}
// called by Help button in platform overlay
function doHelpButton()
{
openHelp("mail-ldap-properties");
}
// Sets the download button state for offline or online.
// This function should only be called for ldap edit dialogs.
function setDownloadOfflineOnlineState(isOffline)
{
if (isOffline)
{
// Disable the download button and add some text indicating why.
document.getElementById("downloadWarningMsg").textContent = document.
getElementById("bundle_addressBook").
getString("abReplicationOfflineWarning");
}
document.getElementById("downloadWarningMsg").hidden = !isOffline;
document.getElementById("download").disabled = isOffline;
}

View file

@ -0,0 +1,152 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/pref-directory-add.dtd">
<dialog id="addDirectory"
style="width: &newDirectoryWidth;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="Startup();"
onunload="onUnload();"
buttons="accept,cancel"
ondialogaccept="return onAccept();"
ondialogcancel="return onCancel();">
<script type="application/javascript" src="chrome://messenger/content/addressbook/pref-directory-add.js"/>
<stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
<stringbundle id="bundle_replication" src="chrome://messenger/locale/addressbook/replicationProgress.properties"/>
<keyset id="keyset"/>
<vbox id="editDirectory">
<tabbox style="margin:5px">
<tabs id="directoryTabBox">
<tab label="&General.tab;"/>
<tab label="&Offline.tab;"/>
<tab label="&Advanced.tab;"/>
</tabs>
<tabpanels id="directoryTabPanels" flex="1">
<vbox>
<grid flex="1">
<columns>
<column/>
<column flex="1"/>
<column/>
</columns>
<rows>
<row align="center">
<label value="&directoryName.label;" accesskey="&directoryName.accesskey;"
control="description"/>
<textbox id="description" flex="1"/>
<spacer flex="1"/>
</row>
<row align="center">
<label value="&directoryHostname.label;" accesskey="&directoryHostname.accesskey;"
control="hostname"/>
<textbox id="hostname" flex="1" disableiflocked="true" class="uri-element"/>
<spacer flex="1"/>
</row>
<row align="center">
<label value="&directoryBaseDN.label;"
accesskey="&directoryBaseDN.accesskey;"
control="basedn"/>
<vbox>
<textbox id="basedn" disableiflocked="true" class="uri-element"/>
</vbox>
<button label="&findButton.label;"
accesskey="&findButton.accesskey;" disabled="true"/>
</row>
<row align="center">
<label value="&portNumber.label;"
accesskey="&portNumber.accesskey;"
control="port"/>
<hbox>
<textbox id="port" type="number" size="5" min="1"
max="65535" hidespinbuttons="true"
disableiflocked="true"/>
</hbox>
</row>
<row align="center">
<label value="&directoryLogin.label;"
accesskey="&directoryLogin.accesskey;"
control="login"/>
<textbox id="login" flex="1" class="uri-element"/>
</row>
</rows>
</grid>
<separator/>
<checkbox id="secure" label="&directorySecure.label;"
accesskey="&directorySecure.accesskey;"
oncommand="onSecure();" disableiflocked="true"/>
</vbox>
<vbox>
<description>&offlineText.label;</description>
<separator/>
<hbox>
<button id="download" oncommand="DownloadNow();"/>
<spacer flex="1"/>
</hbox>
<description id="downloadWarningMsg" hidden="true" class="error"/>
<description id="replicationProgressText" hidden="true"/>
<progressmeter id="replicationProgressMeter" mode="normal" value="0" hidden="true"/>
</vbox>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&return.label;"
accesskey="&return.accesskey;"
control="results"/>
<hbox align="center">
<textbox id="results" type="number" size="10" min="1"
max="2147483647" increment="10"/>
<label value="&results.label;"/>
</hbox>
</row>
<row align="center">
<label value="&scope.label;" control="scope" accesskey="&scope.accesskey;"/>
<radiogroup id="scope" orient="horizontal">
<radio id="one" value="1" label="&scopeOneLevel.label;"
disableiflocked="true" accesskey="&scopeOneLevel.accesskey;"/>
<radio id="sub" value="2" label="&scopeSubtree.label;"
disableiflocked="true" accesskey="&scopeSubtree.accesskey;"/>
</radiogroup>
</row>
<row>
<label value="&searchFilter.label;"
accesskey="&searchFilter.accesskey;"
control="search"/>
<textbox id="search" multiline="true" flex="1" disableiflocked="true"/>
</row>
<row align="center">
<label value="&saslMechanism.label;" control="saslMechanism" accesskey="&saslMechanism.accesskey;"/>
<menulist id="saslMechanism">
<menupopup>
<menuitem id="Simple" value=""
label="&saslOff.label;"
accesskey="&saslOff.accesskey;"/>
<menuitem id="GSSAPI" value="GSSAPI"
label="&saslGSSAPI.label;"
accesskey="&saslGSSAPI.accesskey;"/>
</menupopup>
</menulist>
</row>
</rows>
</grid>
</tabpanels>
</tabbox>
</vbox>
</dialog>

View file

@ -0,0 +1,142 @@
/* -*- 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
// Listener to refresh the list items if something changes. In all these
// cases we just rebuild the list as it is easier than searching/adding in the
// correct places an would be an infrequent operation.
var gAddressBookAbListener = {
onItemAdded: function(parentDir, item) {
if (item instanceof Components.interfaces.nsIAbDirectory) {
fillDirectoryList();
}
},
onItemRemoved: function(parentDir, item) {
if (item instanceof Components.interfaces.nsIAbDirectory) {
fillDirectoryList();
}
},
onItemPropertyChanged: function(item, property, oldValue, newValue) {
if (item instanceof Components.interfaces.nsIAbDirectory) {
fillDirectoryList();
}
}
};
function onInitEditDirectories()
{
// For AbDeleteDirectory in abCommon.js
gAddressBookBundle = document.getElementById("bundle_addressBook");
// If the pref is locked disable the "Add" button
if (Services.prefs.prefIsLocked("ldap_2.disable_button_add"))
document.getElementById("addButton").setAttribute('disabled', true);
// Fill out the directory list
fillDirectoryList();
const nsIAbListener = Components.interfaces.nsIAbListener;
// Add a listener so we can update correctly if the list should change
MailServices.ab.addAddressBookListener(gAddressBookAbListener,
nsIAbListener.itemAdded |
nsIAbListener.directoryRemoved |
nsIAbListener.itemChanged);
}
function onUninitEditDirectories()
{
MailServices.ab.removeAddressBookListener(gAddressBookAbListener);
}
function fillDirectoryList()
{
var abList = document.getElementById("directoriesList");
// Empty out anything in the list
while (abList.hasChildNodes())
abList.lastChild.remove();
// Init the address book list
let directories = MailServices.ab.directories;
let holdingArray = [];
while (directories && directories.hasMoreElements()) {
let ab = directories.getNext();
if (ab instanceof Components.interfaces.nsIAbDirectory && ab.isRemote)
holdingArray.push(ab);
}
holdingArray.sort(function (a, b) { return a.dirName.localeCompare(b.dirName); });
holdingArray.forEach(function (ab) {
var item = document.createElement('listitem');
item.setAttribute("label", ab.dirName);
item.setAttribute("value", ab.URI);
abList.appendChild(item);
});
}
function selectDirectory()
{
var abList = document.getElementById("directoriesList");
var editButton = document.getElementById("editButton");
var removeButton = document.getElementById("removeButton");
if (abList && abList.selectedItem) {
editButton.removeAttribute("disabled");
// If the disable delete button pref for the selected directory is set,
// disable the delete button for that directory.
let disable = false;
let ab = MailServices.ab.getDirectory(abList.value);
try {
disable = Services.prefs.getBoolPref(ab.dirPrefId + ".disable_delete");
}
catch(ex){
// If this preference is not set, it's ok.
}
if (disable)
removeButton.setAttribute("disabled", true);
else
removeButton.removeAttribute("disabled");
}
else {
editButton.setAttribute("disabled", true);
removeButton.setAttribute("disabled", true);
}
}
function dblClickDirectory(event)
{
// We only care about left click events.
if (event.button != 0)
return;
editDirectory();
}
function editDirectory()
{
var abList = document.getElementById("directoriesList");
if (abList && abList.selectedItem) {
let abURI = abList.value;
let ab = MailServices.ab.getDirectory(abURI);
window.openDialog(ab.propertiesChromeURI, "editDirectory",
"chrome,modal=yes,resizable=no",
{ selectedDirectory: ab });
}
}
function removeDirectory()
{
var abList = document.getElementById("directoriesList");
if (abList && abList.selectedItem)
AbDeleteDirectory(abList.value);
}

View file

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://messenger/skin/" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/addressbook/pref-directory.dtd">
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
id="editDirectories"
title="&pref.ldap.window.title;"
buttons="accept"
onload="onInitEditDirectories();"
onunload="onUninitEditDirectories();">
<script type="application/javascript"
src="chrome://messenger/content/addressbook/abCommon.js"/>
<script type="application/javascript"
src="chrome://messenger/content/addressbook/pref-editdirectories.js"/>
<stringbundle id="bundle_addressBook"
src="chrome://messenger/locale/addressbook/addressBook.properties"/>
<label value="&directoriesText.label;"
accesskey="&directoriesText.accesskey;" control="directoriesList"/>
<hbox flex="1">
<listbox id="directoriesList" flex="1" onselect="selectDirectory();"
ondblclick="dblClickDirectory(event);"/>
<vbox>
<button id="addButton" label="&addDirectory.label;"
accesskey="&addDirectory.accesskey;"
oncommand="AbNewLDAPDirectory();"/>
<button id="editButton" label="&editDirectory.label;"
accesskey="&editDirectory.accesskey;" disabled="true"
oncommand="editDirectory();"/>
<button id="removeButton" label="&deleteDirectory.label;"
accesskey="&deleteDirectory.accesskey;" disabled="true"
oncommand="removeDirectory();"/>
</vbox>
</hbox>
</dialog>

View file

@ -0,0 +1,47 @@
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'nsIAbAddressCollector.idl',
'nsIAbAutoCompleteResult.idl',
'nsIAbBooleanExpression.idl',
'nsIAbCard.idl',
'nsIAbCollection.idl',
'nsIAbDirectory.idl',
'nsIAbDirectoryQuery.idl',
'nsIAbDirectoryQueryProxy.idl',
'nsIAbDirectorySearch.idl',
'nsIAbDirFactory.idl',
'nsIAbDirFactoryService.idl',
'nsIAbDirSearchListener.idl',
'nsIAbItem.idl',
'nsIAbLDAPAttributeMap.idl',
'nsIAbLDIFService.idl',
'nsIAbListener.idl',
'nsIAbManager.idl',
'nsIAbMDBDirectory.idl',
'nsIAbView.idl',
'nsIAddbookUrl.idl',
'nsIAddrDatabase.idl',
'nsIAddrDBAnnouncer.idl',
'nsIAddrDBListener.idl',
'nsIMsgVCardService.idl',
]
if CONFIG['MOZ_LDAP_XPCOM']:
XPIDL_SOURCES += [
'nsIAbLDAPCard.idl',
'nsIAbLDAPDirectory.idl',
'nsIAbLDAPReplicationData.idl',
'nsIAbLDAPReplicationQuery.idl',
'nsIAbLDAPReplicationService.idl',
]
XPIDL_MODULE = 'addrbook'
EXPORTS += [
'nsAbBaseCID.h',
]

View file

@ -0,0 +1,445 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbBaseCID_h__
#define nsAbBaseCID_h__
#include "nsISupports.h"
#include "nsIFactory.h"
#include "nsIComponentManager.h"
//
// The start of the contract ID for address book directory factories.
//
#define NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX \
"@mozilla.org/addressbook/directory-factory;1?name="
//
// The start of the contract ID for address book directory types
//
#define NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX \
"@mozilla.org/addressbook/directory;1?type="
//
// nsAbManager
//
#define NS_ABMANAGER_CONTRACTID \
"@mozilla.org/abmanager;1"
#define NS_ABMANAGERSTARTUPHANDLER_CONTRACTID \
"@mozilla.org/commandlinehandler/general-startup;1?type=addressbook"
#define NS_ABMANAGER_CID \
{ /* {ad81b321-8a8a-42ca-a508-fe659de84586} */ \
0xad81b321, 0x8a8a, 0x42ca, \
{0xa5, 0x08, 0xfe, 0x65, 0x9d, 0x8e, 0x45, 0x86} \
}
//
// nsAbContentHandler
//
#define NS_ABCONTENTHANDLER_CID \
{ /* {a72ad552-0484-4b5f-8d45-2d79158d22e3} */ \
0xa72ad552, 0x0484, 0x4b5f, \
{0x8d, 0x45, 0x2d, 0x79, 0x15, 0x8d, 0x22, 0xe3} \
}
//
// nsAbBSDirectory - the root address book
//
#define NS_ABDIRECTORY_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX "moz-abdirectory"
#define NS_ABDIRECTORY_CID \
{ /* {012D3C24-1DD2-11B2-BA79-B4AD359FC461}*/ \
0x012D3C24, 0x1DD2, 0x11B2, \
{0xBA, 0x79, 0xB4, 0xAD, 0x35, 0x9F, 0xC4, 0x61} \
}
//
// nsAddressBookDB
//
#define NS_ADDRDATABASE_CONTRACTID \
"@mozilla.org/addressbook/carddatabase;1"
#define NS_ADDRDATABASE_CID \
{ /* 63187917-1D19-11d3-A302-001083003D0C */ \
0x63187917, 0x1d19, 0x11d3, \
{0xa3, 0x2, 0x0, 0x10, 0x83, 0x0, 0x3d, 0xc} \
}
//
// nsAbCardProperty
//
#define NS_ABCARDPROPERTY_CONTRACTID \
"@mozilla.org/addressbook/cardproperty;1"
#define NS_ABCARDPROPERTY_CID \
{ /* 2B722171-2CEA-11d3-9E0B-00A0C92B5F0D */ \
0x2b722171, 0x2cea, 0x11d3, \
{0x9e, 0xb, 0x0, 0xa0, 0xc9, 0x2b, 0x5f, 0xd} \
}
//
// nsAbDirProperty
//
#define NS_ABDIRPROPERTY_CONTRACTID \
"@mozilla.org/addressbook/directoryproperty;1"
#define NS_ABDIRPROPERTY_CID \
{ /* 6FD8EC67-3965-11d3-A316-001083003D0C */ \
0x6fd8ec67, 0x3965, 0x11d3, \
{0xa3, 0x16, 0x0, 0x10, 0x83, 0x0, 0x3d, 0xc} \
}
//
// nsAbDirectoryProperties
//
#define NS_ABDIRECTORYPROPERTIES_CONTRACTID \
"@mozilla.org/addressbook/properties;1"
#define NS_ABDIRECTORYPROPERTIES_CID \
{ /* 8b00a972-1dd2-11b2-9d9c-9c377a9c3dba */ \
0x8b00a972, 0x1dd2, 0x11b2, \
{0x9d, 0x9c, 0x9c, 0x37, 0x7a, 0x9c, 0x3d, 0xba} \
}
//
// nsAbAddressCollector
//
#define NS_ABADDRESSCOLLECTOR_CONTRACTID \
"@mozilla.org/addressbook/services/addressCollector;1"
#define NS_ABADDRESSCOLLECTOR_CID \
{ /* e7702d5a-99d8-4648-bab7-919ea29f30b6 */ \
0xe7702d5a, 0x99d8, 0x4648, \
{0xba, 0xb7, 0x91, 0x9e, 0xa2, 0x9f, 0x30, 0xb6} \
}
//
// addbook URL
//
#define NS_ADDBOOKURL_CONTRACTID \
"@mozilla.org/addressbook/services/url;1?type=addbook"
#define NS_ADDBOOKURL_CID \
{ /* ff04c8e6-501e-11d3-a527-0060b0fc0444 */ \
0xff04c8e6, 0x501e, 0x11d3, \
{0xa5, 0x27, 0x0, 0x60, 0xb0, 0xfc, 0x4, 0x44} \
}
//
// addbook Protocol Handler
//
#define NS_ADDBOOK_HANDLER_CONTRACTID \
"@mozilla.org/addressbook/services/addbook;1"
#define NS_ADDBOOK_HANDLER_CID \
{ /* ff04c8e6-501e-11d3-ffcc-0060b0fc0444 */ \
0xff04c8e6, 0x501e, 0x11d3, \
{0xff, 0xcc, 0x0, 0x60, 0xb0, 0xfc, 0x4, 0x44} \
}
//
// directory factory service
//
#define NS_ABDIRFACTORYSERVICE_CONTRACTID \
"@mozilla.org/addressbook/directory-factory-service;1"
#define NS_ABDIRFACTORYSERVICE_CID \
{ /* {F8B212F2-742B-4A48-B7A0-4C44D4DDB121}*/ \
0xF8B212F2, 0x742B, 0x4A48, \
{0xB7, 0xA0, 0x4C, 0x44, 0xD4, 0xDD, 0xB1, 0x21} \
}
//
// mdb directory factory
//
#define NS_ABMDBDIRECTORY "moz-abmdbdirectory"
#define NS_ABMDBDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX NS_ABMDBDIRECTORY
#define NS_ABMDBDIRFACTORY_CID \
{ /* {E1CB9C8A-722D-43E4-9D7B-7CCAE4B0338A}*/ \
0xE1CB9C8A, 0x722D, 0x43E4, \
{0x9D, 0x7B, 0x7C, 0xCA, 0xE4, 0xB0, 0x33, 0x8A} \
}
//
// nsAbMDBDirectory
//
#define NS_ABMDBDIRECTORY_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABMDBDIRECTORY
#define NS_ABMDBDIRECTORY_CID \
{ /* {e618f894-1dd1-11b2-889c-9aaefaa90dde}*/ \
0xe618f894, 0x1dd1, 0x11b2, \
{0x88, 0x9c, 0x9a, 0xae, 0xfa, 0xa9, 0x0d, 0xde} \
}
//
// nsAbMDBCard
//
#define NS_ABMDBCARD_CONTRACTID \
"@mozilla.org/addressbook/moz-abmdbcard;1"
#define NS_ABMDBCARD_CID \
{ /* {f578a5d2-1dd1-11b2-8841-f45cc5e765f8} */ \
0xf578a5d2, 0x1dd1, 0x11b2, \
{0x88, 0x41, 0xf4, 0x5c, 0xc5, 0xe7, 0x65, 0xf8} \
}
#ifdef XP_WIN
//
// nsAbOutlookDirectory
//
#define NS_ABOUTLOOKDIRECTORY_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX "moz-aboutlookdirectory"
#define NS_ABOUTLOOKDIRECTORY_CID \
{ /* {9cc57822-0599-4c47-a399-1c6fa185a05c}*/ \
0x9cc57822, 0x0599, 0x4c47, \
{0xa3, 0x99, 0x1c, 0x6f, 0xa1, 0x85, 0xa0, 0x5c} \
}
//
// Outlook directory factory
//
#define NS_ABOUTLOOKDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX "moz-aboutlookdirectory"
#define NS_ABOUTLOOKDIRFACTORY_CID \
{ /* {558ccc0f-2681-4dac-a066-debd8d26faf6}*/ \
0x558ccc0f, 0x2681, 0x4dac, \
{0xa0, 0x66, 0xde, 0xbd, 0x8d, 0x26, 0xfa, 0xf6} \
}
#endif
//
// Addressbook Query support
//
#define NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID \
"@mozilla.org/addressbook/directory/query-arguments;1"
#define NS_ABDIRECTORYQUERYARGUMENTS_CID \
{ /* {f7dc2aeb-8e62-4750-965c-24b9e09ed8d2} */ \
0xf7dc2aeb, 0x8e62, 0x4750, \
{ 0x96, 0x5c, 0x24, 0xb9, 0xe0, 0x9e, 0xd8, 0xd2 } \
}
#define NS_BOOLEANCONDITIONSTRING_CONTRACTID \
"@mozilla.org/boolean-expression/condition-string;1"
#define NS_BOOLEANCONDITIONSTRING_CID \
{ /* {ca1944a9-527e-4c77-895d-d0466dd41cf5} */ \
0xca1944a9, 0x527e, 0x4c77, \
{ 0x89, 0x5d, 0xd0, 0x46, 0x6d, 0xd4, 0x1c, 0xf5 } \
}
#define NS_BOOLEANEXPRESSION_CONTRACTID \
"@mozilla.org/boolean-expression/n-peer;1"
#define NS_BOOLEANEXPRESSION_CID \
{ /* {2c2e75c8-6f56-4a50-af1c-72af5d0e8d41} */ \
0x2c2e75c8, 0x6f56, 0x4a50, \
{ 0xaf, 0x1c, 0x72, 0xaf, 0x5d, 0x0e, 0x8d, 0x41 } \
}
#define NS_ABDIRECTORYQUERYPROXY_CONTRACTID \
"@mozilla.org/addressbook/directory-query/proxy;1"
#define NS_ABDIRECTORYQUERYPROXY_CID \
{ /* {E162E335-541B-43B4-AAEA-FE591E240CAF}*/ \
0xE162E335, 0x541B, 0x43B4, \
{0xAA, 0xEA, 0xFE, 0x59, 0x1E, 0x24, 0x0C, 0xAF} \
}
// nsAbLDAPDirectory
//
#define NS_ABLDAPDIRECTORY_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX "moz-abldapdirectory"
#define NS_ABLDAPDIRECTORY_CID \
{ /* {783E2777-66D7-4826-9E4B-8AB58C228A52}*/ \
0x783E2777, 0x66D7, 0x4826, \
{0x9E, 0x4B, 0x8A, 0xB5, 0x8C, 0x22, 0x8A, 0x52} \
}
// nsAbLDAPDirectoryQuery
//
#define NS_ABLDAPDIRECTORYQUERY_CONTRACTID \
"@mozilla.org/addressbook/ldap-directory-query;1"
#define NS_ABLDAPDIRECTORYQUERY_CID \
{ /* {783E2777-66D7-4826-9E4B-8AB58C228A53}*/ \
0x783E2777, 0x66D7, 0x4826, \
{0x9E, 0x4B, 0x8A, 0xB5, 0x8C, 0x22, 0x8A, 0x53} \
}
//
// nsAbLDAPCard
//
#define NS_ABLDAPCARD_CONTRACTID \
"@mozilla.org/addressbook/moz-abldapcard"
#define NS_ABLDAPCARD_CID \
{ /* {10307B01-EBD6-465F-B972-1630410F70E6}*/ \
0x10307B01, 0xEBD6, 0x465F, \
{0xB9, 0x72, 0x16, 0x30, 0x41, 0x0F, 0x70, 0xE6} \
}
//
// LDAP directory factory
//
#define NS_ABLDAPDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX "moz-abldapdirectory"
#define NS_ABLDAPDIRFACTORY_CID \
{ /* {8e3701af-8828-426c-84ac-124825c778f8} */ \
0x8e3701af, 0x8828, 0x426c, \
{0x84, 0xac, 0x12, 0x48, 0x25, 0xc7, 0x78, 0xf8} \
}
//
// LDAP autocomplete directory factory
//
#define NS_ABLDAPACDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX "ldap"
#define NS_ABLDAPSACDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX "ldaps"
// nsAbLDAPAutoCompFormatter
// 4e276d6d-9981-46b4-9070-92f344ac5f5a
//
#define NS_ABLDAPAUTOCOMPFORMATTER_CID \
{ 0x4e276d6d, 0x9981, 0x46b4, \
{ 0x90, 0x70, 0x92, 0xf3, 0x44, 0xac, 0x5f, 0x5a }}
#define NS_ABLDAPAUTOCOMPFORMATTER_CONTRACTID \
"@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook"
// nsAbLDAPReplicationService
//
// {ece81280-2639-11d6-b791-00b0d06e5f27}
//
#define NS_ABLDAP_REPLICATIONSERVICE_CID \
{0xece81280, 0x2639, 0x11d6, \
{ 0xb7, 0x91, 0x00, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 }}
#define NS_ABLDAP_REPLICATIONSERVICE_CONTRACTID \
"@mozilla.org/addressbook/ldap-replication-service;1"
// nsAbLDAPReplicationQuery
//
// {5414fff0-263b-11d6-b791-00b0d06e5f27}
//
#define NS_ABLDAP_REPLICATIONQUERY_CID \
{0x5414fff0, 0x263b, 0x11d6, \
{ 0xb7, 0x91, 0x00, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 }}
#define NS_ABLDAP_REPLICATIONQUERY_CONTRACTID \
"@mozilla.org/addressbook/ldap-replication-query;1"
// nsAbLDAPChangeLogQuery
//
// {63E11D51-3C9B-11d6-B7B9-00B0D06E5F27}
#define NS_ABLDAP_CHANGELOGQUERY_CID \
{0x63e11d51, 0x3c9b, 0x11d6, \
{ 0xb7, 0xb9, 0x0, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 }}
#define NS_ABLDAP_CHANGELOGQUERY_CONTRACTID \
"@mozilla.org/addressbook/ldap-changelog-query;1"
// nsAbLDAPProcessReplicationData
//
// {5414fff1-263b-11d6-b791-00b0d06e5f27}
//
#define NS_ABLDAP_PROCESSREPLICATIONDATA_CID \
{0x5414fff1, 0x263b, 0x11d6, \
{ 0xb7, 0x91, 0x00, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 }}
#define NS_ABLDAP_PROCESSREPLICATIONDATA_CONTRACTID \
"@mozilla.org/addressbook/ldap-process-replication-data;1"
// nsAbLDAPProcessChangeLogData
//
// {63E11D52-3C9B-11d6-B7B9-00B0D06E5F27}
#define NS_ABLDAP_PROCESSCHANGELOGDATA_CID \
{0x63e11d52, 0x3c9b, 0x11d6, \
{0xb7, 0xb9, 0x0, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 }}
#define NS_ABLDAP_PROCESSCHANGELOGDATA_CONTRACTID \
"@mozilla.org/addressbook/ldap-process-changelog-data;1"
// nsABView
#define NS_ABVIEW_CID \
{ 0xc5eb5d6a, 0x1dd1, 0x11b2, \
{ 0xa0, 0x25, 0x94, 0xd1, 0x18, 0x1f, 0xc5, 0x9c }}
#define NS_ABVIEW_CONTRACTID \
"@mozilla.org/addressbook/abview;1"
#ifdef XP_MACOSX
//
// nsAbOSXDirectory
//
#define NS_ABOSXDIRECTORY_PREFIX "moz-abosxdirectory"
#define NS_ABOSXCARD_PREFIX "moz-abosxcard"
#define NS_ABOSXDIRECTORY_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX
#define NS_ABOSXDIRECTORY_CID \
{ /* {83781cc6-c682-11d6-bdeb-0005024967b8}*/ \
0x83781cc6, 0xc682, 0x11d6, \
{0xbd, 0xeb, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
}
//
// nsAbOSXCard
//
#define NS_ABOSXCARD_CONTRACTID \
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXCARD_PREFIX
#define NS_ABOSXCARD_CID \
{ /* {89bbf582-c682-11d6-bc9d-0005024967b8}*/ \
0x89bbf582, 0xc682, 0x11d6, \
{0xbc, 0x9d, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
}
//
// OS X directory factory
//
#define NS_ABOSXDIRFACTORY_CONTRACTID \
NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX
#define NS_ABOSXDIRFACTORY_CID \
{ /* {90efe2fe-c682-11d6-9c83-0005024967b8}*/ \
0x90efe2fe, 0xc682, 0x11d6, \
{0x9c, 0x83, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \
}
#endif
#define NS_MSGVCARDSERVICE_CID \
{ 0x3c4ac0da, 0x2cda, 0x4018, \
{ 0x95, 0x51, 0xe1, 0x58, 0xb2, 0xe1, 0x22, 0xd3 }}
#define NS_MSGVCARDSERVICE_CONTRACTID \
"@mozilla.org/addressbook/msgvcardservice;1"
#define NS_ABLDIFSERVICE_CID \
{ 0xdb6f46da, 0x8de3, 0x478d, \
{ 0xb5, 0x39, 0x80, 0x13, 0x98, 0x65, 0x6c, 0xf6 }}
#define NS_ABLDIFSERVICE_CONTRACTID \
"@mozilla.org/addressbook/abldifservice;1"
#endif // nsAbBaseCID_h__

View file

@ -0,0 +1,58 @@
/* -*- Mode: IDL; 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/. */
#include "nsISupports.idl"
interface nsIAbCard;
/**
* nsIAbAddressCollector is the interface to the address collecter service.
* It will save and update the supplied addresses into the address book
* specified by the "mail.collect_addressbook" pref.
*/
[scriptable, uuid(069d3fba-37d4-4158-b401-a8efaeea0b66)]
interface nsIAbAddressCollector : nsISupports {
/**
* Collects email addresses into the address book.
* If a card already exists for the email, the first/last/display names
* will be updated if they are supplied alongside the address.
* If a card does not exist for the email it will be created if aCreateCard
* is true.
*
* @param aAddresses The list of emails (in standard header format)
* to collect into the address book.
* @param aCreateCard Set to true if a card should be created if the
* email address doesn't exist.
* @param aSendFormat The send format to save for the card. See
* nsIAbPreferMailFormat for values. If updating a card
* this value will only be changed if the current value
* for the card is "unknown".
*/
void collectAddress(in AUTF8String aAddresses, in boolean aCreateCard,
in unsigned long aSendFormat);
/**
* Collects a single name and email address into the address book.
* By default, it saves the address without checking for an existing one.
* See collectAddress for the general implementation.
*
* @param aEmail The email address to collect.
* @param aDisplayName The display name associated with the email address.
* @param aCreateCard Set to true if a card should be created if the
* email address doesn't exist (ignored if
* aSkipCheckExisting is true).
* @param aSendFormat The send format to save for the card. See
* nsIAbPreferMailFormat for values. If updating a card
* this value will only be changed if the current value
* for the card is "unknown".
* @param aSkipCheckExisting Optional parameter, if this is set then the
* implementation will skip checking for an
* existing card, and just create a new card.
*/
void collectSingleAddress(in AUTF8String aEmail, in AUTF8String aDisplayName,
in boolean aCreateCard,
in unsigned long aSendFormat,
[optional] in boolean aSkipCheckExisting);
};

View file

@ -0,0 +1,36 @@
/* -*- Mode: C++; 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/. */
#include "nsIAutoCompleteResult.idl"
interface nsIAbCard;
/**
* This interface is used to extend the nsIAutoCompleteResult interface to
* provide extra facilities for obtaining more details of the results of
* an address book search.
*/
[scriptable, uuid(c0d35623-f719-4e43-ae24-573e393f87f9)]
interface nsIAbAutoCompleteResult : nsIAutoCompleteResult {
/**
* Get the card from the result at the given index
*/
nsIAbCard getCardAt(in long index);
/**
* Gets the email to use for the card within the result at the given index.
* This is the email that was matched against for the card where there are
* multiple email addresses on a card.
*
* @param index Index of the autocomplete result to return the value for.
* @result The email address to use from the card.
*/
AString getEmailToUse(in long index);
/**
* The template used to build the query for this search. Optional.
*/
attribute AString modelQuery;
};

View file

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
interface nsIArray;
typedef long nsAbBooleanConditionType;
/**
* Condition types
*
* Constants defining the types of condition
* to obtain a boolean result of TRUE or FALSE
*
*/
[scriptable, uuid(F51387B1-5AEF-4A1C-830E-7CD3B02366CE)]
interface nsIAbBooleanConditionTypes
{
const long Exists = 0;
const long DoesNotExist = 1;
const long Contains = 2;
const long DoesNotContain = 3;
const long Is = 4;
const long IsNot = 5;
const long BeginsWith = 6;
const long EndsWith = 7;
const long LessThan = 8;
const long GreaterThan = 9;
const long SoundsLike = 10;
const long RegExp = 11;
};
typedef long nsAbBooleanOperationType;
/*
* Operation types
*
* Constants defining the boolean operation that
* should be performed between two boolean expressions
*
*/
[uuid(9bdd2e51-2be4-49a4-a558-36d1a812231a)]
interface nsIAbBooleanOperationTypes
{
const long AND = 0;
const long OR = 1;
const long NOT = 2;
};
/**
* String condition
*
* A string condition represents a leaf node in a
* boolean expression tree and represents
* test which will return TRUE or FALSE
*
* Condition is an expression which is a
* leaf node in a boolean expression tree
*
*/
[scriptable, uuid(C3869D72-CFD0-45F0-A0EC-3F67D83C7110)]
interface nsIAbBooleanConditionString : nsISupports
{
/**
* The condition for how the a value
* should be compared
*
*/
attribute nsAbBooleanConditionType condition;
/**
* The lhs of the condition
*
* Represents a property name which
* should be evaluated to obtain the
* lhs.
*
*/
attribute string name;
/**
* The rhs of the condition
*
* <name> [condition] value
*
*/
attribute wstring value;
};
/**
* N Boolean expression type
*
* Supports Unary Binary and N boolean expressions
*
* An operation represents a node in a boolean
* expression tree which may contain one or more
* child conditions or expressions
*
*/
[scriptable, uuid(223a9462-1aeb-4c1f-b069-5fc6278989b2)]
interface nsIAbBooleanExpression: nsISupports
{
/**
* The boolean operation to be applied to
* results of all evaluated expressions
*
*/
attribute nsAbBooleanOperationType operation;
/**
* List of peer expressions
*
* e1 [op] e2 [op] .... en
*
*/
attribute nsIArray expressions;
};

View file

@ -0,0 +1,358 @@
/* -*- Mode: C++; 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/. */
#include "nsIAbItem.idl"
interface nsISimpleEnumerator;
interface nsIVariant;
[scriptable, uuid(97448252-F189-11d4-A422-001083003D0C)]
interface nsIAbPreferMailFormat {
const unsigned long unknown = 0;
const unsigned long plaintext = 1;
const unsigned long html = 2;
};
/**
* An interface representing an address book card.
*
* The UUID of a card is a composition of a directory ID and a per-directory ID.
* The per-directory ID is reflected in the localId property. If either of these
* properties change, the UUID will change correspondingly.
*
* None of these IDs will be reflected in the property collection. Neither
* nsIAbCard::properties, nsIAbCard::deleteProperty, nor any of the property
* getters and setters are able to interact with these properties.
*
* Fundamentally, a card is a collection of properties. Modifying a property in
* some way on a card does not change the backend used to store the card; the
* directory is required to do make the changes here.
*
* The following are the core properties that are used:
* - Names:
* - FirstName, LastName
* - PhoneticFirstName, PhoneticLastName
* - DisplayName, NickName
* - SpouseName, FamilyName
* - PrimaryEmail, SecondEmail
* - Home Contact:
* - HomeAddress, HomeAddress2, HomeCity, HomeState, HomeZipCode, HomeCountry
* - HomePhone, HomePhoneType
* - Work contact. Same as home, but with `Work' instead of `Home'
* - Other Contact:
* - FaxNumber, FaxNumberType
* - PagerNumber, PagerNumberType
* - CellularNumber, CellularNumberType
* - JobTitle, Department, Company
* - _AimScreenName
* - Dates:
* - AnniversaryYear, AnniversaryMonth, AnniversaryDay
* - BirthYear, BirthMonth, BirthDay
* - WebPage1 (work), WebPage2 (home)
* - Custom1, Custom2, Custom3, Custom4
* - Notes
* - Integral properties:
* - LastModifiedDate
* - PopularityIndex
* - PreferMailFormat (see nsIAbPreferMailFormat)
* - Photo properties:
* - PhotoName
* - PhotoType
* - PhotoURI
*
* The contract id for the standard implementation is
* <tt>\@mozilla.org/addressbook/cardproperty;1</tt>.
*/
[scriptable, uuid(9bddf024-5178-4097-894e-d84b4ddde101)]
interface nsIAbCard : nsIAbItem {
/**
* The UUID for the nsIAbDirectory containing this card.
*
* The directory considered to contain this card is the directory which
* produced this card (e.g., through nsIAbDirectory::getCardForProperty) or
* the last directory to modify this card, if another directory did so. If the
* last directory to modify this card deleted it, then this card is considered
* unassociated.
*
* If this card is not associated with a directory, this string will be empty.
*
* There is no standardized way to associate a card with multiple directories.
*
* Consumers of this interface outside of directory implementations SHOULD
* NOT, in general, modify this property.
*/
attribute AUTF8String directoryId;
/**
* The per-directory ID of this card.
*
* This property is the second part of the tuple logically representing a card
* UUID. It shares many requirements with that of nsIAbItem::uuid. In
* particular:
* - It MUST be unique (within the scope of its directory).
* - The empty string MUST only be used to indicate that it has not yet been
* assigned a localId.
* - It is STRONGLY RECOMMENDED that this id is consistent across sessions and
* that, should the card be deleted, its ids will not be reused.
* - The format of localId is left undefined.
*
* As long as directoryId is not changed, this property SHOULD NOT be changed.
* If directoryId is changed, the new directory MAY choose to reuse the same
* localId if reasonable. However, consumers MUST NOT assume that two cards
* with different directoryIds but the same localId are logically the same
* card.
*
* Similar to directoryId, consumers of cards outside of directory
* implementations SHOULD NOT, in general, modify this property.
*/
attribute AUTF8String localId;
/**
* A list of all the properties that this card has as an enumerator, whose
* members are all nsIProperty objects.
*/
readonly attribute nsISimpleEnumerator properties;
/**
* Returns a property for the given name.
*
* @param name The case-sensitive name of the property to get.
* @param defaultValue The value to return if the property does not exist.
* @exception NS_ERROR_NOT_AVAILABLE if the named property does not exist.
* @exception NS_ERROR_CANNOT_CONVERT_DATA if the property cannot be converted
* to the desired type.
*/
nsIVariant getProperty(in AUTF8String name, in nsIVariant defaultValue);
/**
* @{
* Returns a property for the given name. Javascript callers should NOT use these,
* but use getProperty instead. XPConnect will do the type conversion automagically.
*
* These functions convert values in the same manner as the default
* implementation of nsIVariant. Of particular note is that boolean variables
* are converted to integers as in C/C++ (true is a non-zero value), so that
* false will be converted to a string of "0" and not "false."
*
*
* @param name The case-sensitive name of the property to get.
* @exception NS_ERROR_NOT_AVAILABLE if the named property does not exist.
* @exception NS_ERROR_CANNOT_CONVERT_DATA if the property cannot be converted
* to the desired type.
*/
AString getPropertyAsAString(in string name);
AUTF8String getPropertyAsAUTF8String(in string name);
unsigned long getPropertyAsUint32(in string name);
boolean getPropertyAsBool(in string name);
/** @} */
/**
* Assigns the given to value to the property of the given name.
*
* Should the property exist, its value will be overwritten. An
* implementation may impose additional semantic constraints for certain
* properties. However, such constraints might not be checked by this method.
*
* @warning A value MUST be convertible to a string; if this convention is not
* followed, consumers of cards may fail unpredictably or return incorrect
* results.
*
* @param name The case-sensitive name of the property to set.
* @param value The new value of the property.
*/
void setProperty(in AUTF8String name, in nsIVariant value);
/**
* @{
* Sets a property for the given name. Javascript callers should NOT use these,
* but use setProperty instead. XPConnect will do the type conversion automagically.
*
* These functions convert values in the same manner as the default
* implementation of nsIVariant.
*/
void setPropertyAsAString(in string name, in AString value);
void setPropertyAsAUTF8String(in string name, in AUTF8String value);
void setPropertyAsUint32(in string name, in unsigned long value);
void setPropertyAsBool(in string name, in boolean value);
/** @} */
/**
* Deletes the property with the given name.
*
* Some properties may not be deleted. However, the implementation will not
* check this constraint at this method. If such a property is deleted, an
* error may be thrown when the card is modified at the database level.
*
* @param name The case-sensitive name of the property to set.
*/
void deleteProperty(in AUTF8String name);
/**
* @{
* These properties are shorthand for getProperty and setProperty.
*/
attribute AString firstName;
attribute AString lastName;
attribute AString displayName;
attribute AString primaryEmail;
/** @} */
/**
* Determines whether or not a card has the supplied email address in either
* of its PrimaryEmail or SecondEmail attributes.
*
* Note: This function is likely to be temporary whilst we work out proper
* APIs for multi-valued attributes in bug 118665.
*
* @param aEmailAddress The email address to attempt to match against.
* @return True if aEmailAddress matches any of the email
* addresses stored in the card.
*/
boolean hasEmailAddress(in AUTF8String aEmailAddress);
/**
* Translates a card into a specific format.
* The following types are supported:
* - base64xml
* - xml
* - vcard
*
* @param aType The type of item to translate the card into.
* @return A string containing the translated card.
* @exception NS_ERROR_ILLEGAL_VALUE if we do not recognize the type.
*/
AUTF8String translateTo(in AUTF8String aType);
/**
* Translates a card from the specified format
*/
//void translateFrom(in AUTF8String aType, in AUTF8String aData);
/**
* Generate a phonetic name from the card, using the firstName and lastName
* values.
*
* @param aLastNameFirst Set to True to put the last name before the first.
* @return A string containing the generated phonetic name.
*/
AString generatePhoneticName(in boolean aLastNameFirst);
/**
* Generate a chat name from the card, containing the value of the
* first non-empty chat field.
*
* @return A string containing the generated chat name.
*/
AString generateChatName();
/**
* This function will copy all values from one card to another.
*
* @param srcCard The source card to copy values from.
*/
void copy(in nsIAbCard aSrcCard);
/**
* Returns true if this card is equal to the other card.
*
* The default implementation defines equal as this card pointing to the
* same object as @arg aCard; another implementation defines it as equality of
* properties and values.
*
* @warning The exact nature of equality is still undefined, and actual
* results may not match theoretical results. Most notably, the code
* <tt>a.equals(b) == b.equals(a)</tt> might not return true. In
* particular, calling equals on cards from different address books
* may return inaccurate results.
*
*
* @return Equality, as defined above.
* @param aCard The card to compare against.
*/
boolean equals(in nsIAbCard aCard);
// PROPERTIES TO BE DELETED AS PART OF REWRITE
attribute boolean isMailList;
/**
* If isMailList is true then mailListURI
* will contain the URI of the associated
* mail list
*/
attribute string mailListURI;
};
%{C++
// A nice list of properties for the benefit of C++ clients
#define kFirstNameProperty "FirstName"
#define kLastNameProperty "LastName"
#define kDisplayNameProperty "DisplayName"
#define kNicknameProperty "NickName"
#define kPriEmailProperty "PrimaryEmail"
#define kPreferMailFormatProperty "PreferMailFormat"
#define kLastModifiedDateProperty "LastModifiedDate"
#define kPopularityIndexProperty "PopularityIndex"
#define kPhoneticFirstNameProperty "PhoneticFirstName"
#define kPhoneticLastNameProperty "PhoneticLastName"
#define kSpouseNameProperty "SpouseName"
#define kFamilyNameProperty "FamilyName"
#define k2ndEmailProperty "SecondEmail"
#define kHomeAddressProperty "HomeAddress"
#define kHomeAddress2Property "HomeAddress2"
#define kHomeCityProperty "HomeCity"
#define kHomeStateProperty "HomeState"
#define kHomeZipCodeProperty "HomeZipCode"
#define kHomeCountryProperty "HomeCountry"
#define kHomeWebPageProperty "WebPage2"
#define kWorkAddressProperty "WorkAddress"
#define kWorkAddress2Property "WorkAddress2"
#define kWorkCityProperty "WorkCity"
#define kWorkStateProperty "WorkState"
#define kWorkZipCodeProperty "WorkZipCode"
#define kWorkCountryProperty "WorkCountry"
#define kWorkWebPageProperty "WebPage1"
#define kHomePhoneProperty "HomePhone"
#define kHomePhoneTypeProperty "HomePhoneType"
#define kWorkPhoneProperty "WorkPhone"
#define kWorkPhoneTypeProperty "WorkPhoneType"
#define kFaxProperty "FaxNumber"
#define kFaxTypeProperty "FaxNumberType"
#define kPagerTypeProperty "PagerNumberType"
#define kPagerProperty "PagerNumber"
#define kCellularProperty "CellularNumber"
#define kCellularTypeProperty "CellularNumberType"
#define kJobTitleProperty "JobTitle"
#define kDepartmentProperty "Department"
#define kCompanyProperty "Company"
#define kScreenNameProperty "_AimScreenName"
#define kCustom1Property "Custom1"
#define kCustom2Property "Custom2"
#define kCustom3Property "Custom3"
#define kCustom4Property "Custom4"
#define kNotesProperty "Notes"
#define kGtalkProperty "_GoogleTalk"
#define kAIMProperty "_AimScreenName"
#define kYahooProperty "_Yahoo"
#define kSkypeProperty "_Skype"
#define kQQProperty "_QQ"
#define kMSNProperty "_MSN"
#define kICQProperty "_ICQ"
#define kXMPPProperty "_JabberId"
#define kIRCProperty "_IRC"
#define kAnniversaryYearProperty "AnniversaryYear"
#define kAnniversaryMonthProperty "AnniversaryMonth"
#define kAnniversaryDayProperty "AnniversaryDay"
#define kBirthYearProperty "BirthYear"
#define kBirthMonthProperty "BirthMonth"
#define kBirthDayProperty "BirthDay"
%}

View file

@ -0,0 +1,92 @@
/* -*- Mode: C++; 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/. */
#include "nsIAbItem.idl"
interface nsIAbCard;
interface nsISimpleEnumerator;
/**
* A collection of address book items.
*/
[scriptable, uuid(70f6123f-e06b-4101-9750-4ce73b38134b)]
interface nsIAbCollection : nsIAbItem {
/**
* Returns true if this collection is read-only.
*/
readonly attribute boolean readOnly;
/**
* Returns true if this collection is accessed over a network connection.
*/
readonly attribute boolean isRemote;
/**
* Returns true if this collection is accessed over a secure connection.
*
* If isRemote returns false, then this value MUST be false as well.
*/
readonly attribute boolean isSecure;
/**
* Returns an address book card for the specified email address if found.
*
* If there are multiple cards with the given email address, this method will
* return one of these cards in an implementation-defined manner.
*
* Matching is performed in a case-insensitive manner.
*
* This method performs a synchronous operation. If the collection cannot do
* the search in such a manner, then it should throw NS_ERROR_NOT_IMPLEMENTED.
*
* @param emailAddress The email address to find in any of the email address
* fields. If emailAddress is empty, the database won't
* be searched and the function will return as if no card
* was found.
* @return An nsIAbCard if one was found, else returns NULL.
* @exception NS_ERROR_NOT_IMPLEMENTED If the collection cannot do this.
*/
nsIAbCard cardForEmailAddress(in AUTF8String emailAddress);
/**
* Returns an address book card for the specified property if found.
*
* If there are multiple cards with the given value for the property, this
* method will return one of these cards in an implementation-defined manner.
*
* This method performs a synchronous operation. If the collection cannot do
* the search in such a manner, then it should throw NS_ERROR_NOT_IMPLEMENTED.
*
* If the property is not natively a string, it can still be searched for
* using the string-encoded value of the property, e.g. "0". See
* nsIAbCard::getPropertyAsAUTF8String for more information. Empty values will
* return no match, to prevent spurious results.
*
* @param aProperty The property to look for.
* @param aValue The value to search for.
* @param aCaseSensitive True if matching should be done case-sensitively.
* @result An nsIAbCard if one was found, else returns NULL.
* @exception NS_ERROR_NOT_IMPLEMENTED If the collection cannot do this.
*/
nsIAbCard getCardFromProperty(in string aProperty, in AUTF8String aValue,
in boolean aCaseSensitive);
/**
* Returns all address book cards with a specific property matching value
*
* This function is almost identical to getCardFromProperty, with the
* exception of returning all cards rather than just the first.
*
* @param aProperty The property to look for.
* @param aValue The value to search for.
* @param aCaseSensitive True if matching should be done case-sensitively.
* @result A nsISimpleEnumerator that holds nsIAbCard
* instances.
*/
nsISimpleEnumerator getCardsFromProperty(in string aProperty,
in AUTF8String aValue,
in boolean aCaseSensitive);
};

View file

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
#include "nsISimpleEnumerator.idl"
interface nsIAbDirectory;
[scriptable, uuid(ad61b4fc-d8d8-40b2-b924-4c10f28a8a17)]
interface nsIAbDirFactory : nsISupports
{
/**
* Get a top level address book directory and sub directories, given some
* properties.
*
* @param aDirName Name of the address book
*
* @param aURI URI of the address book
*
* @param aPrefName Pref name for the preferences of the address book
*
* @return Enumeration of nsIAbDirectory interfaces
*/
nsISimpleEnumerator getDirectories(in AString aDirName, in ACString aURI,
in ACString aPrefName);
/**
* Delete a top level address book directory
*
*/
void deleteDirectory (in nsIAbDirectory directory);
};

View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIAbDirFactory;
[scriptable, uuid(154a951b-a310-400c-b98f-d769cc5d575f)]
interface nsIAbDirFactoryService : nsISupports
{
/**
* Obtain a directory factory component given a uri representing an address
* book. The scheme is extracted from the uri and contract id is generated
* of the form:
* @mozilla.org/addressbook/directory-factory;1?name=<scheme>
*
* This id is used to instantiate a registered component which implemented
* the nsIAbDirFactory interface.
*
* @param aURI The uri which contains the scheme that defines what directory
* factory instance is returned
*/
nsIAbDirFactory getDirFactory(in ACString aURI);
};

View file

@ -0,0 +1,15 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIAbCard;
[scriptable, uuid(eafe2488-4efb-4ac8-a6b4-7756eb1650a3)]
interface nsIAbDirSearchListener : nsISupports {
void onSearchFinished(in long aResult, in AString aErrorMsg);
void onSearchFoundCard(in nsIAbCard aCard);
};

View file

@ -0,0 +1,296 @@
/* -*- Mode: C++; 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/. */
#include "nsIAbCollection.idl"
#include "nsIAbCard.idl"
interface nsISimpleEnumerator;
interface nsIArray;
interface nsIMutableArray;
/* moz-abdirectory:// is the URI to access nsAbBSDirectory,
* which is the root directory for all types of address books
* this is used to get all address book directories. */
%{C++
#define kAllDirectoryRoot "moz-abdirectory://"
#define kPersonalAddressbook "abook.mab"
#define kPersonalAddressbookUri "moz-abmdbdirectory://abook.mab"
#define kCollectedAddressbook "history.mab"
#define kCollectedAddressbookUri "moz-abmdbdirectory://history.mab"
#define kABFileName_PreviousSuffix ".na2" /* final v2 address book format */
#define kABFileName_PreviousSuffixLen 4
#define kABFileName_CurrentSuffix ".mab" /* v3 address book extension */
%}
/**
* A top-level address book directory.
*
* Please note that in order to be properly instantiated by nsIAbManager, every
* type of nsIAbDirectory must have a contract ID of the form:
*
* @mozilla.org/addressbook/directory;1?type=<AB URI Scheme>
*
* Where AB URI Scheme does not include the ://. For example, for the Mork-based
* address book, the scheme is "moz-abmdbdirectory", so the contract ID for
* the Mork-based address book type is:
*
* @mozilla.org/addressbook/directory;1?type=moz-abmdbdirectory
*
* The UUID of an nsIAbDirectory is its preference ID and its name, concatenated
* together.
*/
[scriptable, uuid(72dc868b-db5b-4daa-b6c6-071be4a05d02)]
interface nsIAbDirectory : nsIAbCollection {
/**
* The chrome URI to use for bringing up a dialog to edit this directory.
* When opening the dialog, use a JS argument of
* {selectedDirectory: thisdir} where thisdir is this directory that you just
* got the chrome URI from.
*/
readonly attribute ACString propertiesChromeURI;
/**
* The description of the directory. If this directory is not a mailing list,
* then setting this attribute will send round a "DirName" update via
* nsIAddrBookSession.
*/
attribute AString dirName;
// XXX This should really be replaced by a QI or something better
readonly attribute long dirType;
// eliminated a bit more.
// The filename for address books within this directory.
readonly attribute ACString fileName;
// The URI of the address book
readonly attribute ACString URI;
// The position of the directory on the display.
readonly attribute long position;
// will be used for LDAP replication
attribute unsigned long lastModifiedDate;
// Defines whether this directory is a mail
// list or not
attribute boolean isMailList;
// Get the children directories
readonly attribute nsISimpleEnumerator childNodes;
/**
* Get the cards associated with the directory. This will return the cards
* associated with the mailing lists too.
*/
readonly attribute nsISimpleEnumerator childCards;
/**
* Returns true if this directory represents a query - i.e. the rdf resource
* was something like moz-abmdbdirectory://abook.mab?....
*/
readonly attribute boolean isQuery;
/**
* Initializes a directory, pointing to a particular
* URI
*/
void init(in string aURI);
// Deletes either a mailing list or a top
// level directory, which also updates the
// preferences
void deleteDirectory(in nsIAbDirectory directory);
// Check if directory contains card
// If the implementation is asynchronous the card
// may not yet have arrived. If it is in the process
// of obtaining cards the method will throw an
// NS_ERROR_NOT_AVAILABLE exception if the card
// cannot be found.
boolean hasCard(in nsIAbCard cards);
// Check if directory contains directory
boolean hasDirectory(in nsIAbDirectory dir);
// Check if directory contains a mailinglist by name
boolean hasMailListWithName(in wstring aName);
/**
* Adds a card to the database.
*
* This card does not need to be of the same type as the database, e.g., one
* can add an nsIAbLDAPCard to an nsIAbMDBDirectory.
*
* @return "Real" card (eg nsIAbLDAPCard) that can be used for some
* extra functions.
*/
nsIAbCard addCard(in nsIAbCard card);
/**
* Modifies a card in the database to match that supplied.
*/
void modifyCard(in nsIAbCard modifiedCard);
/**
* Deletes the array of cards from the database.
*
* @param aCards The cards to delete from the database.
*/
void deleteCards(in nsIArray aCards);
void dropCard(in nsIAbCard card, in boolean needToCopyCard);
/**
* Whether or not the directory should be searched when doing autocomplete,
* (currently by using GetChildCards); LDAP does not support this in online
* mode, so that should return false; additionally any other directory types
* that also do not support GetChildCards should return false.
*
* @param aIdentity An optional parameter detailing the identity key (see
* nsIMsgAccountManager) that this autocomplete is being
* run against.
* @return True if this directory should/can be used during
* local autocomplete.
*/
boolean useForAutocomplete(in ACString aIdentityKey);
/**
* Does this directory support mailing lists? Note that in the case
* this directory is a mailing list and nested mailing lists are not
* supported, this will return false rather than true which the parent
* directory might.
*/
readonly attribute boolean supportsMailingLists;
/**
* This attribute serves two purposes
* 1. If this directory is not a mail list, directories are stored here
* 2. If it is a mail list card entries are stored here
*
* @note This is a *live* array and not a static copy
*/
attribute nsIMutableArray addressLists;
// Specific to a directory which stores mail lists
/**
* Creates a new mailing list in the directory. Currently only supported
* for top-level directories.
*
* @param list The new mailing list to add.
* @return The mailing list directory added, which may have been modified.
*/
nsIAbDirectory addMailList(in nsIAbDirectory list);
/**
* Nick Name of the mailing list. This attribute is only really used when
* the nsIAbDirectory represents a mailing list.
*/
attribute AString listNickName;
/**
* Description of the mailing list. This attribute is only really used when
* the nsIAbDirectory represents a mailing list.
*/
attribute AString description;
/**
* Edits an existing mailing list (specified as listCard) into its parent
* directory. You should call this function on the resource with the same
* uri as the listCard.
*
* @param listCard A nsIAbCard version of the mailing list with the new
* values.
*/
void editMailListToDatabase(in nsIAbCard listCard);
// Copies mail list properties from the srcList
void copyMailList(in nsIAbDirectory srcList);
/**
* Only creates a top level address book
* which is stored in the preferences
*
* Need to change to factory based approach
* to create new address books
*
* This method should become redundant or
* be only associated with card folders
*
* The parameters are the same as for
* nsIAbManager::newAddressBook
*/
ACString createNewDirectory(in AString aDirName, in ACString aURI,
in unsigned long aType, in ACString aPrefName);
/* create a directory by passing the display name and address book uri */
void createDirectoryByURI(in AString displayName, in ACString aURI);
/**
* The id of the directory used in prefs e.g. "ldap_2.servers.pab"
* Setting this will cause directoryPrefs to be updated.
*/
attribute ACString dirPrefId;
/**
* @name getXXXValue
*
* Helper functions to get different types of pref, but return a default
* value if a pref value was not obtained.
*
* @param aName The name of the pref within the branch dirPrefId to
* get a value from.
*
* @param aDefaultValue The default value to return if getting the pref fails
* or the pref is not present.
*
* @return The value of the pref or the default value.
*
* @exception NS_ERROR_NOT_INITIALIZED if the pref branch couldn't
* be obtained (e.g. dirPrefId isn't set).
*/
//@{
long getIntValue(in string aName, in long aDefaultValue);
boolean getBoolValue(in string aName, in boolean aDefaultValue);
ACString getStringValue(in string aName, in ACString aDefaultValue);
AUTF8String getLocalizedStringValue(in string aName, in AUTF8String aDefaultValue);
//@}
/**
* The following attributes are read from an nsIAbDirectory via the above methods:
*
* HidesRecipients (Boolean)
* If true, and this nsIAbDirectory is a mailing list, then when sending mail to
* this list, recipients addresses will be hidden from one another by sending
* via BCC.
*/
/**
* @name setXXXValue
*
* Helper functions to set different types of pref values.
*
* @param aName The name of the pref within the branch dirPrefId to
* get a value from.
*
* @param aValue The value to set the pref to.
*
* @exception NS_ERROR_NOT_INITIALIZED if the pref branch couldn't
* be obtained (e.g. dirPrefId isn't set).
*/
//@{
void setIntValue(in string aName, in long aValue);
void setBoolValue(in string aName, in boolean aValue);
void setStringValue(in string aName, in ACString aValue);
void setLocalizedStringValue(in string aName, in AUTF8String aValue);
//@}
};

View file

@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
interface nsIAbDirSearchListener;
interface nsIAbCard;
interface nsIAbDirectory;
/**
* The arguments for a query.
*
* Contains an expression for perform matches
* and an array of properties which should be
* returned if a match is found from the expression
*
*/
[scriptable, uuid(03af3018-2590-4f4c-a88c-1fff6595ef05)]
interface nsIAbDirectoryQueryArguments : nsISupports
{
/**
* Defines the boolean expression for
* the matching of cards
*
*/
attribute nsISupports expression;
/**
* Defines if sub directories should be
* queried
*
*/
attribute boolean querySubDirectories;
/**
* A parameter which can be used to pass in data specific to a particular
* type of addressbook.
*/
attribute nsISupports typeSpecificArg;
/**
* A custom search filter which user wants to use in LDAP query.
*/
attribute AUTF8String filter;
};
[scriptable, uuid(3A6E0C0C-1DD2-11B2-B23D-EA3A8CCB333C)]
interface nsIAbDirectoryQueryPropertyValue : nsISupports
{
/**
* The property which should be matched
*
* For example 'primaryEmail' or 'homePhone'
* for card properties.
*
* Two further properties are defined that
* do not exist as properties on a card.
*
* 'card:nsIAbCard' which represents the interface
* of a card component
*
*/
readonly attribute string name;
/**
* The value of the property
*
*/
readonly attribute wstring value;
/**
* The value of the property
* as an interface
*
* Only valid if the corresponding
* property name is related to an
* interface instead of a wstring
*
*/
readonly attribute nsISupports valueISupports;
};
[scriptable, uuid(516e7ffa-69bc-41db-a493-dfb4895832f3)]
interface nsIAbDirectoryQueryResultListener : nsISupports
{
/**
* Called when a match is found. May be called from a different thread to
* the one that initiates the query.
*
* @param aCard An individual result associated returned from a query
*/
void onQueryFoundCard(in nsIAbCard aCard);
/**
* List of defined query results
*
*/
const long queryResultMatch = 0;
const long queryResultComplete = 1;
const long queryResultStopped = 2;
const long queryResultError = 3;
/**
* Called when a query has finished. May be called from a different thread
* to the one that initiates the query.
*
* @param aResult A result code from the list above.
*
* @param aErrorCode An error code specific to the type of query.
*/
void onQueryResult(in long aResult, in long aErrorCode);
};
[scriptable, uuid(60b5961c-ce61-47b3-aa99-6d865f734dee)]
interface nsIAbDirectoryQuery : nsISupports
{
/**
* Initiates a query on a directory and sub-directories for properties
* on cards
*
* @param aDirectory A directory that the query may get extra details
* from.
*
* @param aArguments The properties and values to match value could of
* type nsIAbDirectoryQueryMatchItem for matches other
* than ?contains?
*
* @param aListener The listener which will obtain individual query
* results.
*
* @param aResultLimit Limits the number of results returned to a maximum
* value.
*
* @param aTimeOut The maximum length of time for the query
*
* @return A context id for the query
*/
long doQuery(in nsIAbDirectory aDirectory,
in nsIAbDirectoryQueryArguments aArguments,
in nsIAbDirSearchListener aListener,
in long aResultLimit,
in long aTimeOut);
/**
* Stops an existing query operation if
* query operation is asynchronous
*
* The nsIAbDirectoryQueryResultListener will
* be notified when query has stopped
*
* It is implementation specific if notification
* synchronous or asynchronous
*
* @param contextID
* The unique number returned from
* the doQuery methods
*
*/
void stopQuery (in long contextID);
};

View file

@ -0,0 +1,14 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsIAbDirectoryQuery.idl"
[scriptable, uuid(b8034849-1e98-4d39-819c-15ba61a7434f)]
interface nsIAbDirectoryQueryProxy : nsIAbDirectoryQuery
{
void initiate();
};

View file

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
/**
* Searching of cards on a directory.
*
* The search data is defined in the query
* section of the directory URI, for example
*
* moz-abldapdirectory://ldap1.holland/dc=sun,dc=com?<query>
*
* If no search data is defined then the methods
* will return immediately with no error.
*/
[scriptable, uuid(ABF26047-37E3-44FD-A28A-6D37A1B9CCB3)]
interface nsIAbDirectorySearch : nsISupports
{
/**
* Starts a search on the directory.
*
* If a search is already being performed
* it is stopped.
*
* The results from a search, cards, will
* returned by informing the address book
* session that a new card has been added
* to the directory.
*
* The nsIAbDirectoryQuery implementation
* of the directory component (or a proxy)
* may be used as an implementation for
* this specialization of query.
*
* This method is semantically equivalent
* to the nsIAbDirectory.getChildCards
* method when there is search criteria
* defined in the directory uri.
*
*/
void startSearch ();
/**
* Stops a search on the directory.
*
*/
void stopSearch ();
};

View file

@ -0,0 +1,90 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIMsgHeaderParser;
interface nsIStringBundle;
/**
* A containable item for address books.
*/
[scriptable, uuid(bb691a55-cbfe-4cf8-974a-e18cfa845a73)]
interface nsIAbItem : nsISupports {
/**
* A universally-unique identifier for this item.
*
* If this item cannot be associated with a UUID for some reason, it MUST
* return the empty string. The empty string MUST NOT be a valid UUID for any
* item. Under no circumstances may this function throw an error.
*
* It is STRONGLY RECOMMENDED that implementations guarantee that this UUID
* will not change between two different sessions of the application and that,
* if this item is deleted, the UUID will not be reused.
*
* The format of the UUID for a generic nsIAbItem is purposefully left
* undefined, although any item contained by an nsIAbDirectory SHOULD use
* nsIAbManager::generateUUID to generate the UUID.
*/
readonly attribute AUTF8String uuid;
/**
* @{
* These constants reflect the possible values of the
* mail.addr_book.lastnamefirst preferences. They are intended to be used in
* generateName, defined below.
*/
const unsigned long GENERATE_DISPLAY_NAME = 0;
const unsigned long GENERATE_LAST_FIRST_ORDER = 1;
const unsigned long GENERATE_FIRST_LAST_ORDER = 2;
/** @} */
/**
* Generate a name from the item for display purposes.
*
* If this item is an nsIAbCard, then it will use the aGenerateFormat option
* to determine the string to return.
* If this item is not an nsIAbCard, then the aGenerateFormat option may be
* ignored, and the displayName of the item returned.
*
* @param aGenerateFormat The format to generate as per the GENERATE_*
* constants above.
* @param aBundle An optional parameter that is a pointer to a string
* bundle that holds:
* chrome://messenger/locale/addressbook/addressBook.properties
* If this bundle is not supplied, then the function
* will obtain the bundle itself. If cached by the
* caller and supplied to this function, then
* performance will be improved over many calls.
* @return A string containing the generated name.
*/
AString generateName(in long aGenerateFormat,
[optional] in nsIStringBundle aBundle);
/**
* Generate a formatted email address from the card, that can be used for
* sending emails.
*
* @param aExpandList If this card is a list, and this parameter is set
* to true, then the list will be expanded to include
* the emails of the cards within the list.
* @param aGroupMailLists If this card (or the items within this card) is a
* list, and this is set to true, then the list will
* be expanded in the RFC 2822 group format
* "displayname : email1 ; email2 ; etc".
* @param aHeaderParser An optional parameter pointing to the
* nsIMsgHeaderParser service. If this is not supplied
* the function will obtain the service itself. If
* cached by the called and supplied to this function,
* then performance will be improved over many calls.
* @return A string containing a comma-separated list of
* formatted addresses.
*/
//AString generateFormattedEmail(in boolean aExpandList,
// in boolean aAsGroupMailLists,
// [optional] in nsIMsgHeaderParser aHeaderParser);
};

View file

@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#include "nsISupports.idl"
interface nsILDAPMessage;
interface nsIAbCard;
/**
* A mapping between addressbook properties and ldap attributes.
*
* Each addressbook property can map to one or more attributes. If
* there is no entry in preferences for a field, the getters generally
* return null; empty strings are passed through as usual. The intent is
* that properties with a non-zero number of attributes can be overridden for
* a specific server by supplying a zero-length string. For this to work,
* most callers are likely to want to check for both success and a
* non-empty string.
*
* Note that the one exception to this pattern is getAttributes, which
* throws NS_ERROR_FAILURE for non-existent property entries, since
* XPConnect doesn't like returning null arrays.
*
* Note that each LDAP attribute can map to at most one addressbook
* property. The checkState method is a useful tool in enforcing
* this. Failure to enforce it may make it impossible to guarantee
* that getProperty will do something consistent and reasonable.
*
* Maybe someday once we support ldap autoconfig stuff (ie
* draft-joslin-config-schema-11.txt), we can simplify this and other
* code and only allow a property to map to a single attribute.
*/
[scriptable, uuid(fa019fd1-7f3d-417a-8957-154cca0240be)]
interface nsIAbLDAPAttributeMap : nsISupports
{
/**
* Get all the LDAP attributes associated with a given property
* name, in order of precedence (highest to lowest).
*
* @param aProperty the address book property to return attrs for
*
* @return a comma-separated list of attributes, null if no entry is
* present
*/
ACString getAttributeList(in ACString aProperty);
/**
* Get all the LDAP attributes associated with a given property name, in
* order of precedence (highest to lowest).
*
* @param aProperty the address book property to return attrs for
*
* @return an array of attributes
*
* @exception NS_ERROR_FAILURE if there is no entry for this property
*/
void getAttributes(in ACString aProperty, out unsigned long aCount,
[retval, array, size_is(aCount)] out string aAttrs);
/**
* Get the first (canonical) LDAP attribute associated with a given property
* name
*
* @param aProperty the address book property to return attrs for
*
* @return the first attribute associated with a given property,
* null if there is no entry for this property
*/
ACString getFirstAttribute(in ACString aProperty);
/**
* Set an existing mapping to the comma-separated list of attributes.
*
* @param aProperty the mozilla addressbook property name
*
* @param aAttributeList a comma-separated list of attributes in
* order of precedence from high to low
*
* @param aAllowInconsistencies allow changes that would result in
* a map with an LDAP attribute associated
* with more than one property. Useful for
* doing a bunch of sets at once, and
* calling checkState at the end.
*
* @exception NS_ERROR_FAILURE making this change would result in a map
* with an LDAP attribute pointing to more
* than one property
*/
void setAttributeList(in ACString aProperty, in ACString aAttributeList,
in boolean allowInconsistencies);
/**
* Find the Mozilla addressbook property name that this attribute should
* map to.
*
* @return the addressbook property name, null if it's not used in the map
*/
ACString getProperty(in ACString aAttribute);
/**
* Get all attributes that may be used in an addressbook card via this
* property map (used for passing to to an LDAP search when you want
* everything that could be in a card returned).
*
* @return a comma-separated list of attribute names
*
* @exception NS_ERROR_FAILURE there are no attributes in this property map
*/
ACString getAllCardAttributes();
/**
* Get all properties that may be used in an addressbook card via this
* property map.
*
* @return an array of properties
*
* @exception NS_ERROR_FAILURE there are no attributes in this property map
*/
void getAllCardProperties(out unsigned long aCount,
[retval, array, size_is(aCount)] out string aProps);
/**
* Check that no LDAP attributes are listed in more than one property.
*
* @exception NS_ERROR_FAILURE one or more LDAP attributes are listed
* multiple times. The object is now in an
* inconsistent state, and should be either
* manually repaired or discarded.
*/
void checkState();
/* These last two methods are really just for the convenience of the caller
* and to avoid tons of unnecessary crossing of the XPConnect boundary.
*/
/**
* Set any attributes specified in the given prefbranch on this object.
*
* @param aPrefBranchName the pref branch containing all the
* property names
*
* @exception NS_ERROR_FAILURE one or more LDAP attributes are listed
* multiple times. The object is now in an
* inconsistent state, and should be either
* manually repaired or discarded.
*/
void setFromPrefs(in ACString aPrefBranchName);
/**
* Set the properties on an addressbook card from the given LDAP message
* using the map in this object.
*
* @param aCard is the card object whose values are to be set
* @param aMessage is the LDAP message to get the values from
*
* @exception NS_ERROR_FAILURE is thrown if no addressbook properties
* are found in the message
*/
void setCardPropertiesFromLDAPMessage(in nsILDAPMessage aMessage,
in nsIAbCard aCard);
};
/**
* The nsIAbLDAPAttributeMapService is used to build and hold a cache
* of maps.
*/
[scriptable, uuid(12e2d589-3c2a-48e4-8c82-b1e6464a0dfd)]
interface nsIAbLDAPAttributeMapService : nsISupports
{
/**
* Accessor to construct or return a cached copy of the attribute
* map for a given preference branch. The map is constructed by
* first taking the default map (as specified by the
* "ldap_2.servers.default.attrmap" prefbranch), and then having any
* preferences specified by aPrefBranchName override the defaults.
* LDIF import and export code should use the default map.
*
* @return the requested map
*
* @exception NS_ERROR_FAILURE error constructing the map;
* possibly because of a failure
* from checkState()
*/
nsIAbLDAPAttributeMap getMapForPrefBranch(in ACString aPrefBranchName);
};
%{C++
// test whether one of the getters has actually found an attribute
#define ATTRMAP_FOUND_ATTR(rv, str) (NS_SUCCEEDED(rv) && !(str).IsEmpty())
%}

View file

@ -0,0 +1,56 @@
/* -*- Mode: C++; 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/. */
#include "nsIAbCard.idl"
interface nsIAbLDAPAttributeMap;
interface nsILDAPModification;
interface nsILDAPMessage;
interface nsIArray;
[scriptable, uuid(2831b3b0-30ef-4070-8ad3-90ae04980e11)]
interface nsIAbLDAPCard : nsISupports
{
/**
* Returns the required information for an LDAP update message.
*
* @param aAttrMap The map between LDAP attributes and card properties
* @param aClassCount The number of objectClass values
* @param aClasses The objectClass values that the card needs to have
* @param updateType This should be one of:
* nsILDAPModification::MOD_ADD
* nsILDAPModification::MOD_REPLACE
*
* @return Returns an array of modifications required to
* add or replace the card in the ldap directory.
*/
nsIArray getLDAPMessageInfo(in nsIAbLDAPAttributeMap aAttrMap,
in unsigned long aClassCount,
[array, size_is(aClassCount)] in string aClasses,
in long updateType);
/**
* Builds a relative distinguished name (RDN) with the given set of
* attributes.
*
* @param aAttrMap The map between LDAP attributes and card properties
* @param aAttrCount The number of attributes to use for the RDN
* @param aAttributes The name of the attributes to use for the RDN
*
*/
ACString buildRdn(in nsIAbLDAPAttributeMap aAttrMap,
in unsigned long aAttrCount,
[array, size_is(aAttrCount)] in string aAttributes);
/**
* Stores meta-properties from a raw LDAP search result.
*
* @param aMessage The LDAP search result message.
*
*/
void setMetaProperties(in nsILDAPMessage aMessage);
attribute ACString dn;
};

View file

@ -0,0 +1,112 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIMutableArray;
interface nsIFile;
interface nsIAddrDatabase;
interface nsIAbLDAPAttributeMap;
interface nsILDAPURL;
%{C++
#define kLDAPDirectoryRoot "moz-abldapdirectory://"
#define kLDAPDirectoryRootLen 22
%}
/**
* XXX This should really inherit from nsIAbDirectory, and some day it will.
* But for now, doing that complicates implementation.
*/
[scriptable, uuid(90dde295-e354-4d58-Add8-f9b29a95942d)]
interface nsIAbLDAPDirectory : nsISupports
{
/**
* If set, these arrays of nsILDAPControls are passed through to the
* nsILDAPOperation that searchExt is called on.
*/
attribute nsIMutableArray searchServerControls;
attribute nsIMutableArray searchClientControls;
/**
* The Replication File Name to use.
*/
attribute ACString replicationFileName;
/**
* The version of LDAP protocol in use.
*/
attribute unsigned long protocolVersion;
/**
* The SASL mechanism to use to authenticate to the LDAP server
* If this is an empty string, then a simple bind will be performed
* A non-zero string is assumed to be the name of the SASL mechanism.
* Currently the only supported mechanism is GSSAPI
*/
attribute ACString saslMechanism;
/**
* The AuthDN to use to access the server.
*/
attribute AUTF8String authDn;
/**
* The maximum number of matches that the server will return per a search.
*/
attribute long maxHits;
/**
* The Last Change Number used for replication.
*/
attribute long lastChangeNumber;
/**
* The LDAP server's scoping of the lastChangeNumber.
*/
attribute ACString dataVersion;
/**
* The attribute map that is associated with this directory's server.
*/
readonly attribute nsIAbLDAPAttributeMap attributeMap;
/**
* The LDAP URL for this directory. Note that this differs from
* nsIAbDirectory::URI. This attribute will give you a true ldap
* url, e.g. ldap://localhost:389/ whereas the uri will give you the
* directories rdf uri, e.g. moz-abldapdirectory://<pref base name>/.
*/
attribute nsILDAPURL lDAPURL;
/**
* The replication (offline) file that this database uses.
*/
readonly attribute nsIFile replicationFile;
/**
* A database that is set up for the replication file.
*/
readonly attribute nsIAddrDatabase replicationDatabase;
/**
* The LDAP attributes used to build the Relative Distinguished Name
* of new cards, in the form of a comma separated list.
*
* The default is to use the common name (cn) attribute.
*/
attribute ACString rdnAttributes;
/**
* The LDAP objectClass values added to cards when they are created/added,
* in the form of a comma separated list.
*
* The default is to use the following classes:
* top,person,organizationalPerson,inetOrgPerson,mozillaAbPersonAlpha
*/
attribute ACString objectClasses;
};

View file

@ -0,0 +1,68 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIAbLDAPDirectory;
interface nsILDAPConnection;
interface nsILDAPURL;
interface nsIAbLDAPReplicationQuery;
interface nsIWebProgressListener;
/**
* this service does replication of an LDAP directory to a local Mork AB Database.
*/
[scriptable, uuid(e628bbc9-8793-4f0b-bce4-990d399b1fca)]
interface nsIAbLDAPProcessReplicationData : nsISupports
{
/**
* readonly attribute giving the current replication state
*/
readonly attribute int32_t replicationState;
/**
* replication states
*/
const long kIdle = 0;
const long kAnonymousBinding = 1;
const long kAuthenticatedBinding = 2;
const long kSyncServerBinding = 3;
const long kSearchingAuthDN = 4;
const long kDecidingProtocol = 5;
const long kAuthenticating = 6;
const long kReplicatingAll = 7;
const long kSearchingRootDSE = 8;
const long kFindingChanges = 9;
const long kReplicatingChanges = 10;
const long kReplicationDone = 11;
/**
* readonly attribute giving the current protocol used
*/
readonly attribute int32_t protocolUsed ;
/**
* replication protocols
*/
const long kDefaultDownloadAll = 0;
const long kChangeLogProtocol = 1;
const long kLCUPProtocol = 2;
const long kLastUpdatedTimeStampMethod = 3;
/**
* this method initializes the implementation
*/
void init(in nsIAbLDAPDirectory directory,
in nsILDAPConnection connection,
in nsILDAPURL url,
in nsIAbLDAPReplicationQuery query,
in nsIWebProgressListener progressListener);
/**
* this method a aborts the ongoing processing
*/
void abort();
};

View file

@ -0,0 +1,67 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIWebProgressListener;
interface nsILDAPURL;
interface nsILDAPConnection;
interface nsILDAPOperation;
interface nsIAbLDAPDirectory;
/**
* this interface provides methods to perform LDAP Replication Queries
*/
[scriptable, uuid(460a739c-a8c1-4f24-b705-c89d136ab9f5)]
interface nsIAbLDAPReplicationQuery : nsISupports
{
/**
* initialize for the query
*/
void init(in nsIAbLDAPDirectory aDirectory,
in nsIWebProgressListener aProgressListener);
/**
* Starts an LDAP query to do replication as needed
*/
void doReplicationQuery();
/**
* Cancels the currently executing query
*/
void cancelQuery();
/**
* this method is the callback when query is done, failed or successful
*/
void done(in boolean aSuccess);
};
// XXX This interface currently isn't implemented as it didn't work.
// Bug 311632 should fix it
[scriptable, uuid(126202D1-4460-11d6-B7C2-00B0D06E5F27)]
interface nsIAbLDAPChangeLogQuery : nsISupports
{
/**
* Starts an LDAP query to find auth DN
*/
void queryAuthDN(in AUTF8String aValueUsedToFindDn);
/**
* Starts an LDAP query to search server's Root DSE
*/
void queryRootDSE();
/**
* Starts an LDAP ChangeLog query to find changelog entries
*/
void queryChangeLog(in AUTF8String aChangeLogDN, in int32_t aLastChangeNo);
/**
* Starts an LDAP query to find changed entries
*/
void queryChangedEntries(in AUTF8String aChangedEntryDN);
};

View file

@ -0,0 +1,32 @@
/* 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/. */
#include "nsISupports.idl"
interface nsIWebProgressListener;
interface nsIAbLDAPDirectory;
/**
* this service does replication of an LDAP directory to a local Mork AB Database.
*/
[scriptable, uuid(3f499c70-5ceb-4b91-8b7f-62c366859383)]
interface nsIAbLDAPReplicationService: nsISupports {
/**
* Start Replication of given LDAP directory represented by the URI
*/
void startReplication(in nsIAbLDAPDirectory aDirectory,
in nsIWebProgressListener progressListener);
/**
* Cancel Replication of given LDAP directory represented by the URI
*/
void cancelReplication(in nsIAbLDAPDirectory aDirectory);
/**
* callback when replication is done, failure or success
*/
void done(in boolean aSuccess);
};

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIFile;
interface nsIAddrDatabase;
[scriptable, uuid(7afaa95f-0b1c-4d8a-a65f-bb5073ed6d39)]
interface nsIAbLDIFService : nsISupports {
/**
* Determine if a file is likely to be an LDIF file based on field
* names that commonly appear in LDIF files.
*
* @param aSrc The file to examine
*
* @return true if the file appears to be of LDIF type,
* false otherwise
*/
boolean isLDIFFile(in nsIFile aSrc);
/**
* Imports a file into the specified address book.
*
* @param aDb The address book to import addresses into.
*
* @param aSrc The file to import addresses from.
*
* @param aStoreLocAsHome Stores the address as a home rather than work
* address.
*
* @param aProgress May be null, but if a pointer is supplied,
* then it will be updated regularly with the
* current position of reading from the file.
*
*/
void importLDIFFile(in nsIAddrDatabase aDb, in nsIFile aSrc, in boolean aStoreLocAsHome, inout unsigned long aProgress);
};

View file

@ -0,0 +1,90 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
typedef unsigned long abListenerNotifyFlagValue;
/**
* nsIAbListener
*
* Implement this interface to receive notifications of address book
* items being added, removed or changed with loaded address books.
*
* Subscribe to events by using nsIAbManager.
*/
[scriptable, uuid(b3ca8745-2dad-4032-ae2f-0b8622f32697)]
interface nsIAbListener : nsISupports {
/**
* These flags are used when registering the listener with nsIAbManager to
* specify when to receive notifications of address book updates.
*/
/**
* An address book, mailing list or card is added.
*/
const abListenerNotifyFlagValue itemAdded = 0x1;
/**
* A mailing list or card is removed from an address book.
*/
const abListenerNotifyFlagValue directoryItemRemoved = 0x2;
/**
* An address book is removed
*/
const abListenerNotifyFlagValue directoryRemoved = 0x4;
/**
* An address book, mailing list or card is changed.
*/
const abListenerNotifyFlagValue itemChanged = 0x8;
/**
* All of the above notifications are to be received.
*/
const abListenerNotifyFlagValue all = 0xFFFFFFFF;
/**
* Called when an address book item (book, card or list) is added
*
* @param parentDir The parent of the item being added.
*
* @param item The item being added to the database (a
* directory or card).
*
*/
void onItemAdded(in nsISupports parentDir, in nsISupports item);
/**
* Called when an address book, mailing list or card is removed. This
* is partially configurable when setting up the listener via
* nsIAddrBookSession
*
* @param parentDir The parent of the item being removed, this
* may be an empty directory in the case of a
* top level address book.
*
* @param item The item being removed from the database.
*
*/
void onItemRemoved(in nsISupports parentDir, in nsISupports item);
/**
* Called when an address book item is changed. Note the current
* implementation means that property is either the literal string "DirName"
* or null, with oldValue and newValue being specified if the property is
* "DirName" otherwise they are null.
*
* @param item The item being updated (a directory or a
* card).
*
* @param property The property of the item being changed.
*
* @param oldValue The old value of the item property being
* changed if it is known, null otherwise.
*
* @param newValue The new value of the item property being
* changed.
*
*/
void onItemPropertyChanged(in nsISupports item, in string property, in wstring oldValue, in wstring newValue);
};

View file

@ -0,0 +1,71 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
interface nsIFile;
interface nsIAbDirectory;
interface nsIAbCard;
interface nsIAddrDatabase;
%{C++
#define kMDBDirectoryRoot "moz-abmdbdirectory://"
#define kMDBDirectoryRootLen 21
%}
[scriptable, uuid(744072be-1ba0-46bc-af24-46e22567a2ea)]
interface nsIAbMDBDirectory : nsISupports {
// Creates a directory component from the
// uriName, adds it to its children and returns
// the component
nsIAbDirectory addDirectory(in string uriName);
/**
* Supplies a nsIFile point to the database file for this directory
*
* @exception NS_ERROR_NOT_INITIALIZED If there is no filename preference
* present or it is empty
*/
readonly attribute nsIFile databaseFile;
/**
* Supplies a nsIAddrDatabase that uses the databaseFile. See also
* databaseFile for possible exceptions.
*/
readonly attribute nsIAddrDatabase database;
// Mail list specific
//
// Removes all elements from the addressLists
// property
[noscript] void removeElementsFromAddressList();
// Specific to a directory which stores mail lists
//
// Adds a directory to the addressLists attribute
void addMailListToDirectory(in nsIAbDirectory mailList);
// Specific to a directory which is a mail list
//
// Copies mail list properties from the srcList
void copyDBMailList(in nsIAbMDBDirectory srcListDB);
// Adds a card to the addressList attribute
void addAddressToList(in nsIAbCard card);
// Removes items from the addressLists member
void removeEmailAddressAt(in unsigned long aIndex);
attribute unsigned long dbRowID;
// Empty implementation, called by the data base
[noscript] void notifyDirItemAdded(in nsISupports item);
[noscript] void clearDatabase();
};

View file

@ -0,0 +1,190 @@
/* -*- Mode: IDL; 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/. */
#include "nsISupports.idl"
#include "nsIAbListener.idl"
interface mozIDOMWindowProxy;
interface nsIAbDirectory;
interface nsIAbCard;
interface nsIAbDirectoryProperties;
interface nsIFile;
interface nsISimpleEnumerator;
interface nsIAbBooleanExpression;
/**
* nsIAbManager is an interface to the main address book mananger
* via the contract id "@mozilla.org/abmanager;1"
*
* It contains the main functions to create and delete address books as well
* as some helper functions.
*/
[scriptable, uuid(ea0d8b3d-a549-4874-82d8-3a82cee2a3f1)]
interface nsIAbManager : nsISupports
{
/**
* Returns an enumerator containing all the top-level directories
* (non-recursive)
*/
readonly attribute nsISimpleEnumerator directories;
/**
* Returns the directory that represents the supplied URI.
*
* @param aURI The URI of the address book to find.
* @return The found address book.
*/
nsIAbDirectory getDirectory(in ACString aURI);
/**
* Returns the directory that has the supplied dirPrefId.
*
* @param aDirPrefId The dirPrefId of the directory.
* @return The found AB directory.
*/
nsIAbDirectory getDirectoryFromId(in ACString aDirPrefId);
/**
* Creates a new address book.
*
* @param aDirName The description of the address book.
* @param aURI The URI for the address book. This is specific to each
* type of address book.
* @param aType The type of the address book (see nsDirPrefs.h)
* @param aPrefName Overrides the default of ldap_2.servers.<aDirName>
* (note that the caller must ensure its uniqueness).
*/
ACString newAddressBook(in AString aDirName, in ACString aURI,
in unsigned long aType,
[optional] in ACString aPrefName);
/**
* Deletes an address book.
*
* @param aURI The URI for the address book. This is specific to each
* type of address book.
*/
void deleteAddressBook(in ACString aURI);
/**
* Exports an address book, it will provide a dialog to the user for the
* location to save the file to and will then save the address book to media.
*
* @param aParentWin Parent Window for the file save dialog to use.
* @param aDirectory The directory to export.
*/
void exportAddressBook(in mozIDOMWindowProxy aParentWin, in nsIAbDirectory aDirectory);
/**
* Adds a nsIAbListener to receive notifications of address book updates
* according to the specified notifyFlags.
*
* @param aListener The listener that is to receive updates.
* @param aNotifyFlags A bitwise-or of abListenerNotifyFlagValue items
* specifying which notifications to receive. See
* nsIAbListener for possible values.
*/
void addAddressBookListener(in nsIAbListener aListener,
in abListenerNotifyFlagValue aNotifyFlags);
/**
* Removes a nsIAbListener from receive notifications of address book
* updates.
*
* @param aListener The listener that is to no longer receive updates.
*/
void removeAddressBookListener(in nsIAbListener aListener);
/**
* Call to notify the registered listeners when a property on an item has
* changed.
*
* @param aItem The items that has changed (e.g. an nsIAbDirectory)
* @param aProperty The property that has changed (e.g. DirName)
* @param aOldValue The old value of the property.
* @param aNewValue The new value of the property.
*/
void notifyItemPropertyChanged(in nsISupports aItem,
in string aProperty,
in wstring aOldValue,
in wstring aNewValue);
/**
* Call to notify the registered listeners when a directory item is added.
*
* @param aParentDirectory The parent directory of the item that has been
* added.
* @param aItem The item that has been added.
*/
void notifyDirectoryItemAdded(in nsIAbDirectory aParentDirectory,
in nsISupports aItem);
/**
* Call to notify the registered listeners when a directory item is removed.
*
* @param aParentDirectory The parent directory of the item that has been
* removed.
* @param aItem The item that has been removed.
*/
void notifyDirectoryItemDeleted(in nsIAbDirectory aParentDirectory,
in nsISupports aItem);
/**
* Call to notify the registered listeners when a directory is removed.
*
* @param aParentDirectory The parent directory of the directory that has
* been removed.
* @param aDirectory The directory that has been removed.
*/
void notifyDirectoryDeleted(in nsIAbDirectory aParentDirectory,
in nsISupports aDirectory);
/**
* Returns the user profile directory. NOTE: this should not be used
* as it may go away soon.
*/
readonly attribute nsIFile userProfileDirectory;
/**
* Finds out if the mailing list name exists in any *mork/MDB* based
* address book
*
* @param aName The name of the list to try and find.
*
* @return True if the name exists.
*/
boolean mailListNameExists(in wstring name);
/**
* Translates an escaped vcard string into a nsIAbCard.
*
* @param escapedVCardStr The string containing the vcard.
*
* @return A card containing the translated vcard data.
*/
nsIAbCard escapedVCardToAbCard(in string escapedVCardStr);
/**
* Generates a UUID from a (directory ID, local ID) tuple.
*
* Use of this method is preferred in such cases, since it is designed to work
* with other methods of this interface.
*
* @param directoryId The directory ID.
* @param localId The per-directory ID.
* @return A string to use for the UUID.
*/
AUTF8String generateUUID(in AUTF8String directoryId, in AUTF8String localId);
/**
* A utility function that converts an nsIAbDirectory query string to an
* nsIAbBooleanExpression.
*
* @param aQueryString The nsIAbDirectory query string
* @return an nsIAbBooleanExpression for the query string
*/
nsIAbBooleanExpression convertQueryStringToExpression(in AUTF8String aQueryString);
};

View file

@ -0,0 +1,109 @@
/* -*- Mode: IDL; 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/. */
#include "nsISupports.idl"
interface nsIAbCard;
interface nsIAbDirectory;
interface nsIArray;
/// Define a class using this interface to listen to updates from nsIAbView.
[scriptable, uuid(79ad5d6e-1dd2-11b2-addd-f547dab50d75)]
interface nsIAbViewListener : nsISupports
{
/// Called when the selection is changed in the tree
void onSelectionChanged();
/// Called when the total count of cards is changed.
void onCountChanged(in long total);
};
/**
* This interface and its associated nsAbView object provides an interface
* to allow a tree to be associated with an address book, and the results
* to be displayed in that tree.
*
* If you wish for the tree to display the results of a different address
* book, then call setView again. There is no need to delete and recreate the
* nsAbView object. If you wish to clear the view, then just call clearView.
*/
[scriptable, uuid(45e2fa9f-0b59-4090-a2fa-fb7042cf64a2)]
interface nsIAbView : nsISupports
{
/**
* Sets up the nsIAbView to look at the specified directory. This may be
* called multiple times.
*
* @param aDirectory The directory to search, this may be a directory
* with a query string.
* @param aViewListener An optional listener.
* @param aSortColumn The column to sort by. See the xul element with
* id abResultsTreeCols for possible values.
* @param aSortDirection The sort direction to use ("ascending"/"descending")
* @return The actual sortColumn (various switching of apps
* could cause the persisted sortColumn to be bogus).
*/
AString setView(in nsIAbDirectory aAddressBook,
in nsIAbViewListener aAbViewListener,
in AString aSortColumn,
in AString aSortDirection);
/**
* Clears the view and releases any locally held copies of the address book
* directory. This should be called when the view is no longer required, e.g.
* on unload.
*/
void clearView();
/**
* Sorts the tree by the specified parameters.
*
* @param aSortColumn The column to sort by. See the xul element with
* id abResultsTreeCols for possible values.
* @param aSortDirection The sort direction to use ("ascending"/"descending")
* @param aResort The function DOES optimize for the case when sortColumn
* and sortDirection is identical since the last call.
* If an unconditional resort is needed, set this to true.
*/
void sortBy(in wstring aSortColumn, in wstring aSortDirection,
[optional] in boolean aResort);
/// Returns the current sort column
readonly attribute AString sortColumn;
/// Returns the current sort direction
readonly attribute AString sortDirection;
/**
* Returns the current directory that this view is hooked up to. May be
* null if no directory has been set.
*/
readonly attribute nsIAbDirectory directory;
/**
* Returns the card associated with the given row.
*
* @param aRow The row from which to return the card.
* @return A card associated with the row, or null if row is not valid.
*/
nsIAbCard getCardFromRow(in long aRow);
/// Selects all rows in the view.
void selectAll();
/// Deletes all the selected cards (no prompts are given).
void deleteSelectedCards();
/**
* Swaps the first and last name order, and updates the appropriate
* preference.
*/
void swapFirstNameLastName();
/**
* Returns an array of the currently selected addresses.
*/
readonly attribute nsIArray selectedAddresses;
};

View file

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsIURI.idl"
[scriptable, uuid(6EB9D874-01AA-11d4-8FBE-000064657374)]
interface nsIAddbookUrlOperation
{
const long InvalidUrl = 0;
const long PrintAddressBook = 1;
const long AddVCard = 2;
};
[uuid(5f965083-e866-4bfb-ba40-13c344395798)]
interface nsIAddbookUrl : nsIURI {
readonly attribute long addbookOperation;
};

View file

@ -0,0 +1,35 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
#include "nsIAbCard.idl"
#include "nsIAbDirectory.idl"
interface nsIAddrDBListener;
[scriptable, uuid(166b19a1-1235-4613-9601-816dedc48c9e)]
interface nsIAddrDBAnnouncer : nsISupports {
void addListener(in nsIAddrDBListener listener);
void removeListener(in nsIAddrDBListener listener);
void notifyCardAttribChange(in unsigned long abCode);
/**
* Notify all the listeners of the database about an event performed
* on a card entry.
*
* @param aAbCode The code to indicate the type of event
* (see nsAddrDatabase.h AB_NOTIFY_CODE for values).
* @param aCard The card entry on which the event occurred.
* @param aParent The parent of card entry. This is set by
* object which performs the operation.
*/
void notifyCardEntryChange(in unsigned long aAbCode,
in nsIAbCard aCard,
in nsIAbDirectory aParent);
void notifyAnnouncerGoingAway();
};

View file

@ -0,0 +1,36 @@
/* -*- Mode: C++; 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/. */
#include "nsISupports.idl"
#include "nsIAbCard.idl"
#include "nsIAbDirectory.idl"
interface nsIAddrDBAnnouncer;
[scriptable, uuid(5d7e5a7a-1ac9-46dc-abfd-758c98be26e9)]
interface nsIAddrDBListener : nsISupports {
void onCardAttribChange(in unsigned long abCode);
/**
* Handle the card entry change event.
*
* @param aAbCode The code to indicate the type of event
* (see nsAddrDatabase.h AB_NOTIFY_CODE for values).
* @param aCard The card entry on which the event occurred.
* @param aParent The parent of card entry.
* If set to null, the event can be ignored.
* This happens during import & sync operations when
* listeners of a database need not be notified about
* card entry changes.
*/
void onCardEntryChange (in unsigned long aAbCode,
in nsIAbCard aCard,
in nsIAbDirectory aParent);
void onListEntryChange (in unsigned long abCode,
in nsIAbDirectory list);
void onAnnouncerGoingAway();
};

View file

@ -0,0 +1,311 @@
/* -*- Mode: C++; 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/. */
#include "nsIAddrDBAnnouncer.idl"
#include "nsIAbCard.idl"
#include "nsIAbDirectory.idl"
interface nsIFile;
interface nsIMdbTableRowCursor;
interface nsIMdbEnv;
interface nsIMdbRow;
interface nsIArray;
interface nsISimpleEnumerator;
%{C++
// this is the prefix we for attributes that are specific
// to the mozilla addressbook, and weren't in 4.x and aren't specified in
// RFC 2789. used when exporting and import LDIF
// see nsTextAddress.cpp, nsAddressBook.cpp
#define MOZ_AB_LDIF_PREFIX "mozilla"
// note, GeneratedName is not a real column
// if you change any of this, make sure to change
// Get / Set CardValue in nsAbCardProperty.cpp
#define kPhoneticNameColumn "_PhoneticName"
#define kAddressCharSetColumn "AddrCharSet"
#define kMailListName "ListName"
#define kMailListNickName "ListNickName"
#define kMailListDescription "ListDescription"
#define kMailListTotalAddresses "ListTotalAddresses"
// not shown in the UI
#define kLowerPriEmailColumn "LowercasePrimaryEmail"
#define kLower2ndEmailColumn "LowercaseSecondEmail"
// Palm Integration
#define CARD_ATTRIB_PALMID "PalmRecId"
#define CARD_ATTRIB_DISPLAY "DisplayName"
%}
[scriptable, uuid(20d4c6c3-0460-403e-aa9c-813654641566)]
interface nsAddrDBCommitType
{
const long kLargeCommit = 1;
const long kSessionCommit = 2;
const long kCompressCommit = 3;
};
[scriptable, uuid(c54973e4-d251-4b93-a0d0-81a616225061)]
interface nsIAddrDatabase : nsIAddrDBAnnouncer {
/**
* Path to the address book database that this instance represents.
*/
attribute nsIFile dbPath;
nsIAddrDatabase open(in nsIFile dbFile, in boolean create, in boolean upgrading);
void close(in boolean forceCommit);
/**
* Open the MDB database synchronously creating it if required. If
* successful, this routine will set up the m_mdbStore and m_mdbEnv of the
* database object so other database calls can work.
*
* @param dbName The location of the database file
* to open.
* @param create If set to true, will create the
* database file if it does not
* already exist.
* @exception NS_ERROR_FILE_NOT_FOUND The file was not found at the
* specified location (and create was
* false).
* @exception NS_ERROR_FILE_ACCESS_DENIED The file could not be opened as
* access was denied.
*/
void openMDB(in nsIFile dbName, in boolean create);
void closeMDB(in boolean commit);
void commit(in unsigned long commitType);
void forceClosed();
/**
* Create a new card and add to the database
*
* @param aNewCard the card to be added
* @param aNotify if set to true, all the listeners of the
* database will be notified.
* @param aParent parent directory or mailing list to which the
* card is added. If set to null, listeners of the
* database will not be notified of card creation.
*/
void createNewCardAndAddToDB(in nsIAbCard aNewCard, in boolean aNotify, in nsIAbDirectory aParent);
void createNewListCardAndAddToDB(in nsIAbDirectory list, in unsigned long listRowID, in nsIAbCard newCard, in boolean aNotify);
/**
* Create a new mailing list and add to the database
*
* @param aNewList the mailing list to be added.
* @param aNotify if set to true, all the listeners of the
* database will be notified.
* @param aParent parent directory to which the mailing list
* is added. If set to null, listeners of the database
* will not be notified of mailing list creation.
*/
void createMailListAndAddToDB(in nsIAbDirectory aNewList, in boolean aNotify, in nsIAbDirectory aParent);
/**
* Enumerate the cards in the directory. The enumerator will return the
* cards associated with mailing lists too.
*
* @param directory the directory of which to enumerate the cards.
* @return an enumerator.
*/
nsISimpleEnumerator enumerateCards(in nsIAbDirectory directory);
/**
* Enumerate the cards associated with the mailing lists in the directory.
*
* @param directory the directory of which to enumerate the cards.
* @return an enumerator.
*/
nsISimpleEnumerator enumerateListAddresses(in nsIAbDirectory directory);
void getMailingListsFromDB(in nsIAbDirectory parentDir);
/**
* Delete a card from the database.
*
* @param aCard the card to be deleted.
* @param aNotify if set to true, all the listeners of the
* database will be notified.
* @param aParent parent directory from which the card
* is to be deleted. If set to null, listeners of
* the database will not be notified of card deletion.
*/
void deleteCard(in nsIAbCard aCard, in boolean aNotify, in nsIAbDirectory aParent);
/**
* Edit a card in the database.
*
* @param aCard the card to be edited.
* @param aNotify if set to true, all the listeners of the
* database will be notified.
* @param aParent parent directory in which the card
* is to be edited. If set to null, listeners of
* the database will not be notified of card entry
* change.
*/
void editCard(in nsIAbCard aCard, in boolean aNotify, in nsIAbDirectory aParent);
boolean containsCard(in nsIAbCard card);
/**
* Deletes a mailing list from the directory
*
* @param aMailList The nsIAbDirectory implementation of the mailing
* list that is to be deleted.
* @param aParent The parent of the mailing list that is being
* deleted. If this is supplied, then a notification
* of card entry change in the database will be made.
*/
void deleteMailList(in nsIAbDirectory aMailList,
[optional] in nsIAbDirectory aParent);
void editMailList(in nsIAbDirectory mailList, in nsIAbCard listCard, in boolean aNotify);
boolean containsMailList(in nsIAbDirectory mailList);
void deleteCardFromMailList(in nsIAbDirectory mailList, in nsIAbCard card, in boolean aNotify);
/**
* Gets the first card which matches the attribute/value pair supplied.
*
* @param aDirectory The current nsIAbDirectory associated with this
* instance of the database.
* @param aName The attribute to look up the value in.
* @param aUTF8Value The value to look up in UTF8 format.
* @param aCaseInsensitive Set to true for case-insenstive matching.
* @result Returns an nsIAbCard if one is found, otherwise
* NULL.
*/
nsIAbCard getCardFromAttribute(in nsIAbDirectory aDirectory, in string aName,
in AUTF8String aUTF8Value,
in boolean aCaseInsensitive);
/**
* Gets all cards which matches the attribute/value pair supplied.
*
* @param aDirectory The current nsIAbDirectory associated with this
* instance of the database.
* @param aName The attribute to look up the value in.
* @param aUTF8Value The value to look up in UTF8 format.
* @param aCaseInsensitive Set to true for case-insenstive matching.
* @result Returns an nsISimpleEnumerator of nsIAbCard
* instances.
*/
nsISimpleEnumerator getCardsFromAttribute(in nsIAbDirectory aDirectory,
in string aName,
in AUTF8String uUTF8Value,
in boolean aCaseInsensitive);
boolean findMailListbyUnicodeName(in wstring listName);
void getCardCount(out uint32_t count);
[noscript] readonly attribute nsIMdbRow newRow;
[noscript] readonly attribute nsIMdbRow newListRow;
[noscript] void addCardRowToDB(in nsIMdbRow newRow);
[noscript] void addLdifListMember(in nsIMdbRow row, in string value);
[noscript] void addFirstName(in nsIMdbRow row, in string value);
[noscript] void addLastName(in nsIMdbRow row, in string value);
[noscript] void addPhoneticFirstName(in nsIMdbRow row, in string value);
[noscript] void addPhoneticLastName(in nsIMdbRow row, in string value);
[noscript] void addDisplayName(in nsIMdbRow row, in string value);
[noscript] void addNickName(in nsIMdbRow row, in string value);
[noscript] void addPrimaryEmail(in nsIMdbRow row, in string value);
[noscript] void add2ndEmail(in nsIMdbRow row, in string value);
[noscript] void addWorkPhone(in nsIMdbRow row, in string value);
[noscript] void addHomePhone(in nsIMdbRow row, in string value);
[noscript] void addFaxNumber(in nsIMdbRow row, in string value);
[noscript] void addPagerNumber(in nsIMdbRow row, in string value);
[noscript] void addCellularNumber(in nsIMdbRow row, in string value);
[noscript] void addWorkPhoneType(in nsIMdbRow row, in string value);
[noscript] void addHomePhoneType(in nsIMdbRow row, in string value);
[noscript] void addFaxNumberType(in nsIMdbRow row, in string value);
[noscript] void addPagerNumberType(in nsIMdbRow row, in string value);
[noscript] void addCellularNumberType(in nsIMdbRow row, in string value);
[noscript] void addHomeAddress(in nsIMdbRow row, in string value);
[noscript] void addHomeAddress2(in nsIMdbRow row, in string value);
[noscript] void addHomeCity(in nsIMdbRow row, in string value);
[noscript] void addHomeState(in nsIMdbRow row, in string value);
[noscript] void addHomeZipCode(in nsIMdbRow row, in string value);
[noscript] void addHomeCountry(in nsIMdbRow row, in string value);
[noscript] void addWorkAddress(in nsIMdbRow row, in string value);
[noscript] void addWorkAddress2(in nsIMdbRow row, in string value);
[noscript] void addWorkCity(in nsIMdbRow row, in string value);
[noscript] void addWorkState(in nsIMdbRow row, in string value);
[noscript] void addWorkZipCode(in nsIMdbRow row, in string value);
[noscript] void addWorkCountry(in nsIMdbRow row, in string value);
[noscript] void addJobTitle(in nsIMdbRow row, in string value);
[noscript] void addDepartment(in nsIMdbRow row, in string value);
[noscript] void addCompany(in nsIMdbRow row, in string value);
[noscript] void addAimScreenName(in nsIMdbRow row, in string value);
[noscript] void addAnniversaryYear(in nsIMdbRow row, in string value);
[noscript] void addAnniversaryMonth(in nsIMdbRow row, in string value);
[noscript] void addAnniversaryDay(in nsIMdbRow row, in string value);
[noscript] void addSpouseName(in nsIMdbRow row, in string value);
[noscript] void addFamilyName(in nsIMdbRow row, in string value);
[noscript] void addDefaultAddress(in nsIMdbRow row, in string value);
[noscript] void addCategory(in nsIMdbRow row, in string value);
[noscript] void addWebPage1(in nsIMdbRow row, in string value);
[noscript] void addWebPage2(in nsIMdbRow row, in string value);
[noscript] void addBirthYear(in nsIMdbRow row, in string value);
[noscript] void addBirthMonth(in nsIMdbRow row, in string value);
[noscript] void addBirthDay(in nsIMdbRow row, in string value);
[noscript] void addCustom1(in nsIMdbRow row, in string value);
[noscript] void addCustom2(in nsIMdbRow row, in string value);
[noscript] void addCustom3(in nsIMdbRow row, in string value);
[noscript] void addCustom4(in nsIMdbRow row, in string value);
[noscript] void addNotes(in nsIMdbRow row, in string value);
[noscript] void addPreferMailFormat(in nsIMdbRow row, in unsigned long value);
[noscript] void addPopularityIndex(in nsIMdbRow row, in unsigned long value);
[noscript] void addListName(in nsIMdbRow row, in string value);
[noscript] void addListNickName(in nsIMdbRow row, in string value);
[noscript] void addListDescription(in nsIMdbRow row, in string value);
[noscript] void addListDirNode(in nsIMdbRow listRow);
/**
* use for getting and setting generic string attributes
* like _AimScreenName
*/
void setCardValue(in nsIAbCard card, in string name, in wstring value, in boolean notify);
wstring getCardValue(in nsIAbCard card, in string name);
/**
* Returns an array of the deleted cards currently stored in the mork file.
*/
readonly attribute nsIArray deletedCardList;
/**
* Returns the count of the deleted card currently stored in the mork file.
*/
readonly attribute unsigned long deletedCardCount;
/**
* Add the column representing the card to the mailing list row
* in the database.
*
* @param aPCard the card to be added.
* @param aPListRow the row to which the column will be added.
* @param aPos the position of the card in the mailing list.
* @param aPNewCard a pointer to hold the new card added to the row.
* @param aInMailingList If set to true, the card is already present
* in the mailing list
* @param aParent parent mailing list to which the card
* is added. If set to null, listeners of the
* database will not be notified of card creation.
* @param aRoot If the card is created while creating a new mailing
* list, its set to the parent addressbook.
* Set to null in other case.
*/
void AddListCardColumnsToRow(in nsIAbCard aPCard,
in nsIMdbRow aPListRow,
in unsigned long aPos,
out nsIAbCard aPNewCard,
in boolean aInMailingList,
in nsIAbDirectory aParent,
in nsIAbDirectory aRoot);
void InitCardFromRow(in nsIAbCard aNewCard,in nsIMdbRow aCardRow);
void SetListAddressTotal(in nsIMdbRow aListRow, in uint32_t aTotal);
nsIMdbRow FindRowByCard(in nsIAbCard aCard);
};

View file

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsISupports.idl"
%{C++
#include "nsVCardObj.h"
%}
[ptr] native VObject_ptr(VObject);
[ptr] native VObjectIterator_ptr(VObjectIterator);
[ptr] native const_char_ptr(const char);
[uuid(8b6ae917-676d-4f1f-bbad-2ecc9be0d9b1)]
interface nsIMsgVCardService : nsISupports {
[noscript, notxpcom] void cleanVObject(in VObject_ptr o);
[noscript, notxpcom] VObject_ptr nextVObjectInList(in VObject_ptr o);
[noscript, notxpcom] VObject_ptr parse_MIME(in string input, in unsigned long len);
[noscript, notxpcom] charPtr fakeCString(in VObject_ptr o);
[noscript, notxpcom] VObject_ptr isAPropertyOf(in VObject_ptr o, in string id);
[noscript, notxpcom] charPtr writeMemoryVObjects(in string s, out long len, in VObject_ptr list, in boolean expandSpaces);
[noscript, notxpcom] VObject_ptr nextVObject(in VObjectIterator_ptr i);
[noscript, notxpcom] void initPropIterator(in VObjectIterator_ptr i, in VObject_ptr o);
[noscript, notxpcom] long moreIteration(in VObjectIterator_ptr i);
[noscript, notxpcom] const_char_ptr vObjectName(in VObject_ptr o);
[noscript, notxpcom] charPtr vObjectAnyValue(in VObject_ptr o);
};

View file

@ -0,0 +1,93 @@
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsAbDirProperty.h',
'nsDirPrefs.h',
'nsVCardObj.h',
]
SOURCES += [
'nsAbAddressCollector.cpp',
'nsAbBooleanExpression.cpp',
'nsAbBSDirectory.cpp',
'nsAbCardProperty.cpp',
'nsAbContentHandler.cpp',
'nsAbDirectoryQuery.cpp',
'nsAbDirectoryQueryProxy.cpp',
'nsAbDirFactoryService.cpp',
'nsAbDirProperty.cpp',
'nsAbLDIFService.cpp',
'nsAbManager.cpp',
'nsAbMDBCard.cpp',
'nsAbMDBDirectory.cpp',
'nsAbMDBDirFactory.cpp',
'nsAbMDBDirProperty.cpp',
'nsAbQueryStringToExpression.cpp',
'nsAbView.cpp',
'nsAddbookProtocolHandler.cpp',
'nsAddbookUrl.cpp',
'nsAddrDatabase.cpp',
'nsDirPrefs.cpp',
'nsMsgVCardService.cpp',
'nsVCard.cpp',
'nsVCardObj.cpp',
]
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MAPI_SUPPORT']:
SOURCES += [
'nsAbOutlookDirectory.cpp',
'nsAbOutlookDirFactory.cpp',
'nsAbWinHelper.cpp',
'nsMapiAddressBook.cpp',
'nsWabAddressBook.cpp',
]
if CONFIG['OS_ARCH'] == 'Darwin':
SOURCES += [
'nsAbOSXDirFactory.cpp',
]
SOURCES += [
'nsAbOSXCard.mm',
'nsAbOSXDirectory.mm',
'nsAbOSXUtils.mm',
]
if CONFIG['MOZ_LDAP_XPCOM']:
SOURCES += [
'nsAbBoolExprToLDAPFilter.cpp',
'nsAbLDAPCard.cpp',
'nsAbLDAPDirectory.cpp',
'nsAbLDAPDirectoryModify.cpp',
'nsAbLDAPDirectoryQuery.cpp',
'nsAbLDAPDirFactory.cpp',
'nsAbLDAPListenerBase.cpp',
'nsAbLDAPReplicationData.cpp',
'nsAbLDAPReplicationQuery.cpp',
'nsAbLDAPReplicationService.cpp',
]
# XXX These files are not being built as they don't work. Bug 311632 should
# fix them.
# nsAbLDAPChangeLogQuery.cpp
# nsAbLDAPChangeLogData.cpp
EXTRA_COMPONENTS += [
'nsAbLDAPAutoCompleteSearch.js',
]
DEFINES['MOZ_LDAP_XPCOM'] = True
EXTRA_COMPONENTS += [
'nsAbAutoCompleteMyDomain.js',
'nsAbAutoCompleteSearch.js',
'nsAbLDAPAttributeMap.js',
]
EXTRA_PP_COMPONENTS += [
'nsAddrbook.manifest',
]
FINAL_LIBRARY = 'mail'

View file

@ -0,0 +1,331 @@
/* -*- Mode: C++; 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/. */
#include "msgCore.h" // for pre-compiled headers
#include "nsISimpleEnumerator.h"
#include "nsIAbCard.h"
#include "nsAbBaseCID.h"
#include "nsAbAddressCollector.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsStringGlue.h"
#include "prmem.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsIAbManager.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
NS_IMPL_ISUPPORTS(nsAbAddressCollector, nsIAbAddressCollector, nsIObserver)
#define PREF_MAIL_COLLECT_ADDRESSBOOK "mail.collect_addressbook"
nsAbAddressCollector::nsAbAddressCollector()
{
}
nsAbAddressCollector::~nsAbAddressCollector()
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> pPrefBranchInt(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv))
pPrefBranchInt->RemoveObserver(PREF_MAIL_COLLECT_ADDRESSBOOK, this);
}
/**
* Returns the first card found with the specified email address. This
* returns an already addrefed pointer to the card if the card is found.
*/
already_AddRefed<nsIAbCard>
nsAbAddressCollector::GetCardForAddress(const nsACString &aEmailAddress,
nsIAbDirectory **aDirectory)
{
nsresult rv;
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, nullptr);
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = abManager->GetDirectories(getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, nullptr);
bool hasMore;
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIAbDirectory> directory;
nsCOMPtr<nsIAbCard> result;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore)
{
rv = enumerator->GetNext(getter_AddRefs(supports));
NS_ENSURE_SUCCESS(rv, nullptr);
directory = do_QueryInterface(supports, &rv);
if (NS_FAILED(rv))
continue;
// Some implementations may return NS_ERROR_NOT_IMPLEMENTED here,
// so just catch the value and continue.
if (NS_FAILED(directory->CardForEmailAddress(aEmailAddress,
getter_AddRefs(result))))
{
continue;
}
if (result)
{
if (aDirectory)
directory.forget(aDirectory);
return result.forget();
}
}
return nullptr;
}
NS_IMETHODIMP
nsAbAddressCollector::CollectAddress(const nsACString &aAddresses,
bool aCreateCard,
uint32_t aSendFormat)
{
// If we've not got a valid directory, no point in going any further
if (!mDirectory)
return NS_OK;
// note that we're now setting the whole recipient list,
// not just the pretty name of the first recipient.
nsTArray<nsCString> names;
nsTArray<nsCString> addresses;
ExtractAllAddresses(EncodedHeader(aAddresses),
UTF16ArrayAdapter<>(names), UTF16ArrayAdapter<>(addresses));
uint32_t numAddresses = names.Length();
for (uint32_t i = 0; i < numAddresses; i++)
{
// Don't allow collection of addresses with no email address, it makes
// no sense. Whilst we should never get here in most normal cases, we
// should still be careful.
if (addresses[i].IsEmpty())
continue;
CollectSingleAddress(addresses[i], names[i], aCreateCard, aSendFormat,
false);
}
return NS_OK;
}
NS_IMETHODIMP
nsAbAddressCollector::CollectSingleAddress(const nsACString &aEmail,
const nsACString &aDisplayName,
bool aCreateCard,
uint32_t aSendFormat,
bool aSkipCheckExisting)
{
if (!mDirectory)
return NS_OK;
nsresult rv;
nsCOMPtr<nsIAbDirectory> originDirectory;
nsCOMPtr<nsIAbCard> card = (!aSkipCheckExisting) ?
GetCardForAddress(aEmail, getter_AddRefs(originDirectory)) : nullptr;
if (!card && (aCreateCard || aSkipCheckExisting))
{
card = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && card)
{
// Set up the fields for the new card.
SetNamesForCard(card, aDisplayName);
AutoCollectScreenName(card, aEmail);
if (NS_SUCCEEDED(card->SetPrimaryEmail(NS_ConvertUTF8toUTF16(aEmail))))
{
card->SetPropertyAsUint32(kPreferMailFormatProperty, aSendFormat);
nsCOMPtr<nsIAbCard> addedCard;
rv = mDirectory->AddCard(card, getter_AddRefs(addedCard));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to add card");
}
}
}
else if (card && originDirectory)
{
// It could be that the origin directory is read-only, so don't try and
// write to it if it is.
bool readOnly;
rv = originDirectory->GetReadOnly(&readOnly);
NS_ENSURE_SUCCESS(rv, rv);
if (readOnly)
return NS_OK;
// address is already in the AB, so update the names
bool modifiedCard = false;
nsString displayName;
card->GetDisplayName(displayName);
// If we already have a display name, don't set the names on the card.
if (displayName.IsEmpty() && !aDisplayName.IsEmpty())
modifiedCard = SetNamesForCard(card, aDisplayName);
if (aSendFormat != nsIAbPreferMailFormat::unknown)
{
uint32_t currentFormat;
rv = card->GetPropertyAsUint32(kPreferMailFormatProperty,
&currentFormat);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get preferred mail format");
// we only want to update the AB if the current format is unknown
if (currentFormat == nsIAbPreferMailFormat::unknown &&
NS_SUCCEEDED(card->SetPropertyAsUint32(kPreferMailFormatProperty,
aSendFormat)))
modifiedCard = true;
}
if (modifiedCard)
originDirectory->ModifyCard(card);
}
return NS_OK;
}
// Works out the screen name to put on the card for some well-known addresses
void
nsAbAddressCollector::AutoCollectScreenName(nsIAbCard *aCard,
const nsACString &aEmail)
{
if (!aCard)
return;
int32_t atPos = aEmail.FindChar('@');
if (atPos == -1)
return;
const nsACString& domain = Substring(aEmail, atPos + 1);
if (domain.IsEmpty())
return;
// username in
// username@aol.com (America Online)
// username@cs.com (Compuserve)
// username@netscape.net (Netscape webmail)
// are all AIM screennames. autocollect that info.
if (domain.Equals("aol.com") || domain.Equals("cs.com") ||
domain.Equals("netscape.net"))
aCard->SetPropertyAsAUTF8String(kScreenNameProperty, Substring(aEmail, 0, atPos));
else if (domain.Equals("gmail.com") || domain.Equals("googlemail.com"))
aCard->SetPropertyAsAUTF8String(kGtalkProperty, Substring(aEmail, 0, atPos));
}
// Returns true if the card was modified successfully.
bool
nsAbAddressCollector::SetNamesForCard(nsIAbCard *aSenderCard,
const nsACString &aFullName)
{
nsCString firstName;
nsCString lastName;
bool modifiedCard = false;
if (NS_SUCCEEDED(aSenderCard->SetDisplayName(NS_ConvertUTF8toUTF16(aFullName))))
modifiedCard = true;
// Now split up the full name.
SplitFullName(nsCString(aFullName), firstName, lastName);
if (!firstName.IsEmpty() &&
NS_SUCCEEDED(aSenderCard->SetFirstName(NS_ConvertUTF8toUTF16(firstName))))
modifiedCard = true;
if (!lastName.IsEmpty() &&
NS_SUCCEEDED(aSenderCard->SetLastName(NS_ConvertUTF8toUTF16(lastName))))
modifiedCard = true;
if (modifiedCard)
aSenderCard->SetPropertyAsBool("PreferDisplayName", false);
return modifiedCard;
}
// Splits the first and last name based on the space between them.
void
nsAbAddressCollector::SplitFullName(const nsCString &aFullName, nsCString &aFirstName,
nsCString &aLastName)
{
int index = aFullName.RFindChar(' ');
if (index != -1)
{
aLastName = Substring(aFullName, index + 1);
aFirstName = Substring(aFullName, 0, index);
}
}
// Observes the collected address book pref in case it changes.
NS_IMETHODIMP
nsAbAddressCollector::Observe(nsISupports *aSubject, const char *aTopic,
const char16_t *aData)
{
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
if (!prefBranch) {
NS_ASSERTION(prefBranch, "failed to get prefs");
return NS_OK;
}
SetUpAbFromPrefs(prefBranch);
return NS_OK;
}
// Initialises the collector with the required items.
nsresult
nsAbAddressCollector::Init(void)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID,
&rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = prefBranch->AddObserver(PREF_MAIL_COLLECT_ADDRESSBOOK, this, false);
NS_ENSURE_SUCCESS(rv, rv);
SetUpAbFromPrefs(prefBranch);
return NS_OK;
}
// Performs the necessary changes to set up the collector for the specified
// collected address book.
void
nsAbAddressCollector::SetUpAbFromPrefs(nsIPrefBranch *aPrefBranch)
{
nsCString abURI;
aPrefBranch->GetCharPref(PREF_MAIL_COLLECT_ADDRESSBOOK,
getter_Copies(abURI));
if (abURI.IsEmpty())
abURI.AssignLiteral(kPersonalAddressbookUri);
if (abURI == mABURI)
return;
mDirectory = nullptr;
mABURI = abURI;
nsresult rv;
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS_VOID(rv);
rv = abManager->GetDirectory(mABURI, getter_AddRefs(mDirectory));
NS_ENSURE_SUCCESS_VOID(rv);
bool readOnly;
rv = mDirectory->GetReadOnly(&readOnly);
NS_ENSURE_SUCCESS_VOID(rv);
// If the directory is read-only, we can't write to it, so just blank it out
// here, and warn because we shouldn't hit this (UI is wrong).
if (readOnly)
{
NS_ERROR("Address Collection book preferences is set to a read-only book. "
"Address collection will not take place.");
mDirectory = nullptr;
}
}

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; 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/. */
#ifndef _nsAbAddressCollector_H_
#define _nsAbAddressCollector_H_
#include "nsIAbAddressCollector.h"
#include "nsCOMPtr.h"
#include "nsIAbDirectory.h"
#include "nsIAbCard.h"
#include "nsIObserver.h"
#include "nsStringGlue.h"
class nsIPrefBranch;
class nsAbAddressCollector : public nsIAbAddressCollector,
public nsIObserver
{
public:
nsAbAddressCollector();
NS_DECL_ISUPPORTS
NS_DECL_NSIABADDRESSCOLLECTOR
NS_DECL_NSIOBSERVER
nsresult Init();
private:
virtual ~nsAbAddressCollector();
already_AddRefed<nsIAbCard> GetCardForAddress(const nsACString &aEmailAddress,
nsIAbDirectory **aDirectory);
void AutoCollectScreenName(nsIAbCard *aCard, const nsACString &aEmail);
bool SetNamesForCard(nsIAbCard *aSenderCard, const nsACString &aFullName);
void SplitFullName(const nsCString &aFullName, nsCString &aFirstName,
nsCString &aLastName);
void SetUpAbFromPrefs(nsIPrefBranch *aPrefBranch);
nsCOMPtr <nsIAbDirectory> mDirectory;
nsCString mABURI;
};
#endif // _nsAbAddressCollector_H_

View file

@ -0,0 +1,58 @@
/* 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/. */
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function nsAbAutoCompleteMyDomain() {}
nsAbAutoCompleteMyDomain.prototype = {
classID: Components.ID("{5b259db2-e451-4de9-8a6f-cfba91402973}"),
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsIAutoCompleteSearch]),
cachedIdKey: "",
cachedIdentity: null,
applicableHeaders: new Set(["addr_to", "addr_cc", "addr_bcc", "addr_reply"]),
startSearch: function(aString, aSearchParam, aResult, aListener) {
let params = aSearchParam ? JSON.parse(aSearchParam) : {};
let applicable = ("type" in params) && this.applicableHeaders.has(params.type);
const ACR = Components.interfaces.nsIAutoCompleteResult;
var address = null;
if (applicable && aString && !aString.includes(",")) {
if (("idKey" in params) && (params.idKey != this.cachedIdKey)) {
this.cachedIdentity = MailServices.accounts.getIdentity(params.idKey);
this.cachedIdKey = params.idKey;
}
if (this.cachedIdentity.autocompleteToMyDomain)
address = aString.includes("@") ? aString :
this.cachedIdentity.email.replace(/[^@]*/, aString);
}
var result = {
searchString: aString,
searchResult: address ? ACR.RESULT_SUCCESS : ACR.RESULT_FAILURE,
defaultIndex: -1,
errorDescription: null,
matchCount: address ? 1 : 0,
getValueAt: function() { return address; },
getLabelAt: function() { return this.getValueAt(); },
getCommentAt: function() { return null; },
getStyleAt: function() { return "default-match"; },
getImageAt: function() { return null; },
getFinalCompleteValueAt: function(aIndex) {
return this.getValueAt(aIndex);
},
removeValueAt: function() {}
};
aListener.onSearchResult(this, result);
},
stopSearch: function() {}
};
var components = [nsAbAutoCompleteMyDomain];
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View file

@ -0,0 +1,466 @@
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/ABQueryUtils.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var ACR = Components.interfaces.nsIAutoCompleteResult;
var nsIAbAutoCompleteResult = Components.interfaces.nsIAbAutoCompleteResult;
function nsAbAutoCompleteResult(aSearchString) {
// Can't create this in the prototype as we'd get the same array for
// all instances
this._searchResults = []; // final results
this.searchString = aSearchString;
this._collectedValues = new Map(); // temporary unsorted results
// Get model query from pref; this will return mail.addr_book.autocompletequery.format.phonetic
// if mail.addr_book.show_phonetic_fields == true
this.modelQuery = getModelQuery("mail.addr_book.autocompletequery.format");
// check if the currently active model query has been modified by user
this._modelQueryHasUserValue = modelQueryHasUserValue("mail.addr_book.autocompletequery.format");
}
nsAbAutoCompleteResult.prototype = {
_searchResults: null,
// nsIAutoCompleteResult
modelQuery: null,
searchString: null,
searchResult: ACR.RESULT_NOMATCH,
defaultIndex: -1,
errorDescription: null,
get matchCount() {
return this._searchResults.length;
},
getValueAt: function getValueAt(aIndex) {
return this._searchResults[aIndex].value;
},
getLabelAt: function getLabelAt(aIndex) {
return this.getValueAt(aIndex);
},
getCommentAt: function getCommentAt(aIndex) {
return this._searchResults[aIndex].comment;
},
getStyleAt: function getStyleAt(aIndex) {
return "local-abook";
},
getImageAt: function getImageAt(aIndex) {
return "";
},
getFinalCompleteValueAt: function(aIndex) {
return this.getValueAt(aIndex);
},
removeValueAt: function removeValueAt(aRowIndex, aRemoveFromDB) {
},
// nsIAbAutoCompleteResult
getCardAt: function getCardAt(aIndex) {
return this._searchResults[aIndex].card;
},
getEmailToUse: function getEmailToUse(aIndex) {
return this._searchResults[aIndex].emailToUse;
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([ACR, nsIAbAutoCompleteResult])
}
function nsAbAutoCompleteSearch() {}
nsAbAutoCompleteSearch.prototype = {
// For component registration
classID: Components.ID("2f946df9-114c-41fe-8899-81f10daf4f0c"),
// This is set from a preference,
// 0 = no comment column, 1 = name of address book this card came from
// Other numbers currently unused (hence default to zero)
_commentColumn: 0,
_parser: MailServices.headerParser,
_abManager: MailServices.ab,
applicableHeaders: new Set(["addr_to", "addr_cc", "addr_bcc", "addr_reply"]),
// Private methods
/**
* Returns the popularity index for a given card. This takes account of a
* translation bug whereby Thunderbird 2 stores its values in mork as
* hexadecimal, and Thunderbird 3 stores as decimal.
*
* @param aDirectory The directory that the card is in.
* @param aCard The card to return the popularity index for.
*/
_getPopularityIndex: function _getPopularityIndex(aDirectory, aCard) {
let popularityValue = aCard.getProperty("PopularityIndex", "0");
let popularityIndex = parseInt(popularityValue);
// If we haven't parsed it the first time round, parse it as hexadecimal
// and repair so that we don't have to keep repairing.
if (isNaN(popularityIndex)) {
popularityIndex = parseInt(popularityValue, 16);
// If its still NaN, just give up, we shouldn't ever get here.
if (isNaN(popularityIndex))
popularityIndex = 0;
// Now store this change so that we're not changing it each time around.
if (!aDirectory.readOnly) {
aCard.setProperty("PopularityIndex", popularityIndex);
try {
aDirectory.modifyCard(aCard);
}
catch (ex) {
Components.utils.reportError(ex);
}
}
}
return popularityIndex;
},
/**
* Gets the score of the (full) address, given the search input. We want
* results that match the beginning of a "word" in the result to score better
* than a result that matches only in the middle of the word.
*
* @param aCard - the card whose score is being decided
* @param aAddress - full lower-cased address, including display name and address
* @param aSearchString - search string provided by user
* @return a score; a higher score is better than a lower one
*/
_getScore: function(aCard, aAddress, aSearchString) {
const BEST = 100;
// We will firstly check if the search term provided by the user
// is the nick name for the card or at least in the beginning of it.
let nick = aCard.getProperty("NickName", "").toLocaleLowerCase();
aSearchString = aSearchString.toLocaleLowerCase();
if (nick == aSearchString)
return BEST + 1;
if (nick.indexOf(aSearchString) == 0)
return BEST;
// We'll do this case-insensitively and ignore the domain.
let atIdx = aAddress.lastIndexOf("@");
if (atIdx != -1) // mail lists don't have an @
aAddress = aAddress.substr(0, atIdx);
let idx = aAddress.indexOf(aSearchString);
if (idx == 0)
return BEST;
if (idx == -1)
return 0;
// We want to treat firstname, lastname and word boundary(ish) parts of
// the email address the same. E.g. for "John Doe (:xx) <jd.who@example.com>"
// all of these should score the same: "John", "Doe", "xx",
// ":xx", "jd", "who".
let prevCh = aAddress.charAt(idx - 1);
if (/[ :."'(\-_<&]/.test(prevCh))
return BEST;
// The match was inside a word -> we don't care about the position.
return 0;
},
/**
* Searches cards in the given directory. If a card is matched (and isn't
* a mailing list) then the function will add a result for each email address
* that exists.
*
* @param searchQuery The boolean search query to use.
* @param directory An nsIAbDirectory to search.
* @param result The result element to append results to.
*/
_searchCards: function(searchQuery, directory, result) {
let childCards;
try {
childCards = this._abManager.getDirectory(directory.URI + searchQuery).childCards;
} catch (e) {
Components.utils.reportError("Error running addressbook query '" + searchQuery + "': " + e);
return;
}
// Cache this values to save going through xpconnect each time
var commentColumn = this._commentColumn == 1 ? directory.dirName : "";
// Now iterate through all the cards.
while (childCards.hasMoreElements()) {
var card = childCards.getNext();
if (card instanceof Components.interfaces.nsIAbCard) {
if (card.isMailList)
this._addToResult(commentColumn, directory, card, "", true, result);
else {
let email = card.primaryEmail;
if (email)
this._addToResult(commentColumn, directory, card, email, true, result);
email = card.getProperty("SecondEmail", "");
if (email)
this._addToResult(commentColumn, directory, card, email, false, result);
}
}
}
},
/**
* Checks the parent card and email address of an autocomplete results entry
* from a previous result against the search parameters to see if that entry
* should still be included in the narrowed-down result.
*
* @param aCard The card to check.
* @param aEmailToUse The email address to check against.
* @param aSearchWords Array of words in the multi word search string.
* @return True if the card matches the search parameters, false
* otherwise.
*/
_checkEntry: function _checkEntry(aCard, aEmailToUse, aSearchWords) {
// Joining values of many fields in a single string so that a single
// search query can be fired on all of them at once. Separating them
// using spaces so that field1=> "abc" and field2=> "def" on joining
// shouldn't return true on search for "bcd".
// Note: This should be constructed from model query pref using
// getModelQuery("mail.addr_book.autocompletequery.format")
// but for now we hard-code the default value equivalent of the pref here
// or else bail out before and reconstruct the full c++ query if the pref
// has been customized (modelQueryHasUserValue), so that we won't get here.
let cumulativeFieldText = aCard.displayName + " " +
aCard.firstName + " " +
aCard.lastName + " " +
aEmailToUse + " " +
aCard.getProperty("NickName", "");
if (aCard.isMailList)
cumulativeFieldText += " " + aCard.getProperty("Notes", "");
cumulativeFieldText = cumulativeFieldText.toLocaleLowerCase();
return aSearchWords.every(String.prototype.includes,
cumulativeFieldText);
},
/**
* Checks to see if an emailAddress (name/address) is a duplicate of an
* existing entry already in the results. If the emailAddress is found, it
* will remove the existing element if the popularity of the new card is
* higher than the previous card.
*
* @param directory The directory that the card is in.
* @param card The card that could be a duplicate.
* @param lcEmailAddress The emailAddress (name/address combination) to check
* for duplicates against. Lowercased.
* @param currentResults The current results list.
*/
_checkDuplicate: function (directory, card, lcEmailAddress, currentResults) {
let existingResult = currentResults._collectedValues.get(lcEmailAddress);
if (!existingResult)
return false;
let popIndex = this._getPopularityIndex(directory, card);
// It's a duplicate, is the new one more popular?
if (popIndex > existingResult.popularity) {
// Yes it is, so delete this element, return false and allow
// _addToResult to sort the new element into the correct place.
currentResults._collectedValues.delete(lcEmailAddress);
return false;
}
// Not more popular, but still a duplicate. Return true and _addToResult
// will just forget about it.
return true;
},
/**
* Adds a card to the results list if it isn't a duplicate. The function will
* order the results by popularity.
*
* @param commentColumn The text to be displayed in the comment column
* (if any).
* @param directory The directory that the card is in.
* @param card The card being added to the results.
* @param emailToUse The email address from the card that should be used
* for this result.
* @param isPrimaryEmail Is the emailToUse the primary email? Set to true if
* it is the case. For mailing lists set it to true.
* @param result The result to add the new entry to.
*/
_addToResult: function(commentColumn, directory, card,
emailToUse, isPrimaryEmail, result) {
let mbox = this._parser.makeMailboxObject(card.displayName,
card.isMailList ? card.getProperty("Notes", "") || card.displayName :
emailToUse);
if (!mbox.email)
return;
let emailAddress = mbox.toString();
let lcEmailAddress = emailAddress.toLocaleLowerCase();
// If it is a duplicate, then just return and don't add it. The
// _checkDuplicate function deals with it all for us.
if (this._checkDuplicate(directory, card, lcEmailAddress, result))
return;
result._collectedValues.set(lcEmailAddress, {
value: emailAddress,
comment: commentColumn,
card: card,
isPrimaryEmail: isPrimaryEmail,
emailToUse: emailToUse,
popularity: this._getPopularityIndex(directory, card),
score: this._getScore(card, lcEmailAddress, result.searchString)
});
},
// nsIAutoCompleteSearch
/**
* Starts a search based on the given parameters.
*
* @see nsIAutoCompleteSearch for parameter details.
*
* It is expected that aSearchParam contains the identity (if any) to use
* for determining if an address book should be autocompleted against.
*/
startSearch: function startSearch(aSearchString, aSearchParam,
aPreviousResult, aListener) {
let params = aSearchParam ? JSON.parse(aSearchParam) : {};
var result = new nsAbAutoCompleteResult(aSearchString);
if (("type" in params) && !this.applicableHeaders.has(params.type)) {
result.searchResult = ACR.RESULT_IGNORED;
aListener.onSearchResult(this, result);
return;
}
let fullString = aSearchString && aSearchString.trim().toLocaleLowerCase();
// If the search string is empty, or contains a comma, or the user
// hasn't enabled autocomplete, then just return no matches or the
// result ignored.
// The comma check is so that we don't autocomplete against the user
// entering multiple addresses.
if (!fullString || aSearchString.includes(",")) {
result.searchResult = ACR.RESULT_IGNORED;
aListener.onSearchResult(this, result);
return;
}
// Array of all the terms from the fullString search query
// (separated on the basis of spaces or exact terms on the
// basis of quotes).
let searchWords = getSearchTokens(fullString);
// Find out about the comment column
try {
this._commentColumn = Services.prefs.getIntPref("mail.autoComplete.commentColumn");
} catch(e) { }
if (aPreviousResult instanceof nsIAbAutoCompleteResult &&
aSearchString.startsWith(aPreviousResult.searchString) &&
aPreviousResult.searchResult == ACR.RESULT_SUCCESS &&
!result._modelQueryHasUserValue &&
result.modelQuery == aPreviousResult.modelQuery) {
// We have successful previous matches, and model query has not changed since
// previous search, therefore just iterate through the list of previous result
// entries and reduce as appropriate (via _checkEntry function).
// Test for model query change is required: when reverting back from custom to
// default query, result._modelQueryHasUserValue==false, but we must bail out.
// Todo: However, if autocomplete model query has been customized, we fall
// back to using the full query again instead of reducing result list in js;
// The full query might be less performant as it's fired against entire AB,
// so we should try morphing the query for js. We can't use the _checkEntry
// js query yet because it is hardcoded (mimic default model query).
// At least we now allow users to customize their autocomplete model query...
for (let i = 0; i < aPreviousResult.matchCount; ++i) {
let card = aPreviousResult.getCardAt(i);
let email = aPreviousResult.getEmailToUse(i);
if (this._checkEntry(card, email, searchWords)) {
// Add matches into the results array. We re-sort as needed later.
result._searchResults.push({
value: aPreviousResult.getValueAt(i),
comment: aPreviousResult.getCommentAt(i),
card: card,
isPrimaryEmail: (card.primaryEmail == email),
emailToUse: email,
popularity: parseInt(card.getProperty("PopularityIndex", "0")),
score: this._getScore(card,
aPreviousResult.getValueAt(i).toLocaleLowerCase(),
fullString)
});
}
}
}
else
{
// Construct the search query from pref; using a query means we can
// optimise on running the search through c++ which is better for string
// comparisons (_checkEntry is relatively slow).
// When user's fullstring search expression is a multiword query, search
// for each word separately so that each result contains all the words
// from the fullstring in the fields of the addressbook card
// (see bug 558931 for explanations).
// Use helper method to split up search query to multi-word search
// query against multiple fields.
let searchWords = getSearchTokens(fullString);
let searchQuery = generateQueryURI(result.modelQuery, searchWords);
// Now do the searching
let allABs = this._abManager.directories;
// We're not going to bother searching sub-directories, currently the
// architecture forces all cards that are in mailing lists to be in ABs as
// well, therefore by searching sub-directories (aka mailing lists) we're
// just going to find duplicates.
while (allABs.hasMoreElements()) {
let dir = allABs.getNext();
if (dir instanceof Components.interfaces.nsIAbDirectory &&
dir.useForAutocomplete(("idKey" in params) ? params.idKey : null)) {
this._searchCards(searchQuery, dir, result);
}
}
result._searchResults = [...result._collectedValues.values()];
}
// Sort the results. Scoring may have changed so do it even if this is
// just filtered previous results.
result._searchResults.sort(function(a, b) {
// Order by 1) descending score, then 2) descending popularity,
// then 3) primary email before secondary for the same card, then
// 4) by emails sorted alphabetically.
return (b.score - a.score) ||
(b.popularity - a.popularity) ||
((a.card == b.card && a.isPrimaryEmail) ? -1 : 0) ||
a.value.localeCompare(b.value);
});
if (result.matchCount) {
result.searchResult = ACR.RESULT_SUCCESS;
result.defaultIndex = 0;
}
aListener.onSearchResult(this, result);
},
stopSearch: function stopSearch() {
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Components.interfaces
.nsIAutoCompleteSearch])
};
// Module
var components = [nsAbAutoCompleteSearch];
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View file

@ -0,0 +1,323 @@
/* -*- Mode: C++; 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/. */
#include "nsIPrefService.h"
#include "nsAbBSDirectory.h"
#include "nsDirPrefs.h"
#include "nsAbBaseCID.h"
#include "nsAddrDatabase.h"
#include "nsIAbManager.h"
#include "nsIAbMDBDirectory.h"
#include "nsServiceManagerUtils.h"
#include "nsAbDirFactoryService.h"
#include "nsAbMDBDirFactory.h"
#include "nsArrayEnumerator.h"
#include "nsCRTGlue.h"
nsAbBSDirectory::nsAbBSDirectory()
: mInitialized(false)
, mServers(13)
{
}
nsAbBSDirectory::~nsAbBSDirectory()
{
}
NS_IMETHODIMP nsAbBSDirectory::Init(const char *aURI)
{
mURI = aURI;
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(nsAbBSDirectory, nsAbDirProperty)
nsresult nsAbBSDirectory::CreateDirectoriesFromFactory(const nsACString &aURI,
DIR_Server *aServer,
bool aNotify)
{
nsresult rv;
// Get the directory factory service
nsCOMPtr<nsIAbDirFactoryService> dirFactoryService =
do_GetService(NS_ABDIRFACTORYSERVICE_CONTRACTID,&rv);
NS_ENSURE_SUCCESS (rv, rv);
// Get the directory factory from the URI
nsCOMPtr<nsIAbDirFactory> dirFactory;
rv = dirFactoryService->GetDirFactory(aURI, getter_AddRefs(dirFactory));
NS_ENSURE_SUCCESS (rv, rv);
// Create the directories
nsCOMPtr<nsISimpleEnumerator> newDirEnumerator;
rv = dirFactory->GetDirectories(NS_ConvertUTF8toUTF16(aServer->description),
aURI,
nsDependentCString(aServer->prefName),
getter_AddRefs(newDirEnumerator));
NS_ENSURE_SUCCESS (rv, rv);
// Enumerate through the directories adding them
// to the sub directories array
bool hasMore;
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
while (NS_SUCCEEDED(newDirEnumerator->HasMoreElements(&hasMore)) && hasMore)
{
nsCOMPtr<nsISupports> newDirSupports;
rv = newDirEnumerator->GetNext(getter_AddRefs(newDirSupports));
if(NS_FAILED(rv))
continue;
nsCOMPtr<nsIAbDirectory> childDir = do_QueryInterface(newDirSupports, &rv);
if(NS_FAILED(rv))
continue;
// Define a relationship between the preference
// entry and the directory
mServers.Put(childDir, aServer);
mSubDirectories.AppendObject(childDir);
if (aNotify && abManager)
abManager->NotifyDirectoryItemAdded(this, childDir);
}
return NS_OK;
}
NS_IMETHODIMP nsAbBSDirectory::GetChildNodes(nsISimpleEnumerator* *aResult)
{
nsresult rv = EnsureInitialized();
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewArrayEnumerator(aResult, mSubDirectories);
}
nsresult nsAbBSDirectory::EnsureInitialized()
{
if (mInitialized)
return NS_OK;
nsresult rv;
nsCOMPtr<nsIAbDirFactoryService> dirFactoryService =
do_GetService(NS_ABDIRFACTORYSERVICE_CONTRACTID,&rv);
NS_ENSURE_SUCCESS (rv, rv);
nsTArray<DIR_Server*> *directories = DIR_GetDirectories();
if (!directories)
return NS_ERROR_FAILURE;
int32_t count = directories->Length();
for (int32_t i = 0; i < count; i++)
{
DIR_Server *server = directories->ElementAt(i);
// if this is a 4.x, local .na2 addressbook (PABDirectory)
// we must skip it.
// mozilla can't handle 4.x .na2 addressbooks
// note, the filename might be na2 for 4.x LDAP directories
// (we used the .na2 file for replication), and we don't want to skip
// those. see bug #127007
uint32_t fileNameLen = strlen(server->fileName);
if (((fileNameLen > kABFileName_PreviousSuffixLen) &&
strcmp(server->fileName + fileNameLen - kABFileName_PreviousSuffixLen,
kABFileName_PreviousSuffix) == 0) &&
(server->dirType == PABDirectory))
continue;
// Set the uri property
nsAutoCString URI (server->uri);
// This is in case the uri is never set
// in the nsDirPref.cpp code.
if (!server->uri)
{
URI = NS_LITERAL_CSTRING(kMDBDirectoryRoot);
URI += nsDependentCString(server->fileName);
}
/*
* Check that we are not converting from a
* a 4.x address book file e.g. pab.na2
* check if the URI ends with ".na2"
*/
if (StringEndsWith(URI, NS_LITERAL_CSTRING(kABFileName_PreviousSuffix)))
URI.Replace(kMDBDirectoryRootLen, URI.Length() - kMDBDirectoryRootLen, server->fileName);
// Create the directories
rv = CreateDirectoriesFromFactory(URI, server, false /* notify */);
// If we failed, this could be because something has set a pref for us
// which is now broke (e.g. no factory present). So just ignore this one
// and move on.
if (NS_FAILED(rv))
NS_WARNING("CreateDirectoriesFromFactory failed - Invalid factory?");
}
mInitialized = true;
// sort directories by position...
return NS_OK;
}
NS_IMETHODIMP nsAbBSDirectory::CreateNewDirectory(const nsAString &aDirName,
const nsACString &aURI,
uint32_t aType,
const nsACString &aPrefName,
nsACString &aResult)
{
nsresult rv = EnsureInitialized();
NS_ENSURE_SUCCESS(rv, rv);
/*
* TODO
* This procedure is still MDB specific
* due to the dependence on the current
* nsDirPref.cpp code
*/
nsCString URI(aURI);
/*
* The creation of the address book in the preferences
* is very MDB implementation specific.
* If the fileName attribute is null then it will
* create an appropriate file name.
* Somehow have to resolve this issue so that it
* is more general.
*
*/
DIR_Server* server = nullptr;
rv = DIR_AddNewAddressBook(aDirName, EmptyCString(), URI,
(DirectoryType)aType, aPrefName, &server);
NS_ENSURE_SUCCESS (rv, rv);
if (aType == PABDirectory) {
// Add the URI property
URI.AssignLiteral(kMDBDirectoryRoot);
URI.Append(nsDependentCString(server->fileName));
}
aResult.Assign(server->prefName);
rv = CreateDirectoriesFromFactory(URI, server, true /* notify */);
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
NS_IMETHODIMP nsAbBSDirectory::CreateDirectoryByURI(const nsAString &aDisplayName,
const nsACString &aURI)
{
nsresult rv = EnsureInitialized();
NS_ENSURE_SUCCESS(rv, rv);
nsCString fileName;
if (StringBeginsWith(aURI, NS_LITERAL_CSTRING(kMDBDirectoryRoot)))
fileName = Substring(aURI, kMDBDirectoryRootLen);
DIR_Server * server = nullptr;
rv = DIR_AddNewAddressBook(aDisplayName, fileName, aURI,
PABDirectory, EmptyCString(), &server);
NS_ENSURE_SUCCESS(rv,rv);
rv = CreateDirectoriesFromFactory(aURI, server, true /* notify */);
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
NS_IMETHODIMP nsAbBSDirectory::DeleteDirectory(nsIAbDirectory *directory)
{
NS_ENSURE_ARG_POINTER(directory);
nsresult rv = EnsureInitialized();
NS_ENSURE_SUCCESS(rv, rv);
DIR_Server *server = nullptr;
mServers.Get(directory, &server);
if (!server)
return NS_ERROR_FAILURE;
struct GetDirectories
{
GetDirectories(DIR_Server* aServer) : mServer(aServer) { }
nsCOMArray<nsIAbDirectory> directories;
DIR_Server* mServer;
};
GetDirectories getDirectories(server);
for (auto iter = mServers.Iter(); !iter.Done(); iter.Next()) {
if (iter.UserData() == getDirectories.mServer) {
nsCOMPtr<nsIAbDirectory> abDir = do_QueryInterface(iter.Key());
getDirectories.directories.AppendObject(abDir);
}
}
DIR_DeleteServerFromList(server);
nsCOMPtr<nsIAbDirFactoryService> dirFactoryService =
do_GetService(NS_ABDIRFACTORYSERVICE_CONTRACTID,&rv);
NS_ENSURE_SUCCESS (rv, rv);
uint32_t count = getDirectories.directories.Count();
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID);
for (uint32_t i = 0; i < count; i++) {
nsCOMPtr<nsIAbDirectory> d = getDirectories.directories[i];
mServers.Remove(d);
mSubDirectories.RemoveObject(d);
if (abManager)
abManager->NotifyDirectoryDeleted(this, d);
nsCString uri;
rv = d->GetURI(uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirFactory> dirFactory;
rv = dirFactoryService->GetDirFactory(uri, getter_AddRefs(dirFactory));
if (NS_FAILED(rv))
continue;
rv = dirFactory->DeleteDirectory(d);
}
return rv;
}
NS_IMETHODIMP nsAbBSDirectory::HasDirectory(nsIAbDirectory *dir, bool *hasDir)
{
if (!hasDir)
return NS_ERROR_NULL_POINTER;
nsresult rv = EnsureInitialized();
NS_ENSURE_SUCCESS(rv, rv);
DIR_Server *dirServer = nullptr;
mServers.Get(dir, &dirServer);
return DIR_ContainsServer(dirServer, hasDir);
}
NS_IMETHODIMP nsAbBSDirectory::UseForAutocomplete(const nsACString &aIdentityKey,
bool *aResult)
{
// For the "root" directory (kAllDirectoryRoot) always return true so that
// we can search sub directories that may or may not be local.
NS_ENSURE_ARG_POINTER(aResult);
*aResult = true;
return NS_OK;
}
NS_IMETHODIMP nsAbBSDirectory::GetURI(nsACString &aURI)
{
if (mURI.IsEmpty())
return NS_ERROR_NOT_INITIALIZED;
aURI = mURI;
return NS_OK;
}

View file

@ -0,0 +1,50 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbBSDirectory_h__
#define nsAbBSDirectory_h__
#include "mozilla/Attributes.h"
#include "nsAbDirProperty.h"
#include "nsDataHashtable.h"
#include "nsCOMArray.h"
class nsAbBSDirectory : public nsAbDirProperty
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsAbBSDirectory();
// nsIAbDirectory methods
NS_IMETHOD Init(const char *aURI) override;
NS_IMETHOD GetChildNodes(nsISimpleEnumerator* *result) override;
NS_IMETHOD CreateNewDirectory(const nsAString &aDirName,
const nsACString &aURI,
uint32_t aType,
const nsACString &aPrefName,
nsACString &aResult) override;
NS_IMETHOD CreateDirectoryByURI(const nsAString &aDisplayName,
const nsACString &aURI) override;
NS_IMETHOD DeleteDirectory(nsIAbDirectory *directory) override;
NS_IMETHOD HasDirectory(nsIAbDirectory *dir, bool *hasDir) override;
NS_IMETHOD UseForAutocomplete(const nsACString &aIdentityKey, bool *aResult) override;
NS_IMETHOD GetURI(nsACString &aURI) override;
protected:
virtual ~nsAbBSDirectory();
nsresult EnsureInitialized();
nsresult CreateDirectoriesFromFactory(const nsACString &aURI,
DIR_Server* aServer, bool aNotify);
protected:
bool mInitialized;
nsCOMArray<nsIAbDirectory> mSubDirectories;
nsDataHashtable<nsISupportsHashKey, DIR_Server*> mServers;
};
#endif

View file

@ -0,0 +1,246 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsIAbLDAPAttributeMap.h"
#include "nsAbBoolExprToLDAPFilter.h"
#include "nsStringGlue.h"
#include "nsIArray.h"
#include "nsArrayUtils.h"
const int nsAbBoolExprToLDAPFilter::TRANSLATE_CARD_PROPERTY = 1 << 0 ;
const int nsAbBoolExprToLDAPFilter::ALLOW_NON_CONVERTABLE_CARD_PROPERTY = 1 << 1 ;
nsresult nsAbBoolExprToLDAPFilter::Convert (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanExpression* expression,
nsCString& filter,
int flags)
{
nsCString f;
nsresult rv = FilterExpression (map, expression, f, flags);
NS_ENSURE_SUCCESS(rv, rv);
filter = f;
return rv;
}
nsresult nsAbBoolExprToLDAPFilter::FilterExpression (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanExpression* expression,
nsCString& filter,
int flags)
{
nsCOMPtr<nsIArray> childExpressions;
nsresult rv = expression->GetExpressions(getter_AddRefs(childExpressions));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t count;
rv = childExpressions->GetLength(&count);
NS_ENSURE_SUCCESS(rv, rv);
if (count == 0)
return NS_OK;
nsAbBooleanOperationType operation;
rv = expression->GetOperation(&operation);
NS_ENSURE_SUCCESS(rv, rv);
/*
* 3rd party query integration with Mozilla is achieved
* by calling nsAbLDAPDirectoryQuery::DoQuery(). Thus
* we can arrive here with a query asking for all the
* ldap attributes using the card:nsIAbCard interface.
*
* So we need to check that we are not creating a condition
* filter against this expression otherwise we will end up with an invalid
* filter equal to "(|)".
*/
if (count == 1 )
{
nsCOMPtr<nsIAbBooleanConditionString>
childCondition(do_QueryElementAt(childExpressions, 1, &rv));
if (NS_SUCCEEDED(rv))
{
nsCString name;
rv = childCondition->GetName (getter_Copies (name));
NS_ENSURE_SUCCESS(rv, rv);
if(name.Equals("card:nsIAbCard"))
return NS_OK;
}
}
filter.AppendLiteral("(");
switch (operation)
{
case nsIAbBooleanOperationTypes::AND:
filter.AppendLiteral("&");
rv = FilterExpressions (map, childExpressions, filter, flags);
break;
case nsIAbBooleanOperationTypes::OR:
filter.AppendLiteral("|");
rv = FilterExpressions (map, childExpressions, filter, flags);
break;
case nsIAbBooleanOperationTypes::NOT:
if (count > 1)
return NS_ERROR_FAILURE;
filter.AppendLiteral("!");
rv = FilterExpressions (map, childExpressions, filter, flags);
break;
default:
break;
}
filter.AppendLiteral(")");
return rv;
}
nsresult nsAbBoolExprToLDAPFilter::FilterExpressions (
nsIAbLDAPAttributeMap *map,
nsIArray* expressions,
nsCString& filter,
int flags)
{
uint32_t count;
nsresult rv = expressions->GetLength(&count);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanConditionString> childCondition;
nsCOMPtr<nsIAbBooleanExpression> childExpression;
for (uint32_t i = 0; i < count; i++)
{
childCondition = do_QueryElementAt(expressions, i, &rv);
if (NS_SUCCEEDED(rv))
{
rv = FilterCondition (map, childCondition, filter, flags);
NS_ENSURE_SUCCESS(rv, rv);
continue;
}
childExpression = do_QueryElementAt(expressions, i, &rv);
if (NS_SUCCEEDED(rv))
{
rv = FilterExpression (map, childExpression, filter, flags);
NS_ENSURE_SUCCESS(rv, rv);
continue;
}
}
return rv;
}
nsresult nsAbBoolExprToLDAPFilter::FilterCondition (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanConditionString* condition,
nsCString& filter,
int flags)
{
nsCString name;
nsresult rv = condition->GetName(getter_Copies (name));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString ldapAttr(name);
if (flags & TRANSLATE_CARD_PROPERTY)
{
rv = map->GetFirstAttribute (name, ldapAttr);
if (!(flags & ALLOW_NON_CONVERTABLE_CARD_PROPERTY) &&
!ATTRMAP_FOUND_ATTR(rv, ldapAttr))
return NS_OK;
}
nsAbBooleanConditionType conditionType;
rv = condition->GetCondition(&conditionType);
NS_ENSURE_SUCCESS(rv, rv);
nsString value;
rv = condition->GetValue (getter_Copies (value));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 vUTF8 (value);
switch (conditionType)
{
case nsIAbBooleanConditionTypes::DoesNotExist:
filter.AppendLiteral("(!(");
filter.Append(ldapAttr);
filter.AppendLiteral("=*))");
break;
case nsIAbBooleanConditionTypes::Exists:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("=*)");
break;
case nsIAbBooleanConditionTypes::Contains:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.Append("=*");
filter.Append(vUTF8);
filter.AppendLiteral("*)");
break;
case nsIAbBooleanConditionTypes::DoesNotContain:
filter.AppendLiteral("(!(");
filter.Append(ldapAttr);
filter.AppendLiteral("=*");
filter.Append(vUTF8);
filter.AppendLiteral("*))");
break;
case nsIAbBooleanConditionTypes::Is:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("=");
filter.Append(vUTF8);
filter.AppendLiteral(")");
break;
case nsIAbBooleanConditionTypes::IsNot:
filter.AppendLiteral("(!(");
filter.Append(ldapAttr);
filter.AppendLiteral("=");
filter.Append(vUTF8);
filter.AppendLiteral("))");
break;
case nsIAbBooleanConditionTypes::BeginsWith:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("=");
filter.Append(vUTF8);
filter.AppendLiteral("*)");
break;
case nsIAbBooleanConditionTypes::EndsWith:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("=*");
filter.Append(vUTF8);
filter.AppendLiteral(")");
break;
case nsIAbBooleanConditionTypes::LessThan:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("<=");
filter.Append(vUTF8);
filter.AppendLiteral(")");
break;
case nsIAbBooleanConditionTypes::GreaterThan:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral(">=");
filter.Append(vUTF8);
filter.AppendLiteral(")");
break;
case nsIAbBooleanConditionTypes::SoundsLike:
filter.AppendLiteral("(");
filter.Append(ldapAttr);
filter.AppendLiteral("~=");
filter.Append(vUTF8);
filter.AppendLiteral(")");
break;
case nsIAbBooleanConditionTypes::RegExp:
break;
default:
break;
}
return rv;
}

View file

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsBooleanExpressionToLDAPFilter_h__
#define nsBooleanExpressionToLDAPFilter_h__
#include "nsIAbBooleanExpression.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
class nsIAbLDAPAttributeMap;
class nsAbBoolExprToLDAPFilter
{
public:
static const int TRANSLATE_CARD_PROPERTY ;
static const int ALLOW_NON_CONVERTABLE_CARD_PROPERTY ;
static nsresult Convert (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanExpression* expression,
nsCString& filter,
int flags = TRANSLATE_CARD_PROPERTY);
protected:
static nsresult FilterExpression (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanExpression* expression,
nsCString& filter,
int flags);
static nsresult FilterExpressions (
nsIAbLDAPAttributeMap* map,
nsIArray* expressions,
nsCString& filter,
int flags);
static nsresult FilterCondition (
nsIAbLDAPAttributeMap* map,
nsIAbBooleanConditionString* condition,
nsCString& filter,
int flags);
};
#endif

View file

@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsAbBooleanExpression.h"
#include "nsComponentManagerUtils.h"
NS_IMPL_ISUPPORTS(nsAbBooleanConditionString, nsIAbBooleanConditionString)
nsAbBooleanConditionString::nsAbBooleanConditionString() :
mCondition (nsIAbBooleanConditionTypes::Exists)
{
}
nsAbBooleanConditionString::~nsAbBooleanConditionString()
{
}
/* attribute nsAbBooleanConditionType condition; */
NS_IMETHODIMP nsAbBooleanConditionString::GetCondition(nsAbBooleanConditionType *aCondition)
{
if (!aCondition)
return NS_ERROR_NULL_POINTER;
*aCondition = mCondition;
return NS_OK;
}
NS_IMETHODIMP nsAbBooleanConditionString::SetCondition(nsAbBooleanConditionType aCondition)
{
mCondition = aCondition;
return NS_OK;
}
/* attribute string name; */
NS_IMETHODIMP nsAbBooleanConditionString::GetName(char** aName)
{
if (!aName)
return NS_ERROR_NULL_POINTER;
*aName = mName.IsEmpty() ? 0 : ToNewCString(mName);
return NS_OK;
}
NS_IMETHODIMP nsAbBooleanConditionString::SetName(const char* aName)
{
if (!aName)
return NS_ERROR_NULL_POINTER;
mName = aName;
return NS_OK;
}
/* attribute wstring value; */
NS_IMETHODIMP nsAbBooleanConditionString::GetValue(char16_t** aValue)
{
if (!aValue)
return NS_ERROR_NULL_POINTER;
*aValue = ToNewUnicode(mValue);
return NS_OK;
}
NS_IMETHODIMP nsAbBooleanConditionString::SetValue(const char16_t * aValue)
{
if (!aValue)
return NS_ERROR_NULL_POINTER;
mValue = aValue;
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsAbBooleanExpression, nsIAbBooleanExpression)
nsAbBooleanExpression::nsAbBooleanExpression() :
mOperation (nsIAbBooleanOperationTypes::AND)
{
}
nsAbBooleanExpression::~nsAbBooleanExpression()
{
}
/* attribute nsAbBooleanOperationType operation; */
NS_IMETHODIMP nsAbBooleanExpression::GetOperation(nsAbBooleanOperationType *aOperation)
{
if (!aOperation)
return NS_ERROR_NULL_POINTER;
*aOperation = mOperation;
return NS_OK;
}
NS_IMETHODIMP nsAbBooleanExpression::SetOperation(nsAbBooleanOperationType aOperation)
{
mOperation = aOperation;
return NS_OK;
}
/* attribute nsIArray expressions; */
NS_IMETHODIMP nsAbBooleanExpression::GetExpressions(nsIArray **aExpressions)
{
if (!aExpressions)
return NS_ERROR_NULL_POINTER;
if (!mExpressions)
{
mExpressions = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!mExpressions)
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aExpressions = mExpressions);
return NS_OK;
}
NS_IMETHODIMP nsAbBooleanExpression::SetExpressions(nsIArray *aExpressions)
{
if (!aExpressions)
return NS_ERROR_NULL_POINTER;
mExpressions = aExpressions;
return NS_OK;
}

View file

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbBooleanExpression_h__
#define nsAbBooleanExpression_h__
#include "nsIAbBooleanExpression.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsIArray.h"
class nsAbBooleanConditionString : public nsIAbBooleanConditionString
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABBOOLEANCONDITIONSTRING
nsAbBooleanConditionString();
protected:
virtual ~nsAbBooleanConditionString();
nsAbBooleanConditionType mCondition;
nsCString mName;
nsString mValue;
};
class nsAbBooleanExpression: public nsIAbBooleanExpression
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABBOOLEANEXPRESSION
nsAbBooleanExpression();
protected:
virtual ~nsAbBooleanExpression();
nsAbBooleanOperationType mOperation;
nsCOMPtr<nsIArray> mExpressions;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
/* -*- Mode: C++; 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/. */
/********************************************************************************************************
Interface for representing Address Book Person Card Property
*********************************************************************************************************/
#ifndef nsAbCardProperty_h__
#define nsAbCardProperty_h__
#include "nsIAbCard.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsInterfaceHashtable.h"
#include "nsIVariant.h"
class nsIStringBundle;
class mozITXTToHTMLConv;
struct AppendItem;
/*
* Address Book Card Property
*/
class nsAbCardProperty: public nsIAbCard
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABCARD
NS_DECL_NSIABITEM
nsAbCardProperty();
protected:
virtual ~nsAbCardProperty();
bool m_IsMailList;
nsCString m_MailListURI;
// Store most of the properties here
nsInterfaceHashtable<nsCStringHashKey, nsIVariant> m_properties;
nsCString m_directoryId, m_localId;
private:
nsresult AppendSection(const AppendItem *aArray, int16_t aCount, const nsString& aHeading, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
nsresult AppendLine(const AppendItem &aItem, mozITXTToHTMLConv *aConv, nsString &aResult);
nsresult AppendLabel(const AppendItem &aItem, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
nsresult AppendCityStateZip(const AppendItem &aItem, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
nsresult ConvertToBase64EncodedXML(nsACString &result);
nsresult ConvertToXMLPrintData(nsAString &result);
nsresult ConvertToEscapedVCard(nsACString &result);
};
#endif

View file

@ -0,0 +1,184 @@
/* -*- Mode: C++; 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/. */
#include "nsAbContentHandler.h"
#include "nsAbBaseCID.h"
#include "nsNetUtil.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsNullPrincipal.h"
#include "nsISupportsPrimitives.h"
#include "plstr.h"
#include "nsPIDOMWindow.h"
#include "mozIDOMWindow.h"
#include "nsMsgUtils.h"
#include "nsIMsgVCardService.h"
#include "nsIAbCard.h"
#include "nsIAbManager.h"
#include "nsVCard.h"
#include "nsIChannel.h"
//
// nsAbContentHandler
//
nsAbContentHandler::nsAbContentHandler()
{
}
nsAbContentHandler::~nsAbContentHandler()
{
}
NS_IMPL_ISUPPORTS(nsAbContentHandler, nsIContentHandler,
nsIStreamLoaderObserver)
NS_IMETHODIMP
nsAbContentHandler::HandleContent(const char *aContentType,
nsIInterfaceRequestor *aWindowContext,
nsIRequest *request)
{
NS_ENSURE_ARG_POINTER(request);
nsresult rv = NS_OK;
// First of all, get the content type and make sure it is a content type we know how to handle!
if (PL_strcasecmp(aContentType, "application/x-addvcard") == 0) {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
if (!aChannel) return NS_ERROR_FAILURE;
rv = aChannel->GetURI(getter_AddRefs(uri));
if (uri)
{
nsAutoCString path;
rv = uri->GetPath(path);
NS_ENSURE_SUCCESS(rv,rv);
const char *startOfVCard = strstr(path.get(), "add?vcard=");
if (startOfVCard)
{
nsCString unescapedData;
// XXX todo, explain why we is escaped twice
MsgUnescapeString(nsDependentCString(startOfVCard + strlen("add?vcard=")),
0, unescapedData);
if (!aWindowContext)
return NS_ERROR_FAILURE;
nsCOMPtr<mozIDOMWindowProxy> domWindow = do_GetInterface(aWindowContext);
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = nsPIDOMWindowOuter::From(domWindow);
parentWindow = parentWindow->GetOuterWindow();
NS_ENSURE_ARG_POINTER(parentWindow);
nsCOMPtr<nsIAbManager> ab =
do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIAbCard> cardFromVCard;
rv = ab->EscapedVCardToAbCard(unescapedData.get(),
getter_AddRefs(cardFromVCard));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupportsInterfacePointer> ifptr =
do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
ifptr->SetData(cardFromVCard);
ifptr->SetDataIID(&NS_GET_IID(nsIAbCard));
nsCOMPtr<nsPIDOMWindowOuter> dialogWindow;
rv = parentWindow->OpenDialog(
NS_LITERAL_STRING("chrome://messenger/content/addressbook/abNewCardDialog.xul"),
EmptyString(),
NS_LITERAL_STRING("chrome,resizable=no,titlebar,modal,centerscreen"),
ifptr, getter_AddRefs(dialogWindow));
NS_ENSURE_SUCCESS(rv, rv);
}
rv = NS_OK;
}
}
else if (PL_strcasecmp(aContentType, "text/x-vcard") == 0) {
// create a vcard stream listener that can parse the data stream
// and bring up the appropriate UI
// (1) cancel the current load operation. We'll restart it
request->Cancel(NS_ERROR_ABORT);
// get the url we were trying to open
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
rv = channel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> nullPrincipal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// create a stream loader to handle the v-card data
nsCOMPtr<nsIStreamLoader> streamLoader;
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader),
uri,
this,
nullPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER);
NS_ENSURE_SUCCESS(rv, rv);
}
else // The content-type was not application/x-addvcard...
return NS_ERROR_WONT_HANDLE_CONTENT;
return rv;
}
NS_IMETHODIMP
nsAbContentHandler::OnStreamComplete(nsIStreamLoader *aLoader,
nsISupports *aContext, nsresult aStatus,
uint32_t datalen, const uint8_t *data)
{
NS_ENSURE_ARG_POINTER(aContext);
NS_ENSURE_SUCCESS(aStatus, aStatus); // don't process the vcard if we got a status error
nsresult rv = NS_OK;
// take our vCard string and open up an address book window based on it
nsCOMPtr<nsIMsgVCardService> vCardService = do_GetService(NS_MSGVCARDSERVICE_CONTRACTID);
if (vCardService)
{
nsAutoPtr<VObject> vObj(vCardService->Parse_MIME((const char *)data, datalen));
if (vObj)
{
int32_t len = 0;
nsCString vCard;
vCard.Adopt(vCardService->WriteMemoryVObjects(0, &len, vObj, false));
nsCOMPtr<nsIAbManager> ab =
do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIAbCard> cardFromVCard;
rv = ab->EscapedVCardToAbCard(vCard.get(),
getter_AddRefs(cardFromVCard));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIDOMWindowProxy> domWindow = do_GetInterface(aContext);
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindowOuter> parentWindow = nsPIDOMWindowOuter::From(domWindow);
parentWindow = parentWindow->GetOuterWindow();
NS_ENSURE_ARG_POINTER(parentWindow);
nsCOMPtr<nsPIDOMWindowOuter> dialogWindow;
rv = parentWindow->OpenDialog(
NS_LITERAL_STRING("chrome://messenger/content/addressbook/abNewCardDialog.xul"),
EmptyString(),
NS_LITERAL_STRING("chrome,resizable=no,titlebar,modal,centerscreen"),
cardFromVCard, getter_AddRefs(dialogWindow));
}
}
return rv;
}

View file

@ -0,0 +1,26 @@
/* -*- Mode: C++; 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/. */
#ifndef __nsAbContentHandler_h
#define __nsAbContentHandler_h
#include "nsIStreamLoader.h"
#include "nsIContentHandler.h"
class nsAbContentHandler : public nsIContentHandler,
public nsIStreamLoaderObserver
{
public:
nsAbContentHandler();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICONTENTHANDLER
NS_DECL_NSISTREAMLOADEROBSERVER
private:
virtual ~nsAbContentHandler();
};
#endif

View file

@ -0,0 +1,54 @@
/* -*- Mode: C++; 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/. */
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIIOService.h"
#include "nsNetCID.h"
#include "nsMemory.h"
#include "nsStringGlue.h"
#include "plstr.h"
#include "nsAbBaseCID.h"
#include "nsAbDirFactoryService.h"
#include "nsIAbDirFactory.h"
#include "mozilla/Services.h"
NS_IMPL_ISUPPORTS(nsAbDirFactoryService, nsIAbDirFactoryService)
nsAbDirFactoryService::nsAbDirFactoryService()
{
}
nsAbDirFactoryService::~nsAbDirFactoryService()
{
}
/* nsIAbDirFactory getDirFactory (in string uri); */
NS_IMETHODIMP
nsAbDirFactoryService::GetDirFactory(const nsACString &aURI,
nsIAbDirFactory** aDirFactory)
{
NS_ENSURE_ARG_POINTER(aDirFactory);
nsresult rv;
// Obtain the network IO service
nsCOMPtr<nsIIOService> nsService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(nsService, NS_ERROR_UNEXPECTED);
// Extract the scheme
nsAutoCString scheme;
rv = nsService->ExtractScheme(aURI, scheme);
NS_ENSURE_SUCCESS(rv, rv);
// Try to find a factory using the component manager.
nsAutoCString contractID;
contractID.AssignLiteral(NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX);
contractID.Append(scheme);
return CallCreateInstance(contractID.get(), aDirFactory);
}

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbDirFactoryService_h__
#define nsAbDirFactoryService_h__
#include "nsIAbDirFactoryService.h"
class nsAbDirFactoryService : public nsIAbDirFactoryService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRFACTORYSERVICE
nsAbDirFactoryService();
private:
virtual ~nsAbDirFactoryService();
};
#endif

View file

@ -0,0 +1,593 @@
/* -*- Mode: C++; 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/. */
#include "nsAbDirProperty.h"
#include "nsAbBaseCID.h"
#include "nsIAbCard.h"
#include "nsDirPrefs.h"
#include "nsIPrefService.h"
#include "nsIPrefLocalizedString.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "prmem.h"
#include "nsIAbManager.h"
#include "nsArrayUtils.h"
// From nsDirPrefs
#define kDefaultPosition 1
nsAbDirProperty::nsAbDirProperty(void)
: m_LastModifiedDate(0),
mIsValidURI(false),
mIsQueryURI(false)
{
m_IsMailList = false;
}
nsAbDirProperty::~nsAbDirProperty(void)
{
#if 0
// this code causes a regression #138647
// don't turn it on until you figure it out
if (m_AddressList) {
uint32_t count;
nsresult rv;
rv = m_AddressList->GetLength(&count);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
int32_t i;
for (i = count - 1; i >= 0; i--)
m_AddressList->RemoveElementAt(i);
}
#endif
}
NS_IMPL_ISUPPORTS(nsAbDirProperty, nsIAbDirectory, nsISupportsWeakReference,
nsIAbCollection, nsIAbItem)
NS_IMETHODIMP nsAbDirProperty::GetUuid(nsACString &uuid)
{
// XXX: not all directories have a dirPrefId...
nsresult rv = GetDirPrefId(uuid);
NS_ENSURE_SUCCESS(rv, rv);
uuid.Append('&');
nsString dirName;
GetDirName(dirName);
uuid.Append(NS_ConvertUTF16toUTF8(dirName));
return rv;
}
NS_IMETHODIMP nsAbDirProperty::GenerateName(int32_t aGenerateFormat,
nsIStringBundle *aBundle,
nsAString &name)
{
return GetDirName(name);
}
NS_IMETHODIMP nsAbDirProperty::GetPropertiesChromeURI(nsACString &aResult)
{
aResult.AssignLiteral("chrome://messenger/content/addressbook/abAddressBookNameDialog.xul");
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetDirName(nsAString &aDirName)
{
if (m_DirPrefId.IsEmpty())
{
aDirName = m_ListDirName;
return NS_OK;
}
nsCString dirName;
nsresult rv = GetLocalizedStringValue("description", EmptyCString(), dirName);
NS_ENSURE_SUCCESS(rv, rv);
// In TB 2 only some prefs had chrome:// URIs. We had code in place that would
// only get the localized string pref for the particular address books that
// were built-in.
// Additionally, nsIPrefBranch::getComplexValue will only get a non-user-set,
// non-locked pref value if it is a chrome:// URI and will get the string
// value at that chrome URI. This breaks extensions/autoconfig that want to
// set default pref values and allow users to change directory names.
//
// Now we have to support this, and so if for whatever reason we fail to get
// the localized version, then we try and get the non-localized version
// instead. If the string value is empty, then we'll just get the empty value
// back here.
if (dirName.IsEmpty())
{
rv = GetStringValue("description", EmptyCString(), dirName);
NS_ENSURE_SUCCESS(rv, rv);
}
CopyUTF8toUTF16(dirName, aDirName);
return NS_OK;
}
// XXX Although mailing lists could use the NotifyItemPropertyChanged
// mechanism here, it requires some rework on how we write/save data
// relating to mailing lists, so we're just using the old method of a
// local variable to store the mailing list name.
NS_IMETHODIMP nsAbDirProperty::SetDirName(const nsAString &aDirName)
{
if (m_DirPrefId.IsEmpty())
{
m_ListDirName = aDirName;
return NS_OK;
}
// Store the old value.
nsString oldDirName;
nsresult rv = GetDirName(oldDirName);
NS_ENSURE_SUCCESS(rv, rv);
// Save the new value
rv = SetLocalizedStringValue("description", NS_ConvertUTF16toUTF8(aDirName));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
// We inherit from nsIAbDirectory, so this static cast should be safe.
abManager->NotifyItemPropertyChanged(static_cast<nsIAbDirectory*>(this),
"DirName", oldDirName.get(),
nsString(aDirName).get());
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetDirType(int32_t *aDirType)
{
return GetIntValue("dirType", LDAPDirectory, aDirType);
}
NS_IMETHODIMP nsAbDirProperty::GetFileName(nsACString &aFileName)
{
return GetStringValue("filename", EmptyCString(), aFileName);
}
NS_IMETHODIMP nsAbDirProperty::GetURI(nsACString &aURI)
{
// XXX Should we complete this for Mailing Lists?
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsAbDirProperty::GetPosition(int32_t *aPosition)
{
return GetIntValue("position", kDefaultPosition, aPosition);
}
NS_IMETHODIMP nsAbDirProperty::GetLastModifiedDate(uint32_t *aLastModifiedDate)
{
NS_ENSURE_ARG_POINTER(aLastModifiedDate);
*aLastModifiedDate = m_LastModifiedDate;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetLastModifiedDate(uint32_t aLastModifiedDate)
{
if (aLastModifiedDate)
{
m_LastModifiedDate = aLastModifiedDate;
}
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetListNickName(nsAString &aListNickName)
{
aListNickName = m_ListNickName;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetListNickName(const nsAString &aListNickName)
{
m_ListNickName = aListNickName;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetDescription(nsAString &aDescription)
{
aDescription = m_Description;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetDescription(const nsAString &aDescription)
{
m_Description = aDescription;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetIsMailList(bool *aIsMailList)
{
*aIsMailList = m_IsMailList;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetIsMailList(bool aIsMailList)
{
m_IsMailList = aIsMailList;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetAddressLists(nsIMutableArray * *aAddressLists)
{
if (!m_AddressList)
{
nsresult rv;
m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
*aAddressLists = m_AddressList;
NS_ADDREF(*aAddressLists);
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetAddressLists(nsIMutableArray * aAddressLists)
{
m_AddressList = aAddressLists;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::CopyMailList(nsIAbDirectory* srcList)
{
SetIsMailList(true);
nsString str;
srcList->GetDirName(str);
SetDirName(str);
srcList->GetListNickName(str);
SetListNickName(str);
srcList->GetDescription(str);
SetDescription(str);
nsCOMPtr<nsIMutableArray> pAddressLists;
srcList->GetAddressLists(getter_AddRefs(pAddressLists));
SetAddressLists(pAddressLists);
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetIsQuery(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// Mailing lists are not queries by default, individual directory types
// will override this.
*aResult = false;
return NS_OK;
}
NS_IMETHODIMP
nsAbDirProperty::Init(const char *aURI)
{
mURINoQuery = aURI;
mURI = aURI;
mIsValidURI = true;
int32_t searchCharLocation = mURINoQuery.FindChar('?');
if (searchCharLocation >= 0)
{
mQueryString = Substring(mURINoQuery, searchCharLocation + 1);
mURINoQuery.SetLength(searchCharLocation);
mIsQueryURI = true;
}
return NS_OK;
}
// nsIAbDirectory NOT IMPLEMENTED methods
NS_IMETHODIMP
nsAbDirProperty::GetChildNodes(nsISimpleEnumerator **childList)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::GetChildCards(nsISimpleEnumerator **childCards)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::DeleteDirectory(nsIAbDirectory *directory)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::HasCard(nsIAbCard *cards, bool *hasCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::HasDirectory(nsIAbDirectory *dir, bool *hasDir)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::HasMailListWithName(const char16_t *aName, bool *aHasList)
{
NS_ENSURE_ARG_POINTER(aName);
NS_ENSURE_ARG_POINTER(aHasList);
*aHasList = false;
bool supportsLists = false;
nsresult rv = GetSupportsMailingLists(&supportsLists);
if (NS_FAILED(rv) || !supportsLists)
return NS_OK;
if (m_IsMailList)
return NS_OK;
nsCOMPtr<nsIMutableArray> addressLists;
rv = GetAddressLists(getter_AddRefs(addressLists));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t listCount = 0;
rv = addressLists->GetLength(&listCount);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0; i < listCount; i++)
{
nsCOMPtr<nsIAbDirectory> listDir(do_QueryElementAt(addressLists, i, &rv));
if (NS_SUCCEEDED(rv) && listDir)
{
nsAutoString listName;
rv = listDir->GetDirName(listName);
if (NS_SUCCEEDED(rv) && listName.Equals(aName))
{
*aHasList = true;
return NS_OK;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsAbDirProperty::CreateNewDirectory(const nsAString &aDirName,
const nsACString &aURI,
uint32_t aType,
const nsACString &aPrefName,
nsACString &aResult)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP
nsAbDirProperty::CreateDirectoryByURI(const nsAString &aDisplayName,
const nsACString &aURI)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::AddMailList(nsIAbDirectory *list, nsIAbDirectory **addedList)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::EditMailListToDatabase(nsIAbCard *listCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::AddCard(nsIAbCard *childCard, nsIAbCard **addedCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::ModifyCard(nsIAbCard *aModifiedCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::DeleteCards(nsIArray *cards)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::DropCard(nsIAbCard *childCard, bool needToCopyCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::CardForEmailAddress(const nsACString &aEmailAddress,
nsIAbCard ** aAbCard)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::GetCardFromProperty(const char *aProperty,
const nsACString &aValue,
bool caseSensitive,
nsIAbCard **result)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::GetCardsFromProperty(const char *aProperty,
const nsACString &aValue,
bool caseSensitive,
nsISimpleEnumerator **result)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsAbDirProperty::GetSupportsMailingLists(bool *aSupportsMailingsLists)
{
NS_ENSURE_ARG_POINTER(aSupportsMailingsLists);
// We don't currently support nested mailing lists, so only return true if
// we're not a mailing list.
*aSupportsMailingsLists = !m_IsMailList;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetReadOnly(bool *aReadOnly)
{
NS_ENSURE_ARG_POINTER(aReadOnly);
// Default is that we are writable. Any implementation that is read-only must
// override this method.
*aReadOnly = false;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetIsRemote(bool *aIsRemote)
{
NS_ENSURE_ARG_POINTER(aIsRemote);
*aIsRemote = false;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetIsSecure(bool *aIsSecure)
{
NS_ENSURE_ARG_POINTER(aIsSecure);
*aIsSecure = false;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::UseForAutocomplete(const nsACString &aIdentityKey,
bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// Is local autocomplete enabled?
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID,
&rv));
NS_ENSURE_SUCCESS(rv, rv);
return prefBranch->GetBoolPref("mail.enable_autocomplete", aResult);
}
NS_IMETHODIMP nsAbDirProperty::GetDirPrefId(nsACString &aDirPrefId)
{
aDirPrefId = m_DirPrefId;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetDirPrefId(const nsACString &aDirPrefId)
{
if (!m_DirPrefId.Equals(aDirPrefId))
{
m_DirPrefId.Assign(aDirPrefId);
// Clear the directory pref branch so that it is re-initialized next
// time its required.
m_DirectoryPrefs = nullptr;
}
return NS_OK;
}
nsresult nsAbDirProperty::InitDirectoryPrefs()
{
if (m_DirPrefId.IsEmpty())
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCString realPrefId(m_DirPrefId);
realPrefId.Append('.');
return prefService->GetBranch(realPrefId.get(), getter_AddRefs(m_DirectoryPrefs));
}
NS_IMETHODIMP nsAbDirProperty::GetIntValue(const char *aName,
int32_t aDefaultValue,
int32_t *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
if (NS_FAILED(m_DirectoryPrefs->GetIntPref(aName, aResult)))
*aResult = aDefaultValue;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetBoolValue(const char *aName,
bool aDefaultValue,
bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
if (NS_FAILED(m_DirectoryPrefs->GetBoolPref(aName, aResult)))
*aResult = aDefaultValue;
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::GetStringValue(const char *aName,
const nsACString &aDefaultValue,
nsACString &aResult)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
nsCString value;
/* unfortunately, there may be some prefs out there which look like (null) */
if (NS_SUCCEEDED(m_DirectoryPrefs->GetCharPref(aName, getter_Copies(value))) &&
!value.EqualsLiteral("(null"))
aResult = value;
else
aResult = aDefaultValue;
return NS_OK;
}
/*
* Get localized unicode string pref from properties file, convert into an
* UTF8 string since address book prefs store as UTF8 strings. So far there
* are 2 default prefs stored in addressbook.properties.
* "ldap_2.servers.pab.description"
* "ldap_2.servers.history.description"
*/
NS_IMETHODIMP nsAbDirProperty::GetLocalizedStringValue(const char *aName,
const nsACString &aDefaultValue,
nsACString &aResult)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
nsString wvalue;
nsCOMPtr<nsIPrefLocalizedString> locStr;
nsresult rv = m_DirectoryPrefs->GetComplexValue(aName,
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(locStr));
if (NS_SUCCEEDED(rv))
{
rv = locStr->ToString(getter_Copies(wvalue));
NS_ENSURE_SUCCESS(rv, rv);
}
if (wvalue.IsEmpty())
aResult = aDefaultValue;
else
CopyUTF16toUTF8(wvalue, aResult);
return NS_OK;
}
NS_IMETHODIMP nsAbDirProperty::SetIntValue(const char *aName,
int32_t aValue)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
return m_DirectoryPrefs->SetIntPref(aName, aValue);
}
NS_IMETHODIMP nsAbDirProperty::SetBoolValue(const char *aName,
bool aValue)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
return m_DirectoryPrefs->SetBoolPref(aName, aValue);
}
NS_IMETHODIMP nsAbDirProperty::SetStringValue(const char *aName,
const nsACString &aValue)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
return m_DirectoryPrefs->SetCharPref(aName, nsCString(aValue).get());
}
NS_IMETHODIMP nsAbDirProperty::SetLocalizedStringValue(const char *aName,
const nsACString &aValue)
{
if (!m_DirectoryPrefs && NS_FAILED(InitDirectoryPrefs()))
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
nsCOMPtr<nsIPrefLocalizedString> locStr(
do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = locStr->SetData(NS_ConvertUTF8toUTF16(aValue).get());
NS_ENSURE_SUCCESS(rv, rv);
return m_DirectoryPrefs->SetComplexValue(aName,
NS_GET_IID(nsIPrefLocalizedString),
locStr);
}

View file

@ -0,0 +1,72 @@
/* -*- Mode: C++; 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/. */
/********************************************************************************************************
Interface for representing Address Book Directory
*********************************************************************************************************/
#ifndef nsAbDirProperty_h__
#define nsAbDirProperty_h__
#include "nsIAbDirectory.h" /* include the interface we are going to support */
#include "nsIAbCard.h"
#include "nsCOMPtr.h"
#include "nsDirPrefs.h"
#include "nsIAddrDatabase.h"
#include "nsStringGlue.h"
#include "nsIPrefBranch.h"
#include "nsIMutableArray.h"
#include "nsWeakReference.h"
/*
* Address Book Directory
*/
class nsAbDirProperty: public nsIAbDirectory,
public nsSupportsWeakReference
{
public:
nsAbDirProperty(void);
NS_DECL_ISUPPORTS
NS_DECL_NSIABITEM
NS_DECL_NSIABCOLLECTION
NS_DECL_NSIABDIRECTORY
protected:
virtual ~nsAbDirProperty(void);
/**
* Initialise the directory prefs for this branch
*/
nsresult InitDirectoryPrefs();
uint32_t m_LastModifiedDate;
nsString m_ListDirName;
nsString m_ListName;
nsString m_ListNickName;
nsString m_Description;
bool m_IsMailList;
nsCString mURI;
nsCString mQueryString;
nsCString mURINoQuery;
bool mIsValidURI;
bool mIsQueryURI;
/*
* Note that any derived implementations should ensure that this item
* (m_DirPrefId) is correctly initialised correctly
*/
nsCString m_DirPrefId; // ie,"ldap_2.servers.pab"
nsCOMPtr<nsIPrefBranch> m_DirectoryPrefs;
nsCOMPtr<nsIMutableArray> m_AddressList;
};
#endif

View file

@ -0,0 +1,528 @@
/* -*- Mode: C++; 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/. */
#include "nsAbDirectoryQuery.h"
#include "nsAbDirectoryQueryProxy.h"
#include "nsAbUtils.h"
#include "nsAbBooleanExpression.h"
#include "nsArrayUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsStringGlue.h"
#include "nsUnicharUtils.h"
#include "nsIAbDirSearchListener.h"
#include "nsISimpleEnumerator.h"
#include "nsMsgUtils.h"
NS_IMPL_ISUPPORTS(nsAbDirectoryQuerySimpleBooleanExpression, nsIAbBooleanExpression)
nsAbDirectoryQuerySimpleBooleanExpression::nsAbDirectoryQuerySimpleBooleanExpression() :
mOperation (nsIAbBooleanOperationTypes::AND)
{
}
nsAbDirectoryQuerySimpleBooleanExpression::~nsAbDirectoryQuerySimpleBooleanExpression()
{
}
/* attribute nsAbBooleanOperationType operation; */
NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::GetOperation(nsAbBooleanOperationType *aOperation)
{
if (!aOperation)
return NS_ERROR_NULL_POINTER;
*aOperation = mOperation;
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::SetOperation(nsAbBooleanOperationType aOperation)
{
if (aOperation != nsIAbBooleanOperationTypes::AND &&
aOperation != nsIAbBooleanOperationTypes::OR)
return NS_ERROR_FAILURE;
mOperation = aOperation;
return NS_OK;
}
/* attribute nsIArray expressions; */
NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::GetExpressions(nsIArray **aExpressions)
{
if (!aExpressions)
return NS_ERROR_NULL_POINTER;
if (!mExpressions)
{
mExpressions = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!mExpressions)
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aExpressions = mExpressions);
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQuerySimpleBooleanExpression::SetExpressions(nsIArray *aExpressions)
{
if (!aExpressions)
return NS_ERROR_NULL_POINTER;
// Ensure all the items are of the right type.
nsresult rv;
uint32_t count;
rv = aExpressions->GetLength(&count);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanConditionString> queryExpression;
for (uint32_t i = 0; i < count; ++i)
{
queryExpression = do_QueryElementAt(aExpressions, i, &rv);
if (NS_FAILED(rv))
return NS_ERROR_ILLEGAL_VALUE;
}
// Values ok, so we can just save and return.
mExpressions = aExpressions;
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsAbDirectoryQueryArguments, nsIAbDirectoryQueryArguments)
nsAbDirectoryQueryArguments::nsAbDirectoryQueryArguments() :
mQuerySubDirectories(true)
{
}
nsAbDirectoryQueryArguments::~nsAbDirectoryQueryArguments()
{
}
/* attribute nsISupports matchItems; */
NS_IMETHODIMP nsAbDirectoryQueryArguments::GetExpression(nsISupports** aExpression)
{
if (!aExpression)
return NS_ERROR_NULL_POINTER;
NS_IF_ADDREF(*aExpression = mExpression);
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::SetExpression(nsISupports* aExpression)
{
mExpression = aExpression;
return NS_OK;
}
/* attribute boolean querySubDirectories; */
NS_IMETHODIMP nsAbDirectoryQueryArguments::GetQuerySubDirectories(bool* aQuerySubDirectories)
{
NS_ENSURE_ARG_POINTER(aQuerySubDirectories);
*aQuerySubDirectories = mQuerySubDirectories;
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::SetQuerySubDirectories(bool aQuerySubDirectories)
{
mQuerySubDirectories = aQuerySubDirectories;
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::GetTypeSpecificArg(nsISupports** aArg)
{
NS_ENSURE_ARG_POINTER(aArg);
NS_IF_ADDREF(*aArg = mTypeSpecificArg);
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::SetTypeSpecificArg(nsISupports* aArg)
{
mTypeSpecificArg = aArg;
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::GetFilter(nsACString & aFilter)
{
aFilter.Assign(mFilter);
return NS_OK;
}
NS_IMETHODIMP nsAbDirectoryQueryArguments::SetFilter(const nsACString & aFilter)
{
mFilter.Assign(aFilter);
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsAbDirectoryQueryPropertyValue, nsIAbDirectoryQueryPropertyValue)
nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue()
{
}
nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue(const char* aName,
const char16_t* aValue)
{
mName = aName;
mValue = aValue;
}
nsAbDirectoryQueryPropertyValue::nsAbDirectoryQueryPropertyValue(const char* aName,
nsISupports* aValueISupports)
{
mName = aName;
mValueISupports = aValueISupports;
}
nsAbDirectoryQueryPropertyValue::~nsAbDirectoryQueryPropertyValue()
{
}
/* read only attribute string name; */
NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetName(char* *aName)
{
*aName = mName.IsEmpty() ? 0 : ToNewCString(mName);
return NS_OK;
}
/* read only attribute wstring value; */
NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetValue(char16_t* *aValue)
{
*aValue = ToNewUnicode(mValue);
if (!(*aValue))
return NS_ERROR_OUT_OF_MEMORY;
else
return NS_OK;
}
/* readonly attribute nsISupports valueISupports; */
NS_IMETHODIMP nsAbDirectoryQueryPropertyValue::GetValueISupports(nsISupports* *aValueISupports)
{
if (!mValueISupports)
return NS_ERROR_NULL_POINTER;
NS_IF_ADDREF(*aValueISupports = mValueISupports);
return NS_OK;
}
/* Implementation file */
NS_IMPL_ISUPPORTS(nsAbDirectoryQuery, nsIAbDirectoryQuery)
nsAbDirectoryQuery::nsAbDirectoryQuery()
{
}
nsAbDirectoryQuery::~nsAbDirectoryQuery()
{
}
NS_IMETHODIMP nsAbDirectoryQuery::DoQuery(nsIAbDirectory *aDirectory,
nsIAbDirectoryQueryArguments* arguments,
nsIAbDirSearchListener* listener,
int32_t resultLimit, int32_t timeOut,
int32_t* _retval)
{
NS_ENSURE_ARG_POINTER(aDirectory);
nsCOMPtr<nsISupports> supportsExpression;
nsresult rv = arguments->GetExpression(getter_AddRefs(supportsExpression));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanExpression> expression(do_QueryInterface(supportsExpression, &rv));
NS_ENSURE_SUCCESS(rv, rv);
bool doSubDirectories;
rv = arguments->GetQuerySubDirectories(&doSubDirectories);
NS_ENSURE_SUCCESS(rv, rv);
rv = query(aDirectory, expression, listener, doSubDirectories, &resultLimit);
rv = NS_FAILED(rv) ? queryError(listener) : queryFinished(listener);
*_retval = 0;
return rv;
}
/* void stopQuery (in long contextID); */
NS_IMETHODIMP nsAbDirectoryQuery::StopQuery(int32_t contextID)
{
return NS_OK;
}
nsresult nsAbDirectoryQuery::query(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
bool doSubDirectories,
int32_t* resultLimit)
{
if (*resultLimit == 0)
return NS_OK;
nsresult rv = queryCards(directory, expression, listener, resultLimit);
NS_ENSURE_SUCCESS(rv, rv);
if (doSubDirectories && resultLimit != 0)
{
rv = queryChildren(directory, expression, listener, doSubDirectories,
resultLimit);
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
nsresult nsAbDirectoryQuery::queryChildren(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
bool doSubDirectories,
int32_t* resultLimit)
{
nsresult rv = NS_OK;
nsCOMPtr<nsISimpleEnumerator> subDirectories;
rv = directory->GetChildNodes(getter_AddRefs(subDirectories));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore;
while (NS_SUCCEEDED(rv = subDirectories->HasMoreElements(&hasMore)) && hasMore)
{
nsCOMPtr<nsISupports> item;
rv = subDirectories->GetNext (getter_AddRefs (item));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectory> subDirectory(do_QueryInterface(item, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = query(subDirectory, expression, listener, doSubDirectories, resultLimit);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult nsAbDirectoryQuery::queryCards(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
int32_t* resultLimit)
{
nsresult rv = NS_OK;
nsCOMPtr<nsISimpleEnumerator> cards;
rv = directory->GetChildCards(getter_AddRefs(cards));
if (NS_FAILED(rv))
{
if (rv != NS_ERROR_NOT_IMPLEMENTED)
NS_ENSURE_SUCCESS(rv, rv);
else
return NS_OK;
}
if (!cards)
return NS_OK;
bool more;
while (NS_SUCCEEDED(cards->HasMoreElements(&more)) && more)
{
nsCOMPtr<nsISupports> item;
rv = cards->GetNext(getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbCard> card(do_QueryInterface(item, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = matchCard (card, expression, listener, resultLimit);
NS_ENSURE_SUCCESS(rv, rv);
if (*resultLimit == 0)
return NS_OK;
}
return NS_OK;
}
nsresult nsAbDirectoryQuery::matchCard(nsIAbCard* card,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
int32_t* resultLimit)
{
bool matchFound = false;
nsresult rv = matchCardExpression(card, expression, &matchFound);
NS_ENSURE_SUCCESS(rv, rv);
if (matchFound)
{
(*resultLimit)--;
rv = queryMatch(card, listener);
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
nsresult nsAbDirectoryQuery::matchCardExpression(nsIAbCard* card,
nsIAbBooleanExpression* expression,
bool* result)
{
nsAbBooleanOperationType operation;
nsresult rv = expression->GetOperation (&operation);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIArray> childExpressions;
rv = expression->GetExpressions (getter_AddRefs (childExpressions));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t count;
rv = childExpressions->GetLength(&count);
NS_ENSURE_SUCCESS(rv, rv);
if (operation == nsIAbBooleanOperationTypes::NOT &&
count > 1)
return NS_ERROR_FAILURE;
bool value = *result = false;
nsCOMPtr<nsIAbBooleanConditionString> childCondition;
nsCOMPtr<nsIAbBooleanExpression> childExpression;
for (uint32_t i = 0; i < count; i++)
{
childCondition = do_QueryElementAt(childExpressions, i, &rv);
if (NS_SUCCEEDED(rv))
{
rv = matchCardCondition (card, childCondition, &value);
NS_ENSURE_SUCCESS(rv, rv);
}
else
{
childExpression = do_QueryElementAt(childExpressions, i, &rv);
if (NS_SUCCEEDED(rv))
{
rv = matchCardExpression (card, childExpression, &value);
NS_ENSURE_SUCCESS(rv, rv);
}
else
return NS_ERROR_FAILURE;
}
if (operation == nsIAbBooleanOperationTypes::OR && value)
break;
else if (operation == nsIAbBooleanOperationTypes::AND && !value)
break;
else if (operation == nsIAbBooleanOperationTypes::NOT)
value = !value;
}
*result = value;
return NS_OK;
}
nsresult nsAbDirectoryQuery::matchCardCondition(nsIAbCard* card,
nsIAbBooleanConditionString* condition,
bool* matchFound)
{
nsAbBooleanConditionType conditionType;
nsresult rv = condition->GetCondition (&conditionType);
NS_ENSURE_SUCCESS(rv, rv);
nsCString name;
rv = condition->GetName (getter_Copies (name));
NS_ENSURE_SUCCESS(rv, rv);
if (name.Equals ("card:nsIAbCard"))
{
*matchFound = (conditionType == nsIAbBooleanConditionTypes::Exists);
return NS_OK;
}
nsString matchValue;
rv = condition->GetValue (getter_Copies (matchValue));
NS_ENSURE_SUCCESS(rv, rv);
if (name.EqualsLiteral("IsMailList"))
{
bool isMailList;
rv = card->GetIsMailList(&isMailList);
NS_ENSURE_SUCCESS(rv, rv);
// Only equals is supported.
if (conditionType != nsIAbBooleanConditionTypes::Is)
return NS_ERROR_FAILURE;
*matchFound = isMailList ? matchValue.EqualsLiteral("TRUE") :
matchValue.EqualsLiteral("FALSE");
return NS_OK;
}
nsString value;
(void)card->GetPropertyAsAString(name.get(), value);
if (value.IsEmpty())
{
*matchFound = (conditionType == nsIAbBooleanConditionTypes::DoesNotExist) ?
true : false;
return NS_OK;
}
/* TODO
* What about allowing choice between case insensitive
* and case sensitive comparisons?
*
*/
switch (conditionType)
{
case nsIAbBooleanConditionTypes::Exists:
*matchFound = true;
break;
case nsIAbBooleanConditionTypes::Contains:
*matchFound = CaseInsensitiveFindInReadable(matchValue, value);
break;
case nsIAbBooleanConditionTypes::DoesNotContain:
*matchFound = !CaseInsensitiveFindInReadable(matchValue, value);
break;
case nsIAbBooleanConditionTypes::Is:
*matchFound = value.Equals(matchValue, nsCaseInsensitiveStringComparator());
break;
case nsIAbBooleanConditionTypes::IsNot:
*matchFound = !value.Equals(matchValue, nsCaseInsensitiveStringComparator());
break;
case nsIAbBooleanConditionTypes::BeginsWith:
*matchFound = StringBeginsWith(value, matchValue, nsCaseInsensitiveStringComparator());
break;
case nsIAbBooleanConditionTypes::LessThan:
*matchFound = Compare(value, matchValue, nsCaseInsensitiveStringComparator()) < 0;
break;
case nsIAbBooleanConditionTypes::GreaterThan:
*matchFound = Compare(value, matchValue, nsCaseInsensitiveStringComparator()) > 0;
break;
case nsIAbBooleanConditionTypes::EndsWith:
*matchFound = StringEndsWith(value, matchValue, nsCaseInsensitiveStringComparator());
break;
case nsIAbBooleanConditionTypes::SoundsLike:
case nsIAbBooleanConditionTypes::RegExp:
*matchFound = false;
break;
default:
*matchFound = false;
}
return rv;
}
nsresult nsAbDirectoryQuery::queryMatch(nsIAbCard* card,
nsIAbDirSearchListener* listener)
{
return listener->OnSearchFoundCard(card);
}
nsresult nsAbDirectoryQuery::queryFinished(nsIAbDirSearchListener* listener)
{
return listener->OnSearchFinished(nsIAbDirectoryQueryResultListener::queryResultComplete, EmptyString());
}
nsresult nsAbDirectoryQuery::queryError(nsIAbDirSearchListener* listener)
{
return listener->OnSearchFinished(nsIAbDirectoryQueryResultListener::queryResultError, EmptyString());
}

View file

@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbDirectoryQuery_h__
#define nsAbDirectoryQuery_h__
#include "nsIAbDirectoryQuery.h"
#include "nsIAbDirectory.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsIArray.h"
#include "nsIAbBooleanExpression.h"
class nsAbDirectoryQuerySimpleBooleanExpression : public nsIAbBooleanExpression
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABBOOLEANEXPRESSION
nsAbDirectoryQuerySimpleBooleanExpression();
private:
virtual ~nsAbDirectoryQuerySimpleBooleanExpression();
public:
nsCOMPtr<nsIArray> mExpressions;
nsAbBooleanOperationType mOperation;
};
class nsAbDirectoryQueryArguments : public nsIAbDirectoryQueryArguments
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABDIRECTORYQUERYARGUMENTS
nsAbDirectoryQueryArguments();
private:
virtual ~nsAbDirectoryQueryArguments();
protected:
nsCOMPtr<nsISupports> mExpression;
nsCOMPtr<nsISupports> mTypeSpecificArg;
bool mQuerySubDirectories;
nsCString mFilter;
};
class nsAbDirectoryQueryPropertyValue : public nsIAbDirectoryQueryPropertyValue
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABDIRECTORYQUERYPROPERTYVALUE
nsAbDirectoryQueryPropertyValue();
nsAbDirectoryQueryPropertyValue(const char* aName,
const char16_t* aValue);
nsAbDirectoryQueryPropertyValue(const char* aName,
nsISupports* aValueISupports);
protected:
virtual ~nsAbDirectoryQueryPropertyValue();
nsCString mName;
nsString mValue;
nsCOMPtr<nsISupports> mValueISupports;
};
class nsAbDirectoryQuery : public nsIAbDirectoryQuery
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRECTORYQUERY
nsAbDirectoryQuery();
protected:
virtual ~nsAbDirectoryQuery();
nsresult query(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
bool doSubDirectories,
int32_t* resultLimit);
nsresult queryChildren(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
bool doSubDirectories,
int32_t* resultLimit);
nsresult queryCards(nsIAbDirectory* directory,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
int32_t* resultLimit);
nsresult matchCard(nsIAbCard* card,
nsIAbBooleanExpression* expression,
nsIAbDirSearchListener* listener,
int32_t* resultLimit);
nsresult matchCardExpression(nsIAbCard* card,
nsIAbBooleanExpression* expression,
bool* result);
nsresult matchCardCondition(nsIAbCard* card,
nsIAbBooleanConditionString* condition,
bool* matchFound);
nsresult queryMatch (nsIAbCard* card,
nsIAbDirSearchListener* listener);
nsresult queryFinished(nsIAbDirSearchListener* listener);
nsresult queryError(nsIAbDirSearchListener* listener);
};
#endif

View file

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "nsAbDirectoryQuery.h"
#include "nsAbDirectoryQueryProxy.h"
NS_IMPL_ISUPPORTS(nsAbDirectoryQueryProxy, nsIAbDirectoryQueryProxy, nsIAbDirectoryQuery)
nsAbDirectoryQueryProxy::nsAbDirectoryQueryProxy() :
mInitiated (false)
{
}
nsAbDirectoryQueryProxy::~nsAbDirectoryQueryProxy()
{
}
/* void initiate (in nsIAbDirectory directory); */
NS_IMETHODIMP nsAbDirectoryQueryProxy::Initiate()
{
if (mInitiated)
return NS_OK;
mDirectoryQuery = new nsAbDirectoryQuery();
mInitiated = true;
return NS_OK;
}

View file

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbDirectoryQueryProxy_h__
#define nsAbDirectoryQueryProxy_h__
#include "nsIAbDirectoryQueryProxy.h"
#include "nsCOMPtr.h"
class nsAbDirectoryQueryProxy : public nsIAbDirectoryQueryProxy
{
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSIABDIRECTORYQUERY(mDirectoryQuery->)
NS_DECL_NSIABDIRECTORYQUERYPROXY
nsAbDirectoryQueryProxy();
protected:
virtual ~nsAbDirectoryQueryProxy();
bool mInitiated;
nsCOMPtr<nsIAbDirectoryQuery> mDirectoryQuery;
};
#endif

View file

@ -0,0 +1,247 @@
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var NS_ABLDAPATTRIBUTEMAP_CID = Components.ID(
"{127b341a-bdda-4270-85e1-edff569a9b85}");
var NS_ABLDAPATTRIBUTEMAPSERVICE_CID = Components.ID(
"{4ed7d5e1-8800-40da-9e78-c4f509d7ac5e}");
function nsAbLDAPAttributeMap() {
this.mPropertyMap = {};
this.mAttrMap = {};
}
nsAbLDAPAttributeMap.prototype = {
classID: NS_ABLDAPATTRIBUTEMAP_CID,
getAttributeList: function getAttributeList(aProperty) {
if (!(aProperty in this.mPropertyMap)) {
return null;
}
// return the joined list
return this.mPropertyMap[aProperty].join(",");
},
getAttributes: function getAttributes(aProperty, aCount, aAttrs) {
// fail if no entry for this
if (!(aProperty in this.mPropertyMap)) {
throw Components.results.NS_ERROR_FAILURE;
}
aAttrs = this.mPropertyMap[aProperty];
aCount = aAttrs.length;
return aAttrs;
},
getFirstAttribute: function getFirstAttribute(aProperty) {
// fail if no entry for this
if (!(aProperty in this.mPropertyMap)) {
return null;
}
return this.mPropertyMap[aProperty][0];
},
setAttributeList: function setAttributeList(aProperty, aAttributeList,
aAllowInconsistencies) {
var attrs = aAttributeList.split(",");
// check to make sure this call won't allow multiple mappings to be
// created, if requested
if (!aAllowInconsistencies) {
for (var attr of attrs) {
if (attr in this.mAttrMap && this.mAttrMap[attr] != aProperty) {
throw Components.results.NS_ERROR_FAILURE;
}
}
}
// delete any attr mappings created by the existing property map entry
if (aProperty in this.mPropertyMap) {
for (attr of this.mPropertyMap[aProperty]) {
delete this.mAttrMap[attr];
}
}
// add these attrs to the attrmap
for (attr of attrs) {
this.mAttrMap[attr] = aProperty;
}
// add them to the property map
this.mPropertyMap[aProperty] = attrs;
},
getProperty: function getProperty(aAttribute) {
if (!(aAttribute in this.mAttrMap)) {
return null;
}
return this.mAttrMap[aAttribute];
},
getAllCardAttributes: function getAllCardAttributes() {
var attrs = [];
for (var prop in this.mPropertyMap) {
let attrArray = this.mPropertyMap[prop];
attrs = attrs.concat(attrArray);
}
if (!attrs.length) {
throw Components.results.NS_ERROR_FAILURE;
}
return attrs.join(",");
},
getAllCardProperties: function getAllCardProperties(aCount) {
var props = [];
for (var prop in this.mPropertyMap) {
props.push(prop);
}
aCount.value = props.length;
return props;
},
setFromPrefs: function setFromPrefs(aPrefBranchName) {
// get the right pref branch
let branch = Services.prefs.getBranch(aPrefBranchName + ".");
// get the list of children
var childCount = {};
var children = branch.getChildList("", childCount);
// do the actual sets
for (var child of children) {
this.setAttributeList(child, branch.getCharPref(child), true);
}
// ensure that everything is kosher
this.checkState();
},
setCardPropertiesFromLDAPMessage: function
setCardPropertiesFromLDAPMessage(aMessage, aCard) {
var cardValueWasSet = false;
var msgAttrCount = {};
var msgAttrs = aMessage.getAttributes(msgAttrCount);
// downcase the array for comparison
function toLower(a) { return a.toLowerCase(); }
msgAttrs = msgAttrs.map(toLower);
// deal with each addressbook property
for (var prop in this.mPropertyMap) {
// go through the list of possible attrs in precedence order
for (var attr of this.mPropertyMap[prop]) {
attr = attr.toLowerCase();
// find the first attr that exists in this message
if (msgAttrs.indexOf(attr) != -1) {
try {
var values = aMessage.getValues(attr, {});
// strip out the optional label from the labeledURI
if (attr == "labeleduri" && values[0]) {
var index = values[0].indexOf(" ");
if (index != -1)
values[0] = values[0].substring(0, index);
}
aCard.setProperty(prop, values[0]);
cardValueWasSet = true;
break;
} catch (ex) {
// ignore any errors getting message values or setting card values
}
}
}
}
if (!cardValueWasSet) {
throw Components.results.NS_ERROR_FAILURE;
}
return;
},
checkState: function checkState() {
var attrsSeen = [];
for (var prop in this.mPropertyMap) {
let attrArray = this.mPropertyMap[prop];
for (var attr of attrArray) {
// multiple attributes that mapped to the empty string are permitted
if (!attr.length) {
continue;
}
// if we've seen this before, there's a problem
if (attrsSeen.indexOf(attr) != -1) {
throw Components.results.NS_ERROR_FAILURE;
}
// remember that we've seen it now
attrsSeen.push(attr);
}
}
return;
},
QueryInterface: XPCOMUtils
.generateQI([Components.interfaces.nsIAbLDAPAttributeMap])
}
function nsAbLDAPAttributeMapService() {
}
nsAbLDAPAttributeMapService.prototype = {
classID: NS_ABLDAPATTRIBUTEMAPSERVICE_CID,
mAttrMaps: {},
getMapForPrefBranch: function getMapForPrefBranch(aPrefBranchName) {
// if we've already got this map, return it
if (aPrefBranchName in this.mAttrMaps) {
return this.mAttrMaps[aPrefBranchName];
}
// otherwise, try and create it
var attrMap = new nsAbLDAPAttributeMap();
attrMap.setFromPrefs("ldap_2.servers.default.attrmap");
attrMap.setFromPrefs(aPrefBranchName + ".attrmap");
// cache
this.mAttrMaps[aPrefBranchName] = attrMap;
// and return
return attrMap;
},
QueryInterface: XPCOMUtils
.generateQI([Components.interfaces.nsIAbLDAPAttributeMapService])
}
var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsAbLDAPAttributeMap, nsAbLDAPAttributeMapService]);

View file

@ -0,0 +1,325 @@
/* -*- 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/. */
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var ACR = Components.interfaces.nsIAutoCompleteResult;
var nsIAbAutoCompleteResult = Components.interfaces.nsIAbAutoCompleteResult;
var nsIAbDirectoryQueryResultListener =
Components.interfaces.nsIAbDirectoryQueryResultListener;
// nsAbLDAPAutoCompleteResult
// Derived from nsIAbAutoCompleteResult, provides a LDAP specific result
// implementation.
function nsAbLDAPAutoCompleteResult(aSearchString) {
// Can't create this in the prototype as we'd get the same array for
// all instances
this._searchResults = [];
this.searchString = aSearchString;
}
nsAbLDAPAutoCompleteResult.prototype = {
_searchResults: null,
_commentColumn: "",
// nsIAutoCompleteResult
searchString: null,
searchResult: ACR.RESULT_NOMATCH,
defaultIndex: -1,
errorDescription: null,
get matchCount() {
return this._searchResults.length;
},
getLabelAt: function getLabelAt(aIndex) {
return this.getValueAt(aIndex);
},
getValueAt: function getValueAt(aIndex) {
return this._searchResults[aIndex].value;
},
getCommentAt: function getCommentAt(aIndex) {
return this._commentColumn;
},
getStyleAt: function getStyleAt(aIndex) {
return this.searchResult == ACR.RESULT_FAILURE ? "remote-err" :
"remote-abook";
},
getImageAt: function getImageAt(aIndex) {
return "";
},
getFinalCompleteValueAt: function(aIndex) {
return this.getValueAt(aIndex);
},
removeValueAt: function removeValueAt(aRowIndex, aRemoveFromDB) {
},
// nsIAbAutoCompleteResult
getCardAt: function getCardAt(aIndex) {
return this._searchResults[aIndex].card;
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([ACR, nsIAbAutoCompleteResult])
}
function nsAbLDAPAutoCompleteSearch() {
Services.obs.addObserver(this, "quit-application", false);
this._timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
}
nsAbLDAPAutoCompleteSearch.prototype = {
// For component registration
classID: Components.ID("227e6482-fe9f-441f-9b7d-7b60375e7449"),
// A short-lived LDAP directory cache.
// To avoid recreating components as the user completes, we maintain the most
// recently used address book, nsAbLDAPDirectoryQuery and search context.
// However the cache is discarded if it has not been used for a minute.
// This is done to avoid problems with LDAP sessions timing out and hanging.
_query: null,
_book: null,
_attributes: null,
_context: -1,
_timer: null,
// The current search result.
_result: null,
// The listener to pass back results to.
_listener: null,
_parser: MailServices.headerParser,
applicableHeaders: new Set(["addr_to", "addr_cc", "addr_bcc", "addr_reply"]),
// Private methods
_checkDuplicate: function _checkDuplicate(card, emailAddress) {
var lcEmailAddress = emailAddress.toLocaleLowerCase();
return this._result._searchResults.some(function(result) {
return result.value.toLocaleLowerCase() == lcEmailAddress;
});
},
_addToResult: function(card) {
let mbox = this._parser.makeMailboxObject(card.displayName,
card.isMailList ? card.getProperty("Notes", "") || card.displayName :
card.primaryEmail);
if (!mbox.email)
return;
let emailAddress = mbox.toString();
// If it is a duplicate, then just return and don't add it. The
// _checkDuplicate function deals with it all for us.
if (this._checkDuplicate(card, emailAddress))
return;
// Find out where to insert the card.
var insertPosition = 0;
// Next sort on full address
while (insertPosition < this._result._searchResults.length &&
emailAddress > this._result._searchResults[insertPosition].value)
++insertPosition;
this._result._searchResults.splice(insertPosition, 0, {
value: emailAddress,
card: card,
});
},
// nsIObserver
observe: function observer(subject, topic, data) {
if (topic == "quit-application") {
Services.obs.removeObserver(this, "quit-application");
} else if (topic != "timer-callback") {
return;
}
// Force the individual query items to null, so that the memory
// gets collected straight away.
this.stopSearch();
this._book = null;
this._context = -1;
this._query = null;
this._attributes = null;
},
// nsIAutoCompleteSearch
startSearch: function startSearch(aSearchString, aParam,
aPreviousResult, aListener) {
let params = JSON.parse(aParam) || {};
let applicable = !("type" in params) || this.applicableHeaders.has(params.type);
this._result = new nsAbLDAPAutoCompleteResult(aSearchString);
aSearchString = aSearchString.toLocaleLowerCase();
// If the search string isn't value, or contains a comma, or the user
// hasn't enabled autocomplete, then just return no matches / or the
// result ignored.
// The comma check is so that we don't autocomplete against the user
// entering multiple addresses.
if (!applicable || !aSearchString || aSearchString.includes(",")) {
this._result.searchResult = ACR.RESULT_IGNORED;
aListener.onSearchResult(this, this._result);
return;
}
// The rules here: If the current identity has a directoryServer set, then
// use that, otherwise, try the global preference instead.
var acDirURI = null;
var identity;
if ("idKey" in params) {
try {
identity = MailServices.accounts.getIdentity(params.idKey);
}
catch(ex) {
Components.utils.reportError("Couldn't get specified identity, " +
"falling back to global settings");
}
}
// Does the current identity override the global preference?
if (identity && identity.overrideGlobalPref)
acDirURI = identity.directoryServer;
else {
// Try the global one
if (Services.prefs.getBoolPref("ldap_2.autoComplete.useDirectory"))
acDirURI = Services.prefs.getCharPref("ldap_2.autoComplete.directoryServer");
}
if (!acDirURI) {
// No directory to search, send a no match and return.
aListener.onSearchResult(this, this._result);
return;
}
this.stopSearch();
// If we don't already have a cached query for this URI, build a new one.
acDirURI = "moz-abldapdirectory://" + acDirURI;
if (!this._book || this._book.URI != acDirURI) {
this._query =
Components.classes["@mozilla.org/addressbook/ldap-directory-query;1"]
.createInstance(Components.interfaces.nsIAbDirectoryQuery);
this._book = MailServices.ab.getDirectory(acDirURI)
.QueryInterface(Components.interfaces.nsIAbLDAPDirectory);
// Create a minimal map just for the display name and primary email.
this._attributes =
Components.classes["@mozilla.org/addressbook/ldap-attribute-map;1"]
.createInstance(Components.interfaces.nsIAbLDAPAttributeMap);
this._attributes.setAttributeList("DisplayName",
this._book.attributeMap.getAttributeList("DisplayName", {}), true);
this._attributes.setAttributeList("PrimaryEmail",
this._book.attributeMap.getAttributeList("PrimaryEmail", {}), true);
}
this._result._commentColumn = this._book.dirName;
this._listener = aListener;
this._timer.init(this, 60000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
var args =
Components.classes["@mozilla.org/addressbook/directory/query-arguments;1"]
.createInstance(Components.interfaces.nsIAbDirectoryQueryArguments);
var filterTemplate = this._book.getStringValue("autoComplete.filterTemplate", "");
// Use default value when preference is not set or it contains empty string
if (!filterTemplate)
filterTemplate = "(|(cn=%v1*%v2-*)(mail=%v1*%v2-*)(sn=%v1*%v2-*))";
// Create filter from filter template and search string
var ldapSvc = Components.classes["@mozilla.org/network/ldap-service;1"]
.getService(Components.interfaces.nsILDAPService);
var filter = ldapSvc.createFilter(1024, filterTemplate, "", "", "", aSearchString);
if (!filter)
throw new Error("Filter string is empty, check if filterTemplate variable is valid in prefs.js.");
args.typeSpecificArg = this._attributes;
args.querySubDirectories = true;
args.filter = filter;
// Start the actual search
this._context =
this._query.doQuery(this._book, args, this, this._book.maxHits, 0);
},
stopSearch: function stopSearch() {
if (this._listener) {
this._query.stopQuery(this._context);
this._listener = null;
}
},
// nsIAbDirSearchListener
onSearchFinished: function onSearchFinished(aResult, aErrorMsg) {
if (!this._listener)
return;
if (aResult == nsIAbDirectoryQueryResultListener.queryResultComplete) {
if (this._result.matchCount) {
this._result.searchResult = ACR.RESULT_SUCCESS;
this._result.defaultIndex = 0;
}
else
this._result.searchResult = ACR.RESULT_NOMATCH;
}
else if (aResult == nsIAbDirectoryQueryResultListener.queryResultError) {
this._result.searchResult = ACR.RESULT_FAILURE;
this._result.defaultIndex = 0;
}
// const long queryResultStopped = 2;
// const long queryResultError = 3;
this._listener.onSearchResult(this, this._result);
this._listener = null;
},
onSearchFoundCard: function onSearchFoundCard(aCard) {
if (!this._listener)
return;
this._addToResult(aCard);
/* XXX autocomplete doesn't expect you to rearrange while searching
if (this._result.matchCount)
this._result.searchResult = ACR.RESULT_SUCCESS_ONGOING;
else
this._result.searchResult = ACR.RESULT_NOMATCH_ONGOING;
this._listener.onSearchResult(this, this._result);
*/
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIObserver,
Components.interfaces
.nsIAutoCompleteSearch,
Components.interfaces
.nsIAbDirSearchListener])
};
// Module
var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsAbLDAPAutoCompleteSearch]);

View file

@ -0,0 +1,297 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPCard.h"
#include "nsIMutableArray.h"
#include "nsCOMPtr.h"
#include "nsILDAPModification.h"
#include "nsILDAPBERValue.h"
#include "nsILDAPMessage.h"
#include "nsIAbLDAPAttributeMap.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsAbBaseCID.h"
#include "nsAbUtils.h"
#include "nsILDAPErrors.h"
#include <stdio.h>
#define kDNColumn "DN"
nsAbLDAPCard::nsAbLDAPCard()
{
}
nsAbLDAPCard::~nsAbLDAPCard()
{
}
NS_IMPL_ISUPPORTS_INHERITED(nsAbLDAPCard, nsAbCardProperty, nsIAbLDAPCard)
/* Retrieves the changes to the LDAP card and stores them in an LDAP
* update message.
*
* Calling this method changes the LDAP card, it updates the
* meta-properties (m_*) to reflect what the LDAP contents will be once
* the update has been performed. This allows you to do multiple (successful)
* consecutive edits on a card in a search result. If the meta-properties
* were not updated, incorrect assuptions would be made about what object
* classes to add, or what attributes to clear.
*
* XXX: We need to take care when integrating this code with the asynchronous
* update dialogs, as the current code in nsAbLDAPDirectory has a problem
* when an update fails: the modified card still gets stored and shown to
* the user instead of being discarded. There is one especially tricky case:
* when you do an update on a card which changes its DN, you have two
* operations (rename, then update the other attributes). If the rename
* operation succeeds and not the update of the attributes, you are
* "somewhere in between" the original card and the updated card.
*/
NS_IMETHODIMP nsAbLDAPCard::GetLDAPMessageInfo(
nsIAbLDAPAttributeMap *aAttributeMap,
const uint32_t aClassCount,
const char **aClasses,
int32_t aType,
nsIArray **aLDAPAddMessageInfo)
{
NS_ENSURE_ARG_POINTER(aAttributeMap);
NS_ENSURE_ARG_POINTER(aClasses);
NS_ENSURE_ARG_POINTER(aLDAPAddMessageInfo);
nsresult rv;
nsCOMPtr<nsIMutableArray> modArray =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Add any missing object classes. We never remove any object
// classes: if an entry has additional object classes, it's probably
// for a good reason.
nsAutoCString oclass;
for (uint32_t i = 0; i < aClassCount; ++i)
{
oclass.Assign(nsDependentCString(aClasses[i]));
ToLowerCase(oclass);
if (!m_objectClass.Contains(oclass))
{
m_objectClass.AppendElement(oclass);
printf("LDAP : adding objectClass %s\n", oclass.get());
}
}
nsCOMPtr<nsILDAPModification> mod =
do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMutableArray> values =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0; i < m_objectClass.Length(); ++i)
{
nsCOMPtr<nsILDAPBERValue> value =
do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = value->SetFromUTF8(m_objectClass.ElementAt(i));
NS_ENSURE_SUCCESS(rv, rv);
rv = values->AppendElement(value, false);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mod->SetUpModification(aType, NS_LITERAL_CSTRING("objectClass"), values);
NS_ENSURE_SUCCESS(rv, rv);
modArray->AppendElement(mod, false);
// Add card properties
CharPtrArrayGuard props;
rv = aAttributeMap->GetAllCardProperties(props.GetSizeAddr(),
props.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString attr;
nsCString propvalue;
for (uint32_t i = 0; i < props.GetSize(); ++i)
{
// Skip some attributes that don't map to LDAP.
//
// BirthYear : by default this is mapped to 'birthyear',
// which is not part of mozillaAbPersonAlpha
//
// LastModifiedDate : by default this is mapped to 'modifytimestamp',
// which cannot be modified
//
// PreferMailFormat : by default this is mapped to 'mozillaUseHtmlMail',
// which is a boolean, not plaintext/html/unknown
if (!strcmp(props[i], kBirthYearProperty) ||
!strcmp(props[i], kLastModifiedDateProperty) ||
!strcmp(props[i], kPreferMailFormatProperty))
continue;
rv = aAttributeMap->GetFirstAttribute(nsDependentCString(props[i]),
attr);
NS_ENSURE_SUCCESS(rv, rv);
ToLowerCase(attr);
// If the property is not mapped to an attribute, skip it.
if (attr.IsEmpty())
continue;
nsCOMPtr<nsILDAPModification> mod =
do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
size_t index = m_attributes.IndexOf(attr);
rv = GetPropertyAsAUTF8String(props[i], propvalue);
if (NS_SUCCEEDED(rv) &&!propvalue.IsEmpty())
{
// If the new value is not empty, add/update it
nsCOMPtr<nsILDAPBERValue> value =
do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = value->SetFromUTF8(propvalue);
NS_ENSURE_SUCCESS(rv, rv);
rv = mod->SetUpModificationOneValue(aType, attr, value);
NS_ENSURE_SUCCESS(rv, rv);
printf("LDAP : setting attribute %s (%s) to '%s'\n", attr.get(),
props[i], propvalue.get());
modArray->AppendElement(mod, false);
if (index != m_attributes.NoIndex)
m_attributes.AppendElement(attr);
}
else if (aType == nsILDAPModification::MOD_REPLACE &&
index != m_attributes.NoIndex)
{
// If the new value is empty, we are performing an update
// and the attribute was previously set, clear it
nsCOMPtr<nsIMutableArray> novalues =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mod->SetUpModification(aType, attr, novalues);
NS_ENSURE_SUCCESS(rv, rv);
printf("LDAP : removing attribute %s (%s)\n", attr.get(), props[i]);
modArray->AppendElement(mod, false);
m_attributes.RemoveElementAt(index);
}
}
NS_ADDREF(*aLDAPAddMessageInfo = modArray);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPCard::BuildRdn(nsIAbLDAPAttributeMap *aAttributeMap,
const uint32_t aAttrCount,
const char **aAttributes,
nsACString &aRdn)
{
NS_ENSURE_ARG_POINTER(aAttributeMap);
NS_ENSURE_ARG_POINTER(aAttributes);
nsresult rv;
nsCString attr;
nsAutoCString prop;
nsCString propvalue;
aRdn.Truncate();
for (uint32_t i = 0; i < aAttrCount; ++i)
{
attr.Assign(nsDependentCString(aAttributes[i]));
// Lookup the property corresponding to the attribute
rv = aAttributeMap->GetProperty(attr, prop);
NS_ENSURE_SUCCESS(rv, rv);
// Get the property value
rv = GetPropertyAsAUTF8String(prop.get(), propvalue);
// XXX The case where an attribute needed to build the Relative
// Distinguished Name is not set needs to be handled by the caller,
// so as to let the user know what is missing.
if (NS_FAILED(rv) || propvalue.IsEmpty())
{
NS_ERROR("nsAbLDAPCard::BuildRdn: a required attribute is not set");
return NS_ERROR_NOT_INITIALIZED;
}
aRdn.Append(attr);
aRdn.AppendLiteral("=");
aRdn.Append(propvalue);
if (i < aAttrCount - 1)
aRdn.AppendLiteral("+");
}
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPCard::GetDn(nsACString &aDN)
{
return GetPropertyAsAUTF8String(kDNColumn, aDN);
}
NS_IMETHODIMP nsAbLDAPCard::SetDn(const nsACString &aDN)
{
SetLocalId(aDN);
return SetPropertyAsAUTF8String(kDNColumn, aDN);
}
NS_IMETHODIMP nsAbLDAPCard::SetMetaProperties(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
// Get DN
nsAutoCString dn;
nsresult rv = aMessage->GetDn(dn);
NS_ENSURE_SUCCESS(rv, rv);
SetDn(dn);
// Get the list of set attributes
CharPtrArrayGuard attrs;
rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString attr;
m_attributes.Clear();
for (uint32_t i = 0; i < attrs.GetSize(); ++i)
{
attr.Assign(nsDependentCString(attrs[i]));
ToLowerCase(attr);
m_attributes.AppendElement(attr);
}
// Get the objectClass values
m_objectClass.Clear();
PRUnicharPtrArrayGuard vals;
rv = aMessage->GetValues("objectClass", vals.GetSizeAddr(),
vals.GetArrayAddr());
// objectClass is not always included in search result entries and
// nsILDAPMessage::GetValues returns NS_ERROR_LDAP_DECODING_ERROR if the
// requested attribute doesn't exist.
if (rv == NS_ERROR_LDAP_DECODING_ERROR)
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString oclass;
for (uint32_t i = 0; i < vals.GetSize(); ++i)
{
oclass.Assign(NS_LossyConvertUTF16toASCII(nsDependentString(vals[i])));
ToLowerCase(oclass);
m_objectClass.AppendElement(oclass);
}
return NS_OK;
}

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPCard_h__
#define nsAbLDAPCard_h__
#include "nsAbCardProperty.h"
#include "nsIAbLDAPCard.h"
#include "nsTArray.h"
class nsIMutableArray;
class nsAbLDAPCard : public nsAbCardProperty,
public nsIAbLDAPCard
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIABLDAPCARD
nsAbLDAPCard();
protected:
virtual ~nsAbLDAPCard();
nsTArray<nsCString> m_attributes;
nsTArray<nsCString> m_objectClass;
};
#endif

View file

@ -0,0 +1,542 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPChangeLogData.h"
#include "nsAbLDAPChangeLogQuery.h"
#include "nsILDAPMessage.h"
#include "nsIAbCard.h"
#include "nsIAddrBookSession.h"
#include "nsAbBaseCID.h"
#include "nsAbUtils.h"
#include "nsAbMDBCard.h"
#include "nsAbLDAPCard.h"
#include "nsIAuthPrompt.h"
#include "nsIStringBundle.h"
#include "nsIWindowWatcher.h"
#include "nsUnicharUtils.h"
#include "plstr.h"
#include "nsILDAPErrors.h"
#include "prmem.h"
#include "mozilla/Services.h"
// Defined here since to be used
// only locally to this file.
enum UpdateOp {
NO_OP,
ENTRY_ADD,
ENTRY_DELETE,
ENTRY_MODIFY
};
nsAbLDAPProcessChangeLogData::nsAbLDAPProcessChangeLogData()
: mUseChangeLog(false),
mChangeLogEntriesCount(0),
mEntriesAddedQueryCount(0)
{
mRootDSEEntry.firstChangeNumber = 0;
mRootDSEEntry.lastChangeNumber = 0;
}
nsAbLDAPProcessChangeLogData::~nsAbLDAPProcessChangeLogData()
{
}
NS_IMETHODIMP nsAbLDAPProcessChangeLogData::Init(nsIAbLDAPReplicationQuery * query, nsIWebProgressListener *progressListener)
{
NS_ENSURE_ARG_POINTER(query);
// Here we are assuming that the caller will pass a nsAbLDAPChangeLogQuery object,
// an implementation derived from the implementation of nsIAbLDAPReplicationQuery.
nsresult rv = NS_OK;
mChangeLogQuery = do_QueryInterface(query, &rv);
if(NS_FAILED(rv))
return rv;
// Call the parent's Init now.
return nsAbLDAPProcessReplicationData::Init(query, progressListener);
}
nsresult nsAbLDAPProcessChangeLogData::OnLDAPBind(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
int32_t errCode;
nsresult rv = aMessage->GetErrorCode(&errCode);
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
if(errCode != nsILDAPErrors::SUCCESS) {
Done(false);
return NS_ERROR_FAILURE;
}
switch(mState) {
case kAnonymousBinding :
rv = GetAuthData();
if(NS_SUCCEEDED(rv))
rv = mChangeLogQuery->QueryAuthDN(mAuthUserID);
if(NS_SUCCEEDED(rv))
mState = kSearchingAuthDN;
break;
case kAuthenticatedBinding :
rv = mChangeLogQuery->QueryRootDSE();
if(NS_SUCCEEDED(rv))
mState = kSearchingRootDSE;
break;
} //end of switch
if(NS_FAILED(rv))
Abort();
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::OnLDAPSearchEntry(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = NS_OK;
switch(mState)
{
case kSearchingAuthDN :
{
nsAutoCString authDN;
rv = aMessage->GetDn(authDN);
if(NS_SUCCEEDED(rv) && !authDN.IsEmpty())
mAuthDN = authDN.get();
}
break;
case kSearchingRootDSE:
rv = ParseRootDSEEntry(aMessage);
break;
case kFindingChanges:
rv = ParseChangeLogEntries(aMessage);
break;
// Fall through since we only add (for updates we delete and add)
case kReplicatingChanges:
case kReplicatingAll :
return nsAbLDAPProcessReplicationData::OnLDAPSearchEntry(aMessage);
}
if(NS_FAILED(rv))
Abort();
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::OnLDAPSearchResult(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
int32_t errorCode;
nsresult rv = aMessage->GetErrorCode(&errorCode);
if(NS_SUCCEEDED(rv))
{
if(errorCode == nsILDAPErrors::SUCCESS || errorCode == nsILDAPErrors::SIZELIMIT_EXCEEDED) {
switch(mState) {
case kSearchingAuthDN :
rv = OnSearchAuthDNDone();
break;
case kSearchingRootDSE:
{
// Before starting the changeLog check the DB file, if its not there or bogus
// we need to create a new one and set to all.
nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
if (NS_FAILED(rv))
break;
nsCOMPtr<nsIFile> dbPath;
rv = abSession->GetUserProfileDirectory(getter_AddRefs(dbPath));
if (NS_FAILED(rv))
break;
nsAutoCString fileName;
rv = mDirectory->GetReplicationFileName(fileName);
if (NS_FAILED(rv))
break;
rv = dbPath->AppendNative(fileName);
if (NS_FAILED(rv))
break;
bool fileExists;
rv = dbPath->Exists(&fileExists);
if (NS_FAILED(rv))
break;
int64_t fileSize;
rv = dbPath->GetFileSize(&fileSize);
if(NS_FAILED(rv))
break;
if (!fileExists || !fileSize)
mUseChangeLog = false;
// Open / create the AB here since it calls Done,
// just return from here.
if (mUseChangeLog)
rv = OpenABForReplicatedDir(false);
else
rv = OpenABForReplicatedDir(true);
if (NS_FAILED(rv))
return rv;
// Now start the appropriate query
rv = OnSearchRootDSEDone();
break;
}
case kFindingChanges:
rv = OnFindingChangesDone();
// If success we return from here since
// this changes state to kReplicatingChanges
// and it falls thru into the if clause below.
if (NS_SUCCEEDED(rv))
return rv;
break;
case kReplicatingAll :
return nsAbLDAPProcessReplicationData::OnLDAPSearchResult(aMessage);
} // end of switch
}
else
rv = NS_ERROR_FAILURE;
// If one of the changed entry in changelog is not found,
// continue with replicating the next one.
if(mState == kReplicatingChanges)
rv = OnReplicatingChangeDone();
} // end of outer if
if(NS_FAILED(rv))
Abort();
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::GetAuthData()
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
if (!wwatch)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIAuthPrompt> dialog;
nsresult rv = wwatch->GetNewAuthPrompter(0, getter_AddRefs(dialog));
if (NS_FAILED(rv))
return rv;
if (!dialog)
return NS_ERROR_FAILURE;
nsCOMPtr<nsILDAPURL> url;
rv = mQuery->GetReplicationURL(getter_AddRefs(url));
if (NS_FAILED(rv))
return rv;
nsAutoCString serverUri;
rv = url->GetSpec(serverUri);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/addressbook/addressBook.properties", getter_AddRefs(bundle));
if (NS_FAILED (rv))
return rv ;
nsString title;
rv = bundle->GetStringFromName(u"AuthDlgTitle", getter_Copies(title));
if (NS_FAILED (rv))
return rv ;
nsString desc;
rv = bundle->GetStringFromName(u"AuthDlgDesc", getter_Copies(desc));
if (NS_FAILED (rv))
return rv ;
nsString username;
nsString password;
bool btnResult = false;
rv = dialog->PromptUsernameAndPassword(title, desc,
NS_ConvertUTF8toUTF16(serverUri).get(),
nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
getter_Copies(username), getter_Copies(password),
&btnResult);
if(NS_SUCCEEDED(rv) && btnResult) {
CopyUTF16toUTF8(username, mAuthUserID);
CopyUTF16toUTF8(password, mAuthPswd);
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::OnSearchAuthDNDone()
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsILDAPURL> url;
nsresult rv = mQuery->GetReplicationURL(getter_AddRefs(url));
if(NS_SUCCEEDED(rv))
rv = mQuery->ConnectToLDAPServer(url, mAuthDN);
if(NS_SUCCEEDED(rv)) {
mState = kAuthenticatedBinding;
rv = mDirectory->SetAuthDn(mAuthDN);
}
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::ParseRootDSEEntry(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
// Populate the RootDSEChangeLogEntry
CharPtrArrayGuard attrs;
nsresult rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr());
// No attributes
if(NS_FAILED(rv))
return rv;
for(int32_t i=attrs.GetSize()-1; i >= 0; i--) {
PRUnicharPtrArrayGuard vals;
rv = aMessage->GetValues(attrs.GetArray()[i], vals.GetSizeAddr(), vals.GetArrayAddr());
if(NS_FAILED(rv))
continue;
if(vals.GetSize()) {
if (!PL_strcasecmp(attrs[i], "changelog"))
CopyUTF16toUTF8(vals[0], mRootDSEEntry.changeLogDN);
if (!PL_strcasecmp(attrs[i], "firstChangeNumber"))
mRootDSEEntry.firstChangeNumber = atol(NS_LossyConvertUTF16toASCII(vals[0]).get());
if (!PL_strcasecmp(attrs[i], "lastChangeNumber"))
mRootDSEEntry.lastChangeNumber = atol(NS_LossyConvertUTF16toASCII(vals[0]).get());
if (!PL_strcasecmp(attrs[i], "dataVersion"))
CopyUTF16toUTF8(vals[0], mRootDSEEntry.dataVersion);
}
}
int32_t lastChangeNumber;
mDirectory->GetLastChangeNumber(&lastChangeNumber);
if ((mRootDSEEntry.lastChangeNumber > 0) &&
(lastChangeNumber < mRootDSEEntry.lastChangeNumber) &&
(lastChangeNumber > mRootDSEEntry.firstChangeNumber))
mUseChangeLog = true;
if (mRootDSEEntry.lastChangeNumber &&
(lastChangeNumber == mRootDSEEntry.lastChangeNumber)) {
Done(true); // We are up to date no need to replicate, db not open yet so call Done
return NS_OK;
}
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::OnSearchRootDSEDone()
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = NS_OK;
if(mUseChangeLog) {
rv = mChangeLogQuery->QueryChangeLog(mRootDSEEntry.changeLogDN, mRootDSEEntry.lastChangeNumber);
if (NS_FAILED(rv))
return rv;
mState = kFindingChanges;
if(mListener)
mListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_START, false);
}
else {
rv = mQuery->QueryAllEntries();
if (NS_FAILED(rv))
return rv;
mState = kReplicatingAll;
if(mListener)
mListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_START, true);
}
rv = mDirectory->SetLastChangeNumber(mRootDSEEntry.lastChangeNumber);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDirectory->SetDataVersion(mRootDSEEntry.dataVersion);
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::ParseChangeLogEntries(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
// Populate the RootDSEChangeLogEntry
CharPtrArrayGuard attrs;
nsresult rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr());
// No attributes
if(NS_FAILED(rv))
return rv;
nsAutoString targetDN;
UpdateOp operation = NO_OP;
for(int32_t i = attrs.GetSize()-1; i >= 0; i--) {
PRUnicharPtrArrayGuard vals;
rv = aMessage->GetValues(attrs.GetArray()[i], vals.GetSizeAddr(), vals.GetArrayAddr());
if(NS_FAILED(rv))
continue;
if(vals.GetSize()) {
if (!PL_strcasecmp(attrs[i], "targetdn"))
targetDN = vals[0];
if (!PL_strcasecmp(attrs[i], "changetype")) {
if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("add"), nsCaseInsensitiveStringComparator()))
operation = ENTRY_ADD;
if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("modify"), nsCaseInsensitiveStringComparator()))
operation = ENTRY_MODIFY;
if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("delete"), nsCaseInsensitiveStringComparator()))
operation = ENTRY_DELETE;
}
}
}
mChangeLogEntriesCount++;
if(!(mChangeLogEntriesCount % 10)) { // Inform the listener every 10 entries
mListener->OnProgressChange(nullptr,nullptr,mChangeLogEntriesCount, -1, mChangeLogEntriesCount, -1);
// In case if the LDAP Connection thread is starved and causes problem
// uncomment this one and try.
// PR_Sleep(PR_INTERVAL_NO_WAIT); // give others a chance
}
#ifdef DEBUG_rdayal
printf ("ChangeLog Replication : Updated Entry : %s for OpType : %u\n",
NS_ConvertUTF16toUTF8(targetDN).get(), operation);
#endif
switch(operation) {
case ENTRY_ADD:
// Add the DN to the add list if not already in the list
if(!(mEntriesToAdd.IndexOf(targetDN) >= 0))
mEntriesToAdd.AppendString(targetDN);
break;
case ENTRY_DELETE:
// Do not check the return here since delete may fail if
// entry deleted in changelog does not exist in DB
// for e.g if the user specifies a filter, so go next entry
DeleteCard(targetDN);
break;
case ENTRY_MODIFY:
// For modify, delete the entry from DB and add updated entry
// we do this since we cannot access the changes attribs of changelog
rv = DeleteCard(targetDN);
if (NS_SUCCEEDED(rv))
if(!(mEntriesToAdd.IndexOf(targetDN) >= 0))
mEntriesToAdd.AppendString(targetDN);
break;
default:
// Should not come here, would come here only
// if the entry is not a changeLog entry
NS_WARNING("nsAbLDAPProcessChangeLogData::ParseChangeLogEntries"
"Not an changelog entry");
}
// Go ahead processing the next entry, a modify or delete DB operation
// can 'correctly' fail if the entry is not present in the DB,
// e.g. in case a filter is specified.
return NS_OK;
}
nsresult nsAbLDAPProcessChangeLogData::OnFindingChangesDone()
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
#ifdef DEBUG_rdayal
printf ("ChangeLog Replication : Finding Changes Done \n");
#endif
nsresult rv = NS_OK;
// No entries to add/update (for updates too we delete and add) entries,
// we took care of deletes in ParseChangeLogEntries, all Done!
mEntriesAddedQueryCount = mEntriesToAdd.Count();
if(mEntriesAddedQueryCount <= 0) {
if(mReplicationDB && mDBOpen) {
// Close the DB, no need to commit since we have not made
// any changes yet to the DB.
rv = mReplicationDB->Close(false);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication DB Close(no commit) on Success failed");
mDBOpen = false;
// Once are done with the replication file, delete the backup file
if(mBackupReplicationFile) {
rv = mBackupReplicationFile->Remove(false);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication BackupFile Remove on Success failed");
}
}
Done(true);
return NS_OK;
}
// Decrement the count first to get the correct array element
mEntriesAddedQueryCount--;
rv = mChangeLogQuery->QueryChangedEntries(NS_ConvertUTF16toUTF8(*(mEntriesToAdd[mEntriesAddedQueryCount])));
if (NS_FAILED(rv))
return rv;
if(mListener && NS_SUCCEEDED(rv))
mListener->OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_START, true);
mState = kReplicatingChanges;
return rv;
}
nsresult nsAbLDAPProcessChangeLogData::OnReplicatingChangeDone()
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = NS_OK;
if(!mEntriesAddedQueryCount)
{
if(mReplicationDB && mDBOpen) {
rv = mReplicationDB->Close(true); // Commit and close the DB
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication DB Close (commit) on Success failed");
mDBOpen = false;
}
// Once we done with the replication file, delete the backup file.
if(mBackupReplicationFile) {
rv = mBackupReplicationFile->Remove(false);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication BackupFile Remove on Success failed");
}
Done(true); // All data is received
return NS_OK;
}
// Remove the entry already added from the list and query the next one.
if(mEntriesAddedQueryCount < mEntriesToAdd.Count() && mEntriesAddedQueryCount >= 0)
mEntriesToAdd.RemoveStringAt(mEntriesAddedQueryCount);
mEntriesAddedQueryCount--;
rv = mChangeLogQuery->QueryChangedEntries(NS_ConvertUTF16toUTF8(*(mEntriesToAdd[mEntriesAddedQueryCount])));
return rv;
}

View file

@ -0,0 +1,57 @@
/* 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/. */
#ifndef nsAbLDAPChangeLogData_h__
#define nsAbLDAPChangeLogData_h__
#include "mozilla/Attributes.h"
#include "nsAbLDAPReplicationData.h"
#include "nsAbLDAPChangeLogQuery.h"
typedef struct {
nsCString changeLogDN;
int32_t firstChangeNumber;
int32_t lastChangeNumber;
nsCString dataVersion;
} RootDSEChangeLogEntry;
class nsAbLDAPProcessChangeLogData : public nsAbLDAPProcessReplicationData
{
public :
nsAbLDAPProcessChangeLogData();
NS_IMETHOD Init(nsIAbLDAPReplicationQuery * query, nsIWebProgressListener *progressListener);
protected :
~nsAbLDAPProcessChangeLogData();
nsCOMPtr <nsIAbLDAPChangeLogQuery> mChangeLogQuery;
nsresult OnLDAPBind(nsILDAPMessage *aMessage);
nsresult OnLDAPSearchEntry(nsILDAPMessage *aMessage) override;
nsresult OnLDAPSearchResult(nsILDAPMessage *aMessage) override;
nsresult ParseChangeLogEntries(nsILDAPMessage *aMessage);
nsresult ParseRootDSEEntry(nsILDAPMessage *aMessage);
nsresult GetAuthData(); // displays username and password prompt
nsCString mAuthUserID; // user id of the user making the connection
nsresult OnSearchAuthDNDone();
nsresult OnSearchRootDSEDone();
nsresult OnFindingChangesDone();
nsresult OnReplicatingChangeDone();
RootDSEChangeLogEntry mRootDSEEntry;
bool mUseChangeLog;
int32_t mChangeLogEntriesCount;
int32_t mEntriesAddedQueryCount;
nsStringArray mEntriesToAdd;
};
#endif // nsAbLDAPChangeLogData_h__

View file

@ -0,0 +1,180 @@
/* -*- Mode: C++; 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/. */
#include "nsCOMPtr.h"
#include "nsAbLDAPChangeLogQuery.h"
#include "nsAbLDAPReplicationService.h"
#include "nsAbLDAPChangeLogData.h"
#include "nsAbUtils.h"
#include "prprf.h"
#include "nsDirPrefs.h"
#include "nsAbBaseCID.h"
// The tables below were originally in nsAbLDAPProperties.cpp, which has since
// gone away.
static const char * sChangeLogRootDSEAttribs[] =
{
"changelog",
"firstChangeNumber",
"lastChangeNumber",
"dataVersion"
};
static const char * sChangeLogEntryAttribs[] =
{
"targetdn",
"changetype"
};
NS_IMPL_ISUPPORTS_INHERITED(nsAbLDAPChangeLogQuery, nsAbLDAPReplicationQuery, nsIAbLDAPChangeLogQuery)
nsAbLDAPChangeLogQuery::nsAbLDAPChangeLogQuery()
{
}
nsAbLDAPChangeLogQuery::~nsAbLDAPChangeLogQuery()
{
}
// this is to be defined only till this is not hooked to SSL to get authDN and authPswd
#define USE_AUTHDLG
NS_IMETHODIMP nsAbLDAPChangeLogQuery::Init(const nsACString & aPrefName, nsIWebProgressListener *aProgressListener)
{
if(aPrefName.IsEmpty())
return NS_ERROR_UNEXPECTED;
mDirPrefName = aPrefName;
nsresult rv = InitLDAPData();
if(NS_FAILED(rv))
return rv;
// create the ChangeLog Data Processor
mDataProcessor = do_CreateInstance(NS_ABLDAP_PROCESSCHANGELOGDATA_CONTRACTID, &rv);
if(NS_FAILED(rv))
return rv;
// 'this' initialized
mInitialized = true;
return mDataProcessor->Init(this, aProgressListener);
}
NS_IMETHODIMP nsAbLDAPChangeLogQuery::DoReplicationQuery()
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
#ifdef USE_AUTHDLG
return ConnectToLDAPServer(mURL, EmptyCString());
#else
mDataProcessor->PopulateAuthData();
return ConnectToLDAPServer(mURL, mAuthDN);
#endif
}
NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryAuthDN(const nsACString & aValueUsedToFindDn)
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIAbLDAPAttributeMap> attrMap;
nsresult rv = mDirectory->GetAttributeMap(getter_AddRefs(attrMap));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString filter;
rv = attrMap->GetFirstAttribute(NS_LITERAL_CSTRING("PrimaryEmail"), filter);
NS_ENSURE_SUCCESS(rv, rv);
filter += '=';
filter += aValueUsedToFindDn;
nsAutoCString dn;
rv = mURL->GetDn(dn);
if(NS_FAILED(rv))
return rv;
rv = CreateNewLDAPOperation();
NS_ENSURE_SUCCESS(rv, rv);
// XXX We really should be using LDAP_NO_ATTRS here once its exposed via
// the XPCOM layer of the directory code.
return mOperation->SearchExt(dn, nsILDAPURL::SCOPE_SUBTREE, filter,
0, nullptr,
0, 0);
}
NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryRootDSE()
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = CreateNewLDAPOperation();
NS_ENSURE_SUCCESS(rv, rv);
return mOperation->SearchExt(EmptyCString(), nsILDAPURL::SCOPE_BASE,
NS_LITERAL_CSTRING("objectclass=*"),
sizeof(sChangeLogRootDSEAttribs),
sChangeLogRootDSEAttribs, 0, 0);
}
NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryChangeLog(const nsACString & aChangeLogDN, int32_t aLastChangeNo)
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
if (aChangeLogDN.IsEmpty())
return NS_ERROR_UNEXPECTED;
int32_t lastChangeNumber;
nsresult rv = mDirectory->GetLastChangeNumber(&lastChangeNumber);
NS_ENSURE_SUCCESS(rv, rv);
// make sure that the filter here just have one condition
// and should not be enclosed in enclosing brackets.
// also condition '>' doesnot work, it should be '>='/
nsAutoCString filter (NS_LITERAL_CSTRING("changenumber>="));
filter.AppendInt(lastChangeNumber + 1);
rv = CreateNewLDAPOperation();
NS_ENSURE_SUCCESS(rv, rv);
return mOperation->SearchExt(aChangeLogDN, nsILDAPURL::SCOPE_ONELEVEL, filter,
sizeof(sChangeLogEntryAttribs),
sChangeLogEntryAttribs, 0, 0);
}
NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryChangedEntries(const nsACString & aChangedEntryDN)
{
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
if(aChangedEntryDN.IsEmpty())
return NS_ERROR_UNEXPECTED;
nsAutoCString urlFilter;
nsresult rv = mURL->GetFilter(urlFilter);
if(NS_FAILED(rv))
return rv;
int32_t scope;
rv = mURL->GetScope(&scope);
if(NS_FAILED(rv))
return rv;
CharPtrArrayGuard attributes;
rv = mURL->GetAttributes(attributes.GetSizeAddr(), attributes.GetArrayAddr());
if(NS_FAILED(rv))
return rv;
rv = CreateNewLDAPOperation();
NS_ENSURE_SUCCESS(rv, rv);
return mOperation->SearchExt(aChangedEntryDN, scope, urlFilter,
attributes.GetSize(), attributes.GetArray(),
0, 0);
}

View file

@ -0,0 +1,28 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPChangeLogQuery_h__
#define nsAbLDAPChangeLogQuery_h__
#include "mozilla/Attributes.h"
#include "nsAbLDAPReplicationQuery.h"
#include "nsStringGlue.h"
class nsAbLDAPChangeLogQuery : public nsIAbLDAPChangeLogQuery,
public nsAbLDAPReplicationQuery
{
public :
NS_DECL_ISUPPORTS
NS_DECL_NSIABLDAPCHANGELOGQUERY
nsAbLDAPChangeLogQuery();
virtual ~nsAbLDAPChangeLogQuery();
NS_IMETHOD DoReplicationQuery() override;
NS_IMETHOD Init(const nsACString & aPrefName, nsIWebProgressListener *aProgressListener);
};
#endif // nsAbLDAPChangeLogQuery_h__

View file

@ -0,0 +1,79 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPDirFactory.h"
#include "nsAbUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIAbManager.h"
#include "nsIAbDirectory.h"
#include "nsAbLDAPDirectory.h"
#include "nsEnumeratorUtils.h"
#include "nsAbBaseCID.h"
NS_IMPL_ISUPPORTS(nsAbLDAPDirFactory, nsIAbDirFactory)
nsAbLDAPDirFactory::nsAbLDAPDirFactory()
{
}
nsAbLDAPDirFactory::~nsAbLDAPDirFactory()
{
}
NS_IMETHODIMP
nsAbLDAPDirFactory::GetDirectories(const nsAString &aDirName,
const nsACString &aURI,
const nsACString &aPrefName,
nsISimpleEnumerator **aDirectories)
{
NS_ENSURE_ARG_POINTER(aDirectories);
nsresult rv;
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectory> directory;
if (Substring(aURI, 0, 5).EqualsLiteral("ldap:") ||
Substring(aURI, 0, 6).EqualsLiteral("ldaps:")) {
/*
* If the URI starts with ldap: or ldaps:
* then this directory is an LDAP directory.
*
* We don't want to use the ldap:// or ldaps:// URI
* as the URI because the ldap:// or ldaps:// URI
* will contain the hostname, basedn, port, etc.
* so if those attributes changed, we'll run into the
* the same problem that we hit with changing username / hostname
* for mail servers. To solve this problem, we add an extra
* level of indirection. The URI that we generate
* (the bridge URI) will be moz-abldapdirectory://<prefName>
* and when we need the hostname, basedn, port, etc,
* we'll use the <prefName> to get the necessary prefs.
* note, <prefName> does not change.
*/
nsAutoCString bridgeURI;
bridgeURI = NS_LITERAL_CSTRING(kLDAPDirectoryRoot);
bridgeURI += aPrefName;
rv = abManager->GetDirectory(bridgeURI, getter_AddRefs(directory));
}
else {
rv = abManager->GetDirectory(aURI, getter_AddRefs(directory));
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewSingletonEnumerator(aDirectories, directory);
}
/* void deleteDirectory (in nsIAbDirectory directory); */
NS_IMETHODIMP
nsAbLDAPDirFactory::DeleteDirectory(nsIAbDirectory *directory)
{
// No actual deletion - as the LDAP Address Book is not physically
// created in the corresponding CreateDirectory() unlike the Personal
// Address Books. But we still need to return NS_OK from here.
return NS_OK;
}

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbLDAPDirFactory_h__
#define nsAbLDAPDirFactory_h__
#include "nsIAbDirFactory.h"
class nsAbLDAPDirFactory : public nsIAbDirFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRFACTORY
nsAbLDAPDirFactory();
private:
virtual ~nsAbLDAPDirFactory();
};
#endif

View file

@ -0,0 +1,948 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPDirectory.h"
#include "nsAbQueryStringToExpression.h"
#include "nsAbBaseCID.h"
#include "nsIAbManager.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsNetCID.h"
#include "nsIIOService.h"
#include "nsCOMArray.h"
#include "nsArrayEnumerator.h"
#include "nsEnumeratorUtils.h"
#include "nsIAbLDAPAttributeMap.h"
#include "nsIAbMDBDirectory.h"
#include "nsILDAPURL.h"
#include "nsILDAPConnection.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIFile.h"
#include "nsILDAPModification.h"
#include "nsILDAPService.h"
#include "nsIAbLDAPCard.h"
#include "nsAbUtils.h"
#include "nsArrayUtils.h"
#include "nsIPrefService.h"
#include "nsIMsgAccountManager.h"
#include "nsMsgBaseCID.h"
#include "nsMsgUtils.h"
#include "mozilla/Services.h"
#define kDefaultMaxHits 100
using namespace mozilla;
nsAbLDAPDirectory::nsAbLDAPDirectory() :
nsAbDirProperty(),
mPerformingQuery(false),
mContext(0),
mLock("nsAbLDAPDirectory.mLock")
{
}
nsAbLDAPDirectory::~nsAbLDAPDirectory()
{
}
NS_IMPL_ISUPPORTS_INHERITED(nsAbLDAPDirectory, nsAbDirProperty,
nsISupportsWeakReference, nsIAbDirSearchListener,
nsIAbLDAPDirectory)
NS_IMETHODIMP nsAbLDAPDirectory::GetPropertiesChromeURI(nsACString &aResult)
{
aResult.AssignLiteral("chrome://messenger/content/addressbook/pref-directory-add.xul");
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::Init(const char* aURI)
{
// We need to ensure that the m_DirPrefId is initialized properly
nsAutoCString uri(aURI);
// Find the first ? (of the search params) if there is one.
// We know we can start at the end of the moz-abldapdirectory:// because
// that's the URI we should have been passed.
int32_t searchCharLocation = uri.FindChar('?', kLDAPDirectoryRootLen);
if (searchCharLocation == -1)
m_DirPrefId = Substring(uri, kLDAPDirectoryRootLen);
else
m_DirPrefId = Substring(uri, kLDAPDirectoryRootLen, searchCharLocation - kLDAPDirectoryRootLen);
return nsAbDirProperty::Init(aURI);
}
nsresult nsAbLDAPDirectory::Initiate()
{
return NS_OK;
}
/*
*
* nsIAbDirectory methods
*
*/
NS_IMETHODIMP nsAbLDAPDirectory::GetURI(nsACString &aURI)
{
if (mURI.IsEmpty())
return NS_ERROR_NOT_INITIALIZED;
aURI = mURI;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetChildNodes(nsISimpleEnumerator* *aResult)
{
return NS_NewEmptyEnumerator(aResult);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetChildCards(nsISimpleEnumerator** result)
{
nsresult rv;
// when offline, we need to get the child cards for the local, replicated mdb directory
bool offline;
nsCOMPtr <nsIIOService> ioService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
rv = ioService->GetOffline(&offline);
NS_ENSURE_SUCCESS(rv,rv);
if (offline) {
nsCString fileName;
rv = GetReplicationFileName(fileName);
NS_ENSURE_SUCCESS(rv,rv);
// if there is no fileName, bail out now.
if (fileName.IsEmpty())
return NS_OK;
// perform the same query, but on the local directory
nsAutoCString localDirectoryURI(NS_LITERAL_CSTRING(kMDBDirectoryRoot));
localDirectoryURI.Append(fileName);
if (mIsQueryURI)
{
localDirectoryURI.AppendLiteral("?");
localDirectoryURI.Append(mQueryString);
}
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID,
&rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIAbDirectory> directory;
rv = abManager->GetDirectory(localDirectoryURI,
getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
rv = directory->GetChildCards(result);
}
else {
// Start the search
rv = StartSearch();
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_NewEmptyEnumerator(result);
}
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetIsQuery(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = mIsQueryURI;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::HasCard(nsIAbCard* card, bool* hasCard)
{
nsresult rv = Initiate ();
NS_ENSURE_SUCCESS(rv, rv);
// Enter lock
MutexAutoLock lock (mLock);
*hasCard = mCache.Get(card, nullptr);
if (!*hasCard && mPerformingQuery)
return NS_ERROR_NOT_AVAILABLE;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetLDAPURL(nsILDAPURL** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// Rather than using GetURI here we call GetStringValue directly so
// we can handle the case where the URI isn't specified (see comments
// below)
nsAutoCString URI;
nsresult rv = GetStringValue("uri", EmptyCString(), URI);
if (NS_FAILED(rv) || URI.IsEmpty())
{
/*
* A recent change in Mozilla now means that the LDAP Address Book
* URI is based on the unique preference name value i.e.
* [moz-abldapdirectory://prefName]
* Prior to this valid change it was based on the actual uri i.e.
* [moz-abldapdirectory://host:port/basedn]
* Basing the resource on the prefName allows these attributes to
* change.
*
* But the uri value was also the means by which third-party
* products could integrate with Mozilla's LDAP Address Books
* without necessarily having an entry in the preferences file
* or more importantly needing to be able to change the
* preferences entries. Thus to set the URI Spec now, it is
* only necessary to read the uri pref entry, while in the
* case where it is not a preference, we need to replace the
* "moz-abldapdirectory".
*/
URI = mURINoQuery;
if (StringBeginsWith(URI, NS_LITERAL_CSTRING(kLDAPDirectoryRoot)))
URI.Replace(0, kLDAPDirectoryRootLen, NS_LITERAL_CSTRING("ldap://"));
}
nsCOMPtr<nsIIOService> ioService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIURI> result;
rv = ioService->NewURI(URI, nullptr, nullptr, getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(result, aResult);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetLDAPURL(nsILDAPURL *aUrl)
{
NS_ENSURE_ARG_POINTER(aUrl);
nsAutoCString oldUrl;
// Note, it doesn't matter if GetStringValue fails - we'll just send an
// update if its blank (i.e. old value not set).
GetStringValue("uri", EmptyCString(), oldUrl);
// Actually set the new value.
nsCString tempLDAPURL;
nsresult rv = aUrl->GetSpec(tempLDAPURL);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetStringValue("uri", tempLDAPURL);
NS_ENSURE_SUCCESS(rv, rv);
// Now we need to send an update which will ensure our indicators and
// listeners get updated correctly.
// See if they both start with ldaps: or ldap:
bool newIsNotSecure = StringHead(tempLDAPURL, 5).Equals("ldap:");
if (oldUrl.IsEmpty() ||
StringHead(oldUrl, 5).Equals("ldap:") != newIsNotSecure)
{
// They don't so its time to send round an update.
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// We inherit from nsIAbDirectory, so this static cast should be safe.
abManager->NotifyItemPropertyChanged(static_cast<nsIAbDirectory*>(this),
"IsSecure",
(newIsNotSecure ? u"true" : u"false"),
(newIsNotSecure ? u"false" : u"true"));
}
return NS_OK;
}
/*
*
* nsIAbDirectorySearch methods
*
*/
NS_IMETHODIMP nsAbLDAPDirectory::StartSearch ()
{
if (!mIsQueryURI || mQueryString.IsEmpty())
return NS_OK;
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
rv = StopSearch();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectoryQueryArguments> arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanExpression> expression;
rv = nsAbQueryStringToExpression::Convert(mQueryString,
getter_AddRefs(expression));
NS_ENSURE_SUCCESS(rv, rv);
rv = arguments->SetExpression(expression);
NS_ENSURE_SUCCESS(rv, rv);
rv = arguments->SetQuerySubDirectories(true);
NS_ENSURE_SUCCESS(rv, rv);
// Get the max hits to return
int32_t maxHits;
rv = GetMaxHits(&maxHits);
if (NS_FAILED(rv))
maxHits = kDefaultMaxHits;
// get the appropriate ldap attribute map, and pass it in via the
// TypeSpecificArgument
nsCOMPtr<nsIAbLDAPAttributeMap> attrMap;
rv = GetAttributeMap(getter_AddRefs(attrMap));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> typeSpecificArg = do_QueryInterface(attrMap, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = arguments->SetTypeSpecificArg(attrMap);
NS_ENSURE_SUCCESS(rv, rv);
if (!mDirectoryQuery)
{
mDirectoryQuery = do_CreateInstance(NS_ABLDAPDIRECTORYQUERY_CONTRACTID,
&rv);
NS_ENSURE_SUCCESS(rv, rv);
}
// Perform the query
rv = mDirectoryQuery->DoQuery(this, arguments, this, maxHits, 0, &mContext);
NS_ENSURE_SUCCESS(rv, rv);
// Enter lock
MutexAutoLock lock(mLock);
mPerformingQuery = true;
mCache.Clear();
return rv;
}
NS_IMETHODIMP nsAbLDAPDirectory::StopSearch ()
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
// Enter lock
{
MutexAutoLock lockGuard(mLock);
if (!mPerformingQuery)
return NS_OK;
mPerformingQuery = false;
}
// Exit lock
if (!mDirectoryQuery)
return NS_ERROR_NULL_POINTER;
return mDirectoryQuery->StopQuery(mContext);
}
/*
*
* nsAbDirSearchListenerContext methods
*
*/
NS_IMETHODIMP nsAbLDAPDirectory::OnSearchFinished(int32_t aResult, const nsAString &aErrorMessage)
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
MutexAutoLock lock(mLock);
mPerformingQuery = false;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::OnSearchFoundCard(nsIAbCard* card)
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
// Enter lock
{
MutexAutoLock lock(mLock);
mCache.Put(card, card);
}
// Exit lock
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
if(NS_SUCCEEDED(rv))
abManager->NotifyDirectoryItemAdded(this, card);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetSupportsMailingLists(bool *aSupportsMailingsLists)
{
NS_ENSURE_ARG_POINTER(aSupportsMailingsLists);
*aSupportsMailingsLists = false;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetReadOnly(bool *aReadOnly)
{
NS_ENSURE_ARG_POINTER(aReadOnly);
*aReadOnly = true;
#ifdef MOZ_EXPERIMENTAL_WRITEABLE_LDAP
bool readOnly;
nsresult rv = GetBoolValue("readonly", false, &readOnly);
NS_ENSURE_SUCCESS(rv, rv);
if (readOnly)
return NS_OK;
// when online, we'll allow writing as well
bool offline;
nsCOMPtr <nsIIOService> ioService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
rv = ioService->GetOffline(&offline);
NS_ENSURE_SUCCESS(rv,rv);
if (!offline)
*aReadOnly = false;
#endif
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetIsRemote(bool *aIsRemote)
{
NS_ENSURE_ARG_POINTER(aIsRemote);
*aIsRemote = true;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetIsSecure(bool *aIsSecure)
{
NS_ENSURE_ARG_POINTER(aIsSecure);
nsAutoCString URI;
nsresult rv = GetStringValue("uri", EmptyCString(), URI);
NS_ENSURE_SUCCESS(rv, rv);
// to determine if this is a secure directory, check if the uri is ldaps:// or not
*aIsSecure = (strncmp(URI.get(), "ldaps:", 6) == 0);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::UseForAutocomplete(const nsACString &aIdentityKey,
bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// Set this to false by default to make the code easier below.
*aResult = false;
nsresult rv;
bool offline = false;
nsCOMPtr <nsIIOService> ioService =
mozilla::services::GetIOService();
NS_ENSURE_TRUE(ioService, NS_ERROR_UNEXPECTED);
rv = ioService->GetOffline(&offline);
NS_ENSURE_SUCCESS(rv, rv);
// If we're online, then don't allow search during local autocomplete - must
// use the separate LDAP autocomplete session due to the current interfaces
if (!offline)
return NS_OK;
// Is the use directory pref set for autocompletion?
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID,
&rv));
NS_ENSURE_SUCCESS(rv, rv);
bool useDirectory = false;
rv = prefs->GetBoolPref("ldap_2.autoComplete.useDirectory", &useDirectory);
NS_ENSURE_SUCCESS(rv, rv);
// No need to search if not set up globally for LDAP autocompletion and we've
// not been given an identity.
if (!useDirectory && aIdentityKey.IsEmpty())
return NS_OK;
nsCString prefName;
if (!aIdentityKey.IsEmpty())
{
// If we have an identity string, try and find out the required directory
// server.
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
// If we failed, just return, we can't do much about this.
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMsgIdentity> identity;
rv = accountManager->GetIdentity(aIdentityKey, getter_AddRefs(identity));
if (NS_SUCCEEDED(rv))
{
bool overrideGlobalPref = false;
identity->GetOverrideGlobalPref(&overrideGlobalPref);
if (overrideGlobalPref)
identity->GetDirectoryServer(prefName);
}
}
// If the preference name is still empty but useDirectory is false, then
// the global one is not available, nor is the overriden one.
if (prefName.IsEmpty() && !useDirectory)
return NS_OK;
}
// If we failed to get the identity preference, or the pref name is empty
// try the global preference.
if (prefName.IsEmpty())
{
nsresult rv = prefs->GetCharPref("ldap_2.autoComplete.directoryServer",
getter_Copies(prefName));
NS_ENSURE_SUCCESS(rv,rv);
}
// Now see if the pref name matches our pref id.
if (prefName.Equals(m_DirPrefId))
{
// Yes it does, one last check - does the replication file exist?
nsresult rv;
nsCOMPtr<nsIFile> databaseFile;
// If we can't get the file, then there is no database to use
if (NS_FAILED(GetReplicationFile(getter_AddRefs(databaseFile))))
return NS_OK;
bool exists;
rv = databaseFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = exists;
}
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetSearchClientControls(nsIMutableArray **aControls)
{
NS_IF_ADDREF(*aControls = mSearchClientControls);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::SetSearchClientControls(nsIMutableArray *aControls)
{
mSearchClientControls = aControls;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetSearchServerControls(nsIMutableArray **aControls)
{
NS_IF_ADDREF(*aControls = mSearchServerControls);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::SetSearchServerControls(nsIMutableArray *aControls)
{
mSearchServerControls = aControls;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetProtocolVersion(uint32_t *aProtocolVersion)
{
nsAutoCString versionString;
nsresult rv = GetStringValue("protocolVersion", NS_LITERAL_CSTRING("3"), versionString);
NS_ENSURE_SUCCESS(rv, rv);
*aProtocolVersion = versionString.EqualsLiteral("3") ?
(uint32_t)nsILDAPConnection::VERSION3 :
(uint32_t)nsILDAPConnection::VERSION2;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::SetProtocolVersion(uint32_t aProtocolVersion)
{
// XXX We should cancel any existing LDAP connections here and
// be ready to re-initialise them with the new auth details.
return SetStringValue("protocolVersion",
aProtocolVersion == nsILDAPConnection::VERSION3 ?
NS_LITERAL_CSTRING("3") : NS_LITERAL_CSTRING("2"));
}
NS_IMETHODIMP nsAbLDAPDirectory::GetMaxHits(int32_t *aMaxHits)
{
return GetIntValue("maxHits", kDefaultMaxHits, aMaxHits);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetMaxHits(int32_t aMaxHits)
{
return SetIntValue("maxHits", aMaxHits);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetReplicationFileName(nsACString &aReplicationFileName)
{
return GetStringValue("filename", EmptyCString(), aReplicationFileName);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetReplicationFileName(const nsACString &aReplicationFileName)
{
return SetStringValue("filename", aReplicationFileName);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetAuthDn(nsACString &aAuthDn)
{
return GetStringValue("auth.dn", EmptyCString(), aAuthDn);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetAuthDn(const nsACString &aAuthDn)
{
// XXX We should cancel any existing LDAP connections here and
// be ready to re-initialise them with the new auth details.
return SetStringValue("auth.dn", aAuthDn);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetSaslMechanism(nsACString &aSaslMechanism)
{
return GetStringValue("auth.saslmech", EmptyCString(), aSaslMechanism);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetSaslMechanism(const nsACString &aSaslMechanism)
{
return SetStringValue("auth.saslmech", aSaslMechanism);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetLastChangeNumber(int32_t *aLastChangeNumber)
{
return GetIntValue("lastChangeNumber", -1, aLastChangeNumber);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetLastChangeNumber(int32_t aLastChangeNumber)
{
return SetIntValue("lastChangeNumber", aLastChangeNumber);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetDataVersion(nsACString &aDataVersion)
{
return GetStringValue("dataVersion", EmptyCString(), aDataVersion);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetDataVersion(const nsACString &aDataVersion)
{
return SetStringValue("dataVersion", aDataVersion);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetAttributeMap(nsIAbLDAPAttributeMap **aAttributeMap)
{
NS_ENSURE_ARG_POINTER(aAttributeMap);
nsresult rv;
nsCOMPtr<nsIAbLDAPAttributeMapService> mapSvc =
do_GetService("@mozilla.org/addressbook/ldap-attribute-map-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
return mapSvc->GetMapForPrefBranch(m_DirPrefId, aAttributeMap);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetReplicationFile(nsIFile **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsCString fileName;
nsresult rv = GetStringValue("filename", EmptyCString(), fileName);
NS_ENSURE_SUCCESS(rv, rv);
if (fileName.IsEmpty())
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIFile> profileDir;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = profileDir->AppendNative(fileName);
NS_ENSURE_SUCCESS(rv, rv);
NS_ADDREF(*aResult = profileDir);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetReplicationDatabase(nsIAddrDatabase **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsresult rv;
nsCOMPtr<nsIFile> databaseFile;
rv = GetReplicationFile(getter_AddRefs(databaseFile));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAddrDatabase> addrDBFactory =
do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return addrDBFactory->Open(databaseFile, false /* no create */, true,
aResult);
}
NS_IMETHODIMP nsAbLDAPDirectory::AddCard(nsIAbCard *aUpdatedCard,
nsIAbCard **aAddedCard)
{
NS_ENSURE_ARG_POINTER(aUpdatedCard);
NS_ENSURE_ARG_POINTER(aAddedCard);
nsCOMPtr<nsIAbLDAPAttributeMap> attrMap;
nsresult rv = GetAttributeMap(getter_AddRefs(attrMap));
NS_ENSURE_SUCCESS(rv, rv);
// Create a new LDAP card
nsCOMPtr<nsIAbLDAPCard> card =
do_CreateInstance(NS_ABLDAPCARD_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
// Copy over the card data
nsCOMPtr<nsIAbCard> copyToCard = do_QueryInterface(card, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = copyToCard->Copy(aUpdatedCard);
NS_ENSURE_SUCCESS(rv, rv);
// Retrieve preferences
nsAutoCString prefString;
rv = GetRdnAttributes(prefString);
NS_ENSURE_SUCCESS(rv, rv);
CharPtrArrayGuard rdnAttrs;
rv = SplitStringList(prefString, rdnAttrs.GetSizeAddr(),
rdnAttrs.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
rv = GetObjectClasses(prefString);
NS_ENSURE_SUCCESS(rv, rv);
CharPtrArrayGuard objClass;
rv = SplitStringList(prefString, objClass.GetSizeAddr(),
objClass.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
// Process updates
nsCOMPtr<nsIArray> modArray;
rv = card->GetLDAPMessageInfo(attrMap, objClass.GetSize(), objClass.GetArray(),
nsILDAPModification::MOD_ADD, getter_AddRefs(modArray));
NS_ENSURE_SUCCESS(rv, rv);
// For new cards, the base DN is the search base DN
nsCOMPtr<nsILDAPURL> currentUrl;
rv = GetLDAPURL(getter_AddRefs(currentUrl));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString baseDN;
rv = currentUrl->GetDn(baseDN);
NS_ENSURE_SUCCESS(rv, rv);
// Calculate DN
nsAutoCString cardDN;
rv = card->BuildRdn(attrMap, rdnAttrs.GetSize(), rdnAttrs.GetArray(),
cardDN);
NS_ENSURE_SUCCESS(rv, rv);
cardDN.AppendLiteral(",");
cardDN.Append(baseDN);
rv = card->SetDn(cardDN);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString ourUuid;
GetUuid(ourUuid);
copyToCard->SetDirectoryId(ourUuid);
// Launch query
rv = DoModify(this, nsILDAPModification::MOD_ADD, cardDN, modArray,
EmptyCString(), EmptyCString());
NS_ENSURE_SUCCESS(rv, rv);
NS_ADDREF(*aAddedCard = copyToCard);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::DeleteCards(nsIArray *aCards)
{
uint32_t cardCount;
uint32_t i;
nsAutoCString cardDN;
nsresult rv = aCards->GetLength(&cardCount);
NS_ENSURE_SUCCESS(rv, rv);
for (i = 0; i < cardCount; ++i)
{
nsCOMPtr<nsIAbLDAPCard> card(do_QueryElementAt(aCards, i, &rv));
if (NS_FAILED(rv))
{
NS_WARNING("Wrong type of card passed to nsAbLDAPDirectory::DeleteCards");
break;
}
// Set up the search ldap url - this is mURL
rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
rv = card->GetDn(cardDN);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbCard> realCard(do_QueryInterface(card));
realCard->SetDirectoryId(EmptyCString());
// Launch query
rv = DoModify(this, nsILDAPModification::MOD_DELETE, cardDN, nullptr,
EmptyCString(), EmptyCString());
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectory::ModifyCard(nsIAbCard *aUpdatedCard)
{
NS_ENSURE_ARG_POINTER(aUpdatedCard);
nsCOMPtr<nsIAbLDAPAttributeMap> attrMap;
nsresult rv = GetAttributeMap(getter_AddRefs(attrMap));
NS_ENSURE_SUCCESS(rv, rv);
// Get the LDAP card
nsCOMPtr<nsIAbLDAPCard> card = do_QueryInterface(aUpdatedCard, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
// Retrieve preferences
nsAutoCString prefString;
rv = GetObjectClasses(prefString);
NS_ENSURE_SUCCESS(rv, rv);
CharPtrArrayGuard objClass;
rv = SplitStringList(prefString, objClass.GetSizeAddr(),
objClass.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
// Process updates
nsCOMPtr<nsIArray> modArray;
rv = card->GetLDAPMessageInfo(attrMap, objClass.GetSize(), objClass.GetArray(),
nsILDAPModification::MOD_REPLACE, getter_AddRefs(modArray));
NS_ENSURE_SUCCESS(rv, rv);
// Get current DN
nsAutoCString oldDN;
rv = card->GetDn(oldDN);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILDAPService> ldapSvc = do_GetService(
"@mozilla.org/network/ldap-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Retrieve base DN and RDN attributes
nsAutoCString baseDN;
nsAutoCString oldRDN;
CharPtrArrayGuard rdnAttrs;
rv = ldapSvc->ParseDn(oldDN.get(), oldRDN, baseDN,
rdnAttrs.GetSizeAddr(), rdnAttrs.GetArrayAddr());
NS_ENSURE_SUCCESS(rv, rv);
// Calculate new RDN and check whether it has changed
nsAutoCString newRDN;
rv = card->BuildRdn(attrMap, rdnAttrs.GetSize(), rdnAttrs.GetArray(),
newRDN);
NS_ENSURE_SUCCESS(rv, rv);
if (newRDN.Equals(oldRDN))
{
// Launch query
rv = DoModify(this, nsILDAPModification::MOD_REPLACE, oldDN, modArray,
EmptyCString(), EmptyCString());
}
else
{
// Build and store the new DN
nsAutoCString newDN(newRDN);
newDN.AppendLiteral(",");
newDN.Append(baseDN);
rv = card->SetDn(newDN);
NS_ENSURE_SUCCESS(rv, rv);
// Launch query
rv = DoModify(this, nsILDAPModification::MOD_REPLACE, oldDN, modArray,
newRDN, baseDN);
}
return rv;
}
NS_IMETHODIMP nsAbLDAPDirectory::GetRdnAttributes(nsACString &aRdnAttributes)
{
return GetStringValue("rdnAttributes", NS_LITERAL_CSTRING("cn"),
aRdnAttributes);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetRdnAttributes(const nsACString &aRdnAttributes)
{
return SetStringValue("rdnAttributes", aRdnAttributes);
}
NS_IMETHODIMP nsAbLDAPDirectory::GetObjectClasses(nsACString &aObjectClasses)
{
return GetStringValue("objectClasses", NS_LITERAL_CSTRING(
"top,person,organizationalPerson,inetOrgPerson,mozillaAbPersonAlpha"),
aObjectClasses);
}
NS_IMETHODIMP nsAbLDAPDirectory::SetObjectClasses(const nsACString &aObjectClasses)
{
return SetStringValue("objectClasses", aObjectClasses);
}
nsresult nsAbLDAPDirectory::SplitStringList(
const nsACString& aString,
uint32_t *aCount,
char ***aValues)
{
NS_ENSURE_ARG_POINTER(aCount);
NS_ENSURE_ARG_POINTER(aValues);
nsTArray<nsCString> strarr;
ParseString(aString, ',', strarr);
char **cArray = nullptr;
if (!(cArray = static_cast<char **>(moz_xmalloc(
strarr.Length() * sizeof(char *)))))
return NS_ERROR_OUT_OF_MEMORY;
for (uint32_t i = 0; i < strarr.Length(); ++i)
{
if (!(cArray[i] = ToNewCString(strarr[i])))
{
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(strarr.Length(), cArray);
return NS_ERROR_OUT_OF_MEMORY;
}
}
*aCount = strarr.Length();
*aValues = cArray;
return NS_OK;
}

View file

@ -0,0 +1,75 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPDirectory_h__
#define nsAbLDAPDirectory_h__
#include "mozilla/Attributes.h"
#include "nsAbDirProperty.h"
#include "nsAbLDAPDirectoryModify.h"
#include "nsIAbDirectoryQuery.h"
#include "nsIAbDirectorySearch.h"
#include "nsIAbDirSearchListener.h"
#include "nsIAbLDAPDirectory.h"
#include "nsIMutableArray.h"
#include "nsInterfaceHashtable.h"
#include "mozilla/Mutex.h"
class nsAbLDAPDirectory :
public nsAbDirProperty, // nsIAbDirectory
public nsAbLDAPDirectoryModify,
public nsIAbDirectorySearch,
public nsIAbLDAPDirectory,
public nsIAbDirSearchListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsAbLDAPDirectory();
NS_IMETHOD Init(const char *aUri) override;
// nsIAbDirectory methods
NS_IMETHOD GetPropertiesChromeURI(nsACString &aResult) override;
NS_IMETHOD GetURI(nsACString &aURI) override;
NS_IMETHOD GetChildNodes(nsISimpleEnumerator* *result) override;
NS_IMETHOD GetChildCards(nsISimpleEnumerator* *result) override;
NS_IMETHOD GetIsQuery(bool *aResult) override;
NS_IMETHOD HasCard(nsIAbCard *cards, bool *hasCard) override;
NS_IMETHOD GetSupportsMailingLists(bool *aSupportsMailingsLists) override;
NS_IMETHOD GetReadOnly(bool *aReadOnly) override;
NS_IMETHOD GetIsRemote(bool *aIsRemote) override;
NS_IMETHOD GetIsSecure(bool *aIsRemote) override;
NS_IMETHOD UseForAutocomplete(const nsACString &aIdentityKey, bool *aResult) override;
NS_IMETHOD AddCard(nsIAbCard *aChildCard, nsIAbCard **aAddedCard) override;
NS_IMETHOD ModifyCard(nsIAbCard *aModifiedCard) override;
NS_IMETHOD DeleteCards(nsIArray *aCards) override;
// nsIAbDirectorySearch methods
NS_DECL_NSIABDIRECTORYSEARCH
NS_DECL_NSIABLDAPDIRECTORY
NS_DECL_NSIABDIRSEARCHLISTENER
protected:
virtual ~nsAbLDAPDirectory();
nsresult Initiate();
nsresult SplitStringList(const nsACString& aString,
uint32_t *aCount,
char ***aValues);
bool mPerformingQuery;
int32_t mContext;
int32_t mMaxHits;
nsInterfaceHashtable<nsISupportsHashKey, nsIAbCard> mCache;
mozilla::Mutex mLock;
nsCOMPtr<nsIAbDirectoryQuery> mDirectoryQuery;
nsCOMPtr<nsIMutableArray> mSearchServerControls;
nsCOMPtr<nsIMutableArray> mSearchClientControls;
};
#endif

View file

@ -0,0 +1,372 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPDirectoryModify.h"
#include "nsILDAPMessage.h"
#include "nsILDAPConnection.h"
#include "nsILDAPErrors.h"
#include "nsILDAPModification.h"
#include "nsIServiceManager.h"
#include "nsIAbLDAPDirectory.h"
#include "nsIMutableArray.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include <stdio.h>
using namespace mozilla;
class nsAbModifyLDAPMessageListener : public nsAbLDAPListenerBase
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
nsAbModifyLDAPMessageListener(const int32_t type,
const nsACString &cardDN,
nsIArray* modArray,
const nsACString &newRDN,
const nsACString &newBaseDN,
nsILDAPURL* directoryUrl,
nsILDAPConnection* connection,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
const int32_t timeOut = 0);
// nsILDAPMessageListener
NS_IMETHOD OnLDAPMessage(nsILDAPMessage *aMessage) override;
protected:
virtual ~nsAbModifyLDAPMessageListener();
nsresult Cancel();
virtual void InitFailed(bool aCancelled = false) override;
virtual nsresult DoTask() override;
nsresult DoMainTask();
nsresult OnLDAPMessageModifyResult(nsILDAPMessage *aMessage);
nsresult OnLDAPMessageRenameResult(nsILDAPMessage *aMessage);
int32_t mType;
nsCString mCardDN;
nsCOMPtr<nsIArray> mModification;
nsCString mNewRDN;
nsCString mNewBaseDN;
bool mFinished;
bool mCanceled;
bool mFlagRename;
nsCOMPtr<nsILDAPOperation> mModifyOperation;
nsCOMPtr<nsIMutableArray> mServerSearchControls;
nsCOMPtr<nsIMutableArray> mClientSearchControls;
};
NS_IMPL_ISUPPORTS(nsAbModifyLDAPMessageListener, nsILDAPMessageListener)
nsAbModifyLDAPMessageListener::nsAbModifyLDAPMessageListener(
const int32_t type,
const nsACString &cardDN,
nsIArray* modArray,
const nsACString &newRDN,
const nsACString &newBaseDN,
nsILDAPURL* directoryUrl,
nsILDAPConnection* connection,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
const int32_t timeOut) :
nsAbLDAPListenerBase(directoryUrl, connection, login, timeOut),
mType(type),
mCardDN(cardDN),
mModification(modArray),
mNewRDN(newRDN),
mNewBaseDN(newBaseDN),
mFinished(false),
mCanceled(false),
mFlagRename(false),
mServerSearchControls(serverSearchControls),
mClientSearchControls(clientSearchControls)
{
if (mType == nsILDAPModification::MOD_REPLACE &&
!mNewRDN.IsEmpty() && !mNewBaseDN.IsEmpty())
mFlagRename = true;
}
nsAbModifyLDAPMessageListener::~nsAbModifyLDAPMessageListener ()
{
}
nsresult nsAbModifyLDAPMessageListener::Cancel ()
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
MutexAutoLock lock(mLock);
if (mFinished || mCanceled)
return NS_OK;
mCanceled = true;
return NS_OK;
}
NS_IMETHODIMP nsAbModifyLDAPMessageListener::OnLDAPMessage(nsILDAPMessage *aMessage)
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
int32_t messageType;
rv = aMessage->GetType(&messageType);
NS_ENSURE_SUCCESS(rv, rv);
bool cancelOperation = false;
// Enter lock
{
MutexAutoLock lock (mLock);
if (mFinished)
return NS_OK;
// for these messages, no matter the outcome, we're done
if ((messageType == nsILDAPMessage::RES_ADD) ||
(messageType == nsILDAPMessage::RES_DELETE) ||
(messageType == nsILDAPMessage::RES_MODIFY))
mFinished = true;
else if (mCanceled)
{
mFinished = true;
cancelOperation = true;
}
}
// Leave lock
// nsCOMPtr<nsIAbDirectoryQueryResult> queryResult;
if (!cancelOperation)
{
switch (messageType)
{
case nsILDAPMessage::RES_BIND:
rv = OnLDAPMessageBind(aMessage);
if (NS_FAILED(rv))
// We know the bind failed and hence the message has an error, so we
// can just call ModifyResult with the message and that'll sort it out
// for us.
rv = OnLDAPMessageModifyResult(aMessage);
break;
case nsILDAPMessage::RES_ADD:
case nsILDAPMessage::RES_MODIFY:
case nsILDAPMessage::RES_DELETE:
rv = OnLDAPMessageModifyResult(aMessage);
break;
case nsILDAPMessage::RES_MODDN:
mFlagRename = false;
rv = OnLDAPMessageRenameResult(aMessage);
if (NS_FAILED(rv))
// Rename failed, so we stop here
mFinished = true;
break;
default:
break;
}
}
else
{
if (mModifyOperation)
rv = mModifyOperation->AbandonExt();
// reset because we might re-use this listener...except don't do this
// until the search is done, so we'll ignore results from a previous
// search.
mCanceled = mFinished = false;
}
return rv;
}
void nsAbModifyLDAPMessageListener::InitFailed(bool aCancelled)
{
// XXX Just cancel the operation for now
// we'll need to review this when we've got the proper listeners in place.
Cancel();
}
nsresult nsAbModifyLDAPMessageListener::DoTask()
{
nsresult rv;
mCanceled = mFinished = false;
mModifyOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mModifyOperation->Init (mConnection, this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
// XXX do we need the search controls?
rv = mModifyOperation->SetServerControls(mServerSearchControls);
NS_ENSURE_SUCCESS(rv, rv);
rv = mModifyOperation->SetClientControls(mClientSearchControls);
NS_ENSURE_SUCCESS(rv, rv);
if (mFlagRename)
return mModifyOperation->Rename(mCardDN, mNewRDN, mNewBaseDN, true);
switch (mType)
{
case nsILDAPModification::MOD_ADD:
return mModifyOperation->AddExt(mCardDN, mModification);
case nsILDAPModification::MOD_DELETE:
return mModifyOperation->DeleteExt(mCardDN);
case nsILDAPModification::MOD_REPLACE:
return mModifyOperation->ModifyExt(mCardDN, mModification);
default:
NS_ERROR("Bad LDAP modification requested");
return NS_ERROR_UNEXPECTED;
}
}
nsresult nsAbModifyLDAPMessageListener::OnLDAPMessageModifyResult(nsILDAPMessage *aMessage)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aMessage);
int32_t errCode;
rv = aMessage->GetErrorCode(&errCode);
NS_ENSURE_SUCCESS(rv, rv);
if (errCode != nsILDAPErrors::SUCCESS)
{
nsAutoCString errMessage;
rv = aMessage->GetErrorMessage(errMessage);
NS_ENSURE_SUCCESS(rv, rv);
printf("LDAP modification failed (code: %i, message: %s)\n",
errCode, errMessage.get());
return NS_ERROR_FAILURE;
}
printf("LDAP modification succeeded\n");
return NS_OK;
}
nsresult nsAbModifyLDAPMessageListener::OnLDAPMessageRenameResult(nsILDAPMessage *aMessage)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aMessage);
int32_t errCode;
rv = aMessage->GetErrorCode(&errCode);
NS_ENSURE_SUCCESS(rv, rv);
if (errCode != nsILDAPErrors::SUCCESS)
{
nsAutoCString errMessage;
rv = aMessage->GetErrorMessage(errMessage);
NS_ENSURE_SUCCESS(rv, rv);
printf("LDAP rename failed (code: %i, message: %s)\n",
errCode, errMessage.get());
return NS_ERROR_FAILURE;
}
// Rename succeeded, now update the card DN and
// process the main task
mCardDN.Assign(mNewRDN);
mCardDN.AppendLiteral(",");
mCardDN.Append(mNewBaseDN);
printf("LDAP rename succeeded\n");
return DoTask();
}
nsAbLDAPDirectoryModify::nsAbLDAPDirectoryModify()
{
}
nsAbLDAPDirectoryModify::~nsAbLDAPDirectoryModify()
{
}
nsresult nsAbLDAPDirectoryModify::DoModify(nsIAbLDAPDirectory *directory,
const int32_t &updateType,
const nsACString &cardDN,
nsIArray* modArray,
const nsACString &newRDN,
const nsACString &newBaseDN)
{
NS_ENSURE_ARG_POINTER(directory);
// modArray may be null in the delete operation case.
if (!modArray &&
(updateType == nsILDAPModification::MOD_ADD ||
updateType == nsILDAPModification::MOD_REPLACE))
return NS_ERROR_NULL_POINTER;
nsresult rv;
// it's an error if we don't have a dn
if (cardDN.IsEmpty())
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsILDAPURL> currentUrl;
rv = directory->GetLDAPURL(getter_AddRefs(currentUrl));
NS_ENSURE_SUCCESS(rv, rv);
// Get the ldap connection
nsCOMPtr<nsILDAPConnection> ldapConnection =
do_CreateInstance(NS_LDAPCONNECTION_CONTRACTID, &rv);
nsCOMPtr<nsIMutableArray> serverSearchControls;
rv = directory->GetSearchServerControls(getter_AddRefs(serverSearchControls));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMutableArray> clientSearchControls;
rv = directory->GetSearchClientControls(getter_AddRefs(clientSearchControls));
NS_ENSURE_SUCCESS(rv, rv);
/*
// XXX we need to fix how this all works - specifically, see the first patch
// on bug 124553 for how the query equivalent did this
// too soon? Do we need a new listener?
if (alreadyInitialized)
{
nsAbQueryLDAPMessageListener *msgListener =
NS_STATIC_CAST(nsAbQueryLDAPMessageListener *,
NS_STATIC_CAST(nsILDAPMessageListener *, mListener.get()));
if (msgListener)
{
msgListener->mUrl = url;
return msgListener->DoSearch();
}
}*/
nsCString login;
rv = directory->GetAuthDn(login);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t protocolVersion;
rv = directory->GetProtocolVersion(&protocolVersion);
NS_ENSURE_SUCCESS(rv, rv);
// Initiate LDAP message listener
nsAbModifyLDAPMessageListener* _messageListener =
new nsAbModifyLDAPMessageListener(updateType, cardDN, modArray,
newRDN, newBaseDN,
currentUrl,
ldapConnection,
serverSearchControls,
clientSearchControls,
login,
0);
if (_messageListener == NULL)
return NS_ERROR_OUT_OF_MEMORY;
// Now lets initialize the LDAP connection properly. We'll kick
// off the bind operation in the callback function, |OnLDAPInit()|.
return ldapConnection->Init(currentUrl, login,
_messageListener, nullptr, protocolVersion);
}

View file

@ -0,0 +1,31 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPDirectoryModify_h__
#define nsAbLDAPDirectoryModify_h__
#include "nsAbLDAPListenerBase.h"
#include "nsIAbLDAPDirectory.h"
#include "nsILDAPOperation.h"
#include "nsIArray.h"
class nsILDAPURL;
class nsAbLDAPDirectoryModify
{
public:
nsAbLDAPDirectoryModify();
virtual ~nsAbLDAPDirectoryModify();
protected:
nsresult DoModify(nsIAbLDAPDirectory *directory,
const int32_t &aUpdateType,
const nsACString &aCardDN,
nsIArray* modArray,
const nsACString &aNewRDN,
const nsACString &aNewBaseDN);
};
#endif // nsAbLDAPDirectoryModify_h__

View file

@ -0,0 +1,610 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPDirectoryQuery.h"
#include "nsAbBoolExprToLDAPFilter.h"
#include "nsILDAPMessage.h"
#include "nsILDAPErrors.h"
#include "nsILDAPOperation.h"
#include "nsIAbLDAPAttributeMap.h"
#include "nsIAbLDAPCard.h"
#include "nsAbUtils.h"
#include "nsAbBaseCID.h"
#include "nsStringGlue.h"
#include "prprf.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsCategoryManagerUtils.h"
#include "nsAbLDAPDirectory.h"
#include "nsAbLDAPListenerBase.h"
#include "nsXPCOMCIDInternal.h"
using namespace mozilla;
// nsAbLDAPListenerBase inherits nsILDAPMessageListener
class nsAbQueryLDAPMessageListener : public nsAbLDAPListenerBase
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
// Note that the directoryUrl is the details of the ldap directory
// without any search params or return attributes specified. The searchUrl
// therefore has the search params and return attributes specified.
// nsAbQueryLDAPMessageListener(nsIAbDirectoryQuery* directoryQuery,
nsAbQueryLDAPMessageListener(nsIAbDirectoryQueryResultListener* resultListener,
nsILDAPURL* directoryUrl,
nsILDAPURL* searchUrl,
nsILDAPConnection* connection,
nsIAbDirectoryQueryArguments* queryArguments,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
const nsACString &mechanism,
const int32_t resultLimit = -1,
const int32_t timeOut = 0);
// nsILDAPMessageListener
NS_IMETHOD OnLDAPMessage(nsILDAPMessage *aMessage) override;
protected:
virtual ~nsAbQueryLDAPMessageListener ();
nsresult OnLDAPMessageSearchEntry(nsILDAPMessage *aMessage);
nsresult OnLDAPMessageSearchResult(nsILDAPMessage *aMessage);
friend class nsAbLDAPDirectoryQuery;
nsresult Cancel();
virtual nsresult DoTask() override;
virtual void InitFailed(bool aCancelled = false) override;
nsCOMPtr<nsILDAPURL> mSearchUrl;
nsIAbDirectoryQueryResultListener *mResultListener;
int32_t mContextID;
nsCOMPtr<nsIAbDirectoryQueryArguments> mQueryArguments;
int32_t mResultLimit;
bool mFinished;
bool mCanceled;
bool mWaitingForPrevQueryToFinish;
nsCOMPtr<nsIMutableArray> mServerSearchControls;
nsCOMPtr<nsIMutableArray> mClientSearchControls;
};
NS_IMPL_ISUPPORTS(nsAbQueryLDAPMessageListener, nsILDAPMessageListener)
nsAbQueryLDAPMessageListener::nsAbQueryLDAPMessageListener(
nsIAbDirectoryQueryResultListener *resultListener,
nsILDAPURL* directoryUrl,
nsILDAPURL* searchUrl,
nsILDAPConnection* connection,
nsIAbDirectoryQueryArguments* queryArguments,
nsIMutableArray* serverSearchControls,
nsIMutableArray* clientSearchControls,
const nsACString &login,
const nsACString &mechanism,
const int32_t resultLimit,
const int32_t timeOut) :
nsAbLDAPListenerBase(directoryUrl, connection, login, timeOut),
mSearchUrl(searchUrl),
mResultListener(resultListener),
mQueryArguments(queryArguments),
mResultLimit(resultLimit),
mFinished(false),
mCanceled(false),
mWaitingForPrevQueryToFinish(false),
mServerSearchControls(serverSearchControls),
mClientSearchControls(clientSearchControls)
{
mSaslMechanism.Assign(mechanism);
}
nsAbQueryLDAPMessageListener::~nsAbQueryLDAPMessageListener ()
{
}
nsresult nsAbQueryLDAPMessageListener::Cancel ()
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
MutexAutoLock lock(mLock);
if (mFinished || mCanceled)
return NS_OK;
mCanceled = true;
if (!mFinished)
mWaitingForPrevQueryToFinish = true;
return NS_OK;
}
NS_IMETHODIMP nsAbQueryLDAPMessageListener::OnLDAPMessage(nsILDAPMessage *aMessage)
{
nsresult rv = Initiate();
NS_ENSURE_SUCCESS(rv, rv);
int32_t messageType;
rv = aMessage->GetType(&messageType);
NS_ENSURE_SUCCESS(rv, rv);
bool cancelOperation = false;
// Enter lock
{
MutexAutoLock lock (mLock);
if (mFinished)
return NS_OK;
if (messageType == nsILDAPMessage::RES_SEARCH_RESULT)
mFinished = true;
else if (mCanceled)
{
mFinished = true;
cancelOperation = true;
}
}
// Leave lock
if (!mResultListener)
return NS_ERROR_NULL_POINTER;
if (!cancelOperation)
{
switch (messageType)
{
case nsILDAPMessage::RES_BIND:
rv = OnLDAPMessageBind(aMessage);
if (NS_FAILED(rv))
// We know the bind failed and hence the message has an error, so we
// can just call SearchResult with the message and that'll sort it out
// for us.
rv = OnLDAPMessageSearchResult(aMessage);
break;
case nsILDAPMessage::RES_SEARCH_ENTRY:
if (!mFinished && !mWaitingForPrevQueryToFinish)
rv = OnLDAPMessageSearchEntry(aMessage);
break;
case nsILDAPMessage::RES_SEARCH_RESULT:
mWaitingForPrevQueryToFinish = false;
rv = OnLDAPMessageSearchResult(aMessage);
NS_ENSURE_SUCCESS(rv, rv);
break;
default:
break;
}
}
else
{
if (mOperation)
rv = mOperation->AbandonExt();
rv = mResultListener->OnQueryResult(
nsIAbDirectoryQueryResultListener::queryResultStopped, 0);
// reset because we might re-use this listener...except don't do this
// until the search is done, so we'll ignore results from a previous
// search.
if (messageType == nsILDAPMessage::RES_SEARCH_RESULT)
mCanceled = mFinished = false;
}
return rv;
}
nsresult nsAbQueryLDAPMessageListener::DoTask()
{
nsresult rv;
mCanceled = mFinished = false;
mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOperation->Init(mConnection, this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString dn;
rv = mSearchUrl->GetDn(dn);
NS_ENSURE_SUCCESS(rv, rv);
int32_t scope;
rv = mSearchUrl->GetScope(&scope);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString filter;
rv = mSearchUrl->GetFilter(filter);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString attributes;
rv = mSearchUrl->GetAttributes(attributes);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOperation->SetServerControls(mServerSearchControls);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOperation->SetClientControls(mClientSearchControls);
NS_ENSURE_SUCCESS(rv, rv);
return mOperation->SearchExt(dn, scope, filter, attributes, mTimeOut,
mResultLimit);
}
void nsAbQueryLDAPMessageListener::InitFailed(bool aCancelled)
{
if (!mResultListener)
return;
// In the !aCancelled case we know there was an error, but we won't be
// able to translate it, so just return an error code of zero.
mResultListener->OnQueryResult(
aCancelled ? nsIAbDirectoryQueryResultListener::queryResultStopped :
nsIAbDirectoryQueryResultListener::queryResultError, 0);
}
nsresult nsAbQueryLDAPMessageListener::OnLDAPMessageSearchEntry(nsILDAPMessage *aMessage)
{
nsresult rv;
if (!mResultListener)
return NS_ERROR_NULL_POINTER;
// the map for translating between LDAP attrs <-> addrbook fields
nsCOMPtr<nsISupports> iSupportsMap;
rv = mQueryArguments->GetTypeSpecificArg(getter_AddRefs(iSupportsMap));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbLDAPAttributeMap> map = do_QueryInterface(iSupportsMap, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbCard> card = do_CreateInstance(NS_ABLDAPCARD_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = map->SetCardPropertiesFromLDAPMessage(aMessage, card);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbLDAPCard> ldapCard = do_QueryInterface(card, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = ldapCard->SetMetaProperties(aMessage);
NS_ENSURE_SUCCESS(rv, rv);
return mResultListener->OnQueryFoundCard(card);
}
nsresult nsAbQueryLDAPMessageListener::OnLDAPMessageSearchResult(nsILDAPMessage *aMessage)
{
int32_t errorCode;
nsresult rv = aMessage->GetErrorCode(&errorCode);
NS_ENSURE_SUCCESS(rv, rv);
if (errorCode == nsILDAPErrors::SUCCESS || errorCode == nsILDAPErrors::SIZELIMIT_EXCEEDED)
return mResultListener->OnQueryResult(
nsIAbDirectoryQueryResultListener::queryResultComplete, 0);
return mResultListener->OnQueryResult(
nsIAbDirectoryQueryResultListener::queryResultError, errorCode);
}
// nsAbLDAPDirectoryQuery
NS_IMPL_ISUPPORTS(nsAbLDAPDirectoryQuery, nsIAbDirectoryQuery,
nsIAbDirectoryQueryResultListener)
nsAbLDAPDirectoryQuery::nsAbLDAPDirectoryQuery() :
mInitialized(false)
{
}
nsAbLDAPDirectoryQuery::~nsAbLDAPDirectoryQuery()
{
}
NS_IMETHODIMP nsAbLDAPDirectoryQuery::DoQuery(nsIAbDirectory *aDirectory,
nsIAbDirectoryQueryArguments* aArguments,
nsIAbDirSearchListener* aListener,
int32_t aResultLimit,
int32_t aTimeOut,
int32_t* _retval)
{
NS_ENSURE_ARG_POINTER(aListener);
NS_ENSURE_ARG_POINTER(aArguments);
mListeners.AppendObject(aListener);
// Ensure existing query is stopped. Context id doesn't matter here
nsresult rv = StopQuery(0);
NS_ENSURE_SUCCESS(rv, rv);
mInitialized = true;
// Get the current directory as LDAP specific
nsCOMPtr<nsIAbLDAPDirectory> directory(do_QueryInterface(aDirectory, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// We also need the current URL to check as well...
nsCOMPtr<nsILDAPURL> currentUrl;
rv = directory->GetLDAPURL(getter_AddRefs(currentUrl));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString login;
rv = directory->GetAuthDn(login);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString saslMechanism;
rv = directory->GetSaslMechanism(saslMechanism);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t protocolVersion;
rv = directory->GetProtocolVersion(&protocolVersion);
NS_ENSURE_SUCCESS(rv, rv);
// To do:
// Ensure query is stopped
// If connection params have changed re-create connection
// else reuse existing connection
bool redoConnection = false;
if (!mConnection || !mDirectoryUrl)
{
mDirectoryUrl = currentUrl;
aDirectory->GetUuid(mDirectoryId);
mCurrentLogin = login;
mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
redoConnection = true;
}
else
{
bool equal;
rv = mDirectoryUrl->Equals(currentUrl, &equal);
NS_ENSURE_SUCCESS(rv, rv);
if (!equal)
{
mDirectoryUrl = currentUrl;
aDirectory->GetUuid(mDirectoryId);
mCurrentLogin = login;
mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
redoConnection = true;
}
else
{
// Has login or version changed?
if (login != mCurrentLogin ||
saslMechanism != mCurrentMechanism ||
protocolVersion != mCurrentProtocolVersion)
{
redoConnection = true;
mCurrentLogin = login;
mCurrentMechanism = saslMechanism;
mCurrentProtocolVersion = protocolVersion;
}
}
}
nsCOMPtr<nsIURI> uri;
rv = mDirectoryUrl->Clone(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILDAPURL> url(do_QueryInterface(uri, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// Get/Set the return attributes
nsCOMPtr<nsISupports> iSupportsMap;
rv = aArguments->GetTypeSpecificArg(getter_AddRefs(iSupportsMap));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbLDAPAttributeMap> map = do_QueryInterface(iSupportsMap, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Require all attributes that are mapped to card properties
nsAutoCString returnAttributes;
rv = map->GetAllCardAttributes(returnAttributes);
NS_ENSURE_SUCCESS(rv, rv);
rv = url->SetAttributes(returnAttributes);
// Now do the error check
NS_ENSURE_SUCCESS(rv, rv);
// Also require the objectClass attribute, it is used by
// nsAbLDAPCard::SetMetaProperties
rv = url->AddAttribute(NS_LITERAL_CSTRING("objectClass"));
nsAutoCString filter;
// Get filter from arguments if set:
rv = aArguments->GetFilter(filter);
NS_ENSURE_SUCCESS(rv, rv);
if (filter.IsEmpty()) {
// Get the filter
nsCOMPtr<nsISupports> supportsExpression;
rv = aArguments->GetExpression(getter_AddRefs(supportsExpression));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanExpression> expression(do_QueryInterface(supportsExpression, &rv));
// figure out how we map attribute names to addressbook fields for this
// query
rv = nsAbBoolExprToLDAPFilter::Convert(map, expression, filter);
NS_ENSURE_SUCCESS(rv, rv);
}
/*
* Mozilla itself cannot arrive here with a blank filter
* as the nsAbLDAPDirectory::StartSearch() disallows it.
* But 3rd party LDAP query integration with Mozilla begins
* in this method.
*
* Default the filter string if blank, otherwise it gets
* set to (objectclass=*) which returns everything. Set
* the default to (objectclass=inetorgperson) as this
* is the most appropriate default objectclass which is
* central to the makeup of the mozilla ldap address book
* entries.
*/
if (filter.IsEmpty())
{
filter.AssignLiteral("(objectclass=inetorgperson)");
}
// get the directoryFilter from the directory url and merge it with the user's
// search filter
nsAutoCString urlFilter;
rv = mDirectoryUrl->GetFilter(urlFilter);
// if urlFilter is unset (or set to the default "objectclass=*"), there's
// no need to AND in an empty search term, so leave prefix and suffix empty
nsAutoCString searchFilter;
if (urlFilter.Length() && !urlFilter.EqualsLiteral("(objectclass=*)"))
{
// if urlFilter isn't parenthesized, we need to add in parens so that
// the filter works as a term to &
//
if (urlFilter[0] != '(')
{
searchFilter = NS_LITERAL_CSTRING("(&(");
searchFilter.Append(urlFilter);
searchFilter.AppendLiteral(")");
}
else
{
searchFilter = NS_LITERAL_CSTRING("(&");
searchFilter.Append(urlFilter);
}
searchFilter += filter;
searchFilter += ')';
}
else
searchFilter = filter;
rv = url->SetFilter(searchFilter);
NS_ENSURE_SUCCESS(rv, rv);
// Now formulate the search string
// Get the scope
int32_t scope;
bool doSubDirectories;
rv = aArguments->GetQuerySubDirectories (&doSubDirectories);
NS_ENSURE_SUCCESS(rv, rv);
scope = doSubDirectories ? nsILDAPURL::SCOPE_SUBTREE :
nsILDAPURL::SCOPE_ONELEVEL;
rv = url->SetScope(scope);
NS_ENSURE_SUCCESS(rv, rv);
// too soon? Do we need a new listener?
// If we already have a connection, and don't need to re-do it, give it the
// new search details and go for it...
if (!redoConnection)
{
nsAbQueryLDAPMessageListener *msgListener =
static_cast<nsAbQueryLDAPMessageListener *>(static_cast<nsILDAPMessageListener *>(mListener.get()));
if (msgListener)
{
// Ensure the urls are correct
msgListener->mDirectoryUrl = mDirectoryUrl;
msgListener->mSearchUrl = url;
// Also ensure we set the correct result limit
msgListener->mResultLimit = aResultLimit;
return msgListener->DoTask();
}
}
nsCOMPtr<nsIAbLDAPDirectory> abLDAPDir = do_QueryInterface(aDirectory, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMutableArray> serverSearchControls;
rv = abLDAPDir->GetSearchServerControls(getter_AddRefs(serverSearchControls));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMutableArray> clientSearchControls;
rv = abLDAPDir->GetSearchClientControls(getter_AddRefs(clientSearchControls));
NS_ENSURE_SUCCESS(rv, rv);
// Create the new connection (which cause the old one to be dropped if necessary)
mConnection = do_CreateInstance(NS_LDAPCONNECTION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectoryQueryResultListener> resultListener =
do_QueryInterface((nsIAbDirectoryQuery*)this, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Initiate LDAP message listener
nsAbQueryLDAPMessageListener* _messageListener =
new nsAbQueryLDAPMessageListener(resultListener, mDirectoryUrl, url,
mConnection, aArguments,
serverSearchControls, clientSearchControls,
mCurrentLogin, mCurrentMechanism,
aResultLimit, aTimeOut);
if (_messageListener == NULL)
return NS_ERROR_OUT_OF_MEMORY;
mListener = _messageListener;
*_retval = 1;
// Now lets initialize the LDAP connection properly. We'll kick
// off the bind operation in the callback function, |OnLDAPInit()|.
rv = mConnection->Init(mDirectoryUrl, mCurrentLogin,
mListener, nullptr, mCurrentProtocolVersion);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
/* void stopQuery (in long contextID); */
NS_IMETHODIMP nsAbLDAPDirectoryQuery::StopQuery(int32_t contextID)
{
mInitialized = true;
if (!mListener)
return NS_OK;
nsAbQueryLDAPMessageListener *listener =
static_cast<nsAbQueryLDAPMessageListener *>(static_cast<nsILDAPMessageListener *>(mListener.get()));
if (listener)
return listener->Cancel();
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectoryQuery::OnQueryFoundCard(nsIAbCard *aCard)
{
aCard->SetDirectoryId(mDirectoryId);
for (int32_t i = 0; i < mListeners.Count(); ++i)
mListeners[i]->OnSearchFoundCard(aCard);
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPDirectoryQuery::OnQueryResult(int32_t aResult,
int32_t aErrorCode)
{
uint32_t count = mListeners.Count();
// XXX: Temporary fix for crasher needs reviewing as part of bug 135231.
// Temporarily add a reference to ourselves, in case the only thing
// keeping us alive is the link with the listener.
NS_ADDREF_THIS();
for (int32_t i = count - 1; i >= 0; --i)
{
mListeners[i]->OnSearchFinished(aResult, EmptyString());
mListeners.RemoveObjectAt(i);
}
NS_RELEASE_THIS();
return NS_OK;
}

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPDirectoryQuery_h__
#define nsAbLDAPDirectoryQuery_h__
#include "nsIAbDirectoryQuery.h"
#include "nsILDAPConnection.h"
#include "nsILDAPMessageListener.h"
#include "nsILDAPURL.h"
#include "nsWeakReference.h"
#include "nsStringGlue.h"
#include "nsCOMArray.h"
class nsAbLDAPDirectoryQuery : public nsIAbDirectoryQuery,
public nsIAbDirectoryQueryResultListener
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABDIRECTORYQUERY
NS_DECL_NSIABDIRECTORYQUERYRESULTLISTENER
nsAbLDAPDirectoryQuery();
protected:
nsCOMPtr<nsILDAPMessageListener> mListener;
private:
virtual ~nsAbLDAPDirectoryQuery();
nsCOMPtr<nsILDAPConnection> mConnection;
nsCOMPtr<nsILDAPURL> mDirectoryUrl;
nsCString mDirectoryId;
nsCOMArray<nsIAbDirSearchListener> mListeners;
nsCString mCurrentLogin;
nsCString mCurrentMechanism;
uint32_t mCurrentProtocolVersion;
bool mInitialized;
};
#endif // nsAbLDAPDirectoryQuery_h__

View file

@ -0,0 +1,358 @@
/* -*- Mode: C++; 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/. */
#include "nsAbLDAPListenerBase.h"
#include "nsIWindowWatcher.h"
#include "nsIWindowMediator.h"
#include "mozIDOMWindow.h"
#include "nsIAuthPrompt.h"
#include "nsIStringBundle.h"
#include "nsILDAPMessage.h"
#include "nsILDAPErrors.h"
#include "nsILoginManager.h"
#include "nsILoginInfo.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMemory.h"
#include "mozilla/Services.h"
using namespace mozilla;
nsAbLDAPListenerBase::nsAbLDAPListenerBase(nsILDAPURL* url,
nsILDAPConnection* connection,
const nsACString &login,
const int32_t timeOut) :
mDirectoryUrl(url), mConnection(connection), mLogin(login),
mTimeOut(timeOut), mBound(false), mInitialized(false),
mLock("nsAbLDAPListenerBase.mLock")
{
}
nsAbLDAPListenerBase::~nsAbLDAPListenerBase()
{
}
nsresult nsAbLDAPListenerBase::Initiate()
{
if (!mConnection || !mDirectoryUrl)
return NS_ERROR_NULL_POINTER;
if (mInitialized)
return NS_OK;
mInitialized = true;
return NS_OK;
}
// If something fails in this function, we must call InitFailed() so that the
// derived class (and listener) knows to cancel what its doing as there is
// a problem.
NS_IMETHODIMP nsAbLDAPListenerBase::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
{
if (!mConnection || !mDirectoryUrl)
{
InitFailed();
return NS_ERROR_NULL_POINTER;
}
nsresult rv;
nsString passwd;
// Make sure that the Init() worked properly
if (NS_FAILED(aStatus))
{
InitFailed();
return NS_OK;
}
// If mLogin is set, we're expected to use it to get a password.
//
if (!mLogin.IsEmpty() && !mSaslMechanism.EqualsLiteral("GSSAPI"))
{
// get the string bundle service
//
nsCOMPtr<nsIStringBundleService> stringBundleSvc =
mozilla::services::GetStringBundleService();
if (!stringBundleSvc)
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
" error getting string bundle service");
InitFailed();
return NS_ERROR_UNEXPECTED;
}
// get the LDAP string bundle
//
nsCOMPtr<nsIStringBundle> ldapBundle;
rv = stringBundleSvc->CreateBundle("chrome://mozldap/locale/ldap.properties",
getter_AddRefs(ldapBundle));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error creating string"
"bundle chrome://mozldap/locale/ldap.properties");
InitFailed();
return rv;
}
// get the title for the authentication prompt
//
nsString authPromptTitle;
rv = ldapBundle->GetStringFromName(u"authPromptTitle",
getter_Copies(authPromptTitle));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error getting"
"'authPromptTitle' string from bundle "
"chrome://mozldap/locale/ldap.properties");
InitFailed();
return rv;
}
// get the host name for the auth prompt
//
nsAutoCString host;
rv = mDirectoryUrl->GetAsciiHost(host);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error getting ascii host"
"name from directory url");
InitFailed();
return rv;
}
// hostTemp is only necessary to work around a code-generation
// bug in egcs 1.1.2 (the version of gcc that comes with Red Hat 6.2),
// which is the default compiler for Mozilla on linux at the moment.
//
NS_ConvertASCIItoUTF16 hostTemp(host);
const char16_t *hostArray[1] = { hostTemp.get() };
// format the hostname into the authprompt text string
//
nsString authPromptText;
rv = ldapBundle->FormatStringFromName(u"authPromptText",
hostArray,
sizeof(hostArray) / sizeof(const char16_t *),
getter_Copies(authPromptText));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
"error getting 'authPromptText' string from bundle "
"chrome://mozldap/locale/ldap.properties");
InitFailed();
return rv;
}
// get the window mediator service, so we can get an auth prompter
//
nsCOMPtr<nsIWindowMediator> windowMediator =
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
" couldn't get window mediator service.");
InitFailed();
return rv;
}
// get the addressbook window, as it will be used to parent the auth
// prompter dialog
//
nsCOMPtr<mozIDOMWindowProxy> window;
rv = windowMediator->GetMostRecentWindow(nullptr,
getter_AddRefs(window));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
" error getting most recent window");
InitFailed();
return rv;
}
// get the window watcher service, so we can get an auth prompter
//
nsCOMPtr<nsIWindowWatcher> windowWatcherSvc =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
" couldn't get window watcher service.");
InitFailed();
return rv;
}
// get the auth prompter itself
//
nsCOMPtr<nsIAuthPrompt> authPrompter;
rv = windowWatcherSvc->GetNewAuthPrompter(window,
getter_AddRefs(authPrompter));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit():"
" error getting auth prompter");
InitFailed();
return rv;
}
// get authentication password, prompting the user if necessary
//
// we're going to use the URL spec of the server as the "realm" for
// wallet to remember the password by / for.
// Get the specification
nsCString spec;
rv = mDirectoryUrl->GetSpec(spec);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit():"
" error getting directory url spec");
InitFailed();
return rv;
}
bool status;
rv = authPrompter->PromptPassword(authPromptTitle.get(),
authPromptText.get(),
NS_ConvertUTF8toUTF16(spec).get(),
nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
getter_Copies(passwd),
&status);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to prompt for"
" password");
InitFailed();
return rv;
}
else if (!status)
{
InitFailed(true);
return NS_OK;
}
}
// Initiate the LDAP operation
mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to create ldap operation");
InitFailed();
return rv;
}
rv = mOperation->Init(mConnection, this, nullptr);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to Initialise operation");
InitFailed();
return rv;
}
// Try non-password mechanisms first
if (mSaslMechanism.EqualsLiteral("GSSAPI"))
{
nsAutoCString service;
rv = mDirectoryUrl->GetAsciiHost(service);
NS_ENSURE_SUCCESS(rv, rv);
service.Insert(NS_LITERAL_CSTRING("ldap@"), 0);
nsCOMPtr<nsIAuthModule> authModule =
do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOperation->SaslBind(service, mSaslMechanism, authModule);
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): "
"failed to perform GSSAPI bind");
mOperation = nullptr; // Break Listener -> Operation -> Listener ref cycle
InitFailed();
}
return rv;
}
// Bind
rv = mOperation->SimpleBind(NS_ConvertUTF16toUTF8(passwd));
if (NS_FAILED(rv))
{
NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to perform bind operation");
mOperation = nullptr; // Break Listener->Operation->Listener reference cycle
InitFailed();
}
return rv;
}
nsresult nsAbLDAPListenerBase::OnLDAPMessageBind(nsILDAPMessage *aMessage)
{
if (mBound)
return NS_OK;
// see whether the bind actually succeeded
//
int32_t errCode;
nsresult rv = aMessage->GetErrorCode(&errCode);
NS_ENSURE_SUCCESS(rv, rv);
if (errCode != nsILDAPErrors::SUCCESS)
{
// if the login failed, tell the wallet to forget this password
//
if (errCode == nsILDAPErrors::INAPPROPRIATE_AUTH ||
errCode == nsILDAPErrors::INVALID_CREDENTIALS)
{
// Login failed, so try again - but first remove the existing login(s)
// so that the user gets prompted. This may not be the best way of doing
// things, we need to review that later.
nsCOMPtr<nsILoginManager> loginMgr =
do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString spec;
rv = mDirectoryUrl->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
nsCString prePath;
rv = mDirectoryUrl->GetPrePath(prePath);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t count;
nsILoginInfo** logins;
rv = loginMgr->FindLogins(&count, NS_ConvertUTF8toUTF16(prePath),
EmptyString(),
NS_ConvertUTF8toUTF16(spec), &logins);
NS_ENSURE_SUCCESS(rv, rv);
// Typically there should only be one-login stored for this url, however,
// just in case there isn't.
for (uint32_t i = 0; i < count; ++i)
{
rv = loginMgr->RemoveLogin(logins[i]);
if (NS_FAILED(rv))
{
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
return rv;
}
}
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
// XXX We should probably pop up an error dialog telling
// the user that the login failed here, rather than just bringing
// up the password dialog again, which is what calling OnLDAPInit()
// does.
return OnLDAPInit(nullptr, NS_OK);
}
// Don't know how to handle this, so use the message error code in
// the failure return value so we hopefully get it back to the UI.
return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, errCode);
}
mBound = true;
return DoTask();
}

View file

@ -0,0 +1,54 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbLDAPListenerBase_h__
#define nsAbLDAPListenerBase_h__
#include "mozilla/Attributes.h"
#include "nsCOMPtr.h"
#include "nsILDAPMessageListener.h"
#include "nsILDAPURL.h"
#include "nsILDAPConnection.h"
#include "nsILDAPOperation.h"
#include "nsStringGlue.h"
#include "mozilla/Mutex.h"
class nsAbLDAPListenerBase : public nsILDAPMessageListener
{
public:
// Note that the directoryUrl is the details of the ldap directory
// without any search params or attributes specified.
nsAbLDAPListenerBase(nsILDAPURL* directoryUrl = nullptr,
nsILDAPConnection* connection = nullptr,
const nsACString &login = EmptyCString(),
const int32_t timeOut = 0);
virtual ~nsAbLDAPListenerBase();
NS_IMETHOD OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus) override;
protected:
nsresult OnLDAPMessageBind(nsILDAPMessage *aMessage);
nsresult Initiate();
// Called if an LDAP initialization fails.
virtual void InitFailed(bool aCancelled = false) = 0;
// Called to start off the required task after a bind.
virtual nsresult DoTask() = 0;
nsCOMPtr<nsILDAPURL> mDirectoryUrl;
nsCOMPtr<nsILDAPOperation> mOperation; // current ldap op
nsILDAPConnection* mConnection;
nsCString mLogin;
nsCString mSaslMechanism;
int32_t mTimeOut;
bool mBound;
bool mInitialized;
mozilla::Mutex mLock;
};
#endif

View file

@ -0,0 +1,489 @@
/* -*- Mode: C++; 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/. */
#include "nsILDAPMessage.h"
#include "nsAbLDAPReplicationData.h"
#include "nsIAbCard.h"
#include "nsAbBaseCID.h"
#include "nsAbUtils.h"
#include "nsAbLDAPReplicationQuery.h"
#include "nsILDAPErrors.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
// once bug # 101252 gets fixed, this should be reverted back to be non threadsafe
// implementation is not really thread safe since each object should exist
// independently along with its related independent nsAbLDAPReplicationQuery object.
NS_IMPL_ISUPPORTS(nsAbLDAPProcessReplicationData, nsIAbLDAPProcessReplicationData, nsILDAPMessageListener)
nsAbLDAPProcessReplicationData::nsAbLDAPProcessReplicationData() :
nsAbLDAPListenerBase(),
mState(kIdle),
mProtocol(-1),
mCount(0),
mDBOpen(false),
mInitialized(false)
{
}
nsAbLDAPProcessReplicationData::~nsAbLDAPProcessReplicationData()
{
/* destructor code */
if(mDBOpen && mReplicationDB)
mReplicationDB->Close(false);
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::Init(
nsIAbLDAPDirectory *aDirectory,
nsILDAPConnection *aConnection,
nsILDAPURL* aURL,
nsIAbLDAPReplicationQuery *aQuery,
nsIWebProgressListener *aProgressListener)
{
NS_ENSURE_ARG_POINTER(aDirectory);
NS_ENSURE_ARG_POINTER(aConnection);
NS_ENSURE_ARG_POINTER(aURL);
NS_ENSURE_ARG_POINTER(aQuery);
mDirectory = aDirectory;
mConnection = aConnection;
mDirectoryUrl = aURL;
mQuery = aQuery;
mListener = aProgressListener;
nsresult rv = mDirectory->GetAttributeMap(getter_AddRefs(mAttrMap));
if (NS_FAILED(rv)) {
mQuery = nullptr;
return rv;
}
rv = mDirectory->GetAuthDn(mLogin);
if (NS_FAILED(rv)) {
mQuery = nullptr;
return rv;
}
rv = mDirectory->GetSaslMechanism(mSaslMechanism);
if (NS_FAILED(rv)) {
mQuery = nullptr;
return rv;
}
mInitialized = true;
return rv;
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::GetReplicationState(int32_t *aReplicationState)
{
NS_ENSURE_ARG_POINTER(aReplicationState);
*aReplicationState = mState;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::GetProtocolUsed(int32_t *aProtocolUsed)
{
NS_ENSURE_ARG_POINTER(aProtocolUsed);
*aProtocolUsed = mProtocol;
return NS_OK;
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::OnLDAPMessage(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
int32_t messageType;
nsresult rv = aMessage->GetType(&messageType);
if (NS_FAILED(rv)) {
Done(false);
return rv;
}
switch (messageType)
{
case nsILDAPMessage::RES_BIND:
rv = OnLDAPMessageBind(aMessage);
if (NS_FAILED(rv))
rv = Abort();
break;
case nsILDAPMessage::RES_SEARCH_ENTRY:
rv = OnLDAPSearchEntry(aMessage);
break;
case nsILDAPMessage::RES_SEARCH_RESULT:
rv = OnLDAPSearchResult(aMessage);
break;
default:
// for messageTypes we do not handle return NS_OK to LDAP and move ahead.
rv = NS_OK;
break;
}
return rv;
}
NS_IMETHODIMP nsAbLDAPProcessReplicationData::Abort()
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = NS_OK;
if (mState != kIdle && mOperation) {
rv = mOperation->AbandonExt();
if (NS_SUCCEEDED(rv))
mState = kIdle;
}
if (mReplicationDB && mDBOpen) {
// force close since we need to delete the file.
mReplicationDB->ForceClosed();
mDBOpen = false;
// delete the unsaved replication file
if (mReplicationFile) {
rv = mReplicationFile->Remove(false);
if (NS_SUCCEEDED(rv) && mDirectory) {
nsAutoCString fileName;
rv = mDirectory->GetReplicationFileName(fileName);
// now put back the backed up replicated file if aborted
if (NS_SUCCEEDED(rv) && mBackupReplicationFile)
rv = mBackupReplicationFile->MoveToNative(nullptr, fileName);
}
}
}
Done(false);
return rv;
}
nsresult nsAbLDAPProcessReplicationData::DoTask()
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = OpenABForReplicatedDir(true);
if (NS_FAILED(rv))
// do not call done here since it is called by OpenABForReplicationDir
return rv;
mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mOperation->Init(mConnection, this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
// get the relevant attributes associated with the directory server url
nsAutoCString urlFilter;
rv = mDirectoryUrl->GetFilter(urlFilter);
if (NS_FAILED(rv))
return rv;
nsAutoCString dn;
rv = mDirectoryUrl->GetDn(dn);
if (NS_FAILED(rv))
return rv;
if (dn.IsEmpty())
return NS_ERROR_UNEXPECTED;
int32_t scope;
rv = mDirectoryUrl->GetScope(&scope);
if (NS_FAILED(rv))
return rv;
nsAutoCString attributes;
rv = mDirectoryUrl->GetAttributes(attributes);
if (NS_FAILED(rv))
return rv;
mState = kReplicatingAll;
if (mListener && NS_SUCCEEDED(rv))
// XXX Cast from bool to nsresult
mListener->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_START,
static_cast<nsresult>(true));
return mOperation->SearchExt(dn, scope, urlFilter, attributes, 0, 0);
}
void nsAbLDAPProcessReplicationData::InitFailed(bool aCancelled)
{
// Just call Done() which will ensure everything is tidied up nicely.
Done(false);
}
nsresult nsAbLDAPProcessReplicationData::OnLDAPSearchEntry(nsILDAPMessage *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
// since this runs on the main thread and is single threaded, this will
// take care of entries returned by LDAP Connection thread after Abort.
if (!mReplicationDB || !mDBOpen)
return NS_ERROR_FAILURE;
nsresult rv = NS_OK;
// Although we would may naturally create an nsIAbLDAPCard here, we don't
// need to as we are writing this straight to the database, so just create
// the database version instead.
nsCOMPtr<nsIAbCard> newCard(do_CreateInstance(NS_ABMDBCARD_CONTRACTID,
&rv));
if (NS_FAILED(rv)) {
Abort();
return rv;
}
rv = mAttrMap->SetCardPropertiesFromLDAPMessage(aMessage, newCard);
if (NS_FAILED(rv))
{
NS_WARNING("nsAbLDAPProcessReplicationData::OnLDAPSearchEntry"
"No card properties could be set");
// if some entries are bogus for us, continue with next one
return NS_OK;
}
rv = mReplicationDB->CreateNewCardAndAddToDB(newCard, false, nullptr);
if(NS_FAILED(rv)) {
Abort();
return rv;
}
// now set the attribute for the DN of the entry in the card in the DB
nsAutoCString authDN;
rv = aMessage->GetDn(authDN);
if(NS_SUCCEEDED(rv) && !authDN.IsEmpty())
{
newCard->SetPropertyAsAUTF8String("_DN", authDN);
}
rv = mReplicationDB->EditCard(newCard, false, nullptr);
if(NS_FAILED(rv)) {
Abort();
return rv;
}
mCount ++;
if (mListener && !(mCount % 10)) // inform the listener every 10 entries
{
mListener->OnProgressChange(nullptr,nullptr,mCount, -1, mCount, -1);
// in case if the LDAP Connection thread is starved and causes problem
// uncomment this one and try.
// PR_Sleep(PR_INTERVAL_NO_WAIT); // give others a chance
}
return rv;
}
nsresult nsAbLDAPProcessReplicationData::OnLDAPSearchResult(nsILDAPMessage *aMessage)
{
#ifdef DEBUG_rdayal
printf("LDAP Replication : Got Results for Completion");
#endif
NS_ENSURE_ARG_POINTER(aMessage);
if(!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
int32_t errorCode;
nsresult rv = aMessage->GetErrorCode(&errorCode);
if(NS_SUCCEEDED(rv)) {
// We are done with the LDAP search for all entries.
if(errorCode == nsILDAPErrors::SUCCESS || errorCode == nsILDAPErrors::SIZELIMIT_EXCEEDED) {
Done(true);
if(mReplicationDB && mDBOpen) {
rv = mReplicationDB->Close(true);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication DB Close on Success failed");
mDBOpen = false;
// once we have saved the new replication file, delete the backup file
if(mBackupReplicationFile)
{
rv = mBackupReplicationFile->Remove(false);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication BackupFile Remove on Success failed");
}
}
return NS_OK;
}
}
// in case if GetErrorCode returned error or errorCode is not SUCCESS / SIZELIMIT_EXCEEDED
if(mReplicationDB && mDBOpen) {
// if error result is returned close the DB without saving ???
// should we commit anyway ??? whatever is returned is not lost then !!
rv = mReplicationDB->ForceClosed(); // force close since we need to delete the file.
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication DB ForceClosed on Failure failed");
mDBOpen = false;
// if error result is returned remove the replicated file
if(mReplicationFile) {
rv = mReplicationFile->Remove(false);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication File Remove on Failure failed");
if(NS_SUCCEEDED(rv)) {
// now put back the backed up replicated file
if(mBackupReplicationFile && mDirectory)
{
nsAutoCString fileName;
rv = mDirectory->GetReplicationFileName(fileName);
if (NS_SUCCEEDED(rv) && !fileName.IsEmpty())
{
rv = mBackupReplicationFile->MoveToNative(nullptr, fileName);
NS_ASSERTION(NS_SUCCEEDED(rv), "Replication Backup File Move back on Failure failed");
}
}
}
}
Done(false);
}
return NS_OK;
}
nsresult nsAbLDAPProcessReplicationData::OpenABForReplicatedDir(bool aCreate)
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = mDirectory->GetReplicationFile(getter_AddRefs(mReplicationFile));
if (NS_FAILED(rv))
{
Done(false);
return NS_ERROR_FAILURE;
}
nsCString fileName;
rv = mReplicationFile->GetNativeLeafName(fileName);
if (NS_FAILED(rv)) {
Done(false);
return rv;
}
// if the AB DB already exists backup existing one,
// in case if the user cancels or Abort put back the backed up file
bool fileExists;
rv = mReplicationFile->Exists(&fileExists);
if(NS_SUCCEEDED(rv) && fileExists) {
// create the backup file object same as the Replication file object.
// we create a backup file here since we need to cleanup the existing file
// for create and then commit so instead of deleting existing cards we just
// clone the existing one for a much better performance - for Download All.
// And also important in case if replication fails we donot lose user's existing
// replicated data for both Download all and Changelog.
nsCOMPtr<nsIFile> clone;
rv = mReplicationFile->Clone(getter_AddRefs(clone));
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
mBackupReplicationFile = do_QueryInterface(clone, &rv);
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
rv = mBackupReplicationFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777);
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
nsAutoString backupFileLeafName;
rv = mBackupReplicationFile->GetLeafName(backupFileLeafName);
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
// remove the newly created unique backup file so that move and copy succeeds.
rv = mBackupReplicationFile->Remove(false);
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
if(aCreate) {
// set backup file to existing replication file for move
mBackupReplicationFile->SetNativeLeafName(fileName);
rv = mBackupReplicationFile->MoveTo(nullptr, backupFileLeafName);
// set the backup file leaf name now
if (NS_SUCCEEDED(rv))
mBackupReplicationFile->SetLeafName(backupFileLeafName);
}
else {
// set backup file to existing replication file for copy
mBackupReplicationFile->SetNativeLeafName(fileName);
// specify the parent here specifically,
// passing nullptr to copy to the same dir actually renames existing file
// instead of making another copy of the existing file.
nsCOMPtr<nsIFile> parent;
rv = mBackupReplicationFile->GetParent(getter_AddRefs(parent));
if (NS_SUCCEEDED(rv))
rv = mBackupReplicationFile->CopyTo(parent, backupFileLeafName);
// set the backup file leaf name now
if (NS_SUCCEEDED(rv))
mBackupReplicationFile->SetLeafName(backupFileLeafName);
}
if(NS_FAILED(rv)) {
Done(false);
return rv;
}
}
nsCOMPtr<nsIAddrDatabase> addrDBFactory =
do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
if(NS_FAILED(rv)) {
if (mBackupReplicationFile)
mBackupReplicationFile->Remove(false);
Done(false);
return rv;
}
rv = addrDBFactory->Open(mReplicationFile, aCreate, true, getter_AddRefs(mReplicationDB));
if(NS_FAILED(rv)) {
Done(false);
if (mBackupReplicationFile)
mBackupReplicationFile->Remove(false);
return rv;
}
mDBOpen = true; // replication DB is now Open
return rv;
}
void nsAbLDAPProcessReplicationData::Done(bool aSuccess)
{
if (!mInitialized)
return;
mState = kReplicationDone;
if (mQuery)
mQuery->Done(aSuccess);
if (mListener)
// XXX Cast from bool to nsresult
mListener->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_STOP,
static_cast<nsresult>(aSuccess));
// since this is called when all is done here, either on success,
// failure or abort release the query now.
mQuery = nullptr;
}
nsresult nsAbLDAPProcessReplicationData::DeleteCard(nsString & aDn)
{
nsCOMPtr<nsIAbCard> cardToDelete;
mReplicationDB->GetCardFromAttribute(nullptr, "_DN", NS_ConvertUTF16toUTF8(aDn),
false, getter_AddRefs(cardToDelete));
return mReplicationDB->DeleteCard(cardToDelete, false, nullptr);
}

View file

@ -0,0 +1,66 @@
/* 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/. */
#ifndef nsAbLDAPReplicationData_h__
#define nsAbLDAPReplicationData_h__
#include "mozilla/Attributes.h"
#include "nsIAbLDAPReplicationData.h"
#include "nsIWebProgressListener.h"
#include "nsIAbLDAPReplicationQuery.h"
#include "nsAbLDAPListenerBase.h"
#include "nsIAddrDatabase.h"
#include "nsIFile.h"
#include "nsDirPrefs.h"
#include "nsIAbLDAPAttributeMap.h"
#include "nsIAbLDAPDirectory.h"
#include "nsStringGlue.h"
class nsAbLDAPProcessReplicationData : public nsIAbLDAPProcessReplicationData,
public nsAbLDAPListenerBase
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABLDAPPROCESSREPLICATIONDATA
nsAbLDAPProcessReplicationData();
// nsILDAPMessageListener
NS_IMETHOD OnLDAPMessage(nsILDAPMessage *aMessage) override;
protected:
virtual ~nsAbLDAPProcessReplicationData();
virtual nsresult DoTask() override;
virtual void InitFailed(bool aCancelled = false) override;
// pointer to the interfaces used by this object
nsCOMPtr<nsIWebProgressListener> mListener;
// pointer to the query to call back to once we've finished
nsCOMPtr<nsIAbLDAPReplicationQuery> mQuery;
nsCOMPtr<nsIAddrDatabase> mReplicationDB;
nsCOMPtr <nsIFile> mReplicationFile;
nsCOMPtr <nsIFile> mBackupReplicationFile;
// state of processing, protocol used and count of results
int32_t mState;
int32_t mProtocol;
int32_t mCount;
bool mDBOpen;
bool mInitialized;
nsCOMPtr<nsIAbLDAPDirectory> mDirectory;
nsCOMPtr<nsIAbLDAPAttributeMap> mAttrMap; // maps ab properties to ldap attrs
virtual nsresult OnLDAPSearchEntry(nsILDAPMessage *aMessage);
virtual nsresult OnLDAPSearchResult(nsILDAPMessage *aMessage);
nsresult OpenABForReplicatedDir(bool bCreate);
nsresult DeleteCard(nsString & aDn);
void Done(bool aSuccess);
};
#endif // nsAbLDAPReplicationData_h__

View file

@ -0,0 +1,153 @@
/* -*- Mode: C++; 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/. */
#include "nsCOMPtr.h"
#include "nsAbLDAPReplicationQuery.h"
#include "nsAbLDAPReplicationService.h"
#include "nsAbLDAPReplicationData.h"
#include "nsILDAPURL.h"
#include "nsAbBaseCID.h"
#include "nsAbUtils.h"
#include "nsDirPrefs.h"
#include "prmem.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
NS_IMPL_ISUPPORTS(nsAbLDAPReplicationQuery,
nsIAbLDAPReplicationQuery)
nsAbLDAPReplicationQuery::nsAbLDAPReplicationQuery()
: mInitialized(false)
{
}
nsresult nsAbLDAPReplicationQuery::InitLDAPData()
{
nsAutoCString fileName;
nsresult rv = mDirectory->GetReplicationFileName(fileName);
NS_ENSURE_SUCCESS(rv, rv);
// this is done here to take care of the problem related to bug # 99124.
// earlier versions of Mozilla could have the fileName associated with the directory
// to be abook.mab which is the profile's personal addressbook. If the pref points to
// it, calls nsDirPrefs to generate a new server filename.
if (fileName.IsEmpty() || fileName.EqualsLiteral(kPersonalAddressbook))
{
// Ensure fileName is empty for DIR_GenerateAbFileName to work
// correctly.
fileName.Truncate();
nsCOMPtr<nsIAbDirectory> standardDir(do_QueryInterface(mDirectory, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCString dirPrefId;
rv = standardDir->GetDirPrefId(dirPrefId);
NS_ENSURE_SUCCESS(rv, rv);
// XXX This should be replaced by a local function at some stage.
// For now we'll continue using the nsDirPrefs version.
DIR_Server* server = DIR_GetServerFromList(dirPrefId.get());
if (server)
{
DIR_SetServerFileName(server);
// Now ensure the prefs are saved
DIR_SavePrefsForOneServer(server);
}
}
rv = mDirectory->SetReplicationFileName(fileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDirectory->GetLDAPURL(getter_AddRefs(mURL));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDirectory->GetAuthDn(mLogin);
NS_ENSURE_SUCCESS(rv, rv);
mConnection = do_CreateInstance(NS_LDAPCONNECTION_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
return rv;
}
nsresult nsAbLDAPReplicationQuery::ConnectToLDAPServer()
{
if (!mInitialized || !mURL)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
nsCOMPtr<nsILDAPMessageListener> mDp = do_QueryInterface(mDataProcessor,
&rv);
if (NS_FAILED(rv))
return NS_ERROR_UNEXPECTED;
// this could be a rebind call
int32_t replicationState = nsIAbLDAPProcessReplicationData::kIdle;
rv = mDataProcessor->GetReplicationState(&replicationState);
if (NS_FAILED(rv) ||
replicationState != nsIAbLDAPProcessReplicationData::kIdle)
return rv;
uint32_t protocolVersion;
rv = mDirectory->GetProtocolVersion(&protocolVersion);
NS_ENSURE_SUCCESS(rv, rv);
// initialize the LDAP connection
return mConnection->Init(mURL, mLogin, mDp, nullptr, protocolVersion);
}
NS_IMETHODIMP nsAbLDAPReplicationQuery::Init(nsIAbLDAPDirectory *aDirectory,
nsIWebProgressListener *aProgressListener)
{
NS_ENSURE_ARG_POINTER(aDirectory);
mDirectory = aDirectory;
nsresult rv = InitLDAPData();
if (NS_FAILED(rv))
return rv;
mDataProcessor =
do_CreateInstance(NS_ABLDAP_PROCESSREPLICATIONDATA_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
// 'this' initialized
mInitialized = true;
return mDataProcessor->Init(mDirectory, mConnection, mURL, this,
aProgressListener);
}
NS_IMETHODIMP nsAbLDAPReplicationQuery::DoReplicationQuery()
{
return ConnectToLDAPServer();
}
NS_IMETHODIMP nsAbLDAPReplicationQuery::CancelQuery()
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
return mDataProcessor->Abort();
}
NS_IMETHODIMP nsAbLDAPReplicationQuery::Done(bool aSuccess)
{
if (!mInitialized)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv = NS_OK;
nsCOMPtr<nsIAbLDAPReplicationService> replicationService =
do_GetService(NS_ABLDAP_REPLICATIONSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
replicationService->Done(aSuccess);
return rv;
}

View file

@ -0,0 +1,44 @@
/* 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/. */
#ifndef nsAbLDAPReplicationQuery_h__
#define nsAbLDAPReplicationQuery_h__
#include "nsIWebProgressListener.h"
#include "nsIAbLDAPReplicationQuery.h"
#include "nsIAbLDAPReplicationData.h"
#include "nsIAbLDAPDirectory.h"
#include "nsILDAPConnection.h"
#include "nsILDAPOperation.h"
#include "nsILDAPURL.h"
#include "nsDirPrefs.h"
#include "nsStringGlue.h"
class nsAbLDAPReplicationQuery final : public nsIAbLDAPReplicationQuery
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABLDAPREPLICATIONQUERY
nsAbLDAPReplicationQuery();
nsresult InitLDAPData();
nsresult ConnectToLDAPServer();
protected :
~nsAbLDAPReplicationQuery() {}
// pointer to interfaces used by this object
nsCOMPtr<nsILDAPConnection> mConnection;
nsCOMPtr<nsILDAPOperation> mOperation;
nsCOMPtr<nsILDAPURL> mURL;
nsCOMPtr<nsIAbLDAPDirectory> mDirectory;
nsCOMPtr<nsIAbLDAPProcessReplicationData> mDataProcessor;
bool mInitialized;
nsCString mLogin;
};
#endif // nsAbLDAPReplicationQuery_h__

View file

@ -0,0 +1,136 @@
/* 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/. */
#include "nsCOMPtr.h"
#include "nsAbLDAPReplicationService.h"
#include "nsAbLDAPReplicationQuery.h"
#include "nsAbBaseCID.h"
#include "nsIWebProgressListener.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
// XXX Change log replication doesn't work. Bug 311632 should fix it.
//#include "nsAbLDAPChangeLogQuery.h"
#include "nsIAbLDAPReplicationData.h"
/*** implementation of the service ******/
NS_IMPL_ISUPPORTS(nsAbLDAPReplicationService, nsIAbLDAPReplicationService)
nsAbLDAPReplicationService::nsAbLDAPReplicationService()
: mReplicating(false)
{
}
nsAbLDAPReplicationService::~nsAbLDAPReplicationService()
{
}
/* void startReplication(in string aURI, in nsIWebProgressListener progressListener); */
NS_IMETHODIMP nsAbLDAPReplicationService::StartReplication(nsIAbLDAPDirectory *aDirectory,
nsIWebProgressListener *progressListener)
{
NS_ENSURE_ARG_POINTER(aDirectory);
#ifdef DEBUG_rdayal
printf("Start Replication called");
#endif
// Makes sure to allow only one replication at a time.
if(mReplicating)
return NS_ERROR_FAILURE;
mDirectory = aDirectory;
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
switch (DecideProtocol())
{
case nsIAbLDAPProcessReplicationData::kDefaultDownloadAll:
mQuery = do_CreateInstance(NS_ABLDAP_REPLICATIONQUERY_CONTRACTID, &rv);
break;
// XXX Change log replication doesn't work. Bug 311632 should fix it.
//case nsIAbLDAPProcessReplicationData::kChangeLogProtocol:
// mQuery = do_CreateInstance (NS_ABLDAP_CHANGELOGQUERY_CONTRACTID, &rv);
// break;
default:
break;
}
if (NS_SUCCEEDED(rv) && mQuery)
{
rv = mQuery->Init(mDirectory, progressListener);
if (NS_SUCCEEDED(rv))
{
rv = mQuery->DoReplicationQuery();
if (NS_SUCCEEDED(rv))
{
mReplicating = true;
return rv;
}
}
}
if (progressListener && NS_FAILED(rv))
progressListener->OnStateChange(nullptr, nullptr,
nsIWebProgressListener::STATE_STOP,
NS_OK);
if (NS_FAILED(rv))
{
mDirectory = nullptr;
mQuery = nullptr;
}
return rv;
}
/* void cancelReplication(in string aURI); */
NS_IMETHODIMP nsAbLDAPReplicationService::CancelReplication(nsIAbLDAPDirectory *aDirectory)
{
NS_ENSURE_ARG_POINTER(aDirectory);
nsresult rv = NS_ERROR_FAILURE;
if (aDirectory == mDirectory)
{
if (mQuery && mReplicating)
rv = mQuery->CancelQuery();
}
// If query has been cancelled successfully
if (NS_SUCCEEDED(rv))
Done(false);
return rv;
}
NS_IMETHODIMP nsAbLDAPReplicationService::Done(bool aSuccess)
{
mReplicating = false;
if (mQuery)
{
mQuery = nullptr; // Release query obj
mDirectory = nullptr; // Release directory
}
return NS_OK;
}
// XXX: This method should query the RootDSE for the changeLog attribute,
// if it exists ChangeLog protocol is supported.
int32_t nsAbLDAPReplicationService::DecideProtocol()
{
// Do the changeLog, it will decide if there is a need to replicate all
// entries or only update existing DB and will do the appropriate thing.
//
// XXX: Bug 231965 changed this from kChangeLogProtocol to
// kDefaultDownloadAll because of a problem with ldap replication not
// working correctly. We need to change this back at some stage (bug 311632).
return nsIAbLDAPProcessReplicationData::kDefaultDownloadAll;
}

View file

@ -0,0 +1,33 @@
/* 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/. */
#ifndef nsAbLDAPReplicationService_h___
#define nsAbLDAPReplicationService_h___
#include "nsIAbLDAPReplicationService.h"
#include "nsIAbLDAPReplicationQuery.h"
#include "nsStringGlue.h"
class nsAbLDAPReplicationService : public nsIAbLDAPReplicationService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABLDAPREPLICATIONSERVICE
nsAbLDAPReplicationService();
int32_t DecideProtocol();
protected:
virtual ~nsAbLDAPReplicationService();
nsCOMPtr<nsIAbLDAPReplicationQuery> mQuery;
bool mReplicating;
nsCOMPtr<nsIAbLDAPDirectory> mDirectory;
};
#endif /* nsAbLDAPReplicationService_h___ */

View file

@ -0,0 +1,868 @@
/* -*- Mode: C++; 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/. */
#include "nsIAddrDatabase.h"
#include "nsStringGlue.h"
#include "nsAbLDIFService.h"
#include "nsIFile.h"
#include "nsILineInputStream.h"
#include "nsIInputStream.h"
#include "nsNetUtil.h"
#include "nsISeekableStream.h"
#include "mdb.h"
#include "plstr.h"
#include "prmem.h"
#include "prprf.h"
#include "nsCRTGlue.h"
#include "nsTArray.h"
#include <ctype.h>
NS_IMPL_ISUPPORTS(nsAbLDIFService, nsIAbLDIFService)
// If we get a line longer than 32K it's just toooooo bad!
#define kTextAddressBufferSz (64 * 1024)
nsAbLDIFService::nsAbLDIFService()
{
mStoreLocAsHome = false;
mLFCount = 0;
mCRCount = 0;
}
nsAbLDIFService::~nsAbLDIFService()
{
}
#define RIGHT2 0x03
#define RIGHT4 0x0f
#define CONTINUED_LINE_MARKER '\001'
// XXX TODO fix me
// use the NSPR base64 library. see plbase64.h
// see bug #145367
static unsigned char b642nib[0x80] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
};
NS_IMETHODIMP nsAbLDIFService::ImportLDIFFile(nsIAddrDatabase *aDb, nsIFile *aSrc, bool aStoreLocAsHome, uint32_t *aProgress)
{
NS_ENSURE_ARG_POINTER(aSrc);
NS_ENSURE_ARG_POINTER(aDb);
mStoreLocAsHome = aStoreLocAsHome;
char buf[1024];
char* pBuf = &buf[0];
int32_t startPos = 0;
uint32_t len = 0;
nsTArray<int32_t> listPosArray; // where each list/group starts in ldif file
nsTArray<int32_t> listSizeArray; // size of the list/group info
int32_t savedStartPos = 0;
int32_t filePos = 0;
uint64_t bytesLeft = 0;
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aSrc);
NS_ENSURE_SUCCESS(rv, rv);
// Initialize the parser for a run...
mLdifLine.Truncate();
while (NS_SUCCEEDED(inputStream->Available(&bytesLeft)) && bytesLeft > 0)
{
if (NS_SUCCEEDED(inputStream->Read(pBuf, sizeof(buf), &len)) && len > 0)
{
startPos = 0;
while (NS_SUCCEEDED(GetLdifStringRecord(buf, len, startPos)))
{
if (mLdifLine.Find("groupOfNames") == -1)
AddLdifRowToDatabase(aDb, false);
else
{
//keep file position for mailing list
listPosArray.AppendElement(savedStartPos);
listSizeArray.AppendElement(filePos + startPos-savedStartPos);
ClearLdifRecordBuffer();
}
savedStartPos = filePos + startPos;
}
filePos += len;
if (aProgress)
*aProgress = (uint32_t)filePos;
}
}
//last row
if (!mLdifLine.IsEmpty() && mLdifLine.Find("groupOfNames") == -1)
AddLdifRowToDatabase(aDb, false);
// mail Lists
int32_t i, pos;
uint32_t size;
int32_t listTotal = listPosArray.Length();
char *listBuf;
ClearLdifRecordBuffer(); // make sure the buffer is clean
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(inputStream, &rv);
NS_ENSURE_SUCCESS(rv, rv);
for (i = 0; i < listTotal; i++)
{
pos = listPosArray[i];
size = listSizeArray[i];
if (NS_SUCCEEDED(seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, pos)))
{
// Allocate enough space for the lists/groups as the size varies.
listBuf = (char *) PR_Malloc(size);
if (!listBuf)
continue;
if (NS_SUCCEEDED(inputStream->Read(listBuf, size, &len)) && len > 0)
{
startPos = 0;
while (NS_SUCCEEDED(GetLdifStringRecord(listBuf, len, startPos)))
{
if (mLdifLine.Find("groupOfNames") != -1)
{
AddLdifRowToDatabase(aDb, true);
if (NS_SUCCEEDED(seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, 0)))
break;
}
}
}
PR_FREEIF(listBuf);
}
}
rv = inputStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
// Finally commit everything to the database and return.
return aDb->Commit(nsAddrDBCommitType::kLargeCommit);
}
/*
* str_parse_line - takes a line of the form "type:[:] value" and splits it
* into components "type" and "value". if a double colon separates type from
* value, then value is encoded in base 64, and parse_line un-decodes it
* (in place) before returning.
* in LDIF, non-ASCII data is treated as base64 encoded UTF-8
*/
nsresult nsAbLDIFService::str_parse_line(char *line, char **type, char **value, int *vlen) const
{
char *p, *s, *d, *byte, *stop;
char nib;
int i, b64;
/* skip any leading space */
while ( isspace( *line ) ) {
line++;
}
*type = line;
for ( s = line; *s && *s != ':'; s++ )
; /* NULL */
if ( *s == '\0' ) {
return NS_ERROR_FAILURE;
}
/* trim any space between type and : */
for ( p = s - 1; p > line && isspace( *p ); p-- ) {
*p = '\0';
}
*s++ = '\0';
/* check for double : - indicates base 64 encoded value */
if ( *s == ':' ) {
s++;
b64 = 1;
/* single : - normally encoded value */
} else {
b64 = 0;
}
/* skip space between : and value */
while ( isspace( *s ) ) {
s++;
}
/* if no value is present, error out */
if ( *s == '\0' ) {
return NS_ERROR_FAILURE;
}
/* check for continued line markers that should be deleted */
for ( p = s, d = s; *p; p++ ) {
if ( *p != CONTINUED_LINE_MARKER )
*d++ = *p;
}
*d = '\0';
*value = s;
if ( b64 ) {
stop = PL_strchr( s, '\0' );
byte = s;
for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
for ( i = 0; i < 3; i++ ) {
if ( p[i] != '=' && (p[i] & 0x80 ||
b642nib[ p[i] & 0x7f ] > 0x3f) ) {
return NS_ERROR_FAILURE;
}
}
/* first digit */
nib = b642nib[ p[0] & 0x7f ];
byte[0] = nib << 2;
/* second digit */
nib = b642nib[ p[1] & 0x7f ];
byte[0] |= nib >> 4;
byte[1] = (nib & RIGHT4) << 4;
/* third digit */
if ( p[2] == '=' ) {
*vlen += 1;
break;
}
nib = b642nib[ p[2] & 0x7f ];
byte[1] |= nib >> 2;
byte[2] = (nib & RIGHT2) << 6;
/* fourth digit */
if ( p[3] == '=' ) {
*vlen += 2;
break;
}
nib = b642nib[ p[3] & 0x7f ];
byte[2] |= nib;
byte += 3;
}
s[ *vlen ] = '\0';
} else {
*vlen = (int) (d - s);
}
return NS_OK;
}
/*
* str_getline - return the next "line" (minus newline) of input from a
* string buffer of lines separated by newlines, terminated by \n\n
* or \0. this routine handles continued lines, bundling them into
* a single big line before returning. if a line begins with a white
* space character, it is a continuation of the previous line. the white
* space character (nb: only one char), and preceeding newline are changed
* into CONTINUED_LINE_MARKER chars, to be deleted later by the
* str_parse_line() routine above.
*
* it takes a pointer to a pointer to the buffer on the first call,
* which it updates and must be supplied on subsequent calls.
*/
char* nsAbLDIFService::str_getline(char **next) const
{
char *lineStr;
char c;
if ( *next == nullptr || **next == '\n' || **next == '\0' ) {
return( nullptr);
}
lineStr = *next;
while ( (*next = PL_strchr( *next, '\n' )) != NULL ) {
c = *(*next + 1);
if ( isspace( c ) && c != '\n' ) {
**next = CONTINUED_LINE_MARKER;
*(*next+1) = CONTINUED_LINE_MARKER;
} else {
*(*next)++ = '\0';
break;
}
}
return( lineStr );
}
nsresult nsAbLDIFService::GetLdifStringRecord(char* buf, int32_t len, int32_t& stopPos)
{
for (; stopPos < len; stopPos++)
{
char c = buf[stopPos];
if (c == 0xA)
{
mLFCount++;
}
else if (c == 0xD)
{
mCRCount++;
}
else
{
if (mLFCount == 0 && mCRCount == 0)
mLdifLine.Append(c);
else if (( mLFCount > 1) || ( mCRCount > 2 && mLFCount ) ||
( !mLFCount && mCRCount > 1 ))
{
return NS_OK;
}
else if ((mLFCount == 1 || mCRCount == 1))
{
mLdifLine.Append('\n');
mLdifLine.Append(c);
mLFCount = 0;
mCRCount = 0;
}
}
}
if (((stopPos == len) && (mLFCount > 1)) || (mCRCount > 2 && mLFCount) ||
(!mLFCount && mCRCount > 1))
return NS_OK;
return NS_ERROR_FAILURE;
}
void nsAbLDIFService::AddLdifRowToDatabase(nsIAddrDatabase *aDatabase,
bool bIsList)
{
// If no data to process then reset CR/LF counters and return.
if (mLdifLine.IsEmpty())
{
mLFCount = 0;
mCRCount = 0;
return;
}
nsCOMPtr <nsIMdbRow> newRow;
if (aDatabase)
{
if (bIsList)
aDatabase->GetNewListRow(getter_AddRefs(newRow));
else
aDatabase->GetNewRow(getter_AddRefs(newRow));
if (!newRow)
return;
}
else
return;
char* cursor = ToNewCString(mLdifLine);
char* saveCursor = cursor; /* keep for deleting */
char* line = 0;
char* typeSlot = 0;
char* valueSlot = 0;
int length = 0; // the length of an ldif attribute
while ( (line = str_getline(&cursor)) != nullptr)
{
if (NS_SUCCEEDED(str_parse_line(line, &typeSlot, &valueSlot, &length))) {
AddLdifColToDatabase(aDatabase, newRow, typeSlot, valueSlot, bIsList);
}
else
continue; // parse error: continue with next loop iteration
}
free(saveCursor);
aDatabase->AddCardRowToDB(newRow);
if (bIsList)
aDatabase->AddListDirNode(newRow);
// Clear buffer for next record
ClearLdifRecordBuffer();
}
void nsAbLDIFService::AddLdifColToDatabase(nsIAddrDatabase *aDatabase,
nsIMdbRow* newRow, char* typeSlot,
char* valueSlot, bool bIsList)
{
nsAutoCString colType(typeSlot);
nsAutoCString column(valueSlot);
// 4.x exports attributes like "givenname",
// mozilla does "givenName" to be compliant with RFC 2798
ToLowerCase(colType);
mdb_u1 firstByte = (mdb_u1)(colType.get())[0];
switch ( firstByte )
{
case 'b':
if (colType.EqualsLiteral("birthyear"))
aDatabase->AddBirthYear(newRow, column.get());
else if (colType.EqualsLiteral("birthmonth"))
aDatabase->AddBirthMonth(newRow, column.get());
else if (colType.EqualsLiteral("birthday"))
aDatabase->AddBirthDay(newRow, column.get());
break; // 'b'
case 'c':
if (colType.EqualsLiteral("cn") || colType.EqualsLiteral("commonname"))
{
if (bIsList)
aDatabase->AddListName(newRow, column.get());
else
aDatabase->AddDisplayName(newRow, column.get());
}
else if (colType.EqualsLiteral("c") || colType.EqualsLiteral("countryname"))
{
if (mStoreLocAsHome )
aDatabase->AddHomeCountry(newRow, column.get());
else
aDatabase->AddWorkCountry(newRow, column.get());
}
else if (colType.EqualsLiteral("cellphone") )
aDatabase->AddCellularNumber(newRow, column.get());
else if (colType.EqualsLiteral("carphone"))
aDatabase->AddCellularNumber(newRow, column.get());
else if (colType.EqualsLiteral("custom1"))
aDatabase->AddCustom1(newRow, column.get());
else if (colType.EqualsLiteral("custom2"))
aDatabase->AddCustom2(newRow, column.get());
else if (colType.EqualsLiteral("custom3"))
aDatabase->AddCustom3(newRow, column.get());
else if (colType.EqualsLiteral("custom4"))
aDatabase->AddCustom4(newRow, column.get());
else if (colType.EqualsLiteral("company"))
aDatabase->AddCompany(newRow, column.get());
break; // 'c'
case 'd':
if (colType.EqualsLiteral("description"))
{
if (bIsList)
aDatabase->AddListDescription(newRow, column.get());
else
aDatabase->AddNotes(newRow, column.get());
}
else if (colType.EqualsLiteral("department"))
aDatabase->AddDepartment(newRow, column.get());
else if (colType.EqualsLiteral("displayname"))
{
if (bIsList)
aDatabase->AddListName(newRow, column.get());
else
aDatabase->AddDisplayName(newRow, column.get());
}
break; // 'd'
case 'f':
if (colType.EqualsLiteral("fax") ||
colType.EqualsLiteral("facsimiletelephonenumber"))
aDatabase->AddFaxNumber(newRow, column.get());
break; // 'f'
case 'g':
if (colType.EqualsLiteral("givenname"))
aDatabase->AddFirstName(newRow, column.get());
break; // 'g'
case 'h':
if (colType.EqualsLiteral("homephone"))
aDatabase->AddHomePhone(newRow, column.get());
else if (colType.EqualsLiteral("homestreet"))
aDatabase->AddHomeAddress(newRow, column.get());
else if (colType.EqualsLiteral("homeurl"))
aDatabase->AddWebPage2(newRow, column.get());
break; // 'h'
case 'l':
if (colType.EqualsLiteral("l") || colType.EqualsLiteral("locality"))
{
if (mStoreLocAsHome)
aDatabase->AddHomeCity(newRow, column.get());
else
aDatabase->AddWorkCity(newRow, column.get());
}
// labeledURI contains a URI and, optionally, a label
// This will remove the label and place the URI as the work URL
else if (colType.EqualsLiteral("labeleduri"))
{
int32_t index = column.FindChar(' ');
if (index != -1)
column.SetLength(index);
aDatabase->AddWebPage1(newRow, column.get());
}
break; // 'l'
case 'm':
if (colType.EqualsLiteral("mail"))
aDatabase->AddPrimaryEmail(newRow, column.get());
else if (colType.EqualsLiteral("member") && bIsList)
aDatabase->AddLdifListMember(newRow, column.get());
else if (colType.EqualsLiteral("mobile"))
aDatabase->AddCellularNumber(newRow, column.get());
else if (colType.EqualsLiteral("mozilla_aimscreenname"))
aDatabase->AddAimScreenName(newRow, column.get());
else if (colType.EqualsLiteral("mozillacustom1"))
aDatabase->AddCustom1(newRow, column.get());
else if (colType.EqualsLiteral("mozillacustom2"))
aDatabase->AddCustom2(newRow, column.get());
else if (colType.EqualsLiteral("mozillacustom3"))
aDatabase->AddCustom3(newRow, column.get());
else if (colType.EqualsLiteral("mozillacustom4"))
aDatabase->AddCustom4(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomecountryname"))
aDatabase->AddHomeCountry(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomelocalityname"))
aDatabase->AddHomeCity(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomestate"))
aDatabase->AddHomeState(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomestreet"))
aDatabase->AddHomeAddress(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomestreet2"))
aDatabase->AddHomeAddress2(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomepostalcode"))
aDatabase->AddHomeZipCode(newRow, column.get());
else if (colType.EqualsLiteral("mozillahomeurl"))
aDatabase->AddWebPage2(newRow, column.get());
else if (colType.EqualsLiteral("mozillanickname"))
{
if (bIsList)
aDatabase->AddListNickName(newRow, column.get());
else
aDatabase->AddNickName(newRow, column.get());
}
else if (colType.EqualsLiteral("mozillasecondemail"))
aDatabase->Add2ndEmail(newRow, column.get());
else if (colType.EqualsLiteral("mozillausehtmlmail"))
{
ToLowerCase(column);
if (-1 != column.Find("true"))
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
else if (-1 != column.Find("false"))
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
else
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
}
else if (colType.EqualsLiteral("mozillaworkstreet2"))
aDatabase->AddWorkAddress2(newRow, column.get());
else if (colType.EqualsLiteral("mozillaworkurl"))
aDatabase->AddWebPage1(newRow, column.get());
break; // 'm'
case 'n':
if (colType.EqualsLiteral("notes"))
aDatabase->AddNotes(newRow, column.get());
else if (colType.EqualsLiteral("nscpaimscreenname") ||
colType.EqualsLiteral("nsaimid"))
aDatabase->AddAimScreenName(newRow, column.get());
break; // 'n'
case 'o':
if (colType.EqualsLiteral("objectclass"))
break;
else if (colType.EqualsLiteral("ou") || colType.EqualsLiteral("orgunit"))
aDatabase->AddDepartment(newRow, column.get());
else if (colType.EqualsLiteral("o")) // organization
aDatabase->AddCompany(newRow, column.get());
break; // 'o'
case 'p':
if (colType.EqualsLiteral("postalcode"))
{
if (mStoreLocAsHome)
aDatabase->AddHomeZipCode(newRow, column.get());
else
aDatabase->AddWorkZipCode(newRow, column.get());
}
else if (colType.EqualsLiteral("postofficebox"))
{
nsAutoCString workAddr1, workAddr2;
SplitCRLFAddressField(column, workAddr1, workAddr2);
aDatabase->AddWorkAddress(newRow, workAddr1.get());
aDatabase->AddWorkAddress2(newRow, workAddr2.get());
}
else if (colType.EqualsLiteral("pager") || colType.EqualsLiteral("pagerphone"))
aDatabase->AddPagerNumber(newRow, column.get());
break; // 'p'
case 'r':
if (colType.EqualsLiteral("region"))
{
aDatabase->AddWorkState(newRow, column.get());
}
break; // 'r'
case 's':
if (colType.EqualsLiteral("sn") || colType.EqualsLiteral("surname"))
aDatabase->AddLastName(newRow, column.get());
else if (colType.EqualsLiteral("street"))
aDatabase->AddWorkAddress(newRow, column.get());
else if (colType.EqualsLiteral("streetaddress"))
{
nsAutoCString addr1, addr2;
SplitCRLFAddressField(column, addr1, addr2);
if (mStoreLocAsHome)
{
aDatabase->AddHomeAddress(newRow, addr1.get());
aDatabase->AddHomeAddress2(newRow, addr2.get());
}
else
{
aDatabase->AddWorkAddress(newRow, addr1.get());
aDatabase->AddWorkAddress2(newRow, addr2.get());
}
}
else if (colType.EqualsLiteral("st"))
{
if (mStoreLocAsHome)
aDatabase->AddHomeState(newRow, column.get());
else
aDatabase->AddWorkState(newRow, column.get());
}
break; // 's'
case 't':
if (colType.EqualsLiteral("title"))
aDatabase->AddJobTitle(newRow, column.get());
else if (colType.EqualsLiteral("telephonenumber") )
{
aDatabase->AddWorkPhone(newRow, column.get());
}
break; // 't'
case 'u':
if (colType.EqualsLiteral("uniquemember") && bIsList)
aDatabase->AddLdifListMember(newRow, column.get());
break; // 'u'
case 'w':
if (colType.EqualsLiteral("workurl"))
aDatabase->AddWebPage1(newRow, column.get());
break; // 'w'
case 'x':
if (colType.EqualsLiteral("xmozillanickname"))
{
if (bIsList)
aDatabase->AddListNickName(newRow, column.get());
else
aDatabase->AddNickName(newRow, column.get());
}
else if (colType.EqualsLiteral("xmozillausehtmlmail"))
{
ToLowerCase(column);
if (-1 != column.Find("true"))
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
else if (-1 != column.Find("false"))
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::plaintext);
else
aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::unknown);
}
break; // 'x'
case 'z':
if (colType.EqualsLiteral("zip")) // alias for postalcode
{
if (mStoreLocAsHome)
aDatabase->AddHomeZipCode(newRow, column.get());
else
aDatabase->AddWorkZipCode(newRow, column.get());
}
break; // 'z'
default:
break; // default
}
}
void nsAbLDIFService::ClearLdifRecordBuffer()
{
if (!mLdifLine.IsEmpty())
{
mLdifLine.Truncate();
mLFCount = 0;
mCRCount = 0;
}
}
// Some common ldif fields, it an ldif file has NONE of these entries
// then it is most likely NOT an ldif file!
static const char *const sLDIFFields[] = {
"objectclass",
"sn",
"dn",
"cn",
"givenName",
"mail",
nullptr
};
#define kMaxLDIFLen 14
// Count total number of legal ldif fields and records in the first 100 lines of the
// file and if the average legal ldif field is 3 or higher than it's a valid ldif file.
NS_IMETHODIMP nsAbLDIFService::IsLDIFFile(nsIFile *pSrc, bool *_retval)
{
NS_ENSURE_ARG_POINTER(pSrc);
NS_ENSURE_ARG_POINTER(_retval);
*_retval = false;
nsresult rv = NS_OK;
nsCOMPtr<nsIInputStream> fileStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), pSrc);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILineInputStream> lineInputStream(do_QueryInterface(fileStream, &rv));
NS_ENSURE_SUCCESS(rv, rv);
int32_t lineLen = 0;
int32_t lineCount = 0;
int32_t ldifFields = 0; // total number of legal ldif fields.
char field[kMaxLDIFLen];
int32_t fLen = 0;
const char *pChar;
int32_t recCount = 0; // total number of records.
int32_t i;
bool gotLDIF = false;
bool more = true;
nsCString line;
while (more && NS_SUCCEEDED(rv) && (lineCount < 100))
{
rv = lineInputStream->ReadLine(line, &more);
if (NS_SUCCEEDED(rv) && more)
{
pChar = line.get();
lineLen = line.Length();
if (!lineLen && gotLDIF)
{
recCount++;
gotLDIF = false;
}
if (lineLen && (*pChar != ' ') && (*pChar != '\t'))
{
fLen = 0;
while (lineLen && (fLen < (kMaxLDIFLen - 1)) && (*pChar != ':'))
{
field[fLen] = *pChar;
pChar++;
fLen++;
lineLen--;
}
field[fLen] = 0;
if (lineLen && (*pChar == ':') && (fLen < (kMaxLDIFLen - 1)))
{
// see if this is an ldif field (case insensitive)?
i = 0;
while (sLDIFFields[i])
{
if (!PL_strcasecmp( sLDIFFields[i], field))
{
ldifFields++;
gotLDIF = true;
break;
}
i++;
}
}
}
}
lineCount++;
}
// If we just saw ldif address, increment recCount.
if (gotLDIF)
recCount++;
rv = fileStream->Close();
if (recCount > 1)
ldifFields /= recCount;
// If the average field number >= 3 then it's a good ldif file.
if (ldifFields >= 3)
{
*_retval = true;
}
return rv;
}
void nsAbLDIFService::SplitCRLFAddressField(nsCString &inputAddress, nsCString &outputLine1, nsCString &outputLine2) const
{
int32_t crlfPos = inputAddress.Find("\r\n");
if (crlfPos != -1)
{
outputLine1 = Substring(inputAddress, 0, crlfPos);
outputLine2 = Substring(inputAddress, crlfPos + 2);
}
else
outputLine1.Assign(inputAddress);
}

View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; 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/. */
#ifndef __nsAbLDIFService_h
#define __nsAbLDIFService_h
#include "nsIAbLDIFService.h"
#include "nsCOMPtr.h"
class nsIMdbRow;
class nsAbLDIFService : public nsIAbLDIFService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABLDIFSERVICE
nsAbLDIFService();
private:
virtual ~nsAbLDIFService();
nsresult str_parse_line(char *line, char **type, char **value, int *vlen) const;
char * str_getline(char **next) const;
nsresult GetLdifStringRecord(char* buf, int32_t len, int32_t& stopPos);
void AddLdifRowToDatabase(nsIAddrDatabase *aDatabase, bool aIsList);
void AddLdifColToDatabase(nsIAddrDatabase *aDatabase, nsIMdbRow* newRow,
char* typeSlot, char* valueSlot, bool bIsList);
void ClearLdifRecordBuffer();
void SplitCRLFAddressField(nsCString &inputAddress, nsCString &outputLine1, nsCString &outputLine2) const;
bool mStoreLocAsHome;
nsCString mLdifLine;
int32_t mLFCount;
int32_t mCRCount;
};
#endif

View file

@ -0,0 +1,55 @@
/* -*- Mode: C++; 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/. */
#include "nsAbMDBCard.h"
nsAbMDBCard::nsAbMDBCard(void)
{
}
nsAbMDBCard::~nsAbMDBCard(void)
{
}
NS_IMPL_ISUPPORTS_INHERITED0(nsAbMDBCard, nsAbCardProperty)
NS_IMETHODIMP nsAbMDBCard::Equals(nsIAbCard *card, bool *result)
{
NS_ENSURE_ARG_POINTER(card);
NS_ENSURE_ARG_POINTER(result);
if (this == card) {
*result = true;
return NS_OK;
}
// If we have the same directory, we will equal the other card merely given
// the row IDs. If not, we are never equal. But we are dumb in that we don't
// know who our directory is, which may change in the future. For now,
// however, the only known users of this method are for locating us in a list
// of cards, most commonly mailing lists; a warning on the IDL has also
// notified consumers that this method is not generally safe to use. In this
// respect, it is safe to assume that the directory portion is satisfied when
// making this call.
// However, if we make the wrong assumption, one of two things will happen.
// If the other directory is a local address book, we could return a spurious
// true result. If not, then DbRowID should be unset and we can definitively
// return false.
uint32_t row;
nsresult rv = card->GetPropertyAsUint32("DbRowID", &row);
if (NS_FAILED(rv))
{
*result = false;
return NS_OK;
}
uint32_t ourRow;
rv = GetPropertyAsUint32("DbRowID", &ourRow);
NS_ENSURE_SUCCESS(rv, rv);
*result = (row == ourRow);
return NS_OK;
}

View file

@ -0,0 +1,26 @@
/* -*- Mode: C++; 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/. */
#ifndef nsAbMDBCard_h__
#define nsAbMDBCard_h__
#include "mozilla/Attributes.h"
#include "nsAbCardProperty.h"
#include "nsCOMPtr.h"
class nsAbMDBCard: public nsAbCardProperty
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsAbMDBCard(void);
NS_IMETHOD Equals(nsIAbCard *card, bool *result) override;
private:
virtual ~nsAbMDBCard();
};
#endif

View file

@ -0,0 +1,118 @@
/* -*- Mode: C++; 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/. */
#include "nsAbMDBDirFactory.h"
#include "nsAbUtils.h"
#include "nsStringGlue.h"
#include "nsServiceManagerUtils.h"
#include "nsIFile.h"
#include "nsIAbManager.h"
#include "nsIAbMDBDirectory.h"
#include "nsAbMDBDirFactory.h"
#include "nsIAddrDBListener.h"
#include "nsIAddrDatabase.h"
#include "nsEnumeratorUtils.h"
#include "nsIMutableArray.h"
#include "nsArrayUtils.h"
#include "nsAbBaseCID.h"
NS_IMPL_ISUPPORTS(nsAbMDBDirFactory, nsIAbDirFactory)
nsAbMDBDirFactory::nsAbMDBDirFactory()
{
}
nsAbMDBDirFactory::~nsAbMDBDirFactory()
{
}
NS_IMETHODIMP nsAbMDBDirFactory::GetDirectories(const nsAString &aDirName,
const nsACString &aURI,
const nsACString &aPrefName,
nsISimpleEnumerator **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
nsresult rv;
nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectory> directory;
rv = abManager->GetDirectory(aURI, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
rv = directory->SetDirPrefId(aPrefName);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> dbPath;
rv = abManager->GetUserProfileDirectory(getter_AddRefs(dbPath));
nsCOMPtr<nsIAddrDatabase> listDatabase;
if (NS_SUCCEEDED(rv))
{
nsAutoCString fileName;
if (StringBeginsWith(aURI, NS_LITERAL_CSTRING(kMDBDirectoryRoot)))
fileName = Substring(aURI, kMDBDirectoryRootLen, aURI.Length() - kMDBDirectoryRootLen);
rv = dbPath->AppendNative(fileName);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAddrDatabase> addrDBFactory = do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = addrDBFactory->Open(dbPath, true, true, getter_AddRefs(listDatabase));
}
NS_ENSURE_SUCCESS(rv, rv);
rv = listDatabase->GetMailingListsFromDB(directory);
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewSingletonEnumerator(_retval, directory);
}
/* void deleteDirectory (in nsIAbDirectory directory); */
NS_IMETHODIMP nsAbMDBDirFactory::DeleteDirectory(nsIAbDirectory *directory)
{
if (!directory)
return NS_ERROR_NULL_POINTER;
nsresult rv = NS_OK;
nsCOMPtr<nsIMutableArray> pAddressLists;
rv = directory->GetAddressLists(getter_AddRefs(pAddressLists));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t total;
rv = pAddressLists->GetLength(&total);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0; i < total; i++)
{
nsCOMPtr<nsIAbDirectory> listDir(do_QueryElementAt(pAddressLists, i, &rv));
if (NS_FAILED(rv))
break;
nsCOMPtr<nsIAbMDBDirectory> dblistDir(do_QueryInterface(listDir, &rv));
if (NS_FAILED(rv))
break;
rv = directory->DeleteDirectory(listDir);
if (NS_FAILED(rv))
break;
rv = dblistDir->RemoveElementsFromAddressList();
if (NS_FAILED(rv))
break;
}
pAddressLists->Clear();
nsCOMPtr<nsIAbMDBDirectory> dbdirectory(do_QueryInterface(directory, &rv));
NS_ENSURE_SUCCESS(rv, rv);
return dbdirectory->ClearDatabase();
}

View file

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsAbMDBDirFactory_h__
#define nsAbMDBDirFactory_h__
#include "nsIAbDirFactory.h"
class nsAbMDBDirFactory : public nsIAbDirFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRFACTORY
nsAbMDBDirFactory();
private:
virtual ~nsAbMDBDirFactory();
};
#endif

View file

@ -0,0 +1,145 @@
/* -*- Mode: C++; 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/. */
#include "nsAbMDBDirProperty.h"
#include "nsIServiceManager.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
#include "nsAbBaseCID.h"
#include "nsAddrDatabase.h"
#include "nsIAbCard.h"
#include "nsIAbListener.h"
#include "nsArrayUtils.h"
#include "mdb.h"
#include "nsComponentManagerUtils.h"
nsAbMDBDirProperty::nsAbMDBDirProperty(void)
: nsAbDirProperty()
{
m_dbRowID = 0;
}
nsAbMDBDirProperty::~nsAbMDBDirProperty(void)
{
}
NS_IMPL_ISUPPORTS_INHERITED(nsAbMDBDirProperty, nsAbDirProperty,
nsIAbDirectory,
nsISupportsWeakReference, nsIAbMDBDirectory)
////////////////////////////////////////////////////////////////////////////////
// nsIAbMDBDirectory attributes
NS_IMETHODIMP nsAbMDBDirProperty::GetDbRowID(uint32_t *aDbRowID)
{
*aDbRowID = m_dbRowID;
return NS_OK;
}
NS_IMETHODIMP nsAbMDBDirProperty::SetDbRowID(uint32_t aDbRowID)
{
m_dbRowID = aDbRowID;
return NS_OK;
}
// nsIAbMDBDirectory methods
/* add mailing list to the parent directory */
NS_IMETHODIMP nsAbMDBDirProperty::AddMailListToDirectory(nsIAbDirectory *mailList)
{
if (!m_AddressList)
{
nsresult rv;
m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
uint32_t position;
if (NS_FAILED(m_AddressList->IndexOf(0, mailList, &position)))
m_AddressList->AppendElement(mailList, false);
return NS_OK;
}
/* add addresses to the mailing list */
NS_IMETHODIMP nsAbMDBDirProperty::AddAddressToList(nsIAbCard *card)
{
if (!m_AddressList)
{
nsresult rv;
m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
uint32_t position;
if (NS_FAILED(m_AddressList->IndexOf(0, card, &position)))
m_AddressList->AppendElement(card, false);
return NS_OK;
}
NS_IMETHODIMP nsAbMDBDirProperty::CopyDBMailList(nsIAbMDBDirectory* srcListDB)
{
nsresult err = NS_OK;
nsCOMPtr<nsIAbDirectory> srcList(do_QueryInterface(srcListDB));
if (NS_FAILED(err))
return NS_ERROR_NULL_POINTER;
CopyMailList (srcList);
uint32_t rowID;
srcListDB->GetDbRowID(&rowID);
SetDbRowID(rowID);
return NS_OK;
}
// nsIAbMDBDirectory NOT IMPLEMENTED methods
/* nsIAbDirectory addDirectory (in string uriName); */
NS_IMETHODIMP nsAbMDBDirProperty::AddDirectory(const char *uriName, nsIAbDirectory **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [noscript] void removeElementsFromAddressList (); */
NS_IMETHODIMP nsAbMDBDirProperty::RemoveElementsFromAddressList()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void removeEmailAddressAt (in unsigned long aIndex); */
NS_IMETHODIMP nsAbMDBDirProperty::RemoveEmailAddressAt(uint32_t aIndex)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [noscript] void notifyDirItemAdded (in nsISupports item); */
NS_IMETHODIMP nsAbMDBDirProperty::NotifyDirItemAdded(nsISupports *item)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* [noscript] void clearDatabase (); */
NS_IMETHODIMP nsAbMDBDirProperty::ClearDatabase()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsAbMDBDirProperty::GetDatabaseFile(nsIFile **aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsAbMDBDirProperty::GetDatabase(nsIAddrDatabase **aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

Some files were not shown because too many files have changed in this diff Show more