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,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;
}

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/. */
/********************************************************************************************************
Interface for representing Address Book Directory
*********************************************************************************************************/
#ifndef nsAbMDBDirProperty_h__
#define nsAbMDBDirProperty_h__
#include "nsIAbMDBDirectory.h"
#include "nsAbDirProperty.h"
#include "nsIAbCard.h"
#include "nsCOMPtr.h"
#include "nsDirPrefs.h"
#include "nsIAddrDatabase.h"
/*
* Address Book Directory
*/
class nsAbMDBDirProperty: public nsIAbMDBDirectory, public nsAbDirProperty
{
public:
nsAbMDBDirProperty(void);
NS_DECL_ISUPPORTS
NS_DECL_NSIABMDBDIRECTORY
protected:
virtual ~nsAbMDBDirProperty();
uint32_t m_dbRowID;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
/* -*- 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 nsAbMDBDirectory_h__
#define nsAbMDBDirectory_h__
#include "mozilla/Attributes.h"
#include "nsAbMDBDirProperty.h"
#include "nsIAbCard.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsDirPrefs.h"
#include "nsIAbDirectorySearch.h"
#include "nsIAbDirSearchListener.h"
#include "nsInterfaceHashtable.h"
#include "nsIAddrDBListener.h"
/*
* Address Book Directory
*/
class nsAbMDBDirectory:
public nsAbMDBDirProperty, // nsIAbDirectory, nsIAbMDBDirectory
public nsIAbDirSearchListener,
public nsIAddrDBListener,
public nsIAbDirectorySearch
{
public:
nsAbMDBDirectory(void);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIADDRDBLISTENER
// Override nsAbMDBDirProperty::Init
NS_IMETHOD Init(const char *aUri) override;
// nsIAbMDBDirectory methods
NS_IMETHOD GetURI(nsACString &aURI) override;
NS_IMETHOD ClearDatabase() override;
NS_IMETHOD NotifyDirItemAdded(nsISupports *item) override { return NotifyItemAdded(item);}
NS_IMETHOD RemoveElementsFromAddressList() override;
NS_IMETHOD RemoveEmailAddressAt(uint32_t aIndex) override;
NS_IMETHOD AddDirectory(const char *uriName, nsIAbDirectory **childDir) override;
NS_IMETHOD GetDatabaseFile(nsIFile **aResult) override;
NS_IMETHOD GetDatabase(nsIAddrDatabase **aResult) override;
// nsIAbDirectory methods:
NS_IMETHOD GetChildNodes(nsISimpleEnumerator* *result) override;
NS_IMETHOD GetChildCards(nsISimpleEnumerator* *result) override;
NS_IMETHOD GetIsQuery(bool *aResult) override;
NS_IMETHOD DeleteDirectory(nsIAbDirectory *directory) override;
NS_IMETHOD DeleteCards(nsIArray *cards) override;
NS_IMETHOD HasCard(nsIAbCard *cards, bool *hasCard) override;
NS_IMETHOD HasDirectory(nsIAbDirectory *dir, bool *hasDir) override;
NS_IMETHOD HasMailListWithName(const char16_t *aName, bool *aHasList) override;
NS_IMETHOD AddMailList(nsIAbDirectory *list, nsIAbDirectory **addedList) override;
NS_IMETHOD AddCard(nsIAbCard *card, nsIAbCard **addedCard) override;
NS_IMETHOD ModifyCard(nsIAbCard *aModifiedCard) override;
NS_IMETHOD DropCard(nsIAbCard *card, bool needToCopyCard) override;
NS_IMETHOD EditMailListToDatabase(nsIAbCard *listCard) override;
NS_IMETHOD CardForEmailAddress(const nsACString &aEmailAddress,
nsIAbCard ** aAbCard) override;
NS_IMETHOD GetCardFromProperty(const char *aProperty,
const nsACString &aValue,
bool caseSensitive, nsIAbCard **result) override;
NS_IMETHOD GetCardsFromProperty(const char *aProperty,
const nsACString &aValue,
bool caseSensitive,
nsISimpleEnumerator **result) override;
// nsIAbDirectorySearch methods
NS_DECL_NSIABDIRECTORYSEARCH
// nsIAbDirSearchListener methods
NS_DECL_NSIABDIRSEARCHLISTENER
protected:
virtual ~nsAbMDBDirectory();
nsresult NotifyPropertyChanged(nsIAbDirectory *list, const char *property, const char16_t* oldValue, const char16_t* newValue);
nsresult NotifyItemAdded(nsISupports *item);
nsresult NotifyItemDeleted(nsISupports *item);
nsresult NotifyItemChanged(nsISupports *item);
nsresult RemoveCardFromAddressList(nsIAbCard* card);
nsresult GetAbDatabase();
nsCOMPtr<nsIAddrDatabase> mDatabase;
nsCOMArray<nsIAbDirectory> mSubDirectories;
int32_t mContext;
bool mPerformingQuery;
nsInterfaceHashtable<nsISupportsHashKey, nsIAbCard> mSearchCache;
};
#endif

File diff suppressed because it is too large Load diff

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/. */
#ifndef __nsAbManager_h
#define __nsAbManager_h
#include "nsIAbManager.h"
#include "nsTObserverArray.h"
#include "nsCOMPtr.h"
#include "nsICommandLineHandler.h"
#include "nsIObserver.h"
#include "nsInterfaceHashtable.h"
#include "nsIAbDirFactoryService.h"
#include "nsIAbDirectory.h"
class nsIAbLDAPAttributeMap;
class nsAbManager : public nsIAbManager,
public nsICommandLineHandler,
public nsIObserver
{
public:
nsAbManager();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIABMANAGER
NS_DECL_NSIOBSERVER
NS_DECL_NSICOMMANDLINEHANDLER
nsresult Init();
private:
virtual ~nsAbManager();
nsresult GetRootDirectory(nsIAbDirectory **aResult);
nsresult ExportDirectoryToDelimitedText(nsIAbDirectory *aDirectory, const char *aDelim,
uint32_t aDelimLen, nsIFile *aLocalFile, bool useUTF8);
nsresult ExportDirectoryToVCard(nsIAbDirectory *aDirectory, nsIFile *aLocalFile);
nsresult ExportDirectoryToLDIF(nsIAbDirectory *aDirectory, nsIFile *aLocalFile);
nsresult AppendLDIFForMailList(nsIAbCard *aCard, nsIAbLDAPAttributeMap *aAttrMap, nsACString &aResult);
nsresult AppendDNForCard(const char *aProperty, nsIAbCard *aCard, nsIAbLDAPAttributeMap *aAttrMap, nsACString &aResult);
nsresult AppendBasicLDIFForCard(nsIAbCard *aCard, nsIAbLDAPAttributeMap *aAttrMap, nsACString &aResult);
nsresult AppendProperty(const char *aProperty, const char16_t *aValue, nsACString &aResult);
bool IsSafeLDIFString(const char16_t *aStr);
struct abListener {
nsCOMPtr<nsIAbListener> mListener;
uint32_t mNotifyFlags;
abListener(nsIAbListener *aListener, uint32_t aNotifyFlags)
: mListener(aListener), mNotifyFlags(aNotifyFlags) {}
abListener(const abListener &aListener)
: mListener(aListener.mListener), mNotifyFlags(aListener.mNotifyFlags) {}
~abListener() {}
int operator==(nsIAbListener* aListener) const {
return mListener == aListener;
}
int operator==(const abListener &aListener) const {
return mListener == aListener.mListener;
}
};
nsTObserverArray<abListener> mListeners;
nsCOMPtr<nsIAbDirectory> mCacheTopLevelAb;
nsInterfaceHashtable<nsCStringHashKey, nsIAbDirectory> mAbStore;
};
#endif

View file

@ -0,0 +1,47 @@
/* -*- 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 nsAbOSXCard_h___
#define nsAbOSXCard_h___
#include "mozilla/Attributes.h"
#include "nsAbCardProperty.h"
#define NS_ABOSXCARD_URI_PREFIX NS_ABOSXCARD_PREFIX "://"
#define NS_IABOSXCARD_IID \
{ 0xa7e5b697, 0x772d, 0x4fb5, \
{ 0x81, 0x16, 0x23, 0xb7, 0x5a, 0xac, 0x94, 0x56 } }
class nsIAbOSXCard : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IABOSXCARD_IID)
virtual nsresult Init(const char *aUri) = 0;
virtual nsresult Update(bool aNotify) = 0;
virtual nsresult GetURI(nsACString &aURI) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAbOSXCard, NS_IABOSXCARD_IID)
class nsAbOSXCard : public nsAbCardProperty,
public nsIAbOSXCard
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsresult Update(bool aNotify) override;
nsresult GetURI(nsACString &aURI) override;
nsresult Init(const char *aUri) override;
// this is needed so nsAbOSXUtils.mm can get at nsAbCardProperty
friend class nsAbOSXUtils;
private:
nsCString mURI;
virtual ~nsAbOSXCard() {}
};
#endif // nsAbOSXCard_h___

View file

@ -0,0 +1,401 @@
/* -*- 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 "nsAbOSXCard.h"
#include "nsAbOSXDirectory.h"
#include "nsAbOSXUtils.h"
#include "nsAutoPtr.h"
#include "nsIAbManager.h"
#include "nsObjCExceptions.h"
#include "nsServiceManagerUtils.h"
#include <AddressBook/AddressBook.h>
NS_IMPL_ISUPPORTS_INHERITED(nsAbOSXCard,
nsAbCardProperty,
nsIAbOSXCard)
#ifdef DEBUG
static ABPropertyType
GetPropertType(ABRecord *aCard, NSString *aProperty)
{
ABPropertyType propertyType = kABErrorInProperty;
if ([aCard isKindOfClass:[ABPerson class]])
propertyType = [ABPerson typeOfProperty:aProperty];
else if ([aCard isKindOfClass:[ABGroup class]])
propertyType = [ABGroup typeOfProperty:aProperty];
return propertyType;
}
#endif
static void
SetStringProperty(nsAbOSXCard *aCard, const nsString &aValue,
const char *aMemberName, bool aNotify,
nsIAbManager *aAbManager)
{
nsString oldValue;
nsresult rv = aCard->GetPropertyAsAString(aMemberName, oldValue);
if (NS_FAILED(rv))
oldValue.Truncate();
if (!aNotify) {
aCard->SetPropertyAsAString(aMemberName, aValue);
}
else if (!oldValue.Equals(aValue)) {
aCard->SetPropertyAsAString(aMemberName, aValue);
nsISupports *supports = NS_ISUPPORTS_CAST(nsAbCardProperty*, aCard);
aAbManager->NotifyItemPropertyChanged(supports, aMemberName,
oldValue.get(), aValue.get());
}
}
static void
SetStringProperty(nsAbOSXCard *aCard, NSString *aValue, const char *aMemberName,
bool aNotify, nsIAbManager *aAbManager)
{
nsAutoString value;
if (aValue)
AppendToString(aValue, value);
SetStringProperty(aCard, value, aMemberName, aNotify, aAbManager);
}
static void
MapStringProperty(nsAbOSXCard *aCard, ABRecord *aOSXCard, NSString *aProperty,
const char *aMemberName, bool aNotify,
nsIAbManager *aAbManager)
{
NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
NS_ASSERTION(GetPropertType(aOSXCard, aProperty) == kABStringProperty,
"Wrong type!");
SetStringProperty(aCard, [aOSXCard valueForProperty:aProperty], aMemberName,
aNotify, aAbManager);
}
static ABMutableMultiValue*
GetMultiValue(ABRecord *aCard, NSString *aProperty)
{
NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
NS_ASSERTION(GetPropertType(aCard, aProperty) & kABMultiValueMask,
"Wrong type!");
return [aCard valueForProperty:aProperty];
}
static void
MapDate(nsAbOSXCard *aCard, NSDate *aDate, const char *aYearPropName,
const char *aMonthPropName, const char *aDayPropName, bool aNotify,
nsIAbManager *aAbManager)
{
// XXX Should we pass a format and timezone?
NSCalendarDate *date = [aDate dateWithCalendarFormat:nil timeZone:nil];
nsAutoString value;
value.AppendInt(static_cast<int32_t>([date yearOfCommonEra]));
SetStringProperty(aCard, value, aYearPropName, aNotify, aAbManager);
value.Truncate();
value.AppendInt(static_cast<int32_t>([date monthOfYear]));
SetStringProperty(aCard, value, aMonthPropName, aNotify, aAbManager);
value.Truncate();
value.AppendInt(static_cast<int32_t>([date dayOfMonth]));
SetStringProperty(aCard, value, aDayPropName, aNotify, aAbManager);
}
static bool
MapMultiValue(nsAbOSXCard *aCard, ABRecord *aOSXCard,
const nsAbOSXPropertyMap &aMap, bool aNotify,
nsIAbManager *aAbManager)
{
ABMultiValue *value = GetMultiValue(aOSXCard, aMap.mOSXProperty);
if (value) {
unsigned int j;
unsigned int count = [value count];
for (j = 0; j < count; ++j) {
if ([[value labelAtIndex:j] isEqualToString:aMap.mOSXLabel]) {
NSString *stringValue = (aMap.mOSXKey)
? [[value valueAtIndex:j] objectForKey:aMap.mOSXKey]
: [value valueAtIndex:j];
SetStringProperty(aCard, stringValue, aMap.mPropertyName, aNotify,
aAbManager);
return true;
}
}
}
// String wasn't found, set value of card to empty if it was set previously
SetStringProperty(aCard, EmptyString(), aMap.mPropertyName, aNotify,
aAbManager);
return false;
}
// Maps Address Book's instant messenger name to the corresponding nsIAbCard field name.
static const char*
InstantMessengerFieldName(NSString* aInstantMessengerName)
{
if ([aInstantMessengerName isEqualToString:@"AIMInstant"]) {
return "_AimScreenName";
}
if ([aInstantMessengerName isEqualToString:@"GoogleTalkInstant"]) {
return "_GoogleTalk";
}
if ([aInstantMessengerName isEqualToString:@"ICQInstant"]) {
return "_ICQ";
}
if ([aInstantMessengerName isEqualToString:@"JabberInstant"]) {
return "_JabberId";
}
if ([aInstantMessengerName isEqualToString:@"MSNInstant"]) {
return "_MSN";
}
if ([aInstantMessengerName isEqualToString:@"QQInstant"]) {
return "_QQ";
}
if ([aInstantMessengerName isEqualToString:@"SkypeInstant"]) {
return "_Skype";
}
if ([aInstantMessengerName isEqualToString:@"YahooInstant"]) {
return "_Yahoo";
}
// Fall back to AIM for everything else.
// We don't have nsIAbCard fields for FacebookInstant and GaduGaduInstant.
return "_AimScreenName";
}
nsresult
nsAbOSXCard::Init(const char *aUri)
{
if (strncmp(aUri, NS_ABOSXCARD_URI_PREFIX,
sizeof(NS_ABOSXCARD_URI_PREFIX) - 1) != 0)
return NS_ERROR_FAILURE;
mURI = aUri;
SetLocalId(nsDependentCString(aUri));
return Update(false);
}
nsresult
nsAbOSXCard::GetURI(nsACString &aURI)
{
if (mURI.IsEmpty())
return NS_ERROR_NOT_INITIALIZED;
aURI = mURI;
return NS_OK;
}
nsresult
nsAbOSXCard::Update(bool aNotify)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
ABAddressBook *addressBook = [ABAddressBook sharedAddressBook];
const char *uid = &((mURI.get())[16]);
ABRecord *card = [addressBook recordForUniqueId:[NSString stringWithUTF8String:uid]];
NS_ENSURE_TRUE(card, NS_ERROR_FAILURE);
nsCOMPtr<nsIAbManager> abManager;
nsresult rv;
if (aNotify) {
abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
if ([card isKindOfClass:[ABGroup class]]) {
m_IsMailList = true;
m_MailListURI.AssignLiteral(NS_ABOSXDIRECTORY_URI_PREFIX);
m_MailListURI.Append(uid);
MapStringProperty(this, card, kABGroupNameProperty, "DisplayName", aNotify,
abManager);
MapStringProperty(this, card, kABGroupNameProperty, "LastName", aNotify,
abManager);
return NS_OK;
}
bool foundHome = false, foundWork = false;
uint32_t i;
for (i = 0; i < nsAbOSXUtils::kPropertyMapSize; ++i) {
const nsAbOSXPropertyMap &propertyMap = nsAbOSXUtils::kPropertyMap[i];
if (!propertyMap.mOSXProperty)
continue;
if (propertyMap.mOSXLabel) {
if (MapMultiValue(this, card, propertyMap, aNotify,
abManager) && propertyMap.mOSXProperty == kABAddressProperty) {
if (propertyMap.mOSXLabel == kABAddressHomeLabel)
foundHome = true;
else
foundWork = true;
}
}
else {
MapStringProperty(this, card, propertyMap.mOSXProperty,
propertyMap.mPropertyName, aNotify, abManager);
}
}
int flags = 0;
if (kABPersonFlags)
flags = [[card valueForProperty:kABPersonFlags] intValue];
#define SET_STRING(_value, _name, _notify, _session) \
SetStringProperty(this, _value, #_name, _notify, _session)
// If kABShowAsCompany is set we use the company name as display name.
if (kABPersonFlags && (flags & kABShowAsCompany)) {
nsString company;
nsresult rv = GetPropertyAsAString(kCompanyProperty, company);
if (NS_FAILED(rv))
company.Truncate();
SET_STRING(company, DisplayName, aNotify, abManager);
}
else {
// Use the order used in the OS X address book to set DisplayName.
int order = kABPersonFlags && (flags & kABNameOrderingMask);
if (kABPersonFlags && (order == kABDefaultNameOrdering)) {
order = [addressBook defaultNameOrdering];
}
nsAutoString displayName, tempName;
if (kABPersonFlags && (order == kABFirstNameFirst)) {
GetFirstName(tempName);
displayName.Append(tempName);
GetLastName(tempName);
// Only append a space if the last name and the first name are not empty
if (!tempName.IsEmpty() && !displayName.IsEmpty())
displayName.Append(' ');
displayName.Append(tempName);
}
else {
GetLastName(tempName);
displayName.Append(tempName);
GetFirstName(tempName);
// Only append a space if the last name and the first name are not empty
if (!tempName.IsEmpty() && !displayName.IsEmpty())
displayName.Append(' ');
displayName.Append(tempName);
}
SET_STRING(displayName, DisplayName, aNotify, abManager);
}
ABMultiValue *value = GetMultiValue(card, kABEmailProperty);
if (value) {
unsigned int count = [value count];
if (count > 0) {
unsigned int j = [value indexForIdentifier:[value primaryIdentifier]];
if (j < count)
SET_STRING([value valueAtIndex:j], PrimaryEmail, aNotify,
abManager);
// If j is 0 (first in the list) we want the second in the list
// (index 1), if j is anything else we want the first in the list
// (index 0).
j = (j == 0);
if (j < count)
SET_STRING([value valueAtIndex:j], SecondEmail, aNotify,
abManager);
}
}
// We map the first home address we can find and the first work address
// we can find. If we find none, we map the primary address to the home
// address.
if (!foundHome && !foundWork) {
value = GetMultiValue(card, kABAddressProperty);
if (value) {
unsigned int count = [value count];
unsigned int j = [value indexForIdentifier:[value primaryIdentifier]];
if (j < count) {
NSDictionary *address = [value valueAtIndex:j];
if (address) {
SET_STRING([address objectForKey:kABAddressStreetKey],
HomeAddress, aNotify, abManager);
SET_STRING([address objectForKey:kABAddressCityKey],
HomeCity, aNotify, abManager);
SET_STRING([address objectForKey:kABAddressStateKey],
HomeState, aNotify, abManager);
SET_STRING([address objectForKey:kABAddressZIPKey],
HomeZipCode, aNotify, abManager);
SET_STRING([address objectForKey:kABAddressCountryKey],
HomeCountry, aNotify, abManager);
}
}
}
}
// This was kABAIMInstantProperty previously, but it was deprecated in OS X 10.7.
value = GetMultiValue(card, kABInstantMessageProperty);
if (value) {
unsigned int count = [value count];
for (size_t i = 0; i < count; i++) {
id imValue = [value valueAtIndex:i];
// Depending on the macOS version, imValue can be an NSString or an NSDictionary.
if ([imValue isKindOfClass:[NSString class]]) {
if (i == [value indexForIdentifier:[value primaryIdentifier]]) {
SET_STRING(imValue, _AimScreenName, aNotify, abManager);
}
} else if ([imValue isKindOfClass:[NSDictionary class]]) {
NSString* instantMessageService = [imValue objectForKey:@"InstantMessageService"];
const char* fieldName = InstantMessengerFieldName(instantMessageService);
NSString* userName = [imValue objectForKey:@"InstantMessageUsername"];
SetStringProperty(this, userName, fieldName, aNotify, abManager);
}
}
}
#define MAP_DATE(_date, _name, _notify, _session) \
MapDate(this, _date, #_name"Year", #_name"Month", #_name"Day", _notify, \
_session)
NSDate *date = [card valueForProperty:kABBirthdayProperty];
if (date)
MAP_DATE(date, Birth, aNotify, abManager);
if (kABOtherDatesProperty) {
value = GetMultiValue(card, kABOtherDatesProperty);
if (value) {
unsigned int j, count = [value count];
for (j = 0; j < count; ++j) {
if ([[value labelAtIndex:j] isEqualToString:kABAnniversaryLabel]) {
date = [value valueAtIndex:j];
if (date) {
MAP_DATE(date, Anniversary, aNotify, abManager);
break;
}
}
}
}
}
#undef MAP_DATE
#undef SET_STRING
date = [card valueForProperty:kABModificationDateProperty];
if (date)
SetPropertyAsUint32("LastModifiedDate",
uint32_t([date timeIntervalSince1970]));
// XXX No way to notify about this?
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}

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/. */
#include "nsAbOSXDirFactory.h"
#include "nsAbBaseCID.h"
#include "nsEnumeratorUtils.h"
#include "nsIAbDirectory.h"
#include "nsIAbManager.h"
#include "nsStringGlue.h"
#include "nsServiceManagerUtils.h"
#include "nsAbOSXDirectory.h"
NS_IMPL_ISUPPORTS(nsAbOSXDirFactory, nsIAbDirFactory)
NS_IMETHODIMP
nsAbOSXDirFactory::GetDirectories(const nsAString &aDirName,
const nsACString &aURI,
const nsACString &aPrefName,
nsISimpleEnumerator **aDirectories)
{
NS_ENSURE_ARG_POINTER(aDirectories);
*aDirectories = nullptr;
nsresult rv;
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectory> directory;
rv = abManager->GetDirectory(NS_LITERAL_CSTRING(NS_ABOSXDIRECTORY_URI_PREFIX "/"),
getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbOSXDirectory> osxDirectory(do_QueryInterface(directory, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = osxDirectory->AssertChildNodes();
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewSingletonEnumerator(aDirectories, osxDirectory);
}
// No actual deletion, since you cannot create the address books from Mozilla.
NS_IMETHODIMP
nsAbOSXDirFactory::DeleteDirectory(nsIAbDirectory *aDirectory)
{
return NS_OK;
}

View file

@ -0,0 +1,21 @@
/* -*- 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 nsAbOSXDirFactory_h___
#define nsAbOSXDirFactory_h___
#include "nsIAbDirFactory.h"
class nsAbOSXDirFactory final : public nsIAbDirFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRFACTORY
private:
~nsAbOSXDirFactory() {}
};
#endif // nsAbOSXDirFactory_h___

View file

@ -0,0 +1,126 @@
/* -*- 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 nsAbOSXDirectory_h___
#define nsAbOSXDirectory_h___
#include "mozilla/Attributes.h"
#include "nsISupports.h"
#include "nsAbBaseCID.h"
#include "nsAbDirProperty.h"
#include "nsIAbDirectoryQuery.h"
#include "nsIAbDirectorySearch.h"
#include "nsIAbDirSearchListener.h"
#include "nsIMutableArray.h"
#include "nsInterfaceHashtable.h"
#include "nsAbOSXCard.h"
#include <CoreFoundation/CoreFoundation.h>
class nsIAbManager;
class nsIAbBooleanExpression;
#define NS_ABOSXDIRECTORY_URI_PREFIX NS_ABOSXDIRECTORY_PREFIX "://"
#define NS_IABOSXDIRECTORY_IID \
{ 0x87ee4bd9, 0x8552, 0x498f, \
{ 0x80, 0x85, 0x34, 0xf0, 0x2a, 0xbb, 0x56, 0x16 } }
class nsIAbOSXDirectory : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IABOSXDIRECTORY_IID)
virtual nsresult AssertChildNodes() = 0;
virtual nsresult Update() = 0;
virtual nsresult AssertDirectory(nsIAbManager *aManager,
nsIAbDirectory *aDirectory) = 0;
virtual nsresult AssertCard(nsIAbManager *aManager,
nsIAbCard *aCard) = 0;
virtual nsresult UnassertCard(nsIAbManager *aManager,
nsIAbCard *aCard,
nsIMutableArray *aCardList) = 0;
virtual nsresult UnassertDirectory(nsIAbManager *aManager,
nsIAbDirectory *aDirectory) = 0;
virtual nsresult DeleteUid(const nsACString &aUid) = 0;
virtual nsresult GetURI(nsACString &aURI) = 0;
virtual nsresult Init(const char *aUri) = 0;
virtual nsresult GetCardByUri(const nsACString &aUri, nsIAbOSXCard **aResult) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAbOSXDirectory, NS_IABOSXDIRECTORY_IID)
class nsAbOSXDirectory final : public nsAbDirProperty,
public nsIAbDirSearchListener,
public nsIAbOSXDirectory
{
public:
nsAbOSXDirectory();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIABDIRSEARCHLISTENER
// nsIAbOSXDirectory method
NS_IMETHOD Init(const char *aUri) override;
// nsAbDirProperty methods
NS_IMETHOD GetReadOnly(bool *aReadOnly) override;
NS_IMETHOD GetChildCards(nsISimpleEnumerator **aCards) override;
NS_IMETHOD GetChildNodes(nsISimpleEnumerator **aNodes) override;
NS_IMETHOD GetIsQuery(bool *aResult) override;
NS_IMETHOD HasCard(nsIAbCard *aCard, bool *aHasCard) override;
NS_IMETHOD HasDirectory(nsIAbDirectory *aDirectory, bool *aHasDirectory) override;
NS_IMETHOD GetURI(nsACString &aURI) override;
NS_IMETHOD GetCardFromProperty(const char *aProperty,
const nsACString &aValue,
bool caseSensitive,
nsIAbCard **aResult) override;
NS_IMETHOD GetCardsFromProperty(const char *aProperty,
const nsACString &aValue,
bool aCaseSensitive,
nsISimpleEnumerator **aResult) override;
NS_IMETHOD CardForEmailAddress(const nsACString &aEmailAddress,
nsIAbCard **aResult) override;
// nsIAbOSXDirectory
nsresult AssertChildNodes() override;
nsresult AssertDirectory(nsIAbManager *aManager,
nsIAbDirectory *aDirectory) override;
nsresult AssertCard(nsIAbManager *aManager,
nsIAbCard *aCard) override;
nsresult UnassertCard(nsIAbManager *aManager,
nsIAbCard *aCard,
nsIMutableArray *aCardList) override;
nsresult UnassertDirectory(nsIAbManager *aManager,
nsIAbDirectory *aDirectory) override;
nsresult Update() override;
nsresult DeleteUid(const nsACString &aUid) override;
nsresult GetCardByUri(const nsACString &aUri, nsIAbOSXCard **aResult) override;
nsresult GetRootOSXDirectory(nsIAbOSXDirectory **aResult);
private:
~nsAbOSXDirectory();
nsresult FallbackSearch(nsIAbBooleanExpression *aExpression,
nsISimpleEnumerator **aCards);
// This is a list of nsIAbCards, kept separate from m_AddressList because:
// - nsIAbDirectory items that are mailing lists, must keep a list of
// nsIAbCards in m_AddressList, however
// - nsIAbDirectory items that are address books, must keep a list of
// nsIAbDirectory (i.e. mailing lists) in m_AddressList, AND no nsIAbCards.
//
// This wasn't too bad for mork, as that just gets a list from its database,
// but because we store our own copy of the list, we must store a separate
// list of nsIAbCards here. nsIMutableArray is used, because then it is
// interchangeable with m_AddressList.
nsCOMPtr<nsIMutableArray> mCardList;
nsInterfaceHashtable<nsCStringHashKey, nsIAbOSXCard> mCardStore;
nsCOMPtr<nsIAbOSXDirectory> mCacheTopLevelOSXAb;
};
#endif // nsAbOSXDirectory_h___

File diff suppressed because it is too large Load diff

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/. */
#ifndef nsAbOSXUtils_h___
#define nsAbOSXUtils_h___
#include <Foundation/NSString.h>
#include "nsStringGlue.h"
class nsString;
class nsCString;
class nsAbCardProperty;
NSString *WrapString(const nsString &aString);
void AppendToString(const NSString *aString, nsString &aResult);
void AssignToString(const NSString *aString, nsString &aResult);
void AppendToCString(const NSString *aString, nsCString &aResult);
struct nsAbOSXPropertyMap
{
NSString * const mOSXProperty;
NSString * const mOSXLabel;
NSString * const mOSXKey;
const char *mPropertyName;
};
class nsAbOSXUtils
{
public:
static const nsAbOSXPropertyMap kPropertyMap[];
static const uint32_t kPropertyMapSize;
};
#endif // nsAbOSXUtils_h___

View file

@ -0,0 +1,117 @@
/* -*- 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 "nsAbOSXUtils.h"
#include "nsStringGlue.h"
#include "nsAbOSXCard.h"
#include "nsMemory.h"
#include "mozilla/ArrayUtils.h"
using namespace mozilla;
#include <AddressBook/AddressBook.h>
#define kABDepartmentProperty (kABDepartmentProperty ? kABDepartmentProperty : @"ABDepartment")
NSString*
WrapString(const nsString &aString)
{
unichar* chars = reinterpret_cast<unichar*>(const_cast<char16_t*>(aString.get()));
return [NSString stringWithCharacters:chars
length:aString.Length()];
}
void
AppendToString(const NSString *aString, nsString &aResult)
{
if (aString) {
const char *chars = [aString UTF8String];
if (chars) {
aResult.Append(NS_ConvertUTF8toUTF16(chars));
}
}
}
void
AssignToString(const NSString *aString, nsString &aResult)
{
if (aString) {
const char *chars = [aString UTF8String];
if (chars)
CopyUTF8toUTF16(nsDependentCString(chars), aResult);
}
}
void
AppendToCString(const NSString *aString, nsCString &aResult)
{
if (aString) {
const char *chars = [aString UTF8String];
if (chars) {
aResult.Append(chars);
}
}
}
// Some properties can't be easily mapped back and forth.
#define DONT_MAP(moz_name, osx_property, osx_label, osx_key)
#define DEFINE_PROPERTY(moz_name, osx_property, osx_label, osx_key) \
{ osx_property, osx_label, osx_key, #moz_name },
const nsAbOSXPropertyMap nsAbOSXUtils::kPropertyMap[] = {
DEFINE_PROPERTY(FirstName, kABFirstNameProperty, nil, nil)
DEFINE_PROPERTY(LastName, kABLastNameProperty, nil, nil)
DONT_MAP("DisplayName", nil, nil, nil)
DEFINE_PROPERTY(PhoneticFirstName, kABFirstNamePhoneticProperty, nil, nil)
DEFINE_PROPERTY(PhoneticLastName, kABLastNamePhoneticProperty, nil, nil)
DEFINE_PROPERTY(NickName, kABNicknameProperty, nil, nil)
DONT_MAP(PrimaryEmail, kABEmailProperty, nil, nil)
DONT_MAP(SecondEmail, kABEmailProperty, nil, nil)
DEFINE_PROPERTY(WorkPhone, kABPhoneProperty, kABPhoneWorkLabel, nil)
DEFINE_PROPERTY(HomePhone, kABPhoneProperty, kABPhoneHomeLabel, nil)
DEFINE_PROPERTY(FaxNumber, kABPhoneProperty, kABPhoneWorkFAXLabel, nil)
DEFINE_PROPERTY(PagerNumber, kABPhoneProperty, kABPhonePagerLabel, nil)
DEFINE_PROPERTY(CellularNumber, kABPhoneProperty, kABPhoneMobileLabel, nil)
DEFINE_PROPERTY(HomeAddress, kABAddressProperty, kABAddressHomeLabel,
kABAddressStreetKey)
DEFINE_PROPERTY(HomeCity, kABAddressProperty, kABAddressHomeLabel,
kABAddressCityKey)
DEFINE_PROPERTY(HomeState, kABAddressProperty, kABAddressHomeLabel,
kABAddressStateKey)
DEFINE_PROPERTY(HomeZipCode, kABAddressProperty, kABAddressHomeLabel,
kABAddressZIPKey)
DEFINE_PROPERTY(HomeCountry, kABAddressProperty, kABAddressHomeLabel,
kABAddressCountryKey)
DEFINE_PROPERTY(WorkAddress, kABAddressProperty, kABAddressWorkLabel,
kABAddressStreetKey)
DEFINE_PROPERTY(WorkCity, kABAddressProperty, kABAddressWorkLabel,
kABAddressCityKey)
DEFINE_PROPERTY(WorkState, kABAddressProperty, kABAddressWorkLabel,
kABAddressStateKey)
DEFINE_PROPERTY(WorkZipCode, kABAddressProperty, kABAddressWorkLabel,
kABAddressZIPKey)
DEFINE_PROPERTY(WorkCountry, kABAddressProperty, kABAddressWorkLabel,
kABAddressCountryKey)
DEFINE_PROPERTY(JobTitle, kABJobTitleProperty, nil, nil)
DEFINE_PROPERTY(Department, kABDepartmentProperty, nil, nil)
DEFINE_PROPERTY(Company, kABOrganizationProperty, nil, nil)
// This was kABAIMInstantProperty previously, but it was deprecated in OS X 10.7.
DONT_MAP(_AimScreenName, kABInstantMessageProperty, nil, nil)
DEFINE_PROPERTY(WebPage1, kABHomePageProperty, nil, nil)
DONT_MAP(WebPage2, kABHomePageProperty, nil, nil)
DONT_MAP(BirthYear, "birthyear", nil, nil)
DONT_MAP(BirthMonth, "birthmonth", nil, nil)
DONT_MAP(BirthDay, "birthday", nil, nil)
DONT_MAP(Custom1, "custom1", nil, nil)
DONT_MAP(Custom2, "custom2", nil, nil)
DONT_MAP(Custom3, "custom3", nil, nil)
DONT_MAP(Custom4, "custom4", nil, nil)
DEFINE_PROPERTY(Note, kABNoteProperty, nil, nil)
DONT_MAP("PreferMailFormat", nil, nil, nil)
DONT_MAP("LastModifiedDate", modifytimestamp, nil, nil)
};
const uint32_t nsAbOSXUtils::kPropertyMapSize =
ArrayLength(nsAbOSXUtils::kPropertyMap);

View file

@ -0,0 +1,87 @@
/* -*- 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 "nsAbOutlookDirFactory.h"
#include "nsAbWinHelper.h"
#include "nsIAbDirectory.h"
#include "nsIAbManager.h"
#include "nsEnumeratorUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsIMutableArray.h"
#include "nsArrayEnumerator.h"
#include "nsAbBaseCID.h"
#include "mozilla/Logging.h"
#ifdef PR_LOGGING
static PRLogModuleInfo* gAbOutlookDirFactoryLog
= PR_NewLogModule("nsAbOutlookDirFactoryLog");
#endif
#define PRINTF(args) MOZ_LOG(nsAbOutlookDirFactoryLog, mozilla::LogLevel::Debug, args)
NS_IMPL_ISUPPORTS(nsAbOutlookDirFactory, nsIAbDirFactory)
nsAbOutlookDirFactory::nsAbOutlookDirFactory(void)
{
}
nsAbOutlookDirFactory::~nsAbOutlookDirFactory(void)
{
}
extern const char *kOutlookDirectoryScheme;
NS_IMETHODIMP
nsAbOutlookDirFactory::GetDirectories(const nsAString &aDirName,
const nsACString &aURI,
const nsACString &aPrefName,
nsISimpleEnumerator **aDirectories)
{
NS_ENSURE_ARG_POINTER(aDirectories);
*aDirectories = nullptr;
nsresult rv = NS_OK;
nsCString stub;
nsCString entry;
nsAbWinType abType = getAbWinType(kOutlookDirectoryScheme,
nsCString(aURI).get(), stub, entry);
if (abType == nsAbWinType_Unknown) {
return NS_ERROR_FAILURE;
}
nsAbWinHelperGuard mapiAddBook(abType);
nsMapiEntryArray folders;
ULONG nbFolders = 0;
nsCOMPtr<nsIMutableArray> directories(do_CreateInstance(NS_ARRAY_CONTRACTID));
NS_ENSURE_SUCCESS(rv, rv);
if (!mapiAddBook->IsOK() || !mapiAddBook->GetFolders(folders)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString entryId;
nsAutoCString uri;
for (ULONG i = 0; i < folders.mNbEntries; ++i) {
folders.mEntries[i].ToString(entryId);
buildAbWinUri(kOutlookDirectoryScheme, abType, uri);
uri.Append(entryId);
nsCOMPtr<nsIAbDirectory> directory;
rv = abManager->GetDirectory(uri, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
directories->AppendElement(directory, false);
}
return NS_NewArrayEnumerator(aDirectories, directories);
}
// No actual deletion, since you cannot create the address books from Mozilla.
NS_IMETHODIMP nsAbOutlookDirFactory::DeleteDirectory(nsIAbDirectory *aDirectory)
{
return NS_OK;
}

View file

@ -0,0 +1,22 @@
/* -*- 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 nsAbOutlookDirFactory_h___
#define nsAbOutlookDirFactory_h___
#include "nsIAbDirFactory.h"
class nsAbOutlookDirFactory : public nsIAbDirFactory
{
public:
nsAbOutlookDirFactory(void);
NS_DECL_ISUPPORTS
NS_DECL_NSIABDIRFACTORY
private:
virtual ~nsAbOutlookDirFactory(void);
};
#endif // nsAbOutlookDirFactory_h___

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,152 @@
/* -*- 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 nsAbOutlookDirectory_h___
#define nsAbOutlookDirectory_h___
#include "mozilla/Attributes.h"
#include "nsAbDirProperty.h"
#include "nsIAbDirectoryQuery.h"
#include "nsIAbDirectorySearch.h"
#include "nsIAbDirSearchListener.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsIMutableArray.h"
#include "nsAbWinHelper.h"
struct nsMapiEntry ;
class nsAbOutlookDirectory : public nsAbDirProperty, // nsIAbDirectory
public nsIAbDirectoryQuery,
public nsIAbDirectorySearch,
public nsIAbDirSearchListener,
public nsIAbDirectoryQueryResultListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIABDIRSEARCHLISTENER
NS_DECL_NSIABDIRECTORYQUERYRESULTLISTENER
nsAbOutlookDirectory(void);
// nsAbDirProperty methods
NS_IMETHOD GetDirType(int32_t *aDirType) override;
NS_IMETHOD GetURI(nsACString &aURI) override;
NS_IMETHOD GetChildCards(nsISimpleEnumerator **aCards) override;
NS_IMETHOD GetChildNodes(nsISimpleEnumerator **aNodes) override;
NS_IMETHOD GetIsQuery(bool *aResult) override;
NS_IMETHOD HasCard(nsIAbCard *aCard, bool *aHasCard) override;
NS_IMETHOD HasDirectory(nsIAbDirectory *aDirectory, bool *aHasDirectory) override;
NS_IMETHOD DeleteCards(nsIArray *aCardList) override;
NS_IMETHOD DeleteDirectory(nsIAbDirectory *aDirectory) override;
NS_IMETHOD UseForAutocomplete(const nsACString &aIdentityKey, bool *aResult) override;
NS_IMETHOD AddCard(nsIAbCard *aData, nsIAbCard **addedCard) override;
NS_IMETHOD ModifyCard(nsIAbCard *aModifiedCard) override;
NS_IMETHOD DropCard(nsIAbCard *aData, bool needToCopyCard) override;
NS_IMETHOD AddMailList(nsIAbDirectory *aMailList, nsIAbDirectory **addedList) override;
NS_IMETHOD EditMailListToDatabase(nsIAbCard *listCard) override;
// nsAbDirProperty method
NS_IMETHOD Init(const char *aUri) override;
// nsIAbDirectoryQuery methods
NS_DECL_NSIABDIRECTORYQUERY
// nsIAbDirectorySearch methods
NS_DECL_NSIABDIRECTORYSEARCH
// Perform a MAPI query (function executed in a separate thread)
nsresult ExecuteQuery(SRestriction &aRestriction,
nsIAbDirSearchListener *aListener,
int32_t aResultLimit, int32_t aTimeout,
int32_t aThreadId);
protected:
// Retrieve hierarchy as cards, with an optional restriction
nsresult GetChildCards(nsIMutableArray *aCards, void *aRestriction);
// Retrieve hierarchy as directories
nsresult GetChildNodes(nsIMutableArray *aNodes);
// Create a new card
nsresult CreateCard(nsIAbCard *aData, nsIAbCard **aNewCard);
// Notification for the UI
nsresult NotifyItemDeletion(nsISupports *aItem);
nsresult NotifyItemAddition(nsISupports *aItem);
// Force update of MAPI repository for mailing list
nsresult CommitAddressList(void);
// Read MAPI repository
nsresult UpdateAddressList(void);
nsMapiEntry *mMapiData;
// Container for the query threads
nsDataHashtable<nsUint32HashKey, PRThread*> mQueryThreads;
int32_t mCurrentQueryId;
PRLock *mProtector;
// Data for the search interfaces
nsInterfaceHashtable<nsISupportsHashKey, nsIAbCard> mCardList;
int32_t mSearchContext;
// Windows AB type
uint32_t mAbWinType;
private:
virtual ~nsAbOutlookDirectory(void);
};
enum
{
index_DisplayName = 0,
index_EmailAddress,
index_FirstName,
index_LastName,
index_NickName,
index_WorkPhoneNumber,
index_HomePhoneNumber,
index_WorkFaxNumber,
index_PagerNumber,
index_MobileNumber,
index_HomeCity,
index_HomeState,
index_HomeZip,
index_HomeCountry,
index_WorkCity,
index_WorkState,
index_WorkZip,
index_WorkCountry,
index_JobTitle,
index_Department,
index_Company,
index_WorkWebPage,
index_HomeWebPage,
index_Comments,
index_LastProp
};
static const ULONG OutlookCardMAPIProps[] =
{
PR_DISPLAY_NAME_W,
PR_EMAIL_ADDRESS_W,
PR_GIVEN_NAME_W,
PR_SURNAME_W,
PR_NICKNAME_W,
PR_BUSINESS_TELEPHONE_NUMBER_W,
PR_HOME_TELEPHONE_NUMBER_W,
PR_BUSINESS_FAX_NUMBER_W,
PR_PAGER_TELEPHONE_NUMBER_W,
PR_MOBILE_TELEPHONE_NUMBER_W,
PR_HOME_ADDRESS_CITY_W,
PR_HOME_ADDRESS_STATE_OR_PROVINCE_W,
PR_HOME_ADDRESS_POSTAL_CODE_W,
PR_HOME_ADDRESS_COUNTRY_W,
PR_BUSINESS_ADDRESS_CITY_W,
PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W,
PR_BUSINESS_ADDRESS_POSTAL_CODE_W,
PR_BUSINESS_ADDRESS_COUNTRY_W,
PR_TITLE_W,
PR_DEPARTMENT_NAME_W,
PR_COMPANY_NAME_W,
PR_BUSINESS_HOME_PAGE_W,
PR_PERSONAL_HOME_PAGE_W,
PR_COMMENT_W
};
nsresult OutlookCardForURI(const nsACString &aUri, nsIAbCard **card);
#endif // nsAbOutlookDirectory_h___

View file

@ -0,0 +1,337 @@
/* -*- 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 "nsAbQueryStringToExpression.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsITextToSubURI.h"
#include "nsAbBooleanExpression.h"
#include "nsAbBaseCID.h"
#include "plstr.h"
#include "nsIMutableArray.h"
/**
* This code parses the query expression passed in as an addressbook URI.
* The expression takes the form:
* (BOOL1(FIELD1,OP1,VALUE1)..(FIELDn,OPn,VALUEn)(BOOL2(FIELD1,OP1,VALUE1)...)...)
*
* BOOLn A boolean operator joining subsequent terms delimited by ().
* For possible values see CreateBooleanExpression().
* FIELDn An addressbook card data field.
* OPn An operator for the search term.
* For possible values see CreateBooleanConditionString().
* VALUEn The value to be matched in the FIELDn via the OPn operator.
* The value must be URL encoded by the caller, if it contains any special
* characters including '(' and ')'.
*/
nsresult nsAbQueryStringToExpression::Convert (
const nsACString &aQueryString,
nsIAbBooleanExpression** expression)
{
nsresult rv;
nsAutoCString q(aQueryString);
q.StripWhitespace();
const char *queryChars = q.get();
nsCOMPtr<nsISupports> s;
rv = ParseExpression(&queryChars, getter_AddRefs(s));
NS_ENSURE_SUCCESS(rv, rv);
// Case: Not end of string
if (*queryChars != 0)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIAbBooleanExpression> e(do_QueryInterface(s, &rv));
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*expression = e);
return rv;
}
nsresult nsAbQueryStringToExpression::ParseExpression (
const char** index,
nsISupports** expression)
{
nsresult rv;
if (**index != '(')
return NS_ERROR_FAILURE;
const char* indexBracket = *index + 1;
while (*indexBracket &&
*indexBracket != '(' && *indexBracket != ')')
indexBracket++;
// Case: End of string
if (*indexBracket == 0)
return NS_ERROR_FAILURE;
// Case: "((" or "()"
if (indexBracket == *index + 1)
{
return NS_ERROR_FAILURE;
}
// Case: "(*("
else if (*indexBracket == '(')
{
// printf ("Case: (*(: %s\n", *index);
nsCString operation;
rv = ParseOperationEntry (
*index, indexBracket,
getter_Copies (operation));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbBooleanExpression> e;
rv = CreateBooleanExpression(operation.get(),
getter_AddRefs(e));
NS_ENSURE_SUCCESS(rv, rv);
// Case: "(*)(*)....(*))"
*index = indexBracket;
rv = ParseExpressions (index, e);
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*expression = e);
}
// Case" "(*)"
else if (*indexBracket == ')')
{
// printf ("Case: (*): %s\n", *index);
nsCOMPtr<nsIAbBooleanConditionString> conditionString;
rv = ParseCondition (index, indexBracket,
getter_AddRefs(conditionString));
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*expression = conditionString);
}
if (**index != ')')
return NS_ERROR_FAILURE;
(*index)++;
return NS_OK;
}
nsresult nsAbQueryStringToExpression::ParseExpressions (
const char** index,
nsIAbBooleanExpression* expression)
{
nsresult rv;
nsCOMPtr<nsIMutableArray> expressions(do_CreateInstance(NS_ARRAY_CONTRACTID,
&rv));
if (NS_FAILED(rv))
return NS_ERROR_OUT_OF_MEMORY;
// Case: ")(*)(*)....(*))"
// printf ("Case: )(*)(*)....(*)): %s\n", *index);
while (**index == '(')
{
nsCOMPtr<nsISupports> childExpression;
rv = ParseExpression(index, getter_AddRefs (childExpression));
NS_ENSURE_SUCCESS(rv, rv);
expressions->AppendElement(childExpression, false);
}
if (**index == 0)
return NS_ERROR_FAILURE;
// Case: "))"
// printf ("Case: )): %s\n", *index);
if (**index != ')')
return NS_ERROR_FAILURE;
expression->SetExpressions (expressions);
return NS_OK;
}
nsresult nsAbQueryStringToExpression::ParseCondition (
const char** index,
const char* indexBracketClose,
nsIAbBooleanConditionString** conditionString)
{
nsresult rv;
(*index)++;
nsCString entries[3];
for (int i = 0; i < 3; i++)
{
rv = ParseConditionEntry (index, indexBracketClose,
getter_Copies (entries[i]));
NS_ENSURE_SUCCESS(rv, rv);
if (*index == indexBracketClose)
break;
}
if (*index != indexBracketClose)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIAbBooleanConditionString> c;
rv = CreateBooleanConditionString (
entries[0].get(),
entries[1].get(),
entries[2].get(),
getter_AddRefs (c));
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*conditionString = c);
return NS_OK;
}
nsresult nsAbQueryStringToExpression::ParseConditionEntry (
const char** index,
const char* indexBracketClose,
char** entry)
{
const char* indexDeliminator = *index;
while (indexDeliminator != indexBracketClose &&
*indexDeliminator != ',')
indexDeliminator++;
int entryLength = indexDeliminator - *index;
if (entryLength)
*entry = PL_strndup (*index, entryLength);
else
*entry = 0;
if (indexDeliminator != indexBracketClose)
*index = indexDeliminator + 1;
else
*index = indexDeliminator;
return NS_OK;
}
nsresult nsAbQueryStringToExpression::ParseOperationEntry (
const char* indexBracketOpen1,
const char* indexBracketOpen2,
char** operation)
{
int operationLength = indexBracketOpen2 - indexBracketOpen1 - 1;
if (operationLength)
*operation = PL_strndup (indexBracketOpen1 + 1,
operationLength);
else
*operation = 0;
return NS_OK;
}
nsresult nsAbQueryStringToExpression::CreateBooleanExpression(
const char* operation,
nsIAbBooleanExpression** expression)
{
nsAbBooleanOperationType op;
if (PL_strcasecmp (operation, "and") == 0)
op = nsIAbBooleanOperationTypes::AND;
else if (PL_strcasecmp (operation, "or") == 0)
op = nsIAbBooleanOperationTypes::OR;
else if (PL_strcasecmp (operation, "not") == 0)
op = nsIAbBooleanOperationTypes::NOT;
else
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr <nsIAbBooleanExpression> expr = do_CreateInstance(NS_BOOLEANEXPRESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*expression = expr);
rv = expr->SetOperation (op);
return rv;
}
nsresult nsAbQueryStringToExpression::CreateBooleanConditionString (
const char* attribute,
const char* condition,
const char* value,
nsIAbBooleanConditionString** conditionString)
{
if (attribute == 0 || condition == 0 || value == 0)
return NS_ERROR_FAILURE;
nsAbBooleanConditionType c;
if (PL_strcasecmp (condition, "=") == 0)
c = nsIAbBooleanConditionTypes::Is;
else if (PL_strcasecmp (condition, "!=") == 0)
c = nsIAbBooleanConditionTypes::IsNot;
else if (PL_strcasecmp (condition, "lt") == 0)
c = nsIAbBooleanConditionTypes::LessThan;
else if (PL_strcasecmp (condition, "gt") == 0)
c = nsIAbBooleanConditionTypes::GreaterThan;
else if (PL_strcasecmp (condition, "bw") == 0)
c = nsIAbBooleanConditionTypes::BeginsWith;
else if (PL_strcasecmp (condition, "ew") == 0)
c = nsIAbBooleanConditionTypes::EndsWith;
else if (PL_strcasecmp (condition, "c")== 0)
c = nsIAbBooleanConditionTypes::Contains;
else if (PL_strcasecmp (condition, "!c") == 0)
c = nsIAbBooleanConditionTypes::DoesNotContain;
else if (PL_strcasecmp (condition, "~=") == 0)
c = nsIAbBooleanConditionTypes::SoundsLike;
else if (PL_strcasecmp (condition, "regex") == 0)
c = nsIAbBooleanConditionTypes::RegExp;
else
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIAbBooleanConditionString> cs = do_CreateInstance(NS_BOOLEANCONDITIONSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = cs->SetCondition (c);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsITextToSubURI> textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID,&rv);
if (NS_SUCCEEDED(rv))
{
nsString attributeUCS2;
nsString valueUCS2;
rv = textToSubURI->UnEscapeAndConvert("UTF-8",
attribute, getter_Copies(attributeUCS2));
NS_ENSURE_SUCCESS(rv, rv);
rv = textToSubURI->UnEscapeAndConvert("UTF-8",
value, getter_Copies(valueUCS2));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 attributeUTF8(attributeUCS2);
rv = cs->SetName (attributeUTF8.get ());
NS_ENSURE_SUCCESS(rv, rv);
rv = cs->SetValue(valueUCS2.get());
NS_ENSURE_SUCCESS(rv, rv);
}
else
{
NS_ConvertUTF8toUTF16 valueUCS2(value);
rv = cs->SetName (attribute);
NS_ENSURE_SUCCESS(rv, rv);
rv = cs->SetValue (valueUCS2.get ());
NS_ENSURE_SUCCESS(rv, rv);
}
NS_IF_ADDREF(*conditionString = cs);
return NS_OK;
}

