summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsAbOutlookDirectory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/src/nsAbOutlookDirectory.cpp')
-rw-r--r--mailnews/addrbook/src/nsAbOutlookDirectory.cpp1539
1 files changed, 1539 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbOutlookDirectory.cpp b/mailnews/addrbook/src/nsAbOutlookDirectory.cpp
new file mode 100644
index 000000000..0d39d1d17
--- /dev/null
+++ b/mailnews/addrbook/src/nsAbOutlookDirectory.cpp
@@ -0,0 +1,1539 @@
+/* -*- 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 "nsAbOutlookDirectory.h"
+#include "nsAbWinHelper.h"
+
+#include "nsAbBaseCID.h"
+#include "nsIAbCard.h"
+#include "nsStringGlue.h"
+#include "nsAbDirectoryQuery.h"
+#include "nsIAbBooleanExpression.h"
+#include "nsIAbManager.h"
+#include "nsIAbMDBDirectory.h"
+#include "nsAbQueryStringToExpression.h"
+#include "nsAbUtils.h"
+#include "nsEnumeratorUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/Logging.h"
+#include "prthread.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsCRTGlue.h"
+#include "nsArrayUtils.h"
+#include "nsArrayEnumerator.h"
+#include "nsMsgUtils.h"
+
+#ifdef PR_LOGGING
+static PRLogModuleInfo* gAbOutlookDirectoryLog
+ = PR_NewLogModule("nsAbOutlookDirectoryLog");
+#endif
+
+#define PRINTF(args) MOZ_LOG(gAbOutlookDirectoryLog, mozilla::LogLevel::Debug, args)
+
+nsAbOutlookDirectory::nsAbOutlookDirectory(void)
+ : nsAbDirProperty(),
+ mCurrentQueryId(0), mSearchContext(-1),
+ mAbWinType(nsAbWinType_Unknown), mMapiData(nullptr)
+{
+ mMapiData = new nsMapiEntry ;
+ mProtector = PR_NewLock() ;
+}
+
+nsAbOutlookDirectory::~nsAbOutlookDirectory(void)
+{
+ if (mMapiData) { delete mMapiData ; }
+ if (mProtector) { PR_DestroyLock(mProtector) ; }
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(nsAbOutlookDirectory, nsAbDirProperty,
+ nsIAbDirectoryQuery, nsIAbDirectorySearch,
+ nsIAbDirSearchListener)
+
+NS_IMETHODIMP nsAbOutlookDirectory::Init(const char *aUri)
+{
+ nsresult rv = nsAbDirProperty::Init(aUri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString entry;
+ nsAutoCString stub;
+
+ mAbWinType = getAbWinType(kOutlookDirectoryScheme, mURINoQuery.get(), stub, entry);
+ if (mAbWinType == nsAbWinType_Unknown) {
+ PRINTF(("Huge problem URI=%s.\n", mURINoQuery));
+ return NS_ERROR_INVALID_ARG;
+ }
+ nsAbWinHelperGuard mapiAddBook (mAbWinType);
+ nsString prefix;
+ nsAutoString unichars;
+ ULONG objectType = 0;
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ mMapiData->Assign(entry);
+ if (!mapiAddBook->GetPropertyLong(*mMapiData, PR_OBJECT_TYPE, objectType)) {
+ PRINTF(("Cannot get type.\n"));
+ return NS_ERROR_FAILURE;
+ }
+ if (!mapiAddBook->GetPropertyUString(*mMapiData, PR_DISPLAY_NAME_W, unichars)) {
+ PRINTF(("Cannot get name.\n"));
+ return NS_ERROR_FAILURE;
+ }
+
+ if (mAbWinType == nsAbWinType_Outlook)
+ prefix.AssignLiteral("OP ");
+ else
+ prefix.AssignLiteral("OE ");
+ prefix.Append(unichars);
+
+ if (objectType == MAPI_DISTLIST) {
+ m_IsMailList = true;
+ SetDirName(unichars);
+ }
+ else {
+ m_IsMailList = false;
+ SetDirName(prefix);
+ }
+
+ return UpdateAddressList();
+}
+
+// nsIAbDirectory methods
+
+NS_IMETHODIMP nsAbOutlookDirectory::GetDirType(int32_t *aDirType)
+{
+ NS_ENSURE_ARG_POINTER(aDirType);
+ *aDirType = MAPIDirectory;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::GetURI(nsACString &aURI)
+{
+ if (mURI.IsEmpty())
+ return NS_ERROR_NOT_INITIALIZED;
+
+ aURI = mURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::GetChildNodes(nsISimpleEnumerator **aNodes)
+{
+ NS_ENSURE_ARG_POINTER(aNodes);
+
+ *aNodes = nullptr;
+
+ if (mIsQueryURI) {
+ return NS_NewEmptyEnumerator(aNodes);
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> nodeList(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = GetChildNodes(nodeList);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewArrayEnumerator(aNodes, nodeList);
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::GetChildCards(nsISimpleEnumerator **aCards)
+{
+ NS_ENSURE_ARG_POINTER(aCards);
+ *aCards = nullptr;
+
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> cardList(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mCardList.Clear();
+
+ rv = mIsQueryURI ? StartSearch() : GetChildCards(cardList, nullptr);
+
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!m_AddressList)
+ {
+ m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Fill the results array and update the card list
+ // Also update the address list and notify any changes.
+ uint32_t nbCards = 0;
+
+ NS_NewArrayEnumerator(aCards, cardList);
+ cardList->GetLength(&nbCards);
+
+ nsCOMPtr<nsIAbCard> card;
+ nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID,
+ &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+
+ for (uint32_t i = 0; i < nbCards; ++i)
+ {
+ card = do_QueryElementAt(cardList, i, &rv);
+ if (NS_FAILED(rv))
+ continue;
+
+ if (!mCardList.Get(card, nullptr))
+ {
+ // We are dealing with a new element (probably directly
+ // added from Outlook), we may need to sync m_AddressList
+ mCardList.Put(card, card);
+
+ bool isMailList = false;
+
+ rv = card->GetIsMailList(&isMailList);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (isMailList)
+ {
+ // We can have mailing lists only in folder,
+ // we must add the directory to m_AddressList
+ nsCString mailListUri;
+ rv = card->GetMailListURI(getter_Copies(mailListUri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIAbDirectory> mailList;
+ rv = abManager->GetDirectory(mailListUri, getter_AddRefs(mailList));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ m_AddressList->AppendElement(mailList, false);
+ NotifyItemAddition(mailList);
+ }
+ else if (m_IsMailList)
+ {
+ m_AddressList->AppendElement(card, false);
+ NotifyItemAddition(card);
+ }
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::GetIsQuery(bool *aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = mIsQueryURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::HasCard(nsIAbCard *aCard, bool *aHasCard)
+{
+ if (!aCard || !aHasCard)
+ return NS_ERROR_NULL_POINTER;
+
+ *aHasCard = mCardList.Get(aCard, nullptr);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::HasDirectory(nsIAbDirectory *aDirectory, bool *aHasDirectory)
+{
+ NS_ENSURE_ARG_POINTER(aDirectory);
+ NS_ENSURE_ARG_POINTER(aHasDirectory);
+
+ *aHasDirectory = false;
+
+ uint32_t pos;
+ if (m_AddressList && NS_SUCCEEDED(m_AddressList->IndexOf(0, aDirectory, &pos)))
+ *aHasDirectory = true;
+
+ return NS_OK;
+}
+
+
+static nsresult ExtractCardEntry(nsIAbCard *aCard, nsCString& aEntry)
+{
+ aEntry.Truncate();
+
+ nsCString uri;
+ aCard->GetPropertyAsAUTF8String("OutlookEntryURI", uri);
+
+ // If we don't have a URI, uri will be empty. getAbWinType doesn't set
+ // aEntry to anything if uri is empty, so it will be truncated, allowing us
+ // to accept cards not initialized by us.
+ nsAutoCString stub;
+ getAbWinType(kOutlookCardScheme, uri.get(), stub, aEntry);
+ return NS_OK;
+}
+
+static nsresult ExtractDirectoryEntry(nsIAbDirectory *aDirectory, nsCString& aEntry)
+{
+ aEntry.Truncate();
+ nsCString uri;
+ nsresult rv = aDirectory->GetURI(uri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString stub;
+ nsAbWinType objType = getAbWinType(kOutlookDirectoryScheme, uri.get(), stub, aEntry);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::DeleteCards(nsIArray *aCardList)
+{
+ if (mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; }
+ if (!aCardList) { return NS_ERROR_NULL_POINTER ; }
+ uint32_t nbCards = 0 ;
+ nsresult retCode = NS_OK ;
+ nsAbWinHelperGuard mapiAddBook (mAbWinType) ;
+
+ if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; }
+
+ retCode = aCardList->GetLength(&nbCards);
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ uint32_t i = 0 ;
+ nsAutoCString entryString ;
+ nsMapiEntry cardEntry ;
+
+ for (i = 0 ; i < nbCards ; ++ i) {
+ nsCOMPtr<nsIAbCard> card(do_QueryElementAt(aCardList, i, &retCode));
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ retCode = ExtractCardEntry(card, entryString) ;
+ if (NS_SUCCEEDED(retCode) && !entryString.IsEmpty()) {
+ card->SetDirectoryId(EmptyCString());
+
+ cardEntry.Assign(entryString) ;
+ if (!mapiAddBook->DeleteEntry(*mMapiData, cardEntry)) {
+ PRINTF(("Cannot delete card %s.\n", entryString.get())) ;
+ }
+ else {
+ mCardList.Remove(card);
+ if (m_IsMailList && m_AddressList)
+ {
+ uint32_t pos;
+ if (NS_SUCCEEDED(m_AddressList->IndexOf(0, card, &pos)))
+ m_AddressList->RemoveElementAt(pos);
+ }
+ retCode = NotifyItemDeletion(card);
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ }
+ }
+ else {
+ PRINTF(("Card doesn't belong in this directory.\n")) ;
+ }
+ }
+ return NS_OK ;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::DeleteDirectory(nsIAbDirectory *aDirectory)
+{
+ if (mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; }
+ if (!aDirectory) { return NS_ERROR_NULL_POINTER ; }
+ nsresult retCode = NS_OK ;
+ nsAbWinHelperGuard mapiAddBook (mAbWinType) ;
+ nsAutoCString entryString ;
+
+ if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; }
+ retCode = ExtractDirectoryEntry(aDirectory, entryString) ;
+ if (NS_SUCCEEDED(retCode) && !entryString.IsEmpty()) {
+ nsMapiEntry directoryEntry ;
+
+ directoryEntry.Assign(entryString) ;
+ if (!mapiAddBook->DeleteEntry(*mMapiData, directoryEntry)) {
+ PRINTF(("Cannot delete directory %s.\n", entryString.get())) ;
+ }
+ else {
+ uint32_t pos;
+ if (m_AddressList && NS_SUCCEEDED(m_AddressList->IndexOf(0, aDirectory, &pos)))
+ m_AddressList->RemoveElementAt(pos);
+
+ retCode = NotifyItemDeletion(aDirectory);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ }
+ }
+ else {
+ PRINTF(("Directory doesn't belong to this folder.\n")) ;
+ }
+ return retCode ;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::AddCard(nsIAbCard *aData, nsIAbCard **addedCard)
+{
+ if (mIsQueryURI)
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ NS_ENSURE_ARG_POINTER(aData);
+
+ nsresult retCode = NS_OK ;
+ bool hasCard = false ;
+
+ retCode = HasCard(aData, &hasCard) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ if (hasCard) {
+ PRINTF(("Has card.\n")) ;
+ NS_IF_ADDREF(*addedCard = aData);
+ return NS_OK ;
+ }
+ retCode = CreateCard(aData, addedCard) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+
+ mCardList.Put(*addedCard, *addedCard);
+
+ if (!m_AddressList)
+ {
+ m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &retCode);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ }
+
+ if (m_IsMailList)
+ m_AddressList->AppendElement(*addedCard, false);
+ NotifyItemAddition(*addedCard) ;
+ return retCode ;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::DropCard(nsIAbCard *aData, bool needToCopyCard)
+{
+ nsCOMPtr <nsIAbCard> addedCard;
+ return AddCard(aData, getter_AddRefs(addedCard));
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::AddMailList(nsIAbDirectory *aMailList, nsIAbDirectory **addedList)
+{
+ if (mIsQueryURI)
+ return NS_ERROR_NOT_IMPLEMENTED;
+ NS_ENSURE_ARG_POINTER(aMailList);
+ NS_ENSURE_ARG_POINTER(addedList);
+ if (m_IsMailList)
+ return NS_OK;
+ nsAbWinHelperGuard mapiAddBook (mAbWinType);
+ nsAutoCString entryString;
+ nsMapiEntry newEntry;
+ bool didCopy = false;
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+ nsresult rv = ExtractDirectoryEntry(aMailList, entryString);
+ if (NS_SUCCEEDED(rv) && !entryString.IsEmpty())
+ {
+ nsMapiEntry sourceEntry;
+
+ sourceEntry.Assign(entryString);
+ mapiAddBook->CopyEntry(*mMapiData, sourceEntry, newEntry);
+ }
+ if (newEntry.mByteCount == 0)
+ {
+ if (!mapiAddBook->CreateDistList(*mMapiData, newEntry))
+ return NS_ERROR_FAILURE;
+ }
+ else {
+ didCopy = true;
+ }
+ newEntry.ToString(entryString);
+ nsAutoCString uri;
+
+ buildAbWinUri(kOutlookDirectoryScheme, mAbWinType, uri);
+ uri.Append(entryString);
+
+ nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID,
+ &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIAbDirectory> newList;
+ rv = abManager->GetDirectory(uri, getter_AddRefs(newList));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!didCopy)
+ {
+ rv = newList->CopyMailList(aMailList);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = newList->EditMailListToDatabase(nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (!m_AddressList)
+ {
+ m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ m_AddressList->AppendElement(newList, false);
+ NotifyItemAddition(newList);
+ NS_IF_ADDREF(*addedList = newList);
+
+ return rv;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::EditMailListToDatabase(nsIAbCard *listCard)
+{
+ if (mIsQueryURI)
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ nsresult rv;
+ nsString name;
+ nsAbWinHelperGuard mapiAddBook(mAbWinType);
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ rv = GetDirName(name);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!mapiAddBook->SetPropertyUString(*mMapiData, PR_DISPLAY_NAME_W,
+ name.get()))
+ return NS_ERROR_FAILURE;
+
+ return CommitAddressList();
+}
+
+struct OutlookTableAttr
+{
+ const char *mOuterName ;
+ ULONG mMapiProp ;
+} ;
+
+// Here, we are forced to use the Ascii versions of the properties
+// instead of the widechar ones, because the content restriction
+// operators do not work on unicode strings in mapi.
+static const OutlookTableAttr OutlookTableStringToProp [] =
+{
+ {kFirstNameProperty, PR_GIVEN_NAME_A},
+ {kLastNameProperty, PR_SURNAME_A},
+ {kDisplayNameProperty, PR_DISPLAY_NAME_A},
+ {kNicknameProperty, PR_NICKNAME_A},
+ {kPriEmailProperty, PR_EMAIL_ADDRESS_A},
+ {kWorkPhoneProperty, PR_BUSINESS_TELEPHONE_NUMBER_A},
+ {kHomePhoneProperty, PR_HOME_TELEPHONE_NUMBER_A},
+ {kFaxProperty, PR_BUSINESS_FAX_NUMBER_A},
+ {kPagerProperty, PR_PAGER_TELEPHONE_NUMBER_A},
+ {kCellularProperty, PR_MOBILE_TELEPHONE_NUMBER_A},
+ {kHomeAddressProperty, PR_HOME_ADDRESS_STREET_A},
+ {kHomeCityProperty, PR_HOME_ADDRESS_CITY_A},
+ {kHomeStateProperty, PR_HOME_ADDRESS_STATE_OR_PROVINCE_A},
+ {kHomeZipCodeProperty, PR_HOME_ADDRESS_POSTAL_CODE_A},
+ {kHomeCountryProperty, PR_HOME_ADDRESS_COUNTRY_A},
+ {kWorkAddressProperty, PR_BUSINESS_ADDRESS_STREET_A},
+ {kWorkCityProperty, PR_BUSINESS_ADDRESS_CITY_A},
+ {kWorkStateProperty, PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A},
+ {kWorkZipCodeProperty, PR_BUSINESS_ADDRESS_POSTAL_CODE_A},
+ {kWorkCountryProperty, PR_BUSINESS_ADDRESS_COUNTRY_A},
+ {kJobTitleProperty, PR_TITLE_A},
+ {kDepartmentProperty, PR_DEPARTMENT_NAME_A},
+ {kCompanyProperty, PR_COMPANY_NAME_A},
+ {kWorkWebPageProperty, PR_BUSINESS_HOME_PAGE_A},
+ {kHomeWebPageProperty, PR_PERSONAL_HOME_PAGE_A},
+ // For the moment, we don't support querying on the birthday
+ // sub-elements.
+#if 0
+ {kBirthYearProperty, PR_BIRTHDAY},
+ {kBirthMonthProperty, PR_BIRTHDAY},
+ {kBirthDayProperty, PR_BIRTHDAY},
+#endif // 0
+ {kNotesProperty, PR_COMMENT_A}
+} ;
+
+static const uint32_t OutlookTableNbProps = sizeof(OutlookTableStringToProp) /
+ sizeof(OutlookTableStringToProp [0]) ;
+
+static ULONG findPropertyTag(const char *aName) {
+ uint32_t i = 0 ;
+
+ for (i = 0 ; i < OutlookTableNbProps ; ++ i) {
+ if (strcmp(aName, OutlookTableStringToProp [i].mOuterName) == 0) {
+ return OutlookTableStringToProp [i].mMapiProp ;
+ }
+ }
+ return 0 ;
+}
+
+static nsresult BuildRestriction(nsIAbBooleanConditionString *aCondition,
+ SRestriction& aRestriction,
+ bool& aSkipItem)
+{
+ if (!aCondition) { return NS_ERROR_NULL_POINTER ; }
+ aSkipItem = false ;
+ nsAbBooleanConditionType conditionType = 0 ;
+ nsresult retCode = NS_OK ;
+ nsCString name;
+ nsString value;
+ ULONG propertyTag = 0 ;
+ nsAutoCString valueAscii ;
+
+ retCode = aCondition->GetCondition(&conditionType) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ retCode = aCondition->GetName(getter_Copies(name)) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ retCode = aCondition->GetValue(getter_Copies(value)) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ LossyCopyUTF16toASCII(value, valueAscii);
+ propertyTag = findPropertyTag(name.get()) ;
+ if (propertyTag == 0) {
+ aSkipItem = true ;
+ return retCode ;
+ }
+ switch (conditionType) {
+ case nsIAbBooleanConditionTypes::Exists :
+ aRestriction.rt = RES_EXIST ;
+ aRestriction.res.resExist.ulPropTag = propertyTag ;
+ break ;
+ case nsIAbBooleanConditionTypes::DoesNotExist :
+ aRestriction.rt = RES_NOT ;
+ aRestriction.res.resNot.lpRes = new SRestriction ;
+ aRestriction.res.resNot.lpRes->rt = RES_EXIST ;
+ aRestriction.res.resNot.lpRes->res.resExist.ulPropTag = propertyTag ;
+ break ;
+ case nsIAbBooleanConditionTypes::Contains :
+ aRestriction.rt = RES_CONTENT ;
+ aRestriction.res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_LOOSE ;
+ aRestriction.res.resContent.ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp = new SPropValue ;
+ aRestriction.res.resContent.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::DoesNotContain :
+ aRestriction.rt = RES_NOT ;
+ aRestriction.res.resNot.lpRes = new SRestriction ;
+ aRestriction.res.resNot.lpRes->rt = RES_CONTENT ;
+ aRestriction.res.resNot.lpRes->res.resContent.ulFuzzyLevel = FL_SUBSTRING | FL_LOOSE ;
+ aRestriction.res.resNot.lpRes->res.resContent.ulPropTag = propertyTag ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp = new SPropValue ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::Is :
+ aRestriction.rt = RES_CONTENT ;
+ aRestriction.res.resContent.ulFuzzyLevel = FL_FULLSTRING | FL_LOOSE ;
+ aRestriction.res.resContent.ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp = new SPropValue ;
+ aRestriction.res.resContent.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::IsNot :
+ aRestriction.rt = RES_NOT ;
+ aRestriction.res.resNot.lpRes = new SRestriction ;
+ aRestriction.res.resNot.lpRes->rt = RES_CONTENT ;
+ aRestriction.res.resNot.lpRes->res.resContent.ulFuzzyLevel = FL_FULLSTRING | FL_LOOSE ;
+ aRestriction.res.resNot.lpRes->res.resContent.ulPropTag = propertyTag ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp = new SPropValue ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resNot.lpRes->res.resContent.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::BeginsWith :
+ aRestriction.rt = RES_CONTENT ;
+ aRestriction.res.resContent.ulFuzzyLevel = FL_PREFIX | FL_LOOSE ;
+ aRestriction.res.resContent.ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp = new SPropValue ;
+ aRestriction.res.resContent.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resContent.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::EndsWith :
+ // This condition should be implemented through regular expressions,
+ // but MAPI doesn't match them correctly.
+#if 0
+ aRestriction.rt = RES_PROPERTY ;
+ aRestriction.res.resProperty.relop = RELOP_RE ;
+ aRestriction.res.resProperty.ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp = new SPropValue ;
+ aRestriction.res.resProperty.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+#else
+ aSkipItem = true ;
+#endif // 0
+ break ;
+ case nsIAbBooleanConditionTypes::SoundsLike :
+ // This condition cannot be implemented in MAPI.
+ aSkipItem = true ;
+ break ;
+ case nsIAbBooleanConditionTypes::RegExp :
+ // This condition should be implemented this way, but the following
+ // code will never match (through MAPI's fault).
+#if 0
+ aRestriction.rt = RES_PROPERTY ;
+ aRestriction.res.resProperty.relop = RELOP_RE ;
+ aRestriction.res.resProperty.ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp = new SPropValue ;
+ aRestriction.res.resProperty.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+#else
+ aSkipItem = true ;
+#endif // 0
+ break ;
+ case nsIAbBooleanConditionTypes::LessThan :
+ aRestriction.rt = RES_PROPERTY ;
+ aRestriction.res.resProperty.relop = RELOP_LT ;
+ aRestriction.res.resProperty.ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp = new SPropValue ;
+ aRestriction.res.resProperty.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ case nsIAbBooleanConditionTypes::GreaterThan :
+ aRestriction.rt = RES_PROPERTY ;
+ aRestriction.res.resProperty.relop = RELOP_GT ;
+ aRestriction.res.resProperty.ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp = new SPropValue ;
+ aRestriction.res.resProperty.lpProp->ulPropTag = propertyTag ;
+ aRestriction.res.resProperty.lpProp->Value.lpszA = strdup(valueAscii.get()) ;
+ break ;
+ default :
+ aSkipItem = true ;
+ break ;
+ }
+ return retCode ;
+}
+
+static nsresult BuildRestriction(nsIAbBooleanExpression *aLevel,
+ SRestriction& aRestriction)
+{
+ if (!aLevel) { return NS_ERROR_NULL_POINTER ; }
+ aRestriction.rt = RES_COMMENT ;
+ nsresult retCode = NS_OK ;
+ nsAbBooleanOperationType operationType = 0 ;
+ uint32_t nbExpressions = 0 ;
+ nsCOMPtr<nsIArray> expressions;
+
+ retCode = aLevel->GetOperation(&operationType);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ retCode = aLevel->GetExpressions(getter_AddRefs(expressions));
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ retCode = expressions->GetLength(&nbExpressions);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ if (nbExpressions == 0) {
+ PRINTF(("Error, no expressions.\n")) ;
+ return NS_OK ;
+ }
+ if (operationType == nsIAbBooleanOperationTypes::NOT && nbExpressions != 1) {
+ PRINTF(("Error, unary operation NOT with multiple operands.\n")) ;
+ return NS_OK ;
+ }
+ LPSRestriction restrictionArray = new SRestriction [nbExpressions] ;
+ uint32_t realNbExpressions = 0 ;
+ bool skipItem = false ;
+ uint32_t i = 0 ;
+
+ nsCOMPtr<nsIAbBooleanConditionString> condition;
+ nsCOMPtr<nsIAbBooleanExpression> subExpression;
+
+ for (i = 0; i < nbExpressions; ++i) {
+ condition = do_QueryElementAt(expressions, i, &retCode);
+
+ if (NS_SUCCEEDED(retCode)) {
+ retCode = BuildRestriction(condition, *restrictionArray, skipItem);
+ if (NS_SUCCEEDED(retCode)) {
+ if (!skipItem) {
+ ++restrictionArray;
+ ++realNbExpressions;
+ }
+ }
+ else
+ PRINTF(("Cannot build restriction for item %d %08x.\n", i, retCode));
+ }
+ else {
+ subExpression = do_QueryElementAt(expressions, i, &retCode);
+
+ if (NS_SUCCEEDED(retCode)) {
+ retCode = BuildRestriction(subExpression, *restrictionArray);
+ if (NS_SUCCEEDED(retCode)) {
+ if (restrictionArray->rt != RES_COMMENT) {
+ ++restrictionArray;
+ ++realNbExpressions;
+ }
+ }
+ }
+ else
+ PRINTF(("Cannot get interface for item %d %08x.\n", i, retCode));
+ }
+ }
+
+ restrictionArray -= realNbExpressions ;
+ if (realNbExpressions > 1) {
+ if (operationType == nsIAbBooleanOperationTypes::OR) {
+ aRestriction.rt = RES_OR ;
+ aRestriction.res.resOr.lpRes = restrictionArray ;
+ aRestriction.res.resOr.cRes = realNbExpressions ;
+ }
+ else if (operationType == nsIAbBooleanOperationTypes::AND) {
+ aRestriction.rt = RES_AND ;
+ aRestriction.res.resAnd.lpRes = restrictionArray ;
+ aRestriction.res.resAnd.cRes = realNbExpressions ;
+ }
+ else {
+ PRINTF(("Unsupported operation %d.\n", operationType)) ;
+ }
+ }
+ else if (realNbExpressions == 1) {
+ if (operationType == nsIAbBooleanOperationTypes::NOT) {
+ aRestriction.rt = RES_NOT ;
+ // This copy is to ensure that every NOT restriction is being
+ // allocated by new and not new[] (see destruction of restriction)
+ aRestriction.res.resNot.lpRes = new SRestriction ;
+ memcpy(aRestriction.res.resNot.lpRes, restrictionArray, sizeof(SRestriction)) ;
+ }
+ else {
+ // Case where the restriction array is redundant,
+ // we need to fill the restriction directly.
+ memcpy(&aRestriction, restrictionArray, sizeof(SRestriction)) ;
+ }
+ delete [] restrictionArray ;
+ }
+ if (aRestriction.rt == RES_COMMENT) {
+ // This means we haven't really built any useful expression
+ delete [] restrictionArray ;
+ }
+ return NS_OK ;
+}
+
+static nsresult BuildRestriction(nsIAbDirectoryQueryArguments *aArguments,
+ SRestriction& aRestriction)
+{
+ if (!aArguments) { return NS_ERROR_NULL_POINTER ; }
+ nsresult retCode = NS_OK ;
+
+ nsCOMPtr<nsISupports> supports ;
+ retCode = aArguments->GetExpression(getter_AddRefs(supports)) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ nsCOMPtr<nsIAbBooleanExpression> booleanQuery =
+ do_QueryInterface(supports, &retCode) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ retCode = BuildRestriction(booleanQuery, aRestriction) ;
+ return retCode ;
+}
+
+static void DestroyRestriction(SRestriction& aRestriction)
+{
+ switch(aRestriction.rt) {
+ case RES_AND :
+ case RES_OR :
+ {
+ for (ULONG i = 0 ; i < aRestriction.res.resAnd.cRes ; ++ i) {
+ DestroyRestriction(aRestriction.res.resAnd.lpRes [i]) ;
+ }
+ delete [] aRestriction.res.resAnd.lpRes ;
+ }
+ break ;
+ case RES_COMMENT :
+ break ;
+ case RES_CONTENT :
+ if (PROP_TYPE(aRestriction.res.resContent.ulPropTag) == PT_UNICODE) {
+ NS_Free(aRestriction.res.resContent.lpProp->Value.lpszW) ;
+ }
+ else if (PROP_TYPE(aRestriction.res.resContent.ulPropTag) == PT_STRING8) {
+ NS_Free(aRestriction.res.resContent.lpProp->Value.lpszA) ;
+ }
+ delete aRestriction.res.resContent.lpProp ;
+ break ;
+ case RES_EXIST :
+ break ;
+ case RES_NOT :
+ DestroyRestriction(*aRestriction.res.resNot.lpRes) ;
+ delete aRestriction.res.resNot.lpRes ;
+ break ;
+ case RES_BITMASK :
+ case RES_COMPAREPROPS :
+ break ;
+ case RES_PROPERTY :
+ if (PROP_TYPE(aRestriction.res.resProperty.ulPropTag) == PT_UNICODE) {
+ NS_Free(aRestriction.res.resProperty.lpProp->Value.lpszW) ;
+ }
+ else if (PROP_TYPE(aRestriction.res.resProperty.ulPropTag) == PT_STRING8) {
+ NS_Free(aRestriction.res.resProperty.lpProp->Value.lpszA) ;
+ }
+ delete aRestriction.res.resProperty.lpProp ;
+ case RES_SIZE :
+ case RES_SUBRESTRICTION :
+ break ;
+ }
+}
+
+struct QueryThreadArgs
+{
+ nsAbOutlookDirectory *mThis ;
+ SRestriction mRestriction ;
+ nsCOMPtr<nsIAbDirSearchListener> mListener ;
+ int32_t mResultLimit ;
+ int32_t mTimeout ;
+ int32_t mThreadId ;
+} ;
+
+static void QueryThreadFunc(void *aArguments)
+{
+ QueryThreadArgs *arguments = reinterpret_cast<QueryThreadArgs *>(aArguments) ;
+
+ if (!aArguments) { return ; }
+ arguments->mThis->ExecuteQuery(arguments->mRestriction, arguments->mListener,
+ arguments->mResultLimit, arguments->mTimeout,
+ arguments->mThreadId) ;
+ DestroyRestriction(arguments->mRestriction) ;
+ delete arguments ;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::DoQuery(nsIAbDirectory *aDirectory,
+ nsIAbDirectoryQueryArguments *aArguments,
+ nsIAbDirSearchListener *aListener,
+ int32_t aResultLimit, int32_t aTimeout,
+ int32_t *aReturnValue)
+{
+ if (!aArguments || !aListener || !aReturnValue) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ *aReturnValue = -1;
+
+ QueryThreadArgs *threadArgs = new QueryThreadArgs;
+ PRThread *newThread = nullptr;
+
+ if (!threadArgs)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsresult rv = BuildRestriction(aArguments, threadArgs->mRestriction);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ threadArgs->mThis = this;
+ threadArgs->mListener = aListener;
+ threadArgs->mResultLimit = aResultLimit;
+ threadArgs->mTimeout = aTimeout;
+
+ PR_Lock(mProtector);
+ *aReturnValue = ++mCurrentQueryId;
+ PR_Unlock(mProtector);
+
+ threadArgs->mThreadId = *aReturnValue;
+ newThread = PR_CreateThread(PR_USER_THREAD,
+ QueryThreadFunc,
+ threadArgs,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0);
+
+ if (!newThread ) {
+ DestroyRestriction(threadArgs->mRestriction);
+ delete threadArgs;
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ mQueryThreads.Put(*aReturnValue, newThread);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::StopQuery(int32_t aContext)
+{
+ PRThread *queryThread;
+ if (mQueryThreads.Get(aContext, &queryThread)) {
+ PR_Interrupt(queryThread);
+ mQueryThreads.Remove(aContext);
+ }
+ return NS_OK;
+}
+
+// nsIAbDirectorySearch methods
+NS_IMETHODIMP nsAbOutlookDirectory::StartSearch(void)
+{
+ if (!mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; }
+ nsresult retCode = NS_OK ;
+
+ retCode = StopSearch() ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ mCardList.Clear();
+
+ nsCOMPtr<nsIAbBooleanExpression> expression ;
+
+ nsCOMPtr<nsIAbDirectoryQueryArguments> arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&retCode);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ retCode = nsAbQueryStringToExpression::Convert(mQueryString, getter_AddRefs(expression)) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ retCode = arguments->SetExpression(expression) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+
+ retCode = arguments->SetQuerySubDirectories(true) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+
+ return DoQuery(this, arguments, this, -1, 0, &mSearchContext);
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::StopSearch(void)
+{
+ if (!mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; }
+ return StopQuery(mSearchContext) ;
+}
+
+// nsIAbDirSearchListener
+NS_IMETHODIMP nsAbOutlookDirectory::OnSearchFinished(int32_t aResult,
+ const nsAString &aErrorMsg)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::OnSearchFoundCard(nsIAbCard *aCard)
+{
+ mCardList.Put(aCard, aCard);
+ nsresult rv;
+ nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv))
+ rv = abManager->NotifyDirectoryItemAdded(this, aCard);
+
+ return rv;
+}
+
+nsresult nsAbOutlookDirectory::ExecuteQuery(SRestriction &aRestriction,
+ nsIAbDirSearchListener *aListener,
+ int32_t aResultLimit, int32_t aTimeout,
+ int32_t aThreadId)
+
+{
+ if (!aListener)
+ return NS_ERROR_NULL_POINTER;
+
+ nsresult retCode = NS_OK;
+
+ nsCOMPtr<nsIMutableArray> resultsArray(do_CreateInstance(NS_ARRAY_CONTRACTID,
+ &retCode));
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ retCode = GetChildCards(resultsArray,
+ aRestriction.rt == RES_COMMENT ? nullptr : &aRestriction);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ uint32_t nbResults = 0;
+ retCode = resultsArray->GetLength(&nbResults);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ if (aResultLimit > 0 && nbResults > static_cast<uint32_t>(aResultLimit)) {
+ nbResults = static_cast<uint32_t>(aResultLimit) ;
+ }
+
+ uint32_t i = 0;
+ nsCOMPtr<nsIAbCard> card;
+
+ for (i = 0 ; i < nbResults ; ++ i) {
+ card = do_QueryElementAt(resultsArray, i, &retCode);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ aListener->OnSearchFoundCard(card);
+ }
+
+ mQueryThreads.Remove(aThreadId);
+
+ aListener->OnSearchFinished(nsIAbDirectoryQueryResultListener::queryResultComplete,
+ EmptyString());
+ return retCode;
+}
+
+// This function expects the aCards array to already be created.
+nsresult nsAbOutlookDirectory::GetChildCards(nsIMutableArray *aCards,
+ void *aRestriction)
+{
+ nsAbWinHelperGuard mapiAddBook(mAbWinType);
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ nsMapiEntryArray cardEntries;
+ LPSRestriction restriction = (LPSRestriction) aRestriction;
+
+ if (!mapiAddBook->GetCards(*mMapiData, restriction, cardEntries)) {
+ PRINTF(("Cannot get cards.\n"));
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoCString ourUuid;
+ GetUuid(ourUuid);
+
+ nsAutoCString entryId;
+ nsAutoCString uriName;
+ nsCOMPtr<nsIAbCard> childCard;
+ nsresult rv;
+
+ for (ULONG card = 0; card < cardEntries.mNbEntries; ++card) {
+ cardEntries.mEntries[card].ToString(entryId);
+ buildAbWinUri(kOutlookCardScheme, mAbWinType, uriName);
+ uriName.Append(entryId);
+
+ rv = OutlookCardForURI(uriName, getter_AddRefs(childCard));
+ NS_ENSURE_SUCCESS(rv, rv);
+ childCard->SetDirectoryId(ourUuid);
+
+ aCards->AppendElement(childCard, false);
+ }
+ return rv;
+}
+
+nsresult nsAbOutlookDirectory::GetChildNodes(nsIMutableArray* aNodes)
+{
+ NS_ENSURE_ARG_POINTER(aNodes);
+
+ aNodes->Clear();
+
+ nsAbWinHelperGuard mapiAddBook(mAbWinType);
+ nsMapiEntryArray nodeEntries;
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ if (!mapiAddBook->GetNodes(*mMapiData, nodeEntries))
+ {
+ PRINTF(("Cannot get nodes.\n"));
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoCString entryId;
+ nsAutoCString uriName;
+ nsresult rv = NS_OK;
+
+ nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ for (ULONG node = 0; node < nodeEntries.mNbEntries; ++node)
+ {
+ nodeEntries.mEntries[node].ToString(entryId);
+ buildAbWinUri(kOutlookDirectoryScheme, mAbWinType, uriName);
+ uriName.Append(entryId);
+
+ nsCOMPtr <nsIAbDirectory> directory;
+ rv = abManager->GetDirectory(uriName, getter_AddRefs(directory));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ aNodes->AppendElement(directory, false);
+ }
+ return rv;
+}
+
+nsresult nsAbOutlookDirectory::NotifyItemDeletion(nsISupports *aItem)
+{
+ nsresult rv;
+ nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
+
+ if (NS_SUCCEEDED(rv))
+ rv = abManager->NotifyDirectoryItemDeleted(this, aItem);
+
+ return rv;
+}
+
+nsresult nsAbOutlookDirectory::NotifyItemAddition(nsISupports *aItem)
+{
+ nsresult rv;
+ nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ rv = abManager->NotifyDirectoryItemAdded(this, aItem);
+
+ return rv;
+}
+
+// This is called from EditMailListToDatabase.
+// We got m_AddressList containing the list of cards the mailing
+// list is supposed to contain at the end.
+nsresult nsAbOutlookDirectory::CommitAddressList(void)
+{
+ if (!m_IsMailList) {
+ PRINTF(("We are not in a mailing list, no commit can be done.\n"));
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsresult rv;
+ uint32_t i = 0;
+ nsCOMPtr<nsIMutableArray> oldList(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = GetChildCards(oldList, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!m_AddressList)
+ return NS_ERROR_NULL_POINTER;
+
+ uint32_t nbCards = 0;
+ rv = m_AddressList->GetLength(&nbCards);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsISupports> element;
+ nsCOMPtr<nsIAbCard> newCard;
+ uint32_t pos;
+
+ for (i = 0; i < nbCards; ++i) {
+ element = do_QueryElementAt(m_AddressList, i, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (NS_SUCCEEDED(oldList->IndexOf(0, element, &pos))) {
+ rv = oldList->RemoveElementAt(pos);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // The entry was not already there
+ nsCOMPtr<nsIAbCard> card(do_QueryInterface(element, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = CreateCard(card, getter_AddRefs(newCard));
+ NS_ENSURE_SUCCESS(rv, rv);
+ m_AddressList->ReplaceElementAt(newCard, i, false);
+ }
+ }
+ return DeleteCards(oldList);
+}
+
+nsresult nsAbOutlookDirectory::UpdateAddressList(void)
+{
+ if (!m_AddressList)
+ {
+ nsresult rv;
+ m_AddressList = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return m_IsMailList ? GetChildCards(m_AddressList, nullptr) :
+ GetChildNodes(m_AddressList);
+}
+
+nsresult nsAbOutlookDirectory::CreateCard(nsIAbCard *aData, nsIAbCard **aNewCard)
+{
+ if (!aData || !aNewCard) { return NS_ERROR_NULL_POINTER ; }
+ *aNewCard = nullptr ;
+ nsresult retCode = NS_OK ;
+ nsAbWinHelperGuard mapiAddBook (mAbWinType) ;
+ nsMapiEntry newEntry ;
+ nsAutoCString entryString ;
+ bool didCopy = false ;
+
+ if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; }
+ // If we get an nsIAbCard that maps onto an Outlook card uri
+ // we simply copy the contents of the Outlook card.
+ retCode = ExtractCardEntry(aData, entryString) ;
+ if (NS_SUCCEEDED(retCode) && !entryString.IsEmpty()) {
+ nsMapiEntry sourceEntry ;
+
+
+ sourceEntry.Assign(entryString) ;
+ if (m_IsMailList) {
+ // In the case of a mailing list, we can use the address
+ // as a direct template to build the new one (which is done
+ // by CopyEntry).
+ mapiAddBook->CopyEntry(*mMapiData, sourceEntry, newEntry) ;
+ didCopy = true ;
+ }
+ else {
+ // Else, we have to create a temporary address and copy the
+ // source into it. Yes it's silly.
+ mapiAddBook->CreateEntry(*mMapiData, newEntry) ;
+ }
+ }
+ // If this approach doesn't work, well we're back to creating and copying.
+ if (newEntry.mByteCount == 0) {
+ // In the case of a mailing list, we cannot directly create a new card,
+ // we have to create a temporary one in a real folder (to be able to use
+ // templates) and then copy it to the mailing list.
+ if (m_IsMailList) {
+ nsMapiEntry parentEntry ;
+ nsMapiEntry temporaryEntry ;
+
+ if (!mapiAddBook->GetDefaultContainer(parentEntry)) {
+ return NS_ERROR_FAILURE ;
+ }
+ if (!mapiAddBook->CreateEntry(parentEntry, temporaryEntry)) {
+ return NS_ERROR_FAILURE ;
+ }
+ if (!mapiAddBook->CopyEntry(*mMapiData, temporaryEntry, newEntry)) {
+ return NS_ERROR_FAILURE ;
+ }
+ if (!mapiAddBook->DeleteEntry(parentEntry, temporaryEntry)) {
+ return NS_ERROR_FAILURE ;
+ }
+ }
+ // If we're on a real address book folder, we can directly create an
+ // empty card.
+ else if (!mapiAddBook->CreateEntry(*mMapiData, newEntry)) {
+ return NS_ERROR_FAILURE ;
+ }
+ }
+ newEntry.ToString(entryString) ;
+ nsAutoCString uri ;
+
+ buildAbWinUri(kOutlookCardScheme, mAbWinType, uri) ;
+ uri.Append(entryString) ;
+
+ nsCOMPtr<nsIAbCard> newCard;
+ retCode = OutlookCardForURI(uri, getter_AddRefs(newCard));
+ NS_ENSURE_SUCCESS(retCode, retCode);
+
+ nsAutoCString ourUuid;
+ GetUuid(ourUuid);
+ newCard->SetDirectoryId(ourUuid);
+
+ if (!didCopy) {
+ retCode = newCard->Copy(aData) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ retCode = ModifyCard(newCard) ;
+ NS_ENSURE_SUCCESS(retCode, retCode) ;
+ }
+ *aNewCard = newCard ;
+ NS_ADDREF(*aNewCard) ;
+ return retCode ;
+}
+
+static void UnicodeToWord(const char16_t *aUnicode, WORD& aWord)
+{
+ aWord = 0 ;
+ if (aUnicode == nullptr || *aUnicode == 0) { return ; }
+ nsresult errorCode = NS_OK;
+ nsAutoString unichar (aUnicode) ;
+
+ aWord = static_cast<WORD>(unichar.ToInteger(&errorCode));
+ if (NS_FAILED(errorCode)) {
+ PRINTF(("Error conversion string %S: %08x.\n", unichar.get(), errorCode)) ;
+ }
+}
+
+#define PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST "mail.addr_book.lastnamefirst"
+
+
+NS_IMETHODIMP nsAbOutlookDirectory::ModifyCard(nsIAbCard *aModifiedCard)
+{
+ NS_ENSURE_ARG_POINTER(aModifiedCard);
+
+ nsString *properties = nullptr;
+ nsAutoString utility;
+ nsAbWinHelperGuard mapiAddBook(mAbWinType);
+
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ nsCString entry;
+ nsresult retCode = ExtractCardEntry(aModifiedCard, entry);
+ NS_ENSURE_SUCCESS(retCode, retCode);
+ // If we don't have the card entry, we can't work.
+ if (entry.IsEmpty())
+ return NS_ERROR_FAILURE;
+
+ nsMapiEntry mapiData;
+ mapiData.Assign(entry);
+
+ // First, all the standard properties in one go
+ properties = new nsString[index_LastProp];
+ if (!properties) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ aModifiedCard->GetFirstName(properties[index_FirstName]);
+ aModifiedCard->GetLastName(properties[index_LastName]);
+ // This triple search for something to put in the name
+ // is because in the case of a mailing list edition in
+ // Mozilla, the display name will not be provided, and
+ // MAPI doesn't allow that, so we fall back on an optional
+ // name, and when all fails, on the email address.
+ aModifiedCard->GetDisplayName(properties[index_DisplayName]);
+ if (properties[index_DisplayName].IsEmpty()) {
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> prefBranch =
+ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ int32_t format;
+ rv = prefBranch->GetIntPref(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, &format);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = aModifiedCard->GenerateName(format, nullptr,
+ properties[index_DisplayName]);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ if (properties[index_DisplayName].IsEmpty()) {
+ aModifiedCard->GetPrimaryEmail(properties[index_DisplayName]);
+ }
+ }
+ aModifiedCard->SetDisplayName(properties[index_DisplayName]);
+ aModifiedCard->GetPrimaryEmail(properties[index_EmailAddress]);
+ aModifiedCard->GetPropertyAsAString(kNicknameProperty, properties[index_NickName]);
+ aModifiedCard->GetPropertyAsAString(kWorkPhoneProperty, properties[index_WorkPhoneNumber]);
+ aModifiedCard->GetPropertyAsAString(kHomePhoneProperty, properties[index_HomePhoneNumber]);
+ aModifiedCard->GetPropertyAsAString(kFaxProperty, properties[index_WorkFaxNumber]);
+ aModifiedCard->GetPropertyAsAString(kPagerProperty, properties[index_PagerNumber]);
+ aModifiedCard->GetPropertyAsAString(kCellularProperty, properties[index_MobileNumber]);
+ aModifiedCard->GetPropertyAsAString(kHomeCityProperty, properties[index_HomeCity]);
+ aModifiedCard->GetPropertyAsAString(kHomeStateProperty, properties[index_HomeState]);
+ aModifiedCard->GetPropertyAsAString(kHomeZipCodeProperty, properties[index_HomeZip]);
+ aModifiedCard->GetPropertyAsAString(kHomeCountryProperty, properties[index_HomeCountry]);
+ aModifiedCard->GetPropertyAsAString(kWorkCityProperty, properties[index_WorkCity]);
+ aModifiedCard->GetPropertyAsAString(kWorkStateProperty, properties[index_WorkState]);
+ aModifiedCard->GetPropertyAsAString(kWorkZipCodeProperty, properties[index_WorkZip]);
+ aModifiedCard->GetPropertyAsAString(kWorkCountryProperty, properties[index_WorkCountry]);
+ aModifiedCard->GetPropertyAsAString(kJobTitleProperty, properties[index_JobTitle]);
+ aModifiedCard->GetPropertyAsAString(kDepartmentProperty, properties[index_Department]);
+ aModifiedCard->GetPropertyAsAString(kCompanyProperty, properties[index_Company]);
+ aModifiedCard->GetPropertyAsAString(kWorkWebPageProperty, properties[index_WorkWebPage]);
+ aModifiedCard->GetPropertyAsAString(kHomeWebPageProperty, properties[index_HomeWebPage]);
+ aModifiedCard->GetPropertyAsAString(kNotesProperty, properties[index_Comments]);
+ if (!mapiAddBook->SetPropertiesUString(mapiData, OutlookCardMAPIProps,
+ index_LastProp, properties)) {
+ PRINTF(("Cannot set general properties.\n")) ;
+ }
+
+ delete [] properties;
+ nsString unichar;
+ nsString unichar2;
+ WORD year = 0;
+ WORD month = 0;
+ WORD day = 0;
+
+ aModifiedCard->GetPropertyAsAString(kHomeAddressProperty, unichar);
+ aModifiedCard->GetPropertyAsAString(kHomeAddress2Property, unichar2);
+
+ utility.Assign(unichar.get());
+ if (!utility.IsEmpty())
+ utility.AppendLiteral("\r\n");
+
+ utility.Append(unichar2.get());
+ if (!mapiAddBook->SetPropertyUString(mapiData, PR_HOME_ADDRESS_STREET_W, utility.get())) {
+ PRINTF(("Cannot set home address.\n")) ;
+ }
+
+ unichar.Truncate();
+ aModifiedCard->GetPropertyAsAString(kWorkAddressProperty, unichar);
+ unichar2.Truncate();
+ aModifiedCard->GetPropertyAsAString(kWorkAddress2Property, unichar2);
+
+ utility.Assign(unichar.get());
+ if (!utility.IsEmpty())
+ utility.AppendLiteral("\r\n");
+
+ utility.Append(unichar2.get());
+ if (!mapiAddBook->SetPropertyUString(mapiData, PR_BUSINESS_ADDRESS_STREET_W, utility.get())) {
+ PRINTF(("Cannot set work address.\n")) ;
+ }
+
+ unichar.Truncate();
+ aModifiedCard->GetPropertyAsAString(kBirthYearProperty, unichar);
+ UnicodeToWord(unichar.get(), year);
+ unichar.Truncate();
+ aModifiedCard->GetPropertyAsAString(kBirthMonthProperty, unichar);
+ UnicodeToWord(unichar.get(), month);
+ unichar.Truncate();
+ aModifiedCard->GetPropertyAsAString(kBirthDayProperty, unichar);
+ UnicodeToWord(unichar.get(), day);
+ if (!mapiAddBook->SetPropertyDate(mapiData, PR_BIRTHDAY, year, month, day)) {
+ PRINTF(("Cannot set date.\n")) ;
+ }
+
+ return retCode;
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::OnQueryFoundCard(nsIAbCard *aCard)
+{
+ return OnSearchFoundCard(aCard);
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::OnQueryResult(int32_t aResult,
+ int32_t aErrorCode)
+{
+ return OnSearchFinished(aResult, EmptyString());
+}
+
+NS_IMETHODIMP nsAbOutlookDirectory::UseForAutocomplete(const nsACString &aIdentityKey, bool *aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = false;
+ return NS_OK;
+}
+
+static void splitString(nsString& aSource, nsString& aTarget)
+{
+ aTarget.Truncate();
+ int32_t offset = aSource.FindChar('\n');
+
+ if (offset >= 0)
+ {
+ const char16_t *source = aSource.get() + offset + 1;
+ while (*source)
+ {
+ if (*source == '\n' || *source == '\r')
+ aTarget.Append(char16_t(' '));
+ else
+ aTarget.Append(*source);
+ ++source;
+ }
+ aSource.SetLength(offset);
+ }
+}
+
+nsresult OutlookCardForURI(const nsACString &aUri, nsIAbCard **newCard)
+{
+ NS_ENSURE_ARG_POINTER(newCard);
+
+ nsAutoCString entry;
+ nsAutoCString stub;
+ uint32_t abWinType = getAbWinType(kOutlookCardScheme,
+ PromiseFlatCString(aUri).get(), stub, entry);
+ if (abWinType == nsAbWinType_Unknown)
+ {
+ PRINTF(("Huge problem URI=%s.\n", PromiseFlatCString(aUri).get()));
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsAbWinHelperGuard mapiAddBook(abWinType);
+ if (!mapiAddBook->IsOK())
+ return NS_ERROR_FAILURE;
+
+ nsresult rv;
+ nsCOMPtr<nsIAbCard> card = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ card->SetPropertyAsAUTF8String("OutlookEntryURI", aUri);
+ card->SetLocalId(aUri);
+
+ nsMapiEntry mapiData;
+ mapiData.Assign(entry);
+
+ nsString unichars[index_LastProp];
+
+ if (mapiAddBook->GetPropertiesUString(mapiData, OutlookCardMAPIProps,
+ index_LastProp, unichars))
+ {
+ card->SetFirstName(unichars[index_FirstName]);
+ card->SetLastName(unichars[index_LastName]);
+ card->SetDisplayName(unichars[index_DisplayName]);
+ card->SetPrimaryEmail(unichars[index_EmailAddress]);
+ card->SetPropertyAsAString(kNicknameProperty, unichars[index_NickName]);
+ card->SetPropertyAsAString(kWorkPhoneProperty, unichars[index_WorkPhoneNumber]);
+ card->SetPropertyAsAString(kHomePhoneProperty, unichars[index_HomePhoneNumber]);
+ card->SetPropertyAsAString(kFaxProperty, unichars[index_WorkFaxNumber]);
+ card->SetPropertyAsAString(kPagerProperty, unichars[index_PagerNumber]);
+ card->SetPropertyAsAString(kCellularProperty, unichars[index_MobileNumber]);
+ card->SetPropertyAsAString(kHomeCityProperty, unichars[index_HomeCity]);
+ card->SetPropertyAsAString(kHomeStateProperty, unichars[index_HomeState]);
+ card->SetPropertyAsAString(kHomeZipCodeProperty, unichars[index_HomeZip]);
+ card->SetPropertyAsAString(kHomeCountryProperty, unichars[index_HomeCountry]);
+ card->SetPropertyAsAString(kWorkCityProperty, unichars[index_WorkCity]);
+ card->SetPropertyAsAString(kWorkStateProperty, unichars[index_WorkState]);
+ card->SetPropertyAsAString(kWorkZipCodeProperty, unichars[index_WorkZip]);
+ card->SetPropertyAsAString(kWorkCountryProperty, unichars[index_WorkCountry]);
+ card->SetPropertyAsAString(kJobTitleProperty, unichars[index_JobTitle]);
+ card->SetPropertyAsAString(kDepartmentProperty, unichars[index_Department]);
+ card->SetPropertyAsAString(kCompanyProperty, unichars[index_Company]);
+ card->SetPropertyAsAString(kWorkWebPageProperty, unichars[index_WorkWebPage]);
+ card->SetPropertyAsAString(kHomeWebPageProperty, unichars[index_HomeWebPage]);
+ card->SetPropertyAsAString(kNotesProperty, unichars[index_Comments]);
+ }
+
+ ULONG cardType = 0;
+ if (mapiAddBook->GetPropertyLong(mapiData, PR_OBJECT_TYPE, cardType))
+ {
+ card->SetIsMailList(cardType == MAPI_DISTLIST);
+ if (cardType == MAPI_DISTLIST)
+ {
+ nsAutoCString normalChars;
+ buildAbWinUri(kOutlookDirectoryScheme, abWinType, normalChars);
+ normalChars.Append(entry);
+ card->SetMailListURI(normalChars.get());
+ }
+ }
+
+ nsAutoString unichar;
+ nsAutoString unicharBis;
+ if (mapiAddBook->GetPropertyUString(mapiData, PR_HOME_ADDRESS_STREET_W, unichar))
+ {
+ splitString(unichar, unicharBis);
+ card->SetPropertyAsAString(kHomeAddressProperty, unichar);
+ card->SetPropertyAsAString(kHomeAddress2Property, unicharBis);
+ }
+ if (mapiAddBook->GetPropertyUString(mapiData, PR_BUSINESS_ADDRESS_STREET_W,
+ unichar))
+ {
+ splitString(unichar, unicharBis);
+ card->SetPropertyAsAString(kWorkAddressProperty, unichar);
+ card->SetPropertyAsAString(kWorkAddress2Property, unicharBis);
+ }
+
+ WORD year = 0, month = 0, day = 0;
+ if (mapiAddBook->GetPropertyDate(mapiData, PR_BIRTHDAY, year, month, day))
+ {
+ card->SetPropertyAsUint32(kBirthYearProperty, year);
+ card->SetPropertyAsUint32(kBirthMonthProperty, month);
+ card->SetPropertyAsUint32(kBirthDayProperty, day);
+ }
+
+ card.swap(*newCard);
+ return NS_OK;
+}