/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Sun Microsystems, Inc. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Created by Cyrille Moureaux * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsAbOutlookDirectory.h" #include "nsAbWinHelper.h" #include "nsIRDFService.h" #include "nsAbBaseCID.h" #include "nsIAbCard.h" #include "nsXPIDLString.h" #include "nsAbDirectoryQuery.h" #include "nsIAbBooleanExpression.h" #include "nsIAddressBook.h" #include "nsIAddrBookSession.h" #include "nsAbQueryStringToExpression.h" #include "nsAbUtils.h" #include "nsIProxyObjectManager.h" #include "nsEnumeratorUtils.h" #include "prlog.h" #include "prthread.h" #ifdef PR_LOGGING static PRLogModuleInfo* gAbOutlookDirectoryLog = PR_NewLogModule("nsAbOutlookDirectoryLog"); #endif #define PRINTF(args) PR_LOG(gAbOutlookDirectoryLog, PR_LOG_DEBUG, args) // Class for the int key class nsIntegerKey : public nsHashKey { public: nsIntegerKey(PRInt32 aInteger) : mInteger(aInteger) { } virtual ~nsIntegerKey(void) {} PRUint32 HashCode(void) const { return NS_STATIC_CAST(PRUint32, mInteger) ; } PRBool Equals(const nsHashKey *aKey) const { return aKey && NS_REINTERPRET_CAST(const nsIntegerKey *, aKey)->mInteger == mInteger ; } nsHashKey *Clone(void) const { return new nsIntegerKey(mInteger) ; } protected: PRInt32 mInteger ; private: } ; nsAbOutlookDirectory::nsAbOutlookDirectory(void) : nsAbDirectoryRDFResource(), nsAbDirProperty(), nsAbDirSearchListenerContext(), mQueryThreads(16, PR_TRUE), mCurrentQueryId(0), mSearchContext(-1), mAbWinType(nsAbWinType_Unknown), mMapiData(nsnull) { mMapiData = new nsMapiEntry ; mProtector = PR_NewLock() ; } nsAbOutlookDirectory::~nsAbOutlookDirectory(void) { if (mMapiData) { delete mMapiData ; } if (mProtector) { PR_DestroyLock(mProtector) ; } } NS_IMPL_ISUPPORTS_INHERITED3(nsAbOutlookDirectory, nsAbDirectoryRDFResource, nsIAbDirectory, nsIAbDirectoryQuery, nsIAbDirectorySearch) // nsIRDFResource method NS_IMETHODIMP nsAbOutlookDirectory::Init(const char *aUri) { nsresult retCode = nsAbDirectoryRDFResource::Init(aUri) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCAutoString entry ; nsCAutoString 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) ; SetDirName(prefix.get()) ; if (objectType == MAPI_DISTLIST) { SetDirName(unichars.get()) ; SetIsMailList(PR_TRUE) ; } else { SetIsMailList(PR_FALSE) ; } return UpdateAddressList() ; } // nsIAbDirectory methods NS_IMETHODIMP nsAbOutlookDirectory::GetChildNodes(nsISimpleEnumerator **aNodes) { if (!aNodes) { return NS_ERROR_NULL_POINTER ; } *aNodes = nsnull ; nsCOMPtr nodeList ; nsresult retCode = NS_OK ; if (mIsQueryURI) { NS_NewISupportsArray(getter_AddRefs(nodeList)) ; } else { retCode = GetChildNodes(getter_AddRefs(nodeList)) ; } if (NS_SUCCEEDED(retCode)) retCode = NS_NewArrayEnumerator(aNodes, nodeList); return retCode; } NS_IMETHODIMP nsAbOutlookDirectory::GetChildCards(nsIEnumerator **aCards) { if (!aCards) { return NS_ERROR_NULL_POINTER ; } *aCards = nsnull ; nsCOMPtr cardList ; nsresult retCode ; mCardList.Reset() ; if (mIsQueryURI) { retCode = StartSearch() ; NS_NewISupportsArray(getter_AddRefs(cardList)) ; } else { retCode = GetChildCards(getter_AddRefs(cardList), nsnull) ; } if (NS_SUCCEEDED(retCode)) { // Fill the results array and update the card list // Also update the address list and notify any changes. PRUint32 nbCards = 0 ; nsCOMPtr element ; cardList->Enumerate(aCards) ; cardList->Count(&nbCards) ; for (PRUint32 i = 0 ; i < nbCards ; ++ i) { cardList->GetElementAt(i, getter_AddRefs(element)) ; nsVoidKey newKey (NS_STATIC_CAST(void *, element)) ; nsCOMPtr oldElement = mCardList.Get(&newKey) ; if (!oldElement) { // We are dealing with a new element (probably directly // added from Outlook), we may need to sync m_AddressList mCardList.Put(&newKey, element) ; nsCOMPtr card (do_QueryInterface(element, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; PRBool isMailList = PR_FALSE ; retCode = card->GetIsMailList(&isMailList) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (isMailList) { // We can have mailing lists only in folder, // we must add the directory to m_AddressList nsXPIDLCString mailListUri ; retCode = card->GetMailListURI(getter_Copies(mailListUri)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr resource ; retCode = gRDFService->GetResource(mailListUri, getter_AddRefs(resource)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr mailList(do_QueryInterface(resource, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; m_AddressList->AppendElement(mailList) ; NotifyItemAddition(mailList) ; } else if (m_IsMailList) { m_AddressList->AppendElement(card) ; NotifyItemAddition(card) ; } } else { NS_ASSERTION(oldElement == element, "Different card stored") ; } } } return retCode ; } NS_IMETHODIMP nsAbOutlookDirectory::HasCard(nsIAbCard *aCard, PRBool *aHasCard) { if (!aCard || !aHasCard) { return NS_ERROR_NULL_POINTER ; } nsVoidKey key (NS_STATIC_CAST(void *, aCard)) ; *aHasCard = mCardList.Exists(&key) ; return NS_OK ; } NS_IMETHODIMP nsAbOutlookDirectory::HasDirectory(nsIAbDirectory *aDirectory, PRBool *aHasDirectory) { if (!aDirectory || !aHasDirectory ) { return NS_ERROR_NULL_POINTER ; } *aHasDirectory = (m_AddressList->IndexOf(aDirectory) >= 0) ; return NS_OK ; } static nsresult ExtractEntryFromUri(nsIRDFResource *aResource, nsCString &aEntry, const char *aPrefix) { aEntry.Truncate() ; if (!aPrefix ) { return NS_ERROR_NULL_POINTER ; } nsXPIDLCString uri ; nsresult retCode = aResource->GetValue(getter_Copies(uri)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCAutoString stub ; nsAbWinType objType = getAbWinType(aPrefix, uri.get(), stub, aEntry) ; return NS_OK ; } static nsresult ExtractCardEntry(nsIAbCard *aCard, nsCString& aEntry) { aEntry.Truncate() ; nsresult retCode = NS_OK ; nsCOMPtr resource (do_QueryInterface(aCard, &retCode)) ; // Receiving a non-RDF card is accepted if (NS_FAILED(retCode)) { return NS_OK ; } return ExtractEntryFromUri(resource, aEntry, kOutlookCardScheme) ; } static nsresult ExtractDirectoryEntry(nsIAbDirectory *aDirectory, nsCString& aEntry) { aEntry.Truncate() ; nsresult retCode = NS_OK ; nsCOMPtr resource (do_QueryInterface(aDirectory, &retCode)) ; // Receiving a non-RDF directory is accepted if (NS_FAILED(retCode)) { return NS_OK ; } return ExtractEntryFromUri(resource, aEntry, kOutlookDirectoryScheme) ; } NS_IMETHODIMP nsAbOutlookDirectory::DeleteCards(nsISupportsArray *aCardList) { if (mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; } if (!aCardList) { return NS_ERROR_NULL_POINTER ; } PRUint32 nbCards = 0 ; nsresult retCode = NS_OK ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } retCode = aCardList->Count(&nbCards) ; NS_ENSURE_SUCCESS(retCode, retCode) ; PRUint32 i = 0 ; nsCOMPtr element ; nsCAutoString entryString ; nsMapiEntry cardEntry ; for (i = 0 ; i < nbCards ; ++ i) { retCode = aCardList->GetElementAt(i, getter_AddRefs(element)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr card (do_QueryInterface(element, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = ExtractCardEntry(card, entryString) ; if (NS_SUCCEEDED(retCode) && !entryString.IsEmpty()) { cardEntry.Assign(entryString) ; if (!mapiAddBook->DeleteEntry(*mMapiData, cardEntry)) { PRINTF(("Cannot delete card %s.\n", entryString.get())) ; } else { nsVoidKey key (NS_STATIC_CAST(void *, element)) ; mCardList.Remove(&key) ; if (m_IsMailList) { m_AddressList->RemoveElement(element) ; } retCode = NotifyItemDeletion(element) ; NS_ENSURE_SUCCESS(retCode, retCode) ; } } else { PRINTF(("Card doesn't belong in this directory.\n")) ; } } return NS_OK ; } NS_IMETHODIMP nsAbOutlookDirectory::ModifyDirectory(nsIAbDirectory *directory, nsIAbDirectoryProperties *aProperties) { return NS_ERROR_NOT_IMPLEMENTED; } 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) ; nsCAutoString 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 { m_AddressList->RemoveElement(aDirectory) ; 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 ; PRBool hasCard = PR_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) ; nsVoidKey newKey (NS_STATIC_CAST(void *, *addedCard)) ; mCardList.Put(&newKey, *addedCard) ; if (m_IsMailList) { m_AddressList->AppendElement(*addedCard) ; } NotifyItemAddition(*addedCard) ; return retCode ; } NS_IMETHODIMP nsAbOutlookDirectory::DropCard(nsIAbCard *aData, PRBool needToCopyCard) { nsCOMPtr addedCard; return AddCard(aData, getter_AddRefs(addedCard)); } NS_IMETHODIMP nsAbOutlookDirectory::AddMailList(nsIAbDirectory *aMailList) { if (mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; } if (!aMailList) { return NS_ERROR_NULL_POINTER ; } if (m_IsMailList) { return NS_OK ; } nsresult retCode = NS_OK ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; nsCAutoString entryString ; nsMapiEntry newEntry ; PRBool didCopy = PR_FALSE ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } retCode = ExtractDirectoryEntry(aMailList, entryString) ; if (NS_SUCCEEDED(retCode) && !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 = PR_TRUE ; } newEntry.ToString(entryString) ; nsCAutoString uri ; buildAbWinUri(kOutlookDirectoryScheme, mAbWinType, uri) ; uri.Append(entryString) ; nsCOMPtr resource ; retCode = gRDFService->GetResource(uri, getter_AddRefs(resource)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr newList(do_QueryInterface(resource, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!didCopy) { retCode = newList->CopyMailList(aMailList) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = newList->EditMailListToDatabase(mURINoQuery.get(), nsnull) ; NS_ENSURE_SUCCESS(retCode, retCode) ; } m_AddressList->AppendElement(newList) ; NotifyItemAddition(newList) ; return retCode ; } NS_IMETHODIMP nsAbOutlookDirectory::EditMailListToDatabase(const char *aUri, nsIAbCard *listCard) { if (mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; } nsresult retCode = NS_OK ; nsXPIDLString name ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } retCode = GetDirName(getter_Copies(name)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!mapiAddBook->SetPropertyUString(*mMapiData, PR_DISPLAY_NAME_W, name.get())) { return NS_ERROR_FAILURE ; } retCode = CommitAddressList() ; return retCode ; } struct OutlookTableAttr { const char *mOuterName ; ULONG mMapiProp ; } ; /*static const OutlookTableAttr OutlookTableStringToProp [] = { {"FirstName", PR_GIVEN_NAME_W}, {"LastName", PR_SURNAME_W}, {"DisplayName", PR_DISPLAY_NAME_W}, {"NickName", PR_NICKNAME_W}, {"PrimaryEmail", PR_EMAIL_ADDRESS_W}, {"WorkPhone", PR_BUSINESS_TELEPHONE_NUMBER_W}, {"HomePhone", PR_HOME_TELEPHONE_NUMBER_W}, {"FaxNumber", PR_BUSINESS_FAX_NUMBER_W}, {"PagerNumber", PR_PAGER_TELEPHONE_NUMBER_W}, {"CellularNumber", PR_MOBILE_TELEPHONE_NUMBER_W}, {"HomeAddress", PR_HOME_ADDRESS_STREET_W}, {"HomeCity", PR_HOME_ADDRESS_CITY_W}, {"HomeState", PR_HOME_ADDRESS_STATE_OR_PROVINCE_W}, {"HomeZipCode", PR_HOME_ADDRESS_POSTAL_CODE_W}, {"HomeCountry", PR_HOME_ADDRESS_COUNTRY_W}, {"WorkAddress", PR_BUSINESS_ADDRESS_STREET_W}, {"WorkCity", PR_BUSINESS_ADDRESS_CITY_W}, {"WorkState", PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W}, {"WorkZipCode", PR_BUSINESS_ADDRESS_POSTAL_CODE_W}, {"WorkCountry", PR_BUSINESS_ADDRESS_COUNTRY_W}, {"JobTitle", PR_TITLE_W}, {"Department", PR_DEPARTMENT_NAME_W}, {"Company", PR_COMPANY_NAME_W}, {"WebPage1", PR_BUSINESS_HOME_PAGE_W}, {"WebPage2", PR_PERSONAL_HOME_PAGE_W}, // For the moment, we don't support querying on the birthday // sub-elements. #if 0 {"BirthYear", PR_BIRTHDAY}, {"BirthMonth", PR_BIRTHDAY}, {"BirthDay", PR_BIRTHDAY}, #endif // 0 {"Notes", PR_COMMENT_W} } ;*/ // 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 [] = { // replace "PrimaryEmail" with kPriEmailColumn etc. {"FirstName", PR_GIVEN_NAME_A}, {"LastName", PR_SURNAME_A}, {"DisplayName", PR_DISPLAY_NAME_A}, {"NickName", PR_NICKNAME_A}, {"PrimaryEmail", PR_EMAIL_ADDRESS_A}, {"WorkPhone", PR_BUSINESS_TELEPHONE_NUMBER_A}, {"HomePhone", PR_HOME_TELEPHONE_NUMBER_A}, {"FaxNumber", PR_BUSINESS_FAX_NUMBER_A}, {"PagerNumber", PR_PAGER_TELEPHONE_NUMBER_A}, {"CellularNumber", PR_MOBILE_TELEPHONE_NUMBER_A}, {"HomeAddress", PR_HOME_ADDRESS_STREET_A}, {"HomeCity", PR_HOME_ADDRESS_CITY_A}, {"HomeState", PR_HOME_ADDRESS_STATE_OR_PROVINCE_A}, {"HomeZipCode", PR_HOME_ADDRESS_POSTAL_CODE_A}, {"HomeCountry", PR_HOME_ADDRESS_COUNTRY_A}, {"WorkAddress", PR_BUSINESS_ADDRESS_STREET_A}, {"WorkCity", PR_BUSINESS_ADDRESS_CITY_A}, {"WorkState", PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A}, {"WorkZipCode", PR_BUSINESS_ADDRESS_POSTAL_CODE_A}, {"WorkCountry", PR_BUSINESS_ADDRESS_COUNTRY_A}, {"JobTitle", PR_TITLE_A}, {"Department", PR_DEPARTMENT_NAME_A}, {"Company", PR_COMPANY_NAME_A}, {"WebPage1", PR_BUSINESS_HOME_PAGE_A}, {"WebPage2", PR_PERSONAL_HOME_PAGE_A}, // For the moment, we don't support querying on the birthday // sub-elements. #if 0 {"BirthYear", PR_BIRTHDAY}, {"BirthMonth", PR_BIRTHDAY}, {"BirthDay", PR_BIRTHDAY}, #endif // 0 {"Notes", PR_COMMENT_A} } ; static const PRUint32 OutlookTableNbProps = sizeof(OutlookTableStringToProp) / sizeof(OutlookTableStringToProp [0]) ; static ULONG findPropertyTag(const char *aName) { PRUint32 i = 0 ; for (i = 0 ; i < OutlookTableNbProps ; ++ i) { if (nsCRT::strcmp(aName, OutlookTableStringToProp [i].mOuterName) == 0) { return OutlookTableStringToProp [i].mMapiProp ; } } return 0 ; } static nsresult BuildRestriction(nsIAbBooleanConditionString *aCondition, SRestriction& aRestriction, PRBool& aSkipItem) { if (!aCondition) { return NS_ERROR_NULL_POINTER ; } aSkipItem = PR_FALSE ; nsAbBooleanConditionType conditionType = 0 ; nsresult retCode = NS_OK ; nsXPIDLCString name ; nsXPIDLString value ; ULONG propertyTag = 0 ; nsCAutoString 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) ; valueAscii.AssignWithConversion(value.get()) ; propertyTag = findPropertyTag(name.get()) ; if (propertyTag == 0) { aSkipItem = PR_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 = nsCRT::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 = nsCRT::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 = nsCRT::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 = nsCRT::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 = nsCRT::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 = nsCRT::strdup(valueAscii.get()) ; #else aSkipItem = PR_TRUE ; #endif // 0 break ; case nsIAbBooleanConditionTypes::SoundsLike : // This condition cannot be implemented in MAPI. aSkipItem = PR_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 = nsCRT::strdup(valueAscii.get()) ; #else aSkipItem = PR_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 = nsCRT::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 = nsCRT::strdup(valueAscii.get()) ; break ; default : aSkipItem = PR_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 ; PRUint32 nbExpressions = 0 ; nsCOMPtr expressions ; retCode = aLevel->GetOperation(&operationType) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = aLevel->GetExpressions(getter_AddRefs(expressions)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = expressions->Count(&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] ; PRUint32 realNbExpressions = 0 ; PRBool skipItem = PR_FALSE ; PRUint32 i = 0 ; nsCOMPtr element ; for (i = 0 ; i < nbExpressions ; ++ i) { retCode = expressions->GetElementAt(i, getter_AddRefs(element)) ; if (NS_SUCCEEDED(retCode)) { nsCOMPtr condition (do_QueryInterface(element, &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 { nsCOMPtr subExpression (do_QueryInterface(element, &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)) ; } } } else { PRINTF(("Cannot get 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 booleanQuery ; retCode = aArguments->GetExpression(getter_AddRefs(booleanQuery)) ; 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) { nsCRT::free(aRestriction.res.resContent.lpProp->Value.lpszW) ; } else if (PROP_TYPE(aRestriction.res.resContent.ulPropTag) == PT_STRING8) { nsCRT::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) { nsCRT::free(aRestriction.res.resProperty.lpProp->Value.lpszW) ; } else if (PROP_TYPE(aRestriction.res.resProperty.ulPropTag) == PT_STRING8) { nsCRT::free(aRestriction.res.resProperty.lpProp->Value.lpszA) ; } delete aRestriction.res.resProperty.lpProp ; case RES_SIZE : case RES_SUBRESTRICTION : break ; } } nsresult FillPropertyValues(nsIAbCard *aCard, nsIAbDirectoryQueryArguments *aArguments, nsISupportsArray **aValues) { if (!aCard || !aArguments || !aValues ) { return NS_ERROR_NULL_POINTER ; } *aValues = nsnull ; CharPtrArrayGuard properties ; nsCOMPtr values ; nsresult retCode = NS_OK ; retCode = aArguments->GetReturnProperties(properties.GetSizeAddr(), properties.GetArrayAddr()) ; NS_ENSURE_SUCCESS(retCode, retCode) ; PRUint32 i = 0 ; nsAbDirectoryQueryPropertyValue *newValue = nsnull ; nsCOMPtr propertyValue ; for (i = 0 ; i < properties.GetSize() ; ++ i) { const char* cPropName = properties[i] ; newValue = nsnull ; if (!nsCRT::strcmp(cPropName, "card:nsIAbCard")) { nsCOMPtr bogusInterface (do_QueryInterface(aCard, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; newValue = new nsAbDirectoryQueryPropertyValue (cPropName, bogusInterface) ; } else { nsXPIDLString value ; retCode = aCard->GetCardValue(cPropName, getter_Copies(value)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!value.IsEmpty()) { newValue = new nsAbDirectoryQueryPropertyValue(cPropName, value.get()) ; } } if (newValue) { if (!values) { NS_NewISupportsArray(getter_AddRefs(values)) ; } propertyValue = newValue ; values->AppendElement (propertyValue) ; } } *aValues = values ; NS_ADDREF(*aValues) ; return retCode ; } struct QueryThreadArgs { nsAbOutlookDirectory *mThis ; nsCOMPtr mArguments ; nsCOMPtr mListener ; PRInt32 mResultLimit ; PRInt32 mTimeout ; PRInt32 mThreadId ; } ; static void QueryThreadFunc(void *aArguments) { QueryThreadArgs *arguments = NS_REINTERPRET_CAST(QueryThreadArgs *, aArguments) ; if (!aArguments) { return ; } arguments->mThis->ExecuteQuery(arguments->mArguments, arguments->mListener, arguments->mResultLimit, arguments->mTimeout, arguments->mThreadId) ; delete arguments ; } nsresult nsAbOutlookDirectory::DoQuery(nsIAbDirectoryQueryArguments *aArguments, nsIAbDirectoryQueryResultListener *aListener, PRInt32 aResultLimit, PRInt32 aTimeout, PRInt32 *aReturnValue) { if (!aArguments || !aListener || !aReturnValue) { return NS_ERROR_NULL_POINTER ; } *aReturnValue = -1 ; QueryThreadArgs *threadArgs = new QueryThreadArgs ; PRThread *newThread = nsnull ; if (!threadArgs) { return NS_ERROR_OUT_OF_MEMORY ; } threadArgs->mThis = this ; threadArgs->mArguments = aArguments ; 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 ) { delete threadArgs ; return NS_ERROR_OUT_OF_MEMORY ; } nsIntegerKey newKey(*aReturnValue) ; mQueryThreads.Put(&newKey, newThread) ; return NS_OK ; } nsresult nsAbOutlookDirectory::StopQuery(PRInt32 aContext) { nsIntegerKey contextKey(aContext) ; PRThread *queryThread = NS_REINTERPRET_CAST(PRThread *, mQueryThreads.Get(&contextKey)) ; if (queryThread) { PR_Interrupt(queryThread) ; mQueryThreads.Remove(&contextKey) ; } 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.Reset() ; nsCOMPtr expression ; nsCOMPtr arguments = do_CreateInstance(NS_ABDIRECTORYQUERYARGUMENTS_CONTRACTID,&retCode); NS_ENSURE_SUCCESS(retCode, retCode); retCode = nsAbQueryStringToExpression::Convert(mQueryString.get (), getter_AddRefs(expression)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = arguments->SetExpression(expression) ; NS_ENSURE_SUCCESS(retCode, retCode) ; const char *arr = "card:nsIAbCard"; retCode = arguments->SetReturnProperties(1, &arr); NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = arguments->SetQuerySubDirectories(PR_TRUE) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr proxyListener; retCode = NS_GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIAbDirectoryQueryResultListener), NS_STATIC_CAST(nsIAbDirectoryQueryResultListener *, new nsAbDirSearchListener(this)), PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs(proxyListener)); NS_ENSURE_SUCCESS(retCode, retCode) ; return DoQuery(arguments, proxyListener, -1, 0, &mSearchContext) ; } NS_IMETHODIMP nsAbOutlookDirectory::StopSearch(void) { if (!mIsQueryURI) { return NS_ERROR_NOT_IMPLEMENTED ; } return StopQuery(mSearchContext) ; } // nsAbDirSearchListenerContext nsresult nsAbOutlookDirectory::OnSearchFinished(PRInt32 aResult) { return NS_OK ; } nsresult nsAbOutlookDirectory::OnSearchFoundCard(nsIAbCard *aCard) { nsVoidKey newKey (NS_STATIC_CAST(void *, aCard)) ; nsresult retCode = NS_OK ; mCardList.Put(&newKey, aCard) ; nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &retCode); if (NS_SUCCEEDED(retCode)) { abSession->NotifyDirectoryItemAdded(this, aCard) ; } return retCode ; } nsresult nsAbOutlookDirectory::ExecuteQuery(nsIAbDirectoryQueryArguments *aArguments, nsIAbDirectoryQueryResultListener *aListener, PRInt32 aResultLimit, PRInt32 aTimeout, PRInt32 aThreadId) { if (!aArguments || !aListener) { return NS_ERROR_NULL_POINTER ; } SRestriction arguments ; nsresult retCode = NS_OK ; retCode = BuildRestriction(aArguments, arguments) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr resultsArray ; PRUint32 nbResults = 0 ; retCode = GetChildCards(getter_AddRefs(resultsArray), arguments.rt == RES_COMMENT ? nsnull : &arguments) ; DestroyRestriction(arguments) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = resultsArray->Count(&nbResults) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr result ; nsAbDirectoryQueryResult *newResult = nsnull ; if (aResultLimit > 0 && nbResults > NS_STATIC_CAST(PRUint32, aResultLimit)) { nbResults = NS_STATIC_CAST(PRUint32, aResultLimit) ; } PRUint32 i = 0 ; nsCOMPtr element ; nsCOMPtr propertyValues ; for (i = 0 ; i < nbResults ; ++ i) { retCode = resultsArray->GetElementAt(i, getter_AddRefs(element)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr card (do_QueryInterface(element, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; FillPropertyValues(card, aArguments, getter_AddRefs(propertyValues)) ; newResult = new nsAbDirectoryQueryResult(0, aArguments, nsIAbDirectoryQueryResult::queryResultMatch, propertyValues) ; if (!newResult) { return NS_ERROR_OUT_OF_MEMORY ; } result = newResult ; aListener->OnQueryItem(result) ; } nsIntegerKey hashKey(aThreadId) ; mQueryThreads.Remove(&hashKey) ; newResult = new nsAbDirectoryQueryResult(0, aArguments, nsIAbDirectoryQueryResult::queryResultComplete, 0) ; result = newResult ; aListener->OnQueryItem(result) ; return retCode ; } nsresult nsAbOutlookDirectory::GetChildCards(nsISupportsArray **aCards, void *aRestriction) { if (!aCards) { return NS_ERROR_NULL_POINTER ; } *aCards = nsnull ; nsresult retCode = NS_OK ; nsCOMPtr cards ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; nsMapiEntryArray cardEntries ; LPSRestriction restriction = (LPSRestriction) aRestriction ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } retCode = NS_NewISupportsArray(getter_AddRefs(cards)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!mapiAddBook->GetCards(*mMapiData, restriction, cardEntries)) { PRINTF(("Cannot get cards.\n")) ; return NS_ERROR_FAILURE ; } nsCAutoString entryId ; nsCAutoString uriName ; nsCOMPtr resource ; nsCOMPtr childCard; for (ULONG card = 0 ; card < cardEntries.mNbEntries ; ++ card) { cardEntries.mEntries [card].ToString(entryId) ; buildAbWinUri(kOutlookCardScheme, mAbWinType, uriName) ; uriName.Append(entryId) ; childCard = do_CreateInstance(NS_ABOUTLOOKCARD_CONTRACTID, &retCode); NS_ENSURE_SUCCESS(retCode, retCode) ; resource = do_QueryInterface(childCard, &retCode) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = resource->Init(uriName.get()) ; NS_ENSURE_SUCCESS(retCode, retCode) ; cards->AppendElement(childCard) ; } *aCards = cards ; NS_ADDREF(*aCards) ; return retCode ; } nsresult nsAbOutlookDirectory::GetChildNodes(nsISupportsArray **aNodes) { if (!aNodes) { return NS_ERROR_NULL_POINTER ; } *aNodes = nsnull ; nsresult retCode = NS_OK ; nsCOMPtr nodes ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; nsMapiEntryArray nodeEntries ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } retCode = NS_NewISupportsArray(getter_AddRefs(nodes)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!mapiAddBook->GetNodes(*mMapiData, nodeEntries)) { PRINTF(("Cannot get nodes.\n")) ; return NS_ERROR_FAILURE ; } nsCAutoString entryId ; nsCAutoString uriName ; nsCOMPtr resource ; for (ULONG node = 0 ; node < nodeEntries.mNbEntries ; ++ node) { nodeEntries.mEntries [node].ToString(entryId) ; buildAbWinUri(kOutlookDirectoryScheme, mAbWinType, uriName) ; uriName.Append(entryId) ; retCode = gRDFService->GetResource(uriName, getter_AddRefs(resource)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nodes->AppendElement(resource) ; } *aNodes = nodes ; NS_ADDREF(*aNodes) ; return retCode ; } nsresult nsAbOutlookDirectory::NotifyItemDeletion(nsISupports *aItem) { nsresult retCode = NS_OK ; nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &retCode); NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = abSession->NotifyDirectoryItemDeleted(this, aItem) ; return retCode ; } nsresult nsAbOutlookDirectory::NotifyItemAddition(nsISupports *aItem) { nsresult retCode = NS_OK ; nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &retCode); NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = abSession->NotifyDirectoryItemAdded(this, aItem) ; return retCode ; } // 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) { nsresult retCode = NS_OK ; nsCOMPtr oldList ; PRUint32 nbCards = 0 ; PRUint32 i = 0 ; if (!m_IsMailList) { PRINTF(("We are not in a mailing list, no commit can be done.\n")) ; return NS_ERROR_UNEXPECTED ; } retCode = GetChildCards(getter_AddRefs(oldList), nsnull) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = m_AddressList->Count(&nbCards) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr element ; nsCOMPtr newCard ; for (i = 0 ; i < nbCards ; ++ i) { retCode = m_AddressList->GetElementAt(i, getter_AddRefs(element)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!oldList->RemoveElement(element)) { // The entry was not already there nsCOMPtr card (do_QueryInterface(element, &retCode)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = CreateCard(card, getter_AddRefs(newCard)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; m_AddressList->ReplaceElementAt(newCard, i) ; } } retCode = DeleteCards(oldList) ; return retCode ; } nsresult nsAbOutlookDirectory::UpdateAddressList(void) { nsresult retCode = S_OK ; if (m_IsMailList) { retCode = GetChildCards(getter_AddRefs(m_AddressList), nsnull) ; } else { retCode = GetChildNodes(getter_AddRefs(m_AddressList)) ; } return retCode ; } nsresult nsAbOutlookDirectory::CreateCard(nsIAbCard *aData, nsIAbCard **aNewCard) { if (!aData || !aNewCard) { return NS_ERROR_NULL_POINTER ; } *aNewCard = nsnull ; nsresult retCode = NS_OK ; nsAbWinHelperGuard mapiAddBook (mAbWinType) ; nsMapiEntry newEntry ; nsCAutoString entryString ; PRBool didCopy = PR_FALSE ; if (!mapiAddBook->IsOK()) { return NS_ERROR_FAILURE ; } // If we get a RDF resource and it 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 = PR_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) ; nsCAutoString uri ; buildAbWinUri(kOutlookCardScheme, mAbWinType, uri) ; uri.Append(entryString) ; nsCOMPtr resource ; nsCOMPtr newCard = do_CreateInstance(NS_ABOUTLOOKCARD_CONTRACTID, &retCode); NS_ENSURE_SUCCESS(retCode, retCode) ; resource = do_QueryInterface(newCard, &retCode) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = resource->Init(uri.get()) ; NS_ENSURE_SUCCESS(retCode, retCode) ; if (!didCopy) { retCode = newCard->Copy(aData) ; NS_ENSURE_SUCCESS(retCode, retCode) ; retCode = newCard->EditCardToDatabase(mURINoQuery.get()) ; NS_ENSURE_SUCCESS(retCode, retCode) ; } *aNewCard = newCard ; NS_ADDREF(*aNewCard) ; return retCode ; }