View file

@ -0,0 +1,49 @@
/* -*- 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 nsAbQueryStringToExpression_h__
#define nsAbQueryStringToExpression_h__
#include "nsIAbBooleanExpression.h"
class nsAbQueryStringToExpression
{
public:
static nsresult Convert (
const nsACString &aQueryString,
nsIAbBooleanExpression** expression);
protected:
static nsresult ParseExpression (
const char** index,
nsISupports** expression);
static nsresult ParseExpressions (
const char** index,
nsIAbBooleanExpression* expression);
static nsresult ParseCondition (
const char** index,
const char* indexBracketClose,
nsIAbBooleanConditionString** conditionString);
static nsresult ParseConditionEntry (
const char** index,
const char* indexBracketClose,
char** entry);
static nsresult ParseOperationEntry (
const char* indexBracketOpen1,
const char* indexBracketOpen2,
char** operation);
static nsresult CreateBooleanExpression(
const char* operation,
nsIAbBooleanExpression** expression);
static nsresult CreateBooleanConditionString (
const char* attribute,
const char* condition,
const char* value,
nsIAbBooleanConditionString** conditionString);
};
#endif

View file

@ -0,0 +1,140 @@
/* -*- 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 nsAbUtils_h__
#define nsAbUtils_h__
#include "nsMemory.h"
/*
* Wrapper class to automatically free an array of
* char* when class goes out of scope
*/
class CharPtrArrayGuard
{
public:
CharPtrArrayGuard (bool freeElements = true) :
mFreeElements (freeElements),
mArray (0),
mSize (0)
{
}
~CharPtrArrayGuard ()
{
Free ();
}
char* operator[](int i)
{
return mArray[i];
}
uint32_t* GetSizeAddr(void)
{
return &mSize;
}
uint32_t GetSize(void)
{
return mSize;
}
char*** GetArrayAddr(void)
{
return &mArray;
}
const char** GetArray(void)
{
return (const char** ) mArray;
}
public:
private:
bool mFreeElements;
char **mArray;
uint32_t mSize;
void Free ()
{
if (!mArray)
return;
if (mFreeElements)
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mSize, mArray);
else
{
free(mArray);
}
}
};
/*
* Wrapper class to automatically free an array of
* char16_t* when class goes out of scope
*/
class PRUnicharPtrArrayGuard
{
public:
PRUnicharPtrArrayGuard (bool freeElements = true) :
mFreeElements (freeElements),
mArray (0),
mSize (0)
{
}
~PRUnicharPtrArrayGuard ()
{
Free ();
}
char16_t* operator[](int i)
{
return mArray[i];
}
uint32_t* GetSizeAddr(void)
{
return &mSize;
}
uint32_t GetSize(void)
{
return mSize;
}
char16_t*** GetArrayAddr(void)
{
return &mArray;
}
const char16_t** GetArray(void)
{
return (const char16_t** ) mArray;
}
public:
private:
bool mFreeElements;
char16_t **mArray;
uint32_t mSize;
void Free ()
{
if (!mArray)
return;
if (mFreeElements)
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mSize, mArray);
else
{
free(mArray);
}
}
};
#endif /* nsAbUtils_h__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
/* -*- 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 _nsAbView_H_
#define _nsAbView_H_
#include "nsISupports.h"
#include "nsStringGlue.h"
#include "nsIAbView.h"
#include "nsITreeView.h"
#include "nsITreeBoxObject.h"
#include "nsITreeSelection.h"
#include "nsTArray.h"
#include "nsIAbDirectory.h"
#include "nsIAtom.h"
#include "nsICollation.h"
#include "nsIAbListener.h"
#include "nsIObserver.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMemory.h"
#include "nsIStringBundle.h"
typedef struct AbCard
{
nsIAbCard *card;
uint32_t primaryCollationKeyLen;
uint32_t secondaryCollationKeyLen;
uint8_t *primaryCollationKey;
uint8_t *secondaryCollationKey;
} AbCard;
class nsAbView : public nsIAbView, public nsITreeView, public nsIAbListener, public nsIObserver
{
public:
nsAbView();
NS_DECL_ISUPPORTS
NS_DECL_NSIABVIEW
NS_DECL_NSITREEVIEW
NS_DECL_NSIABLISTENER
NS_DECL_NSIOBSERVER
int32_t CompareCollationKeys(uint8_t *key1, uint32_t len1, uint8_t *key2, uint32_t len2);
private:
virtual ~nsAbView();
nsresult Initialize();
int32_t FindIndexForInsert(AbCard *abcard);
int32_t FindIndexForCard(nsIAbCard *card);
nsresult GenerateCollationKeysForCard(const char16_t *colID, AbCard *abcard);
nsresult InvalidateTree(int32_t row);
nsresult RemoveCardAt(int32_t row);
nsresult AddCard(AbCard *abcard, bool selectCardAfterAdding, int32_t *index);
nsresult RemoveCardAndSelectNextCard(nsISupports *item);
nsresult EnumerateCards();
nsresult SetGeneratedNameFormatFromPrefs();
nsresult GetSelectedCards(nsCOMPtr<nsIMutableArray> &aSelectedCards);
nsresult ReselectCards(nsIArray *aCards, nsIAbCard *aIndexCard);
nsresult GetCardValue(nsIAbCard *card, const char16_t *colID, nsAString &_retval);
nsresult RefreshTree();
nsCOMPtr<nsITreeBoxObject> mTree;
nsCOMPtr<nsITreeSelection> mTreeSelection;
nsCOMPtr <nsIAbDirectory> mDirectory;
nsTArray<AbCard*> mCards;
nsString mSortColumn;
nsString mSortDirection;
nsCOMPtr<nsICollation> mCollationKeyGenerator;
nsCOMPtr<nsIAbViewListener> mAbViewListener;
nsCOMPtr<nsIStringBundle> mABBundle;
bool mInitialized;
bool mIsAllDirectoryRootView;
bool mSuppressSelectionChange;
bool mSuppressCountChange;
int32_t mGeneratedNameFormat;
};
#endif /* _nsAbView_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,156 @@
/* -*- 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 nsAbWinHelper_h___
#define nsAbWinHelper_h___
#include <windows.h>
#include <mapix.h>
#include "nsStringGlue.h"
#include "mozilla/Mutex.h"
#include "nsAutoPtr.h"
struct nsMapiEntry
{
ULONG mByteCount ;
LPENTRYID mEntryId ;
nsMapiEntry(void) ;
~nsMapiEntry(void) ;
nsMapiEntry(ULONG aByteCount, LPENTRYID aEntryId) ;
void Assign(ULONG aByteCount, LPENTRYID aEntryId) ;
void Assign(const nsCString& aString) ;
void ToString(nsCString& aString) const ;
void Dump(void) const ;
} ;
struct nsMapiEntryArray
{
nsMapiEntry *mEntries ;
ULONG mNbEntries ;
nsMapiEntryArray(void) ;
~nsMapiEntryArray(void) ;
const nsMapiEntry& operator [] (int aIndex) const { return mEntries [aIndex] ; }
void CleanUp(void) ;
} ;
class nsAbWinHelper
{
public:
nsAbWinHelper(void) ;
virtual ~nsAbWinHelper(void) ;
// Get the top address books
BOOL GetFolders(nsMapiEntryArray& aFolders) ;
// Get a list of entries for cards/mailing lists in a folder/mailing list
BOOL GetCards(const nsMapiEntry& aParent, LPSRestriction aRestriction,
nsMapiEntryArray& aCards) ;
// Get a list of mailing lists in a folder
BOOL GetNodes(const nsMapiEntry& aParent, nsMapiEntryArray& aNodes) ;
// Get the number of cards/mailing lists in a folder/mailing list
BOOL GetCardsCount(const nsMapiEntry& aParent, ULONG& aNbCards) ;
// Access last MAPI error
HRESULT LastError(void) const { return mLastError ; }
// Get the value of a MAPI property of type string
BOOL GetPropertyString(const nsMapiEntry& aObject, ULONG aPropertyTag, nsCString& aValue) ;
// Same as previous, but string is returned as unicode
BOOL GetPropertyUString(const nsMapiEntry& aObject, ULONG aPropertyTag, nsString& aValue) ;
// Get multiple string MAPI properties in one call.
BOOL GetPropertiesUString(const nsMapiEntry& aObject, const ULONG *aPropertiesTag,
ULONG aNbProperties, nsString *aValues);
// Get the value of a MAPI property of type SYSTIME
BOOL GetPropertyDate(const nsMapiEntry& aObject, ULONG aPropertyTag,
WORD& aYear, WORD& aMonth, WORD& aDay) ;
// Get the value of a MAPI property of type LONG
BOOL GetPropertyLong(const nsMapiEntry& aObject, ULONG aPropertyTag, ULONG& aValue) ;
// Get the value of a MAPI property of type BIN
BOOL GetPropertyBin(const nsMapiEntry& aObject, ULONG aPropertyTag, nsMapiEntry& aValue) ;
// Tests if a container contains an entry
BOOL TestOpenEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aEntry) ;
// Delete an entry in the address book
BOOL DeleteEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aEntry) ;
// Set the value of a MAPI property of type string in unicode
BOOL SetPropertyUString (const nsMapiEntry& aObject, ULONG aPropertyTag,
const char16_t *aValue) ;
// Same as previous, but with a bunch of properties in one call
BOOL SetPropertiesUString(const nsMapiEntry& aObject, const ULONG *aPropertiesTag,
ULONG aNbProperties, nsString *aValues) ;
// Set the value of a MAPI property of type SYSTIME
BOOL SetPropertyDate(const nsMapiEntry& aObject, ULONG aPropertyTag,
WORD aYear, WORD aMonth, WORD aDay) ;
// Create entry in the address book
BOOL CreateEntry(const nsMapiEntry& aParent, nsMapiEntry& aNewEntry) ;
// Create a distribution list in the address book
BOOL CreateDistList(const nsMapiEntry& aParent, nsMapiEntry& aNewEntry) ;
// Copy an existing entry in the address book
BOOL CopyEntry(const nsMapiEntry& aContainer, const nsMapiEntry& aSource, nsMapiEntry& aTarget) ;
// Get a default address book container
BOOL GetDefaultContainer(nsMapiEntry& aContainer) ;
// Is the helper correctly initialised?
BOOL IsOK(void) const { return mAddressBook != NULL ; }
protected:
HRESULT mLastError ;
LPADRBOOK mAddressBook ;
static uint32_t mEntryCounter ;
static uint32_t mUseCount ;
static nsAutoPtr<mozilla::Mutex> mMutex ;
// Retrieve the contents of a container, with an optional restriction
BOOL GetContents(const nsMapiEntry& aParent, LPSRestriction aRestriction,
nsMapiEntry **aList, ULONG &aNbElements, ULONG aMapiType) ;
// Retrieve the values of a set of properties on a MAPI object
BOOL GetMAPIProperties(const nsMapiEntry& aObject, const ULONG *aPropertyTags,
ULONG aNbProperties,
LPSPropValue& aValues, ULONG& aValueCount) ;
// Set the values of a set of properties on a MAPI object
BOOL SetMAPIProperties(const nsMapiEntry& aObject, ULONG aNbProperties,
const LPSPropValue& aValues) ;
// Clean-up a rowset returned by QueryRows
void MyFreeProws(LPSRowSet aSet) ;
// Allocation of a buffer for transmission to interfaces
virtual void AllocateBuffer(ULONG aByteCount, LPVOID *aBuffer) = 0 ;
// Destruction of a buffer provided by the interfaces
virtual void FreeBuffer(LPVOID aBuffer) = 0 ;
private:
} ;
enum nsAbWinType
{
nsAbWinType_Unknown,
nsAbWinType_Outlook,
nsAbWinType_OutlookExp
} ;
class nsAbWinHelperGuard
{
public :
nsAbWinHelperGuard(uint32_t aType) ;
~nsAbWinHelperGuard(void) ;
nsAbWinHelper *operator ->(void) { return mHelper ; }
private:
nsAbWinHelper *mHelper ;
} ;
extern const char *kOutlookDirectoryScheme ;
extern const int kOutlookDirSchemeLength ;
extern const char *kOutlookStub ;
extern const char *kOutlookExpStub ;
extern const char *kOutlookCardScheme ;
nsAbWinType getAbWinType(const char *aScheme, const char *aUri,
nsCString& aStub, nsCString& aEntry) ;
void buildAbWinUri(const char *aScheme, uint32_t aType, nsCString& aUri) ;
#endif // nsAbWinHelper_h___

View file

@ -0,0 +1,323 @@
/* -*- 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 "msgCore.h" // precompiled header...
#include "nsStringGlue.h"
#include "nsIIOService.h"
#include "nsIStreamListener.h"
#include "nsAddbookProtocolHandler.h"
#include "nsAddbookUrl.h"
#include "nsAddbookProtocolHandler.h"
#include "nsCOMPtr.h"
#include "nsAbBaseCID.h"
#include "nsNetUtil.h"
#include "nsStringStream.h"
#include "nsIAbDirectory.h"
#include "nsIAbManager.h"
#include "prmem.h"
#include "nsIAbView.h"
#include "nsITreeView.h"
#include "nsIStringBundle.h"
#include "nsIServiceManager.h"
#include "mozilla/Services.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIPipe.h"
#include "nsIPrincipal.h"
nsAddbookProtocolHandler::nsAddbookProtocolHandler()
{
mAddbookOperation = nsIAddbookUrlOperation::InvalidUrl;
}
nsAddbookProtocolHandler::~nsAddbookProtocolHandler()
{
}
NS_IMPL_ISUPPORTS(nsAddbookProtocolHandler, nsIProtocolHandler)
NS_IMETHODIMP nsAddbookProtocolHandler::GetScheme(nsACString &aScheme)
{
aScheme = "addbook";
return NS_OK;
}
NS_IMETHODIMP nsAddbookProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
{
return NS_OK;
}
NS_IMETHODIMP nsAddbookProtocolHandler::GetProtocolFlags(uint32_t *aUritype)
{
*aUritype = URI_STD | URI_LOADABLE_BY_ANYONE | URI_FORBIDS_COOKIE_ACCESS;
return NS_OK;
}
NS_IMETHODIMP nsAddbookProtocolHandler::NewURI(const nsACString &aSpec,
const char *aOriginCharset, // ignored
nsIURI *aBaseURI,
nsIURI **_retval)
{
nsresult rv;
nsCOMPtr <nsIAddbookUrl> addbookUrl = do_CreateInstance(NS_ADDBOOKURL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = addbookUrl->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIURI> uri = do_QueryInterface(addbookUrl, &rv);
NS_ENSURE_SUCCESS(rv,rv);
NS_ADDREF(*_retval = uri);
return NS_OK;
}
NS_IMETHODIMP
nsAddbookProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
{
// don't override anything.
*_retval = false;
return NS_OK;
}
nsresult
nsAddbookProtocolHandler::GenerateXMLOutputChannel( nsString &aOutput,
nsIAddbookUrl *addbookUrl,
nsIURI *aURI,
nsILoadInfo *aLoadInfo,
nsIChannel **_retval)
{
nsresult rv;
nsCOMPtr<nsIStringInputStream> inStr(do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 utf8String(aOutput.get());
rv = inStr->SetData(utf8String.get(), utf8String.Length());
NS_ENSURE_SUCCESS(rv, rv);
if (aLoadInfo) {
return NS_NewInputStreamChannelInternal(_retval,
aURI,
inStr,
NS_LITERAL_CSTRING("text/xml"),
EmptyCString(),
aLoadInfo);
}
nsCOMPtr<nsIPrincipal> nullPrincipal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "CreateInstance of nullprincipalfailed.");
if (NS_FAILED(rv))
return rv;
return NS_NewInputStreamChannel(_retval, aURI, inStr,
nullPrincipal, nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING("text/xml"));
}
NS_IMETHODIMP
nsAddbookProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{
return NewChannel2(aURI, nullptr, _retval);
}
NS_IMETHODIMP
nsAddbookProtocolHandler::NewChannel2(nsIURI *aURI,
nsILoadInfo* aLoadInfo,
nsIChannel **_retval)
{
nsresult rv;
nsCOMPtr <nsIAddbookUrl> addbookUrl = do_QueryInterface(aURI, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = addbookUrl->GetAddbookOperation(&mAddbookOperation);
NS_ENSURE_SUCCESS(rv,rv);
if (mAddbookOperation == nsIAddbookUrlOperation::InvalidUrl) {
nsAutoString errorString;
errorString.AssignLiteral("Unsupported format/operation requested for ");
nsAutoCString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv,rv);
errorString.Append(NS_ConvertUTF8toUTF16(spec));
rv = GenerateXMLOutputChannel(errorString, addbookUrl, aURI, aLoadInfo, _retval);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
if (mAddbookOperation == nsIAddbookUrlOperation::AddVCard) {
// create an empty pipe for use with the input stream channel.
nsCOMPtr<nsIAsyncInputStream> pipeIn;
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
nsCOMPtr<nsIPipe> pipe = do_CreateInstance("@mozilla.org/pipe;1");
rv = pipe->Init(false, false, 0, 0);
NS_ENSURE_SUCCESS(rv, rv);
// These always succeed because the pipe is initialized above.
MOZ_ALWAYS_SUCCEEDS(pipe->GetInputStream(getter_AddRefs(pipeIn)));
MOZ_ALWAYS_SUCCEEDS(pipe->GetOutputStream(getter_AddRefs(pipeOut)));
pipeOut->Close();
if (aLoadInfo) {
return NS_NewInputStreamChannelInternal(_retval,
aURI,
pipeIn,
NS_LITERAL_CSTRING("application/x-addvcard"),
EmptyCString(),
aLoadInfo);
}
nsCOMPtr<nsIPrincipal> nullPrincipal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "CreateInstance of nullprincipal failed.");
if (NS_FAILED(rv))
return rv;
return NS_NewInputStreamChannel(_retval, aURI, pipeIn,
nullPrincipal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING("application/x-addvcard"));
}
nsString output;
rv = GeneratePrintOutput(addbookUrl, output);
if (NS_FAILED(rv)) {
output.AssignLiteral("failed to print. url=");
nsAutoCString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv,rv);
output.Append(NS_ConvertUTF8toUTF16(spec));
}
rv = GenerateXMLOutputChannel(output, addbookUrl, aURI, aLoadInfo, _retval);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
nsresult
nsAddbookProtocolHandler::GeneratePrintOutput(nsIAddbookUrl *addbookUrl,
nsString &aOutput)
{
NS_ENSURE_ARG_POINTER(addbookUrl);
nsAutoCString uri;
nsresult rv = addbookUrl->GetPath(uri);
NS_ENSURE_SUCCESS(rv,rv);
/* turn
"//moz-abmdbdirectory/abook.mab?action=print"
into "moz-abmdbdirectory://abook.mab"
*/
/* step 1:
turn "//moz-abmdbdirectory/abook.mab?action=print"
into "moz-abmdbdirectory/abook.mab?action=print"
*/
if (uri[0] != '/' && uri[1] != '/')
return NS_ERROR_UNEXPECTED;
uri.Cut(0,2);
/* step 2:
turn "moz-abmdbdirectory/abook.mab?action=print"
into "moz-abmdbdirectory/abook.mab"
*/
int32_t pos = uri.Find("?action=print");
if (pos == -1)
return NS_ERROR_UNEXPECTED;
uri.SetLength(pos);
/* step 2:
turn "moz-abmdbdirectory/abook.mab"
into "moz-abmdbdirectory://abook.mab"
*/
pos = uri.FindChar('/');
if (pos == -1)
return NS_ERROR_UNEXPECTED;
uri.Insert('/', pos);
uri.Insert(':', pos);
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAbDirectory> directory;
rv = abManager->GetDirectory(uri, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
rv = BuildDirectoryXML(directory, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsAddbookProtocolHandler::BuildDirectoryXML(nsIAbDirectory *aDirectory,
nsString &aOutput)
{
NS_ENSURE_ARG_POINTER(aDirectory);
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> cardsEnumerator;
nsCOMPtr<nsIAbCard> card;
aOutput.AppendLiteral("<?xml version=\"1.0\"?>\n"
"<?xml-stylesheet type=\"text/css\" href=\"chrome://messagebody/content/addressbook/print.css\"?>\n"
"<directory>\n");
// Get Address Book string and set it as title of XML document
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundleService> stringBundleService =
mozilla::services::GetStringBundleService();
if (stringBundleService) {
rv = stringBundleService->CreateBundle("chrome://messenger/locale/addressbook/addressBook.properties", getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) {
nsString addrBook;
rv = bundle->GetStringFromName(u"addressBook", getter_Copies(addrBook));
if (NS_SUCCEEDED(rv)) {
aOutput.AppendLiteral("<title xmlns=\"http://www.w3.org/1999/xhtml\">");
aOutput.Append(addrBook);
aOutput.AppendLiteral("</title>\n");
}
}
}
// create a view and init it with the generated name sort order. Then, iterate
// over the view, getting the card for each row, and printing them.
nsString sortColumn;
nsCOMPtr <nsIAbView> view = do_CreateInstance("@mozilla.org/addressbook/abview;1", &rv);
view->SetView(aDirectory, nullptr, NS_LITERAL_STRING("GeneratedName"),
NS_LITERAL_STRING("ascending"), sortColumn);
int32_t numRows;
nsCOMPtr <nsITreeView> treeView = do_QueryInterface(view, &rv);
NS_ENSURE_SUCCESS(rv, rv);
treeView->GetRowCount(&numRows);
for (int32_t row = 0; row < numRows; row++)
{
nsCOMPtr <nsIAbCard> card;
view->GetCardFromRow(row, getter_AddRefs(card));
nsCString xmlSubstr;
rv = card->TranslateTo(NS_LITERAL_CSTRING("xml"), xmlSubstr);
NS_ENSURE_SUCCESS(rv,rv);
aOutput.AppendLiteral("<separator/>");
aOutput.Append(NS_ConvertUTF8toUTF16(xmlSubstr));
aOutput.AppendLiteral("<separator/>");
}
aOutput.AppendLiteral("</directory>\n");
return NS_OK;
}

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 nsAddbookProtocolHandler_h___
#define nsAddbookProtocolHandler_h___
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsAddbookProtocolHandler.h"
#include "nsIProtocolHandler.h"
#include "nsIAddbookUrl.h"
#include "nsIAddrDatabase.h"
class nsAddbookProtocolHandler : public nsIProtocolHandler
{
public:
nsAddbookProtocolHandler();
NS_DECL_ISUPPORTS
//////////////////////////////////////////////////////////////////////////
// We support the nsIProtocolHandler interface.
//////////////////////////////////////////////////////////////////////////
NS_DECL_NSIPROTOCOLHANDLER
private:
virtual ~nsAddbookProtocolHandler();
nsresult GenerateXMLOutputChannel(nsString &aOutput,
nsIAddbookUrl *addbookUrl,
nsIURI *aURI,
nsILoadInfo *aLoadInfo,
nsIChannel **_retval);
nsresult GeneratePrintOutput(nsIAddbookUrl *addbookUrl,
nsString &aOutput);
nsresult BuildDirectoryXML(nsIAbDirectory *aDirectory,
nsString &aOutput);
int32_t mAddbookOperation;
};
#endif /* nsAddbookProtocolHandler_h___ */

View file

@ -0,0 +1,282 @@
/* -*- 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.h"
#include "nsNetCID.h"
#include "nsAddbookUrl.h"
#include "nsStringGlue.h"
#include "nsAbBaseCID.h"
#include "nsComponentManagerUtils.h"
#include "nsAutoPtr.h"
/////////////////////////////////////////////////////////////////////////////////////
// addbook url definition
/////////////////////////////////////////////////////////////////////////////////////
nsAddbookUrl::nsAddbookUrl()
{
m_baseURL = do_CreateInstance(NS_SIMPLEURI_CONTRACTID);
mOperationType = nsIAddbookUrlOperation::InvalidUrl;
}
nsAddbookUrl::~nsAddbookUrl()
{
}
NS_IMPL_ISUPPORTS(nsAddbookUrl, nsIAddbookUrl, nsIURI)
NS_IMETHODIMP
nsAddbookUrl::SetSpec(const nsACString &aSpec)
{
nsresult rv = m_baseURL->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv, rv);
return ParseUrl();
}
nsresult nsAddbookUrl::ParseUrl()
{
nsAutoCString pathStr;
nsresult rv = m_baseURL->GetPath(pathStr);
NS_ENSURE_SUCCESS(rv,rv);
if (strstr(pathStr.get(), "?action=print"))
mOperationType = nsIAddbookUrlOperation::PrintAddressBook;
else if (strstr(pathStr.get(), "?action=add"))
mOperationType = nsIAddbookUrlOperation::AddVCard;
else
mOperationType = nsIAddbookUrlOperation::InvalidUrl;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////////
// Begin nsIURI support
////////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsAddbookUrl::GetSpec(nsACString &aSpec)
{
return m_baseURL->GetSpec(aSpec);
}
NS_IMETHODIMP nsAddbookUrl::GetPrePath(nsACString &aPrePath)
{
return m_baseURL->GetPrePath(aPrePath);
}
NS_IMETHODIMP nsAddbookUrl::GetScheme(nsACString &aScheme)
{
return m_baseURL->GetScheme(aScheme);
}
NS_IMETHODIMP nsAddbookUrl::SetScheme(const nsACString &aScheme)
{
return m_baseURL->SetScheme(aScheme);
}
NS_IMETHODIMP nsAddbookUrl::GetUserPass(nsACString &aUserPass)
{
return m_baseURL->GetUserPass(aUserPass);
}
NS_IMETHODIMP nsAddbookUrl::SetUserPass(const nsACString &aUserPass)
{
return m_baseURL->SetUserPass(aUserPass);
}
NS_IMETHODIMP nsAddbookUrl::GetUsername(nsACString &aUsername)
{
return m_baseURL->GetUsername(aUsername);
}
NS_IMETHODIMP nsAddbookUrl::SetUsername(const nsACString &aUsername)
{
return m_baseURL->SetUsername(aUsername);
}
NS_IMETHODIMP nsAddbookUrl::GetPassword(nsACString &aPassword)
{
return m_baseURL->GetPassword(aPassword);
}
NS_IMETHODIMP nsAddbookUrl::SetPassword(const nsACString &aPassword)
{
return m_baseURL->SetPassword(aPassword);
}
NS_IMETHODIMP nsAddbookUrl::GetHostPort(nsACString &aHostPort)
{
return m_baseURL->GetHostPort(aHostPort);
}
NS_IMETHODIMP nsAddbookUrl::SetHostPort(const nsACString &aHostPort)
{
return m_baseURL->SetHostPort(aHostPort);
}
NS_IMETHODIMP nsAddbookUrl::SetHostAndPort(const nsACString &aHostPort)
{
return m_baseURL->SetHostAndPort(aHostPort);
}
NS_IMETHODIMP nsAddbookUrl::GetHost(nsACString &aHost)
{
return m_baseURL->GetHost(aHost);
}
NS_IMETHODIMP nsAddbookUrl::SetHost(const nsACString &aHost)
{
return m_baseURL->SetHost(aHost);
}
NS_IMETHODIMP nsAddbookUrl::GetPort(int32_t *aPort)
{
return m_baseURL->GetPort(aPort);
}
NS_IMETHODIMP nsAddbookUrl::SetPort(int32_t aPort)
{
return m_baseURL->SetPort(aPort);
}
NS_IMETHODIMP nsAddbookUrl::GetPath(nsACString &aPath)
{
return m_baseURL->GetPath(aPath);
}
NS_IMETHODIMP nsAddbookUrl::SetPath(const nsACString &aPath)
{
m_baseURL->SetPath(aPath);
return ParseUrl();
}
NS_IMETHODIMP nsAddbookUrl::GetAsciiHost(nsACString &aHostA)
{
return m_baseURL->GetAsciiHost(aHostA);
}
NS_IMETHODIMP nsAddbookUrl::GetAsciiHostPort(nsACString &aHostPortA)
{
return m_baseURL->GetAsciiHostPort(aHostPortA);
}
NS_IMETHODIMP nsAddbookUrl::GetAsciiSpec(nsACString &aSpecA)
{
return m_baseURL->GetAsciiSpec(aSpecA);
}
NS_IMETHODIMP nsAddbookUrl::GetOriginCharset(nsACString &aOriginCharset)
{
return m_baseURL->GetOriginCharset(aOriginCharset);
}
NS_IMETHODIMP nsAddbookUrl::SchemeIs(const char *aScheme, bool *_retval)
{
return m_baseURL->SchemeIs(aScheme, _retval);
}
NS_IMETHODIMP nsAddbookUrl::Equals(nsIURI *other, bool *_retval)
{
// The passed-in URI might be an nsMailtoUrl. Pass our inner URL to its
// Equals method. The other nsMailtoUrl will then pass its inner URL to
// to the Equals method of our inner URL. Other URIs will return false.
if (other)
return other->Equals(m_baseURL, _retval);
return m_baseURL->Equals(other, _retval);
}
nsresult
nsAddbookUrl::CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** _retval)
{
NS_ENSURE_ARG_POINTER(_retval);
RefPtr<nsAddbookUrl> clone = new nsAddbookUrl();
if (!clone)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
if (aRefHandlingMode == eHonorRef) {
rv = m_baseURL->Clone(getter_AddRefs(clone->m_baseURL));
} else if (aRefHandlingMode == eReplaceRef) {
rv = m_baseURL->CloneWithNewRef(newRef, getter_AddRefs(clone->m_baseURL));
} else {
rv = m_baseURL->CloneIgnoringRef(getter_AddRefs(clone->m_baseURL));
}
NS_ENSURE_SUCCESS(rv, rv);
clone->ParseUrl();
clone.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP nsAddbookUrl::Clone(nsIURI **_retval)
{
return CloneInternal(eHonorRef, EmptyCString(), _retval);
}
NS_IMETHODIMP
nsAddbookUrl::CloneIgnoringRef(nsIURI** _retval)
{
return CloneInternal(eIgnoreRef, EmptyCString(), _retval);
}
NS_IMETHODIMP
nsAddbookUrl::CloneWithNewRef(const nsACString& newRef, nsIURI** _retval)
{
return CloneInternal(eReplaceRef, newRef, _retval);
}
NS_IMETHODIMP nsAddbookUrl::Resolve(const nsACString &relativePath, nsACString &result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsAddbookUrl::GetRef(nsACString &result)
{
return m_baseURL->GetRef(result);
}
NS_IMETHODIMP
nsAddbookUrl::SetRef(const nsACString &aRef)
{
m_baseURL->SetRef(aRef);
return ParseUrl();
}
NS_IMETHODIMP nsAddbookUrl::EqualsExceptRef(nsIURI *other, bool *_retval)
{
// The passed-in URI might be an nsMailtoUrl. Pass our inner URL to its
// Equals method. The other nsMailtoUrl will then pass its inner URL to
// to the Equals method of our inner URL. Other URIs will return false.
if (other)
return other->EqualsExceptRef(m_baseURL, _retval);
return m_baseURL->EqualsExceptRef(other, _retval);
}
NS_IMETHODIMP
nsAddbookUrl::GetSpecIgnoringRef(nsACString &result)
{
return m_baseURL->GetSpecIgnoringRef(result);
}
NS_IMETHODIMP
nsAddbookUrl::GetHasRef(bool *result)
{
return m_baseURL->GetHasRef(result);
}
//
// Specific nsAddbookUrl operations
//
NS_IMETHODIMP
nsAddbookUrl::GetAddbookOperation(int32_t *_retval)
{
*_retval = mOperationType;
return NS_OK;
}

View file

@ -0,0 +1,39 @@
/* -*- 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 nsAddbookUrl_h__
#define nsAddbookUrl_h__
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsIAddbookUrl.h"
class nsAddbookUrl : public nsIAddbookUrl
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURI
NS_DECL_NSIADDBOOKURL
nsAddbookUrl();
protected:
enum RefHandlingEnum {
eIgnoreRef,
eHonorRef,
eReplaceRef
};
virtual ~nsAddbookUrl();
nsresult
CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** _retval);
nsresult ParseUrl();
int32_t mOperationType; // the internal ID for the operation
nsCOMPtr<nsIURI> m_baseURL; // the base URL for the object
};
#endif // nsAddbookUrl_h__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,439 @@
/* -*- 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 _nsAddrDatabase_H_
#define _nsAddrDatabase_H_
#include "mozilla/Attributes.h"
#include "nsIAddrDatabase.h"
#include "mdb.h"
#include "nsStringGlue.h"
#include "nsIAddrDBListener.h"
#include "nsCOMPtr.h"
#include "nsTObserverArray.h"
#include "nsWeakPtr.h"
#include "nsIWeakReferenceUtils.h"
typedef enum
{
AB_NotifyInserted,
AB_NotifyDeleted,
AB_NotifyPropertyChanged
} AB_NOTIFY_CODE;
class nsAddrDatabase : public nsIAddrDatabase
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIADDRDBANNOUNCER
//////////////////////////////////////////////////////////////////////////////
// nsIAddrDatabase methods:
NS_IMETHOD GetDbPath(nsIFile * *aDbPath) override;
NS_IMETHOD SetDbPath(nsIFile * aDbPath) override;
NS_IMETHOD Open(nsIFile *aMabFile, bool aCreate, bool upgrading, nsIAddrDatabase **pCardDB) override;
NS_IMETHOD Close(bool forceCommit) override;
NS_IMETHOD OpenMDB(nsIFile *dbName, bool create) override;
NS_IMETHOD CloseMDB(bool commit) override;
NS_IMETHOD Commit(uint32_t commitType) override;
NS_IMETHOD ForceClosed() override;
NS_IMETHOD CreateNewCardAndAddToDB(nsIAbCard *newCard, bool notify, nsIAbDirectory *parent) override;
NS_IMETHOD CreateNewListCardAndAddToDB(nsIAbDirectory *list, uint32_t listRowID, nsIAbCard *newCard, bool notify) override;
NS_IMETHOD CreateMailListAndAddToDB(nsIAbDirectory *newList, bool notify, nsIAbDirectory *parent) override;
NS_IMETHOD EnumerateCards(nsIAbDirectory *directory, nsISimpleEnumerator **result) override;
NS_IMETHOD GetMailingListsFromDB(nsIAbDirectory *parentDir) override;
NS_IMETHOD EnumerateListAddresses(nsIAbDirectory *directory, nsISimpleEnumerator **result) override;
NS_IMETHOD DeleteCard(nsIAbCard *newCard, bool notify, nsIAbDirectory *parent) override;
NS_IMETHOD EditCard(nsIAbCard *card, bool notify, nsIAbDirectory *parent) override;
NS_IMETHOD ContainsCard(nsIAbCard *card, bool *hasCard) override;
NS_IMETHOD DeleteMailList(nsIAbDirectory *aMailList, nsIAbDirectory *aParent) override;
NS_IMETHOD EditMailList(nsIAbDirectory *mailList, nsIAbCard *listCard, bool notify) override;
NS_IMETHOD ContainsMailList(nsIAbDirectory *mailList, bool *hasCard) override;
NS_IMETHOD DeleteCardFromMailList(nsIAbDirectory *mailList, nsIAbCard *card, bool aNotify) override;
NS_IMETHOD GetCardFromAttribute(nsIAbDirectory *aDirectory, const char *aName,
const nsACString &aValue,
bool aCaseInsensitive, nsIAbCard **card) override;
NS_IMETHOD GetCardsFromAttribute(nsIAbDirectory *aDirectory,
const char *aName,
const nsACString & uUTF8Value,
bool aCaseInsensitive,
nsISimpleEnumerator **cards) override;
NS_IMETHOD GetNewRow(nsIMdbRow * *newRow) override;
NS_IMETHOD GetNewListRow(nsIMdbRow * *newRow) override;
NS_IMETHOD AddCardRowToDB(nsIMdbRow *newRow) override;
NS_IMETHOD AddLdifListMember(nsIMdbRow* row, const char * value) override;
NS_IMETHOD GetDeletedCardList(nsIArray **aResult) override;
NS_IMETHOD GetDeletedCardCount(uint32_t *aCount) override;
NS_IMETHOD PurgeDeletedCardTable();
NS_IMETHOD AddFirstName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_FirstNameColumnToken, value); }
NS_IMETHOD AddLastName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_LastNameColumnToken, value); }
NS_IMETHOD AddPhoneticFirstName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_PhoneticFirstNameColumnToken, value); }
NS_IMETHOD AddPhoneticLastName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_PhoneticLastNameColumnToken, value); }
NS_IMETHOD AddDisplayName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_DisplayNameColumnToken, value); }
NS_IMETHOD AddNickName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_NickNameColumnToken, value); }
NS_IMETHOD AddPrimaryEmail(nsIMdbRow * row, const char * value) override;
NS_IMETHOD Add2ndEmail(nsIMdbRow * row, const char * value) override;
NS_IMETHOD AddPreferMailFormat(nsIMdbRow * row, uint32_t value) override
{ return AddIntColumn(row, m_MailFormatColumnToken, value); }
NS_IMETHOD AddPopularityIndex(nsIMdbRow * row, uint32_t value) override
{ return AddIntColumn(row, m_PopularityIndexColumnToken, value); }
NS_IMETHOD AddWorkPhone(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkPhoneColumnToken, value); }
NS_IMETHOD AddHomePhone(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomePhoneColumnToken, value); }
NS_IMETHOD AddFaxNumber(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_FaxColumnToken, value); }
NS_IMETHOD AddPagerNumber(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_PagerColumnToken, value); }
NS_IMETHOD AddCellularNumber(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_CellularColumnToken, value); }
NS_IMETHOD AddWorkPhoneType(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkPhoneTypeColumnToken, value); }
NS_IMETHOD AddHomePhoneType(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomePhoneTypeColumnToken, value); }
NS_IMETHOD AddFaxNumberType(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_FaxTypeColumnToken, value); }
NS_IMETHOD AddPagerNumberType(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_PagerTypeColumnToken, value); }
NS_IMETHOD AddCellularNumberType(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_CellularTypeColumnToken, value); }
NS_IMETHOD AddHomeAddress(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeAddressColumnToken, value); }
NS_IMETHOD AddHomeAddress2(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeAddress2ColumnToken, value); }
NS_IMETHOD AddHomeCity(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeCityColumnToken, value); }
NS_IMETHOD AddHomeState(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeStateColumnToken, value); }
NS_IMETHOD AddHomeZipCode(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeZipCodeColumnToken, value); }
NS_IMETHOD AddHomeCountry(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_HomeCountryColumnToken, value); }
NS_IMETHOD AddWorkAddress(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkAddressColumnToken, value); }
NS_IMETHOD AddWorkAddress2(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkAddress2ColumnToken, value); }
NS_IMETHOD AddWorkCity(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkCityColumnToken, value); }
NS_IMETHOD AddWorkState(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkStateColumnToken, value); }
NS_IMETHOD AddWorkZipCode(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkZipCodeColumnToken, value); }
NS_IMETHOD AddWorkCountry(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WorkCountryColumnToken, value); }
NS_IMETHOD AddJobTitle(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_JobTitleColumnToken, value); }
NS_IMETHOD AddDepartment(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_DepartmentColumnToken, value); }
NS_IMETHOD AddCompany(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_CompanyColumnToken, value); }
NS_IMETHOD AddAimScreenName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_AimScreenNameColumnToken, value); }
NS_IMETHOD AddAnniversaryYear(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_AnniversaryYearColumnToken, value); }
NS_IMETHOD AddAnniversaryMonth(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_AnniversaryMonthColumnToken, value); }
NS_IMETHOD AddAnniversaryDay(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_AnniversaryDayColumnToken, value); }
NS_IMETHOD AddSpouseName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_SpouseNameColumnToken, value); }
NS_IMETHOD AddFamilyName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_FamilyNameColumnToken, value); }
NS_IMETHOD AddDefaultAddress(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_DefaultAddressColumnToken, value); }
NS_IMETHOD AddCategory(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_CategoryColumnToken, value); }
NS_IMETHOD AddWebPage1(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WebPage1ColumnToken, value); }
NS_IMETHOD AddWebPage2(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_WebPage2ColumnToken, value); }
NS_IMETHOD AddBirthYear(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_BirthYearColumnToken, value); }
NS_IMETHOD AddBirthMonth(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_BirthMonthColumnToken, value); }
NS_IMETHOD AddBirthDay(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_BirthDayColumnToken, value); }
NS_IMETHOD AddCustom1(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_Custom1ColumnToken, value); }
NS_IMETHOD AddCustom2(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_Custom2ColumnToken, value); }
NS_IMETHOD AddCustom3(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_Custom3ColumnToken, value); }
NS_IMETHOD AddCustom4(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_Custom4ColumnToken, value); }
NS_IMETHOD AddNotes(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_NotesColumnToken, value); }
NS_IMETHOD AddListName(nsIMdbRow * row, const char * value) override;
NS_IMETHOD AddListNickName(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_ListNickNameColumnToken, value); }
NS_IMETHOD AddListDescription(nsIMdbRow * row, const char * value) override
{ return AddCharStringColumn(row, m_ListDescriptionColumnToken, value); }
NS_IMETHOD AddListDirNode(nsIMdbRow * listRow) override;
NS_IMETHOD FindMailListbyUnicodeName(const char16_t *listName, bool *exist) override;
NS_IMETHOD GetCardCount(uint32_t *count) override;
NS_IMETHOD SetCardValue(nsIAbCard *card, const char *name, const char16_t *value, bool notify) override;
NS_IMETHOD GetCardValue(nsIAbCard *card, const char *name, char16_t **value) override;
// nsAddrDatabase methods:
nsAddrDatabase();
void GetMDBFactory(nsIMdbFactory ** aMdbFactory);
nsIMdbEnv *GetEnv() {return m_mdbEnv;}
uint32_t GetCurVersion();
nsIMdbTableRowCursor *GetTableRowCursor();
nsIMdbTable *GetPabTable() {return m_mdbPabTable;}
static nsAddrDatabase* FindInCache(nsIFile *dbName);
static void CleanupCache();
nsresult CreateABCard(nsIMdbRow* cardRow, mdb_id listRowID, nsIAbCard **result);
nsresult CreateABListCard(nsIMdbRow* listRow, nsIAbCard **result);
nsresult CreateABList(nsIMdbRow* listRow, nsIAbDirectory **result);
bool IsListRowScopeToken(mdb_scope scope) { return (scope == m_ListRowScopeToken) ? true: false; }
bool IsCardRowScopeToken(mdb_scope scope) { return (scope == m_CardRowScopeToken) ? true: false; }
bool IsDataRowScopeToken(mdb_scope scope) { return (scope == m_DataRowScopeToken) ? true: false; }
nsresult GetCardRowByRowID(mdb_id rowID, nsIMdbRow **dbRow);
nsresult GetListRowByRowID(mdb_id rowID, nsIMdbRow **dbRow);
uint32_t GetListAddressTotal(nsIMdbRow* listRow);
nsresult GetAddressRowByPos(nsIMdbRow* listRow, uint16_t pos, nsIMdbRow** cardRow);
NS_IMETHOD AddListCardColumnsToRow(nsIAbCard *aPCard, nsIMdbRow *aPListRow, uint32_t aPos, nsIAbCard** aPNewCard, bool aInMailingList, nsIAbDirectory *aParent, nsIAbDirectory *aRoot) override;
NS_IMETHOD InitCardFromRow(nsIAbCard *aNewCard, nsIMdbRow* aCardRow) override;
NS_IMETHOD SetListAddressTotal(nsIMdbRow* aListRow, uint32_t aTotal) override;
NS_IMETHOD FindRowByCard(nsIAbCard * card,nsIMdbRow **aRow) override;
protected:
virtual ~nsAddrDatabase();
static void RemoveFromCache(nsAddrDatabase* pAddrDB);
bool MatchDbName(nsIFile *dbName); // returns TRUE if they match
void YarnToUInt32(struct mdbYarn *yarn, uint32_t *pResult);
void GetCharStringYarn(char* str, struct mdbYarn* strYarn);
void GetStringYarn(const nsAString & aStr, struct mdbYarn* strYarn);
void GetIntYarn(uint32_t nValue, struct mdbYarn* intYarn);
nsresult AddCharStringColumn(nsIMdbRow* cardRow, mdb_column inColumn, const char* str);
nsresult AddStringColumn(nsIMdbRow* aCardRow, mdb_column aInColumn, const nsAString & aStr);
nsresult AddIntColumn(nsIMdbRow* cardRow, mdb_column inColumn, uint32_t nValue);
nsresult AddBoolColumn(nsIMdbRow* cardRow, mdb_column inColumn, bool bValue);
nsresult GetStringColumn(nsIMdbRow *cardRow, mdb_token outToken, nsString& str);
nsresult GetIntColumn(nsIMdbRow *cardRow, mdb_token outToken,
uint32_t* pValue, uint32_t defaultValue);
nsresult GetBoolColumn(nsIMdbRow *cardRow, mdb_token outToken, bool* pValue);
nsresult GetListCardFromDB(nsIAbCard *listCard, nsIMdbRow* listRow);
nsresult GetListFromDB(nsIAbDirectory *newCard, nsIMdbRow* listRow);
nsresult AddRecordKeyColumnToRow(nsIMdbRow *pRow);
nsresult AddAttributeColumnsToRow(nsIAbCard *card, nsIMdbRow *cardRow);
nsresult AddListAttributeColumnsToRow(nsIAbDirectory *list, nsIMdbRow *listRow, nsIAbDirectory *parent);
nsresult CreateCard(nsIMdbRow* cardRow, mdb_id listRowID, nsIAbCard **result);
nsresult CreateCardFromDeletedCardsTable(nsIMdbRow* cardRow, mdb_id listRowID, nsIAbCard **result);
nsresult DeleteCardFromListRow(nsIMdbRow* pListRow, mdb_id cardRowID);
void DeleteCardFromAllMailLists(mdb_id cardRowID);
nsresult NotifyListEntryChange(uint32_t abCode, nsIAbDirectory *dir);
nsresult AddLowercaseColumn(nsIMdbRow * row, mdb_token columnToken, const char* utf8String);
nsresult GetRowFromAttribute(const char *aName, const nsACString &aUTF8Value,
bool aCaseInsensitive, nsIMdbRow **aCardRow,
mdb_pos *aRowPos);
static nsTArray<nsAddrDatabase*>* m_dbCache;
static nsTArray<nsAddrDatabase*>* GetDBCache();
// mdb bookkeeping stuff
nsresult InitExistingDB();
nsresult InitNewDB();
nsresult InitMDBInfo();
nsresult InitPabTable();
nsresult InitDeletedCardsTable(bool aCreate);
nsresult AddRowToDeletedCardsTable(nsIAbCard *card, nsIMdbRow **pCardRow);
nsresult DeleteRowFromDeletedCardsTable(nsIMdbRow *pCardRow);
nsresult InitLastRecorKey();
nsresult GetDataRow(nsIMdbRow **pDataRow);
nsresult GetLastRecordKey();
nsresult UpdateLastRecordKey();
nsresult CheckAndUpdateRecordKey();
nsresult UpdateLowercaseEmailListName();
nsresult ConvertAndAddLowercaseColumn(nsIMdbRow * row, mdb_token fromCol, mdb_token toCol);
nsresult AddUnicodeToColumn(nsIMdbRow * row, mdb_token colToken, mdb_token lowerCaseColToken, const char16_t* pUnicodeStr);
nsresult DeleteRow(nsIMdbTable* dbTable, nsIMdbRow* dbRow);
nsIMdbEnv *m_mdbEnv; // to be used in all the db calls.
nsIMdbStore *m_mdbStore;
nsIMdbTable *m_mdbPabTable;
nsIMdbTable *m_mdbDeletedCardsTable;
nsCOMPtr<nsIFile> m_dbName;
bool m_mdbTokensInitialized;
nsTObserverArray<nsIAddrDBListener*> m_ChangeListeners;
mdb_kind m_PabTableKind;
mdb_kind m_MailListTableKind;
mdb_kind m_DeletedCardsTableKind;
mdb_scope m_CardRowScopeToken;
mdb_scope m_ListRowScopeToken;
mdb_scope m_DataRowScopeToken;
mdb_token m_FirstNameColumnToken;
mdb_token m_LastNameColumnToken;
mdb_token m_PhoneticFirstNameColumnToken;
mdb_token m_PhoneticLastNameColumnToken;
mdb_token m_DisplayNameColumnToken;
mdb_token m_NickNameColumnToken;
mdb_token m_PriEmailColumnToken;
mdb_token m_2ndEmailColumnToken;
mdb_token m_DefaultEmailColumnToken;
mdb_token m_CardTypeColumnToken;
mdb_token m_WorkPhoneColumnToken;
mdb_token m_HomePhoneColumnToken;
mdb_token m_FaxColumnToken;
mdb_token m_PagerColumnToken;
mdb_token m_CellularColumnToken;
mdb_token m_WorkPhoneTypeColumnToken;
mdb_token m_HomePhoneTypeColumnToken;
mdb_token m_FaxTypeColumnToken;
mdb_token m_PagerTypeColumnToken;
mdb_token m_CellularTypeColumnToken;
mdb_token m_HomeAddressColumnToken;
mdb_token m_HomeAddress2ColumnToken;
mdb_token m_HomeCityColumnToken;
mdb_token m_HomeStateColumnToken;
mdb_token m_HomeZipCodeColumnToken;
mdb_token m_HomeCountryColumnToken;
mdb_token m_WorkAddressColumnToken;
mdb_token m_WorkAddress2ColumnToken;
mdb_token m_WorkCityColumnToken;
mdb_token m_WorkStateColumnToken;
mdb_token m_WorkZipCodeColumnToken;
mdb_token m_WorkCountryColumnToken;
mdb_token m_JobTitleColumnToken;
mdb_token m_DepartmentColumnToken;
mdb_token m_CompanyColumnToken;
mdb_token m_AimScreenNameColumnToken;
mdb_token m_AnniversaryYearColumnToken;
mdb_token m_AnniversaryMonthColumnToken;
mdb_token m_AnniversaryDayColumnToken;
mdb_token m_SpouseNameColumnToken;
mdb_token m_FamilyNameColumnToken;
mdb_token m_DefaultAddressColumnToken;
mdb_token m_CategoryColumnToken;
mdb_token m_WebPage1ColumnToken;
mdb_token m_WebPage2ColumnToken;
mdb_token m_BirthYearColumnToken;
mdb_token m_BirthMonthColumnToken;
mdb_token m_BirthDayColumnToken;
mdb_token m_Custom1ColumnToken;
mdb_token m_Custom2ColumnToken;
mdb_token m_Custom3ColumnToken;
mdb_token m_Custom4ColumnToken;
mdb_token m_NotesColumnToken;
mdb_token m_LastModDateColumnToken;
mdb_token m_RecordKeyColumnToken;
mdb_token m_LowerPriEmailColumnToken;
mdb_token m_Lower2ndEmailColumnToken;
mdb_token m_MailFormatColumnToken;
mdb_token m_PopularityIndexColumnToken;
mdb_token m_AddressCharSetColumnToken;
mdb_token m_LastRecordKeyColumnToken;
mdb_token m_ListNameColumnToken;
mdb_token m_ListNickNameColumnToken;
mdb_token m_ListDescriptionColumnToken;
mdb_token m_ListTotalColumnToken;
mdb_token m_LowerListNameColumnToken;
uint32_t m_LastRecordKey;
nsWeakPtr m_dbDirectory;
nsCOMPtr<nsIMdbFactory> mMdbFactory;
private:
nsresult GetRowForCharColumn(const char16_t *unicodeStr,
mdb_column findColumn, bool bIsCard,
bool aCaseInsensitive, nsIMdbRow **findRow,
mdb_pos *aRowPos);
bool HasRowButDeletedForCharColumn(const char16_t *unicodeStr, mdb_column findColumn, bool aIsCard, nsIMdbRow **aFindRow);
nsresult OpenInternal(nsIFile *aMabFile, bool aCreate, nsIAddrDatabase **pCardDB);
nsresult AlertAboutCorruptMabFile(const char16_t *aOldFileName, const char16_t *aNewFileName);
nsresult AlertAboutLockedMabFile(const char16_t *aFileName);
nsresult DisplayAlert(const char16_t *titleName, const char16_t *alertStringName,
const char16_t **formatStrings, int32_t numFormatStrings);
};
#endif

View file

@ -0,0 +1,12 @@
component {5b259db2-e451-4de9-8a6f-cfba91402973} nsAbAutoCompleteMyDomain.js
contract @mozilla.org/autocomplete/search;1?name=mydomain {5b259db2-e451-4de9-8a6f-cfba91402973}
component {2f946df9-114c-41fe-8899-81f10daf4f0c} nsAbAutoCompleteSearch.js
contract @mozilla.org/autocomplete/search;1?name=addrbook {2f946df9-114c-41fe-8899-81f10daf4f0c}
component {127b341a-bdda-4270-85e1-edff569a9b85} nsAbLDAPAttributeMap.js
contract @mozilla.org/addressbook/ldap-attribute-map;1 {127b341a-bdda-4270-85e1-edff569a9b85}
component {4ed7d5e1-8800-40da-9e78-c4f509d7ac5e} nsAbLDAPAttributeMap.js
contract @mozilla.org/addressbook/ldap-attribute-map-service;1 {4ed7d5e1-8800-40da-9e78-c4f509d7ac5e}
#ifdef MOZ_LDAP_XPCOM
component {227e6482-fe9f-441f-9b7d-7b60375e7449} nsAbLDAPAutoCompleteSearch.js
contract @mozilla.org/autocomplete/search;1?name=ldap {227e6482-fe9f-441f-9b7d-7b60375e7449}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
/* -*- 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 _NSDIRPREFS_H_
#define _NSDIRPREFS_H_
#include "nsTArray.h"
//
// XXX nsDirPrefs is being greatly reduced if not removed altogether. Directory
// Prefs etc. should be handled via their appropriate nsAb*Directory classes.
//
#define kPreviousListVersion 2
#define kCurrentListVersion 3
#define PREF_LDAP_GLOBAL_TREE_NAME "ldap_2"
#define PREF_LDAP_VERSION_NAME "ldap_2.version"
#define PREF_LDAP_SERVER_TREE_NAME "ldap_2.servers"
#define kMainLdapAddressBook "ldap.mab" /* v3 main ldap address book file */
/* DIR_Server.dirType */
typedef enum
{
LDAPDirectory,
HTMLDirectory,
PABDirectory,
MAPIDirectory,
FixedQueryLDAPDirectory = 777
} DirectoryType;
typedef enum
{
idNone = 0, /* Special value */
idPrefName,
idPosition,
idDescription,
idFileName,
idUri,
idType
} DIR_PrefId;
#define DIR_Server_typedef 1 /* this quiets a redeclare warning in libaddr */
typedef struct DIR_Server
{
/* Housekeeping fields */
char *prefName; /* preference name, this server's subtree */
int32_t position; /* relative position in server list */
/* General purpose fields */
char *description; /* human readable name */
char *fileName; /* XP path name of local DB */
DirectoryType dirType;
char *uri; // URI of the address book
// Set whilst saving the server to avoid updating it again
bool savingServer;
} DIR_Server;
/* We are developing a new model for managing DIR_Servers. In the 4.0x world, the FEs managed each list.
Calls to FE_GetDirServer caused the FEs to manage and return the DIR_Server list. In our new view of the
world, the back end does most of the list management so we are going to have the back end create and
manage the list. Replace calls to FE_GetDirServers() with DIR_GetDirServers(). */
nsTArray<DIR_Server*>* DIR_GetDirectories();
DIR_Server* DIR_GetServerFromList(const char* prefName);
nsresult DIR_ShutDown(void); /* FEs should call this when the app is shutting down. It frees all DIR_Servers regardless of ref count values! */
nsresult DIR_AddNewAddressBook(const nsAString &dirName,
const nsACString &fileName,
const nsACString &uri,
DirectoryType dirType,
const nsACString &prefName,
DIR_Server** pServer);
nsresult DIR_ContainsServer(DIR_Server* pServer, bool *hasDir);
nsresult DIR_DeleteServerFromList (DIR_Server *);
void DIR_SavePrefsForOneServer(DIR_Server *server);
void DIR_SetServerFileName(DIR_Server* pServer);
#endif /* dirprefs.h */

View file

@ -0,0 +1,147 @@
/* -*- 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 "nsMapiAddressBook.h"
#include "mozilla/Logging.h"
#ifdef PR_LOGGING
static PRLogModuleInfo* gMapiAddressBookLog
= PR_NewLogModule("nsMapiAddressBookLog");
#endif
#define PRINTF(args) MOZ_LOG(gMapiAddressBookLog, mozilla::LogLevel::Debug, args)
using namespace mozilla;
HMODULE nsMapiAddressBook::mLibrary = NULL ;
int32_t nsMapiAddressBook::mLibUsage = 0 ;
LPMAPIINITIALIZE nsMapiAddressBook::mMAPIInitialize = NULL ;
LPMAPIUNINITIALIZE nsMapiAddressBook::mMAPIUninitialize = NULL ;
LPMAPIALLOCATEBUFFER nsMapiAddressBook::mMAPIAllocateBuffer = NULL ;
LPMAPIFREEBUFFER nsMapiAddressBook::mMAPIFreeBuffer = NULL ;
LPMAPILOGONEX nsMapiAddressBook::mMAPILogonEx = NULL ;
BOOL nsMapiAddressBook::mInitialized = FALSE ;
BOOL nsMapiAddressBook::mLogonDone = FALSE ;
LPMAPISESSION nsMapiAddressBook::mRootSession = NULL ;
LPADRBOOK nsMapiAddressBook::mRootBook = NULL ;
BOOL nsMapiAddressBook::LoadMapiLibrary(void)
{
if (mLibrary) { ++ mLibUsage ; return TRUE ; }
HMODULE libraryHandle = LoadLibrary("MAPI32.DLL") ;
if (!libraryHandle) { return FALSE ; }
FARPROC entryPoint = GetProcAddress(libraryHandle, "MAPIGetNetscapeVersion") ;
if (entryPoint) {
FreeLibrary(libraryHandle) ;
libraryHandle = LoadLibrary("MAPI32BAK.DLL") ;
if (!libraryHandle) { return FALSE ; }
}
mLibrary = libraryHandle ;
++ mLibUsage ;
mMAPIInitialize = reinterpret_cast<LPMAPIINITIALIZE>(GetProcAddress(mLibrary, "MAPIInitialize")) ;
if (!mMAPIInitialize) { return FALSE ; }
mMAPIUninitialize = reinterpret_cast<LPMAPIUNINITIALIZE>(GetProcAddress(mLibrary, "MAPIUninitialize")) ;
if (!mMAPIUninitialize) { return FALSE ; }
mMAPIAllocateBuffer = reinterpret_cast<LPMAPIALLOCATEBUFFER>(GetProcAddress(mLibrary, "MAPIAllocateBuffer")) ;
if (!mMAPIAllocateBuffer) { return FALSE ; }
mMAPIFreeBuffer = reinterpret_cast<LPMAPIFREEBUFFER>(GetProcAddress(mLibrary, "MAPIFreeBuffer")) ;
if (!mMAPIFreeBuffer) { return FALSE ; }
mMAPILogonEx = reinterpret_cast<LPMAPILOGONEX>(GetProcAddress(mLibrary, "MAPILogonEx")) ;
if (!mMAPILogonEx) { return FALSE ; }
MAPIINIT_0 mapiInit = { MAPI_INIT_VERSION, MAPI_MULTITHREAD_NOTIFICATIONS } ;
HRESULT retCode = mMAPIInitialize(&mapiInit) ;
if (HR_FAILED(retCode)) {
PRINTF(("Cannot initialize MAPI %08x.\n", retCode)) ; return FALSE ;
}
mInitialized = TRUE ;
retCode = mMAPILogonEx(0, NULL, NULL,
MAPI_NO_MAIL |
MAPI_USE_DEFAULT |
MAPI_EXTENDED |
MAPI_NEW_SESSION,
&mRootSession) ;
if (HR_FAILED(retCode)) {
PRINTF(("Cannot logon to MAPI %08x.\n", retCode)) ; return FALSE ;
}
mLogonDone = TRUE ;
retCode = mRootSession->OpenAddressBook(0, NULL, 0, &mRootBook) ;
if (HR_FAILED(retCode)) {
PRINTF(("Cannot open MAPI address book %08x.\n", retCode)) ;
}
return HR_SUCCEEDED(retCode) ;
}
void nsMapiAddressBook::FreeMapiLibrary(void)
{
if (mLibrary) {
if (-- mLibUsage == 0) {
{
if (mRootBook) { mRootBook->Release() ; }
if (mRootSession) {
if (mLogonDone) {
mRootSession->Logoff(NULL, 0, 0) ;
mLogonDone = FALSE ;
}
mRootSession->Release() ;
}
if (mInitialized) {
mMAPIUninitialize() ;
mInitialized = FALSE ;
}
}
FreeLibrary(mLibrary) ;
mLibrary = NULL ;
}
}
}
nsMapiAddressBook::nsMapiAddressBook(void)
: nsAbWinHelper()
{
BOOL result = Initialize() ;
NS_ASSERTION(result == TRUE, "Couldn't initialize Mapi Helper") ;
MOZ_COUNT_CTOR(nsMapiAddressBook) ;
}
nsMapiAddressBook::~nsMapiAddressBook(void)
{
MutexAutoLock guard(*mMutex) ;
FreeMapiLibrary() ;
MOZ_COUNT_DTOR(nsMapiAddressBook) ;
}
BOOL nsMapiAddressBook::Initialize(void)
{
if (mAddressBook) { return TRUE ; }
MutexAutoLock guard(*mMutex) ;
if (!LoadMapiLibrary()) {
PRINTF(("Cannot load library.\n")) ;
return FALSE ;
}
mAddressBook = mRootBook ;
return TRUE ;
}
void nsMapiAddressBook::AllocateBuffer(ULONG aByteCount, LPVOID *aBuffer)
{
mMAPIAllocateBuffer(aByteCount, aBuffer) ;
}
void nsMapiAddressBook::FreeBuffer(LPVOID aBuffer)
{
mMAPIFreeBuffer(aBuffer) ;
}

View file

@ -0,0 +1,54 @@
/* -*- 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 nsMapiAddressBook_h___
#define nsMapiAddressBook_h___
#include "mozilla/Attributes.h"
#include "nsAbWinHelper.h"
class nsMapiAddressBook : public nsAbWinHelper
{
public :
nsMapiAddressBook(void) ;
virtual ~nsMapiAddressBook(void) ;
protected :
// Class members to handle the library/entry points
static HMODULE mLibrary ;
static int32_t mLibUsage ;
static LPMAPIINITIALIZE mMAPIInitialize ;
static LPMAPIUNINITIALIZE mMAPIUninitialize ;
static LPMAPIALLOCATEBUFFER mMAPIAllocateBuffer ;
static LPMAPIFREEBUFFER mMAPIFreeBuffer ;
static LPMAPILOGONEX mMAPILogonEx ;
// Shared session and address book used by all instances.
// For reasons best left unknown, MAPI doesn't seem to like
// having different threads playing with supposedly different
// sessions and address books. They ll end up fighting over
// the same resources, with hangups and GPF resulting. Not nice.
// So it seems that if everybody (as long as some client is
// still alive) is using the same sessions and address books,
// MAPI feels better. And who are we to get in the way of MAPI
// happiness? Thus the following class members:
static BOOL mInitialized ;
static BOOL mLogonDone ;
static LPMAPISESSION mRootSession ;
static LPADRBOOK mRootBook ;
// Load the MAPI environment
BOOL Initialize(void) ;
// Allocation of a buffer for transmission to interfaces
virtual void AllocateBuffer(ULONG aByteCount, LPVOID *aBuffer) override;
// Destruction of a buffer provided by the interfaces
virtual void FreeBuffer(LPVOID aBuffer) override;
// Library management
static BOOL LoadMapiLibrary(void) ;
static void FreeMapiLibrary(void) ;
private :
} ;
#endif // nsMapiAddressBook_h___

View file

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 4; 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 "nsMsgVCardService.h"
#include "nsVCard.h"
#include "prmem.h"
#include "plstr.h"
NS_IMPL_ISUPPORTS(nsMsgVCardService, nsIMsgVCardService)
nsMsgVCardService::nsMsgVCardService()
{
}
nsMsgVCardService::~nsMsgVCardService()
{
}
NS_IMETHODIMP_(void) nsMsgVCardService::CleanVObject(VObject * o)
{
cleanVObject(o);
}
NS_IMETHODIMP_(VObject *) nsMsgVCardService::NextVObjectInList(VObject * o)
{
return nextVObjectInList(o);
}
NS_IMETHODIMP_(VObject *) nsMsgVCardService::Parse_MIME(const char *input, uint32_t len)
{
return parse_MIME(input, (unsigned long)len);
}
NS_IMETHODIMP_(char *) nsMsgVCardService::FakeCString(VObject * o)
{
return fakeCString(vObjectUStringZValue(o));
}
NS_IMETHODIMP_(VObject *) nsMsgVCardService::IsAPropertyOf(VObject * o, const char *id)
{
return isAPropertyOf(o,id);
}
NS_IMETHODIMP_(char *) nsMsgVCardService::WriteMemoryVObjects(const char *s, int32_t *len, VObject * list, bool expandSpaces)
{
return writeMemoryVObjects((char *)s, len, list, expandSpaces);
}
NS_IMETHODIMP_(VObject *) nsMsgVCardService::NextVObject(VObjectIterator * i)
{
return nextVObject(i);
}
NS_IMETHODIMP_(void) nsMsgVCardService::InitPropIterator(VObjectIterator * i, VObject * o)
{
initPropIterator(i,o);
}
NS_IMETHODIMP_(int32_t) nsMsgVCardService::MoreIteration(VObjectIterator * i)
{
return ((int32_t)moreIteration(i));
}
NS_IMETHODIMP_(const char *) nsMsgVCardService::VObjectName(VObject * o)
{
return vObjectName(o);
}
NS_IMETHODIMP_(char *) nsMsgVCardService::VObjectAnyValue(VObject * o)
{
char *retval = (char *)PR_MALLOC(strlen((char *)vObjectAnyValue(o)) + 1);
if (retval)
PL_strcpy(retval, (char *) vObjectAnyValue(o));
return retval;
}

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 nsMsgVCardService_h___
#define nsMsgVCardService_h___
#include "nsIMsgVCardService.h"
#include "nsISupports.h"
class nsMsgVCardService : public nsIMsgVCardService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGVCARDSERVICE
nsMsgVCardService();
private:
virtual ~nsMsgVCardService();
};
#endif /* nsMsgVCardService_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/* -*- Mode: C; tab-width: 4; 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/. */
/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
#ifndef __VCC_H__
#define __VCC_H__ 1
#include "nsVCardObj.h"
#ifdef __cplusplus
extern "C" {
#endif
VObject* parse_MIME(const char *input, unsigned long len);
typedef void (*MimeErrorHandler)(char *);
void registerMimeErrorHandler(MimeErrorHandler);
#ifdef __cplusplus
}
#endif
#endif /* __VCC_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,396 @@
/* -*- Mode: C; tab-width: 4; 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/. */
/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
/*
The vCard/vCalendar C interface is implemented in the set
of files as follows:
vcc.y, yacc source, and vcc.c, the yacc output you will use
implements the core parser
vobject.c implements an API that insulates the caller from
the parser and changes in the vCard/vCalendar BNF
port.h defines compilation environment dependent stuff
vcc.h and vobject.h are header files for their .c counterparts
vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
which you may find useful.
test.c is a standalone test driver that exercises some of
the features of the APIs provided. Invoke test.exe on a
VCARD/VCALENDAR input text file and you will see the pretty
print output of the internal representation (this pretty print
output should give you a good idea of how the internal
representation looks like -- there is one such output in the
following too). Also, a file with the .out suffix is generated
to show that the internal representation can be written back
in the original text format.
For more information on this API see the readme.txt file
which accompanied this distribution.
Also visit:
http://www.versit.com
http://www.ralden.com
*/
#ifndef __VOBJECT_H__
#define __VOBJECT_H__ 1
/*
Unfortunately, on the Mac (and possibly other platforms) with our current, out-dated
libraries (Plauger), |wchar_t| is defined incorrectly, which breaks vcards.
We can't fix Plauger because it doesn't come with source. Later, when we
upgrade to MSL, we can make this evil hack go away. In the mean time,
vcards are not allowed to use the (incorrectly defined) |wchar_t| type. Instead,
they will use an appropriately defined local type |vwchar_t|.
*/
typedef wchar_t vwchar_t;
#ifdef __cplusplus
extern "C" {
#endif
#define VC7bitProp "7bit"
#define VC8bitProp "8bit"
#define VCAAlarmProp "aalarm"
#define VCAdditionalNamesProp "addn"
#define VCAdrProp "adr"
#define VCAgentProp "agent"
#define VCAIFFProp "aiff"
#define VCAOLProp "aol"
#define VCAppleLinkProp "applelink"
#define VCAttachProp "attach"
#define VCAttendeeProp "attendee"
#define VCATTMailProp "attmail"
#define VCAudioContentProp "audiocontent"
#define VCAVIProp "avi"
#define VCBase64Prop "base64"
#define VCBBSProp "bbs"
#define VCBirthDateProp "bday"
#define VCBMPProp "bmp"
#define VCBodyProp "body"
#define VCBusinessRoleProp "role"
#define VCCalProp "vcalendar"
#define VCCaptionProp "cap"
#define VCCardProp "vcard"
#define VCCarProp "car"
#define VCCategoriesProp "categories"
#define VCCellularProp "cell"
#define VCCGMProp "cgm"
#define VCCharSetProp "cs"
#define VCCIDProp "cid"
#define VCCISProp "cis"
#define VCCityProp "l"
#define VCClassProp "class"
#define VCCommentProp "note"
#define VCCompletedProp "completed"
#define VCContentIDProp "content-id"
#define VCCountryNameProp "c"
#define VCDAlarmProp "dalarm"
#define VCDataSizeProp "datasize"
#define VCDayLightProp "daylight"
#define VCDCreatedProp "dcreated"
#define VCDeliveryLabelProp "label"
#define VCDescriptionProp "description"
#define VCDIBProp "dib"
#define VCDisplayStringProp "displaystring"
#define VCDomesticProp "dom"
#define VCDTendProp "dtend"
#define VCDTstartProp "dtstart"
#define VCDueProp "due"
#define VCEmailAddressProp "email"
#define VCEncodingProp "encoding"
#define VCEndProp "end"
#define VCEventProp "vevent"
#define VCEWorldProp "eworld"
#define VCExNumProp "exnum"
#define VCExpDateProp "exdate"
#define VCExpectProp "expect"
#define VCExtAddressProp "ext add"
#define VCFamilyNameProp "f"
#define VCFaxProp "fax"
#define VCFullNameProp "fn"
#define VCGeoProp "geo"
#define VCGeoLocationProp "geo"
#define VCGIFProp "gif"
#define VCGivenNameProp "g"
#define VCGroupingProp "grouping"
#define VCHomeProp "home"
#define VCIBMMailProp "ibmmail"
#define VCInlineProp "inline"
#define VCInternationalProp "intl"
#define VCInternetProp "internet"
#define VCISDNProp "isdn"
#define VCJPEGProp "jpeg"
#define VCLanguageProp "lang"
#define VCLastModifiedProp "last-modified"
#define VCLastRevisedProp "rev"
#define VCLocationProp "location"
#define VCLogoProp "logo"
#define VCMailerProp "mailer"
#define VCMAlarmProp "malarm"
#define VCMCIMailProp "mcimail"
#define VCMessageProp "msg"
#define VCMETProp "met"
#define VCModemProp "modem"
#define VCMPEG2Prop "mpeg2"
#define VCMPEGProp "mpeg"
#define VCMSNProp "msn"
#define VCNamePrefixesProp "npre"
#define VCNameProp "n"
#define VCNameSuffixesProp "nsuf"
#define VCNoteProp "note"
#define VCOrgNameProp "orgname"
#define VCOrgProp "org"
#define VCOrgUnit2Prop "oun2"
#define VCOrgUnit3Prop "oun3"
#define VCOrgUnit4Prop "oun4"
#define VCOrgUnitProp "oun"
#define VCPagerProp "pager"
#define VCPAlarmProp "palarm"
#define VCParcelProp "parcel"
#define VCPartProp "part"
#define VCPCMProp "pcm"
#define VCPDFProp "pdf"
#define VCPGPProp "pgp"
#define VCPhotoProp "photo"
#define VCPICTProp "pict"
#define VCPMBProp "pmb"
#define VCPostalBoxProp "box"
#define VCPostalCodeProp "pc"
#define VCPostalProp "postal"
#define VCPowerShareProp "powershare"
#define VCPreferredProp "pref"
#define VCPriorityProp "priority"
#define VCProcedureNameProp "procedurename"
#define VCProdIdProp "prodid"
#define VCProdigyProp "prodigy"
#define VCPronunciationProp "sound"
#define VCPSProp "ps"
#define VCPublicKeyProp "key"
#define VCQPProp "qp"
#define VCQuickTimeProp "qtime"
#define VCQuotedPrintableProp "quoted-printable"
#define VCRDateProp "rdate"
#define VCRegionProp "r"
#define VCRelatedToProp "related-to"
#define VCRepeatCountProp "repeatcount"
#define VCResourcesProp "resources"
#define VCRNumProp "rnum"
#define VCRoleProp "role"
#define VCRRuleProp "rrule"
#define VCRSVPProp "rsvp"
#define VCRunTimeProp "runtime"
#define VCSequenceProp "sequence"
#define VCSnoozeTimeProp "snoozetime"
#define VCStartProp "start"
#define VCStatusProp "status"
#define VCStreetAddressProp "street"
#define VCSubTypeProp "subtype"
#define VCSummaryProp "summary"
#define VCTelephoneProp "tel"
#define VCTIFFProp "tiff"
#define VCTimeZoneProp "tz"
#define VCTitleProp "title"
#define VCTLXProp "tlx"
#define VCTodoProp "vtodo"
#define VCTranspProp "transp"
#define VCUniqueStringProp "uid"
#define VCURLProp "url"
#define VCURLValueProp "urlval"
#define VCValueProp "value"
#define VCVersionProp "version"
#define VCVideoProp "video"
#define VCVoiceProp "voice"
#define VCWAVEProp "wave"
#define VCWMFProp "wmf"
#define VCWorkProp "work"
#define VCX400Prop "x400"
#define VCX509Prop "x509"
#define VCXRuleProp "xrule"
#define VCCooltalk "x-mozilla-cpt"
#define VCCooltalkAddress "x-moxilla-cpadr"
#define VCUseServer "x-mozilla-cpsrv"
#define VCUseHTML "x-mozilla-html"
/* return type of vObjectValueType: */
#define VCVT_NOVALUE 0
/* if the VObject has no value associated with it. */
#define VCVT_STRINGZ 1
/* if the VObject has value set by setVObjectStringZValue. */
#define VCVT_USTRINGZ 2
/* if the VObject has value set by setVObjectUStringZValue. */
#define VCVT_UINT 3
/* if the VObject has value set by setVObjectIntegerValue. */
#define VCVT_ULONG 4
/* if the VObject has value set by setVObjectLongValue. */
#define VCVT_RAW 5
/* if the VObject has value set by setVObjectAnyValue. */
#define VCVT_VOBJECT 6
/* if the VObject has value set by setVObjectVObjectValue. */
#define NAME_OF(o) o->id
#define VALUE_TYPE(o) o->valType
#define STRINGZ_VALUE_OF(o) o->val.strs
#define USTRINGZ_VALUE_OF(o) o->val.ustrs
#define INTEGER_VALUE_OF(o) o->val.i
#define LONG_VALUE_OF(o) o->val.l
#define ANY_VALUE_OF(o) o->val.any
#define VOBJECT_VALUE_OF(o) o->val.vobj
typedef struct VObject VObject;
typedef union ValueItem {
const char *strs;
const vwchar_t *ustrs;
unsigned int i;
unsigned long l;
void *any;
VObject *vobj;
} ValueItem;
struct VObject {
VObject *next;
const char *id;
VObject *prop;
unsigned short valType;
ValueItem val;
};
typedef struct StrItem StrItem;
struct StrItem {
StrItem *next;
const char *s;
unsigned int refCnt;
};
typedef struct OFile {
char *s;
int len;
int limit;
int alloc:1;
int fail:1;
} OFile;
typedef struct VObjectIterator {
VObject* start;
VObject* next;
} VObjectIterator;
VObject* newVObject(const char *id);
void deleteVObject(VObject *p);
char* dupStr(const char *s, unsigned int size);
extern "C" void deleteString(char *p);
void unUseStr(const char *s);
void setVObjectName(VObject *o, const char* id);
void setVObjectStringZValue(VObject *o, const char *s);
void setVObjectStringZValue_(VObject *o, const char *s);
void setVObjectUStringZValue(VObject *o, const vwchar_t *s);
void setVObjectUStringZValue_(VObject *o, const vwchar_t *s);
void setVObjectIntegerValue(VObject *o, unsigned int i);
void setVObjectLongValue(VObject *o, unsigned long l);
void setVObjectAnyValue(VObject *o, void *t);
VObject* setValueWithSize(VObject *prop, void *val, unsigned int size);
VObject* setValueWithSize_(VObject *prop, void *val, unsigned int size);
const char* vObjectName(VObject *o);
const char* vObjectStringZValue(VObject *o);
const vwchar_t* vObjectUStringZValue(VObject *o);
unsigned int vObjectIntegerValue(VObject *o);
unsigned long vObjectLongValue(VObject *o);
void* vObjectAnyValue(VObject *o);
VObject* vObjectVObjectValue(VObject *o);
void setVObjectVObjectValue(VObject *o, VObject *p);
VObject* addVObjectProp(VObject *o, VObject *p);
VObject* addProp(VObject *o, const char *id);
VObject* addProp_(VObject *o, const char *id);
VObject* addPropValue(VObject *o, const char *p, const char *v);
VObject* addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size);
VObject* addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size);
VObject* addGroup(VObject *o, const char *g);
void addList(VObject **o, VObject *p);
VObject* isAPropertyOf(VObject *o, const char *id);
VObject* nextVObjectInList(VObject *o);
void initPropIterator(VObjectIterator *i, VObject *o);
int moreIteration(VObjectIterator *i);
VObject* nextVObject(VObjectIterator *i);
void writeVObject_(OFile *fp, VObject *o);
char* writeMemVObject(char *s, int *len, VObject *o);
extern "C" char* writeMemoryVObjects(char *s, int *len, VObject *list, bool expandSpaces);
const char* lookupStr(const char *s);
void cleanVObject(VObject *o);
void cleanVObjects(VObject *list);
const char* lookupProp(const char* str);
const char* lookupProp_(const char* str);
vwchar_t* fakeUnicode(const char *ps, int *bytes);
int uStrLen(const vwchar_t *u);
char* fakeCString(const vwchar_t *u);
#define MAXPROPNAMESIZE 256
#define MAXMOZPROPNAMESIZE 16
#ifdef __cplusplus
}
#endif
#endif /* __VOBJECT_H__ */

View file

@ -0,0 +1,128 @@
/* -*- 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 <tchar.h>
#include "nsWabAddressBook.h"
#include "mozilla/Logging.h"
#include <algorithm>
#ifdef PR_LOGGING
static PRLogModuleInfo* gWabAddressBookLog
= PR_NewLogModule("nsWabAddressBookLog");
#endif
#define PRINTF(args) MOZ_LOG(gWabAddressBookLog, mozilla::LogLevel::Debug, args)
using namespace mozilla;
HMODULE nsWabAddressBook::mLibrary = NULL ;
int32_t nsWabAddressBook::mLibUsage = 0 ;
LPWABOPEN nsWabAddressBook::mWABOpen = NULL ;
LPWABOBJECT nsWabAddressBook::mRootSession = NULL ;
LPADRBOOK nsWabAddressBook::mRootBook = NULL ;
BOOL nsWabAddressBook::LoadWabLibrary(void)
{
if (mLibrary) { ++ mLibUsage ; return TRUE ; }
// We try to fetch the location of the WAB DLL from the registry
TCHAR wabDLLPath [MAX_PATH] ;
DWORD keyType = 0 ;
ULONG byteCount = sizeof(wabDLLPath) ;
HKEY keyHandle = NULL ;
wabDLLPath [MAX_PATH - 1] = 0 ;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &keyHandle) == ERROR_SUCCESS) {
RegQueryValueEx(keyHandle, "", NULL, &keyType, (LPBYTE) wabDLLPath, &byteCount) ;
if (keyType == REG_EXPAND_SZ) {
// Expand the environment variables
DWORD bufferSize = ExpandEnvironmentStrings(wabDLLPath, NULL, 0);
if (bufferSize && bufferSize < MAX_PATH) {
TCHAR tmp[MAX_PATH];
ExpandEnvironmentStrings(wabDLLPath, tmp, bufferSize);
_tcscpy(wabDLLPath, tmp);
}
else {
return FALSE;
}
}
}
else {
if (GetSystemDirectory(wabDLLPath, MAX_PATH)) {
_tcsncat(wabDLLPath, WAB_DLL_NAME,
std::min(_tcslen(WAB_DLL_NAME), MAX_PATH - _tcslen(wabDLLPath) - 1));
}
else {
return FALSE;
}
}
if (keyHandle) { RegCloseKey(keyHandle) ; }
mLibrary = LoadLibrary( (lstrlen(wabDLLPath)) ? wabDLLPath : WAB_DLL_NAME );
if (!mLibrary) { return FALSE ; }
++ mLibUsage ;
mWABOpen = reinterpret_cast<LPWABOPEN>(GetProcAddress(mLibrary, "WABOpen")) ;
if (!mWABOpen) { return FALSE ; }
HRESULT retCode = mWABOpen(&mRootBook, &mRootSession, NULL, 0) ;
if (HR_FAILED(retCode)) {
PRINTF(("Cannot initialize WAB %08x.\n", retCode)) ; return FALSE ;
}
return TRUE ;
}
void nsWabAddressBook::FreeWabLibrary(void)
{
if (mLibrary) {
if (-- mLibUsage == 0) {
if (mRootBook) { mRootBook->Release() ; }
if (mRootSession) { mRootSession->Release() ; }
FreeLibrary(mLibrary) ;
mLibrary = NULL ;
}
}
}
nsWabAddressBook::nsWabAddressBook(void)
: nsAbWinHelper()
{
BOOL result = Initialize() ;
NS_ASSERTION(result == TRUE, "Couldn't initialize Wab Helper") ;
MOZ_COUNT_CTOR(nsWabAddressBook) ;
}
nsWabAddressBook::~nsWabAddressBook(void)
{
MutexAutoLock guard(*mMutex) ;
FreeWabLibrary() ;
MOZ_COUNT_DTOR(nsWabAddressBook) ;
}
BOOL nsWabAddressBook::Initialize(void)
{
if (mAddressBook) { return TRUE ; }
MutexAutoLock guard(*mMutex) ;
if (!LoadWabLibrary()) {
PRINTF(("Cannot load library.\n")) ;
return FALSE ;
}
mAddressBook = mRootBook ;
return TRUE ;
}
void nsWabAddressBook::AllocateBuffer(ULONG aByteCount, LPVOID *aBuffer)
{
mRootSession->AllocateBuffer(aByteCount, aBuffer) ;
}
void nsWabAddressBook::FreeBuffer(LPVOID aBuffer)
{
mRootSession->FreeBuffer(aBuffer) ;
}

View file

@ -0,0 +1,57 @@
/* -*- 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 nsWabAddressBook_h___
#define nsWabAddressBook_h___
#include "mozilla/Attributes.h"
#include "nsAbWinHelper.h"
#include <wab.h>
class nsWabAddressBook : public nsAbWinHelper
{
public :
nsWabAddressBook(void) ;
virtual ~nsWabAddressBook(void) ;
protected :
// Session and address book that will be shared by all instances
// (see nsMapiAddressBook.h for details)
static LPWABOBJECT mRootSession ;
static LPADRBOOK mRootBook ;
// Class members to handle library loading/entry points
static int32_t mLibUsage ;
static HMODULE mLibrary ;
static LPWABOPEN mWABOpen ;
// Load the WAB environment
BOOL Initialize(void) ;
// Allocation of a buffer for transmission to interfaces
virtual void AllocateBuffer(ULONG aByteCount, LPVOID *aBuffer) override;
// Destruction of a buffer provided by the interfaces
virtual void FreeBuffer(LPVOID aBuffer) override;
// Manage the library
static BOOL LoadWabLibrary(void) ;
static void FreeWabLibrary(void) ;
private :
} ;
// Additional definitions for WAB stuff. These properties are
// only defined with regards to the default character sizes,
// and not in two _A and _W versions...
#define PR_BUSINESS_ADDRESS_CITY_A PR_LOCALITY_A
#define PR_BUSINESS_ADDRESS_COUNTRY_A PR_COUNTRY_A
#define PR_BUSINESS_ADDRESS_POSTAL_CODE_A PR_POSTAL_CODE_A
#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A PR_STATE_OR_PROVINCE_A
#define PR_BUSINESS_ADDRESS_STREET_A PR_STREET_ADDRESS_A
#define PR_BUSINESS_ADDRESS_CITY_W PR_LOCALITY_W
#define PR_BUSINESS_ADDRESS_COUNTRY_W PR_COUNTRY_W
#define PR_BUSINESS_ADDRESS_POSTAL_CODE_W PR_POSTAL_CODE_W
#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W PR_STATE_OR_PROVINCE_W
#define PR_BUSINESS_ADDRESS_STREET_W PR_STREET_ADDRESS_W
#endif // nsWABAddressBook_h___