NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryChangedEntries(const nsACString & aChangedEntryDN) { if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; if(aChangedEntryDN.IsEmpty()) return NS_ERROR_UNEXPECTED; nsCAutoString urlFilter; nsresult rv = mURL->GetFilter(urlFilter); if(NS_FAILED(rv)) return rv; PRInt32 scope; rv = mURL->GetScope(&scope); if(NS_FAILED(rv)) return rv; CharPtrArrayGuard attributes; rv = mURL->GetAttributes(attributes.GetSizeAddr(), attributes.GetArrayAddr()); if(NS_FAILED(rv)) return rv; rv = CreateNewLDAPOperation(); NS_ENSURE_SUCCESS(rv, rv); return mOperation->SearchExt(aChangedEntryDN, scope, urlFilter, attributes.GetSize(), attributes.GetArray(), 0, 0); }
nsresult nsAbQueryLDAPMessageListener::DoSearch() { nsresult rv; mCanceled = mFinished = PR_FALSE; mSearchOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIProxyObjectManager> proxyMgr = do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsILDAPMessageListener> proxyListener; rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID(nsILDAPMessageListener), this, PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs(proxyListener)); NS_ENSURE_SUCCESS(rv, rv); rv = mSearchOperation->Init (mConnection, proxyListener, nsnull); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString dn; rv = mUrl->GetDn (dn); NS_ENSURE_SUCCESS(rv, rv); PRInt32 scope; rv = mUrl->GetScope (&scope); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString filter; rv = mUrl->GetFilter (filter); NS_ENSURE_SUCCESS(rv, rv); CharPtrArrayGuard attributes; rv = mUrl->GetAttributes (attributes.GetSizeAddr (), attributes.GetArrayAddr ()); NS_ENSURE_SUCCESS(rv, rv); // I don't _think_ it's ever actually possible to get here without having // an nsAbLDAPDirectory object, but, just in case, I'll do a QI instead // of just static casts... nsCOMPtr<nsIAbLDAPDirectory> nsIAbDir = do_QueryInterface(mDirectoryQuery, &rv); NS_ENSURE_SUCCESS(rv, rv); nsAbLDAPDirectory *dir = NS_STATIC_CAST(nsAbLDAPDirectory *, NS_STATIC_CAST(nsIAbLDAPDirectory *, nsIAbDir.get())); rv = mSearchOperation->SetServerControls(dir->mSearchServerControls.get()); NS_ENSURE_SUCCESS(rv, rv); rv = mSearchOperation->SetClientControls(dir->mSearchClientControls.get()); NS_ENSURE_SUCCESS(rv, rv); rv = mSearchOperation->SearchExt (dn, scope, filter, attributes.GetSize (), attributes.GetArray (), mTimeOut, mResultLimit); return rv; }
NS_IMETHODIMP nsAbLDAPCard::SetMetaProperties(nsILDAPMessage *aMessage) { NS_ENSURE_ARG_POINTER(aMessage); // Get DN nsAutoCString dn; nsresult rv = aMessage->GetDn(dn); NS_ENSURE_SUCCESS(rv, rv); SetDn(dn); // Get the list of set attributes CharPtrArrayGuard attrs; rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString attr; m_attributes.Clear(); for (uint32_t i = 0; i < attrs.GetSize(); ++i) { attr.Assign(nsDependentCString(attrs[i])); ToLowerCase(attr); m_attributes.AppendElement(attr); } // Get the objectClass values m_objectClass.Clear(); PRUnicharPtrArrayGuard vals; rv = aMessage->GetValues("objectClass", vals.GetSizeAddr(), vals.GetArrayAddr()); // objectClass is not always included in search result entries and // nsILDAPMessage::GetValues returns NS_ERROR_LDAP_DECODING_ERROR if the // requested attribute doesn't exist. if (rv == NS_ERROR_LDAP_DECODING_ERROR) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); nsAutoCString oclass; for (uint32_t i = 0; i < vals.GetSize(); ++i) { oclass.Assign(NS_LossyConvertUTF16toASCII(nsDependentString(vals[i]))); ToLowerCase(oclass); m_objectClass.AppendElement(oclass); } return NS_OK; }
nsresult nsAbLDAPProcessChangeLogData::ParseRootDSEEntry(nsILDAPMessage *aMessage) { NS_ENSURE_ARG_POINTER(aMessage); if (!mInitialized) return NS_ERROR_NOT_INITIALIZED; // Populate the RootDSEChangeLogEntry CharPtrArrayGuard attrs; nsresult rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr()); // No attributes if(NS_FAILED(rv)) return rv; for(PRInt32 i=attrs.GetSize()-1; i >= 0; i--) { PRUnicharPtrArrayGuard vals; rv = aMessage->GetValues(attrs.GetArray()[i], vals.GetSizeAddr(), vals.GetArrayAddr()); if(NS_FAILED(rv)) continue; if(vals.GetSize()) { if (!PL_strcasecmp(attrs[i], "changelog")) CopyUTF16toUTF8(vals[0], mRootDSEEntry.changeLogDN); if (!PL_strcasecmp(attrs[i], "firstChangeNumber")) mRootDSEEntry.firstChangeNumber = atol(NS_LossyConvertUTF16toASCII(vals[0]).get()); if (!PL_strcasecmp(attrs[i], "lastChangeNumber")) mRootDSEEntry.lastChangeNumber = atol(NS_LossyConvertUTF16toASCII(vals[0]).get()); if (!PL_strcasecmp(attrs[i], "dataVersion")) CopyUTF16toUTF8(vals[0], mRootDSEEntry.dataVersion); } } PRInt32 lastChangeNumber; mDirectory->GetLastChangeNumber(&lastChangeNumber); if ((mRootDSEEntry.lastChangeNumber > 0) && (lastChangeNumber < mRootDSEEntry.lastChangeNumber) && (lastChangeNumber > mRootDSEEntry.firstChangeNumber)) mUseChangeLog = PR_TRUE; if (mRootDSEEntry.lastChangeNumber && (lastChangeNumber == mRootDSEEntry.lastChangeNumber)) { Done(PR_TRUE); // We are up to date no need to replicate, db not open yet so call Done return NS_OK; } return rv; }
NS_IMETHODIMP nsAbLDAPChangeLogQuery::QueryAuthDN(const nsACString & aValueUsedToFindDn) { if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; nsresult rv = NS_OK; CharPtrArrayGuard attributes; *attributes.GetSizeAddr() = 2; *attributes.GetArrayAddr() = NS_STATIC_CAST(char **, nsMemory::Alloc((*attributes.GetSizeAddr()) * sizeof(char *))); attributes.GetArray()[0] = ToNewCString(nsDependentCString(DIR_GetFirstAttributeString(mDirServer, cn))); attributes.GetArray()[1] = nsnull; nsCAutoString filter(DIR_GetFirstAttributeString(mDirServer, auth)); filter += '='; filter += aValueUsedToFindDn; nsCAutoString dn; rv = mURL->GetDn(dn); if(NS_FAILED(rv)) return rv; rv = CreateNewLDAPOperation(); NS_ENSURE_SUCCESS(rv, rv); return mOperation->SearchExt(dn, nsILDAPURL::SCOPE_SUBTREE, filter, attributes.GetSize(), attributes.GetArray(), 0, 0); }
NS_IMETHODIMP nsAbLDAPDirectory::ModifyCard(nsIAbCard *aUpdatedCard) { NS_ENSURE_ARG_POINTER(aUpdatedCard); nsCOMPtr<nsIAbLDAPAttributeMap> attrMap; nsresult rv = GetAttributeMap(getter_AddRefs(attrMap)); NS_ENSURE_SUCCESS(rv, rv); // Get the LDAP card nsCOMPtr<nsIAbLDAPCard> card = do_QueryInterface(aUpdatedCard, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = Initiate(); NS_ENSURE_SUCCESS(rv, rv); // Retrieve preferences nsAutoCString prefString; rv = GetObjectClasses(prefString); NS_ENSURE_SUCCESS(rv, rv); CharPtrArrayGuard objClass; rv = SplitStringList(prefString, objClass.GetSizeAddr(), objClass.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); // Process updates nsCOMPtr<nsIArray> modArray; rv = card->GetLDAPMessageInfo(attrMap, objClass.GetSize(), objClass.GetArray(), nsILDAPModification::MOD_REPLACE, getter_AddRefs(modArray)); NS_ENSURE_SUCCESS(rv, rv); // Get current DN nsAutoCString oldDN; rv = card->GetDn(oldDN); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsILDAPService> ldapSvc = do_GetService( "@mozilla.org/network/ldap-service;1", &rv); NS_ENSURE_SUCCESS(rv, rv); // Retrieve base DN and RDN attributes nsAutoCString baseDN; nsAutoCString oldRDN; CharPtrArrayGuard rdnAttrs; rv = ldapSvc->ParseDn(oldDN.get(), oldRDN, baseDN, rdnAttrs.GetSizeAddr(), rdnAttrs.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); // Calculate new RDN and check whether it has changed nsAutoCString newRDN; rv = card->BuildRdn(attrMap, rdnAttrs.GetSize(), rdnAttrs.GetArray(), newRDN); NS_ENSURE_SUCCESS(rv, rv); if (newRDN.Equals(oldRDN)) { // Launch query rv = DoModify(this, nsILDAPModification::MOD_REPLACE, oldDN, modArray, EmptyCString(), EmptyCString()); } else { // Build and store the new DN nsAutoCString newDN(newRDN); newDN.AppendLiteral(","); newDN.Append(baseDN); rv = card->SetDn(newDN); NS_ENSURE_SUCCESS(rv, rv); // Launch query rv = DoModify(this, nsILDAPModification::MOD_REPLACE, oldDN, modArray, newRDN, baseDN); } return rv; }
NS_IMETHODIMP nsAbLDAPDirectory::AddCard(nsIAbCard *aUpdatedCard, nsIAbCard **aAddedCard) { NS_ENSURE_ARG_POINTER(aUpdatedCard); NS_ENSURE_ARG_POINTER(aAddedCard); nsCOMPtr<nsIAbLDAPAttributeMap> attrMap; nsresult rv = GetAttributeMap(getter_AddRefs(attrMap)); NS_ENSURE_SUCCESS(rv, rv); // Create a new LDAP card nsCOMPtr<nsIAbLDAPCard> card = do_CreateInstance(NS_ABLDAPCARD_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = Initiate(); NS_ENSURE_SUCCESS(rv, rv); // Copy over the card data nsCOMPtr<nsIAbCard> copyToCard = do_QueryInterface(card, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = copyToCard->Copy(aUpdatedCard); NS_ENSURE_SUCCESS(rv, rv); // Retrieve preferences nsAutoCString prefString; rv = GetRdnAttributes(prefString); NS_ENSURE_SUCCESS(rv, rv); CharPtrArrayGuard rdnAttrs; rv = SplitStringList(prefString, rdnAttrs.GetSizeAddr(), rdnAttrs.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); rv = GetObjectClasses(prefString); NS_ENSURE_SUCCESS(rv, rv); CharPtrArrayGuard objClass; rv = SplitStringList(prefString, objClass.GetSizeAddr(), objClass.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); // Process updates nsCOMPtr<nsIArray> modArray; rv = card->GetLDAPMessageInfo(attrMap, objClass.GetSize(), objClass.GetArray(), nsILDAPModification::MOD_ADD, getter_AddRefs(modArray)); NS_ENSURE_SUCCESS(rv, rv); // For new cards, the base DN is the search base DN nsCOMPtr<nsILDAPURL> currentUrl; rv = GetLDAPURL(getter_AddRefs(currentUrl)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString baseDN; rv = currentUrl->GetDn(baseDN); NS_ENSURE_SUCCESS(rv, rv); // Calculate DN nsAutoCString cardDN; rv = card->BuildRdn(attrMap, rdnAttrs.GetSize(), rdnAttrs.GetArray(), cardDN); NS_ENSURE_SUCCESS(rv, rv); cardDN.AppendLiteral(","); cardDN.Append(baseDN); rv = card->SetDn(cardDN); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString ourUuid; GetUuid(ourUuid); copyToCard->SetDirectoryId(ourUuid); // Launch query rv = DoModify(this, nsILDAPModification::MOD_ADD, cardDN, modArray, EmptyCString(), EmptyCString()); NS_ENSURE_SUCCESS(rv, rv); NS_ADDREF(*aAddedCard = copyToCard); return NS_OK; }
nsresult nsAbLDAPProcessChangeLogData::ParseChangeLogEntries(nsILDAPMessage *aMessage) { NS_ENSURE_ARG_POINTER(aMessage); if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; // Populate the RootDSEChangeLogEntry CharPtrArrayGuard attrs; nsresult rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr()); // No attributes if(NS_FAILED(rv)) return rv; nsAutoString targetDN; UpdateOp operation = NO_OP; for(PRInt32 i = attrs.GetSize()-1; i >= 0; i--) { PRUnicharPtrArrayGuard vals; rv = aMessage->GetValues(attrs.GetArray()[i], vals.GetSizeAddr(), vals.GetArrayAddr()); if(NS_FAILED(rv)) continue; if(vals.GetSize()) { if (!PL_strcasecmp(attrs[i], "targetdn")) targetDN = vals[0]; if (!PL_strcasecmp(attrs[i], "changetype")) { if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("add"), nsCaseInsensitiveStringComparator())) operation = ENTRY_ADD; if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("modify"), nsCaseInsensitiveStringComparator())) operation = ENTRY_MODIFY; if (!Compare(nsDependentString(vals[0]), NS_LITERAL_STRING("delete"), nsCaseInsensitiveStringComparator())) operation = ENTRY_DELETE; } } } mChangeLogEntriesCount++; if(!(mChangeLogEntriesCount % 10)) { // Inform the listener every 10 entries mListener->OnProgressChange(nsnull,nsnull,mChangeLogEntriesCount, -1, mChangeLogEntriesCount, -1); // In case if the LDAP Connection thread is starved and causes problem // uncomment this one and try. // PR_Sleep(PR_INTERVAL_NO_WAIT); // give others a chance } #ifdef DEBUG_rdayal printf ("ChangeLog Replication : Updated Entry : %s for OpType : %u\n", NS_ConvertUTF16toUTF8(targetDN).get(), operation); #endif switch(operation) { case ENTRY_ADD: // Add the DN to the add list if not already in the list if(!(mEntriesToAdd.IndexOf(targetDN) >= 0)) mEntriesToAdd.AppendString(targetDN); break; case ENTRY_DELETE: // Do not check the return here since delete may fail if // entry deleted in changelog does not exist in DB // for e.g if the user specifies a filter, so go next entry DeleteCard(targetDN); break; case ENTRY_MODIFY: // For modify, delete the entry from DB and add updated entry // we do this since we cannot access the changes attribs of changelog rv = DeleteCard(targetDN); if (NS_SUCCEEDED(rv)) if(!(mEntriesToAdd.IndexOf(targetDN) >= 0)) mEntriesToAdd.AppendString(targetDN); break; default: // Should not come here, would come here only // if the entry is not a changeLog entry NS_WARNING("nsAbLDAPProcessChangeLogData::ParseChangeLogEntries" "Not an changelog entry"); } // Go ahead processing the next entry, a modify or delete DB operation // can 'correctly' fail if the entry is not present in the DB, // e.g. in case a filter is specified. return NS_OK; }
/* Retrieves the changes to the LDAP card and stores them in an LDAP * update message. * * Calling this method changes the LDAP card, it updates the * meta-properties (m_*) to reflect what the LDAP contents will be once * the update has been performed. This allows you to do multiple (successful) * consecutive edits on a card in a search result. If the meta-properties * were not updated, incorrect assuptions would be made about what object * classes to add, or what attributes to clear. * * XXX: We need to take care when integrating this code with the asynchronous * update dialogs, as the current code in nsAbLDAPDirectory has a problem * when an update fails: the modified card still gets stored and shown to * the user instead of being discarded. There is one especially tricky case: * when you do an update on a card which changes its DN, you have two * operations (rename, then update the other attributes). If the rename * operation succeeds and not the update of the attributes, you are * "somewhere in between" the original card and the updated card. */ NS_IMETHODIMP nsAbLDAPCard::GetLDAPMessageInfo( nsIAbLDAPAttributeMap *aAttributeMap, const uint32_t aClassCount, const char **aClasses, int32_t aType, nsIArray **aLDAPAddMessageInfo) { NS_ENSURE_ARG_POINTER(aAttributeMap); NS_ENSURE_ARG_POINTER(aClasses); NS_ENSURE_ARG_POINTER(aLDAPAddMessageInfo); nsresult rv; nsCOMPtr<nsIMutableArray> modArray = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); // Add any missing object classes. We never remove any object // classes: if an entry has additional object classes, it's probably // for a good reason. nsAutoCString oclass; for (uint32_t i = 0; i < aClassCount; ++i) { oclass.Assign(nsDependentCString(aClasses[i])); ToLowerCase(oclass); if (m_objectClass.IndexOf(oclass) == nsTArray<nsCString>::NoIndex) { m_objectClass.AppendElement(oclass); printf("LDAP : adding objectClass %s\n", oclass.get()); } } nsCOMPtr<nsILDAPModification> mod = do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIMutableArray> values = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); for (uint32_t i = 0; i < m_objectClass.Length(); ++i) { nsCOMPtr<nsILDAPBERValue> value = do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv); NS_ENSURE_SUCCESS(rv, rv); rv = value->SetFromUTF8(m_objectClass.ElementAt(i)); NS_ENSURE_SUCCESS(rv, rv); rv = values->AppendElement(value, false); NS_ENSURE_SUCCESS(rv, rv); } rv = mod->SetUpModification(aType, NS_LITERAL_CSTRING("objectClass"), values); NS_ENSURE_SUCCESS(rv, rv); modArray->AppendElement(mod, false); // Add card properties CharPtrArrayGuard props; rv = aAttributeMap->GetAllCardProperties(props.GetSizeAddr(), props.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString attr; nsCString propvalue; for (uint32_t i = 0; i < props.GetSize(); ++i) { // Skip some attributes that don't map to LDAP. // // BirthYear : by default this is mapped to 'birthyear', // which is not part of mozillaAbPersonAlpha // // LastModifiedDate : by default this is mapped to 'modifytimestamp', // which cannot be modified // // PreferMailFormat : by default this is mapped to 'mozillaUseHtmlMail', // which is a boolean, not plaintext/html/unknown if (!strcmp(props[i], kBirthYearProperty) || !strcmp(props[i], kLastModifiedDateProperty) || !strcmp(props[i], kPreferMailFormatProperty)) continue; rv = aAttributeMap->GetFirstAttribute(nsDependentCString(props[i]), attr); NS_ENSURE_SUCCESS(rv, rv); ToLowerCase(attr); // If the property is not mapped to an attribute, skip it. if (attr.IsEmpty()) continue; nsCOMPtr<nsILDAPModification> mod = do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv); NS_ENSURE_SUCCESS(rv, rv); uint32_t index = m_attributes.IndexOf(attr); rv = GetPropertyAsAUTF8String(props[i], propvalue); if (NS_SUCCEEDED(rv) &&!propvalue.IsEmpty()) { // If the new value is not empty, add/update it nsCOMPtr<nsILDAPBERValue> value = do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv); NS_ENSURE_SUCCESS(rv, rv); rv = value->SetFromUTF8(propvalue); NS_ENSURE_SUCCESS(rv, rv); rv = mod->SetUpModificationOneValue(aType, attr, value); NS_ENSURE_SUCCESS(rv, rv); printf("LDAP : setting attribute %s (%s) to '%s'\n", attr.get(), props[i], propvalue.get()); modArray->AppendElement(mod, false); if (index != nsTArray<nsCString>::NoIndex) m_attributes.AppendElement(attr); } else if (aType == nsILDAPModification::MOD_REPLACE && index != nsTArray<nsCString>::NoIndex) { // If the new value is empty, we are performing an update // and the attribute was previously set, clear it nsCOMPtr<nsIMutableArray> novalues = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = mod->SetUpModification(aType, attr, novalues); NS_ENSURE_SUCCESS(rv, rv); printf("LDAP : removing attribute %s (%s)\n", attr.get(), props[i]); modArray->AppendElement(mod, false); m_attributes.RemoveElementAt(index); } } NS_ADDREF(*aLDAPAddMessageInfo = modArray); return NS_OK; }
nsresult nsAbQueryLDAPMessageListener::OnLDAPMessageSearchEntry (nsILDAPMessage *aMessage, nsIAbDirectoryQueryResult** result) { nsresult rv; if (!mDirectoryQuery) return NS_ERROR_NULL_POINTER; // the address book fields that we'll be asking for CharPtrArrayGuard properties; rv = mQueryArguments->GetReturnProperties (properties.GetSizeAddr(), properties.GetArrayAddr()); NS_ENSURE_SUCCESS(rv, rv); // the map for translating between LDAP attrs <-> addrbook fields nsCOMPtr<nsISupports> iSupportsMap; rv = mQueryArguments->GetTypeSpecificArg(getter_AddRefs(iSupportsMap)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIAbLDAPAttributeMap> map = do_QueryInterface(iSupportsMap, &rv); NS_ENSURE_SUCCESS(rv, rv); // set up variables for handling the property values to be returned nsCOMPtr<nsISupportsArray> propertyValues; nsCOMPtr<nsIAbDirectoryQueryPropertyValue> propertyValue; rv = NS_NewISupportsArray(getter_AddRefs(propertyValues)); NS_ENSURE_SUCCESS(rv, rv); if (!strcmp(properties[0], "card:nsIAbCard")) { // Meta property nsCAutoString dn; rv = aMessage->GetDn (dn); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIAbCard> card; rv = mDirectoryQuery->CreateCard (mUrl, dn.get(), getter_AddRefs (card)); NS_ENSURE_SUCCESS(rv, rv); rv = map->SetCardPropertiesFromLDAPMessage(aMessage, card); NS_ENSURE_SUCCESS(rv, rv); propertyValue = new nsAbDirectoryQueryPropertyValue(properties[0], card); if (!propertyValue) return NS_ERROR_OUT_OF_MEMORY; rv = propertyValues->AppendElement(propertyValue); NS_ENSURE_SUCCESS(rv, rv); } else { for (PRUint32 i = 0; i < properties.GetSize(); i++) { // this is the precedence order list of attrs for this property CharPtrArrayGuard attrs; rv = map->GetAttributes(nsDependentCString(properties[i]), attrs.GetSizeAddr(), attrs.GetArrayAddr()); // if there are no attrs for this property, just move on if (NS_FAILED(rv) || !strlen(attrs[0])) { continue; } // iterate through list, until first property found for (PRUint32 j=0; j < attrs.GetSize(); j++) { // try and get the values for this ldap attribute PRUnicharPtrArrayGuard vals; rv = aMessage->GetValues(attrs[j], vals.GetSizeAddr(), vals.GetArrayAddr()); if (NS_SUCCEEDED(rv) && vals.GetSize()) { propertyValue = new nsAbDirectoryQueryPropertyValue( properties[i], vals[0]); if (!propertyValue) { return NS_ERROR_OUT_OF_MEMORY; } (void)propertyValues->AppendElement (propertyValue); break; } } } } return QueryResultStatus (propertyValues, result, nsIAbDirectoryQueryResult::queryResultMatch); }