/* -*- 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 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 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 card; nsCOMPtr 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 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 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 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 abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr 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 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 condition; nsCOMPtr 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 supports ; retCode = aArguments->GetExpression(getter_AddRefs(supports)) ; NS_ENSURE_SUCCESS(retCode, retCode) ; nsCOMPtr 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 mListener ; int32_t mResultLimit ; int32_t mTimeout ; int32_t mThreadId ; } ; static void QueryThreadFunc(void *aArguments) { QueryThreadArgs *arguments = reinterpret_cast(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 expression ; nsCOMPtr 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 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 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(aResultLimit)) { nbResults = static_cast(aResultLimit) ; } uint32_t i = 0; nsCOMPtr 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 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 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 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 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 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 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 element; nsCOMPtr 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 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 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(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 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 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; }