diff options
Diffstat (limited to 'mailnews/addrbook/src/nsAbLDAPCard.cpp')
-rw-r--r-- | mailnews/addrbook/src/nsAbLDAPCard.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbLDAPCard.cpp b/mailnews/addrbook/src/nsAbLDAPCard.cpp new file mode 100644 index 000000000..6dcfdedbb --- /dev/null +++ b/mailnews/addrbook/src/nsAbLDAPCard.cpp @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsAbLDAPCard.h" +#include "nsIMutableArray.h" +#include "nsCOMPtr.h" +#include "nsILDAPModification.h" +#include "nsILDAPBERValue.h" +#include "nsILDAPMessage.h" +#include "nsIAbLDAPAttributeMap.h" +#include "nsServiceManagerUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsAbBaseCID.h" +#include "nsAbUtils.h" +#include "nsILDAPErrors.h" + +#include <stdio.h> + +#define kDNColumn "DN" + +nsAbLDAPCard::nsAbLDAPCard() +{ +} + +nsAbLDAPCard::~nsAbLDAPCard() +{ +} + +NS_IMPL_ISUPPORTS_INHERITED(nsAbLDAPCard, nsAbCardProperty, nsIAbLDAPCard) + +/* Retrieves the changes to the LDAP card and stores them in an LDAP + * update message. + * + * Calling this method changes the LDAP card, it updates the + * meta-properties (m_*) to reflect what the LDAP contents will be once + * the update has been performed. This allows you to do multiple (successful) + * consecutive edits on a card in a search result. If the meta-properties + * were not updated, incorrect assuptions would be made about what object + * classes to add, or what attributes to clear. + * + * XXX: We need to take care when integrating this code with the asynchronous + * update dialogs, as the current code in nsAbLDAPDirectory has a problem + * when an update fails: the modified card still gets stored and shown to + * the user instead of being discarded. There is one especially tricky case: + * when you do an update on a card which changes its DN, you have two + * operations (rename, then update the other attributes). If the rename + * operation succeeds and not the update of the attributes, you are + * "somewhere in between" the original card and the updated card. +*/ +NS_IMETHODIMP nsAbLDAPCard::GetLDAPMessageInfo( + nsIAbLDAPAttributeMap *aAttributeMap, + const uint32_t aClassCount, + const char **aClasses, + int32_t aType, + nsIArray **aLDAPAddMessageInfo) +{ + NS_ENSURE_ARG_POINTER(aAttributeMap); + NS_ENSURE_ARG_POINTER(aClasses); + NS_ENSURE_ARG_POINTER(aLDAPAddMessageInfo); + + nsresult rv; + nsCOMPtr<nsIMutableArray> modArray = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Add any missing object classes. We never remove any object + // classes: if an entry has additional object classes, it's probably + // for a good reason. + nsAutoCString oclass; + for (uint32_t i = 0; i < aClassCount; ++i) + { + oclass.Assign(nsDependentCString(aClasses[i])); + ToLowerCase(oclass); + + if (!m_objectClass.Contains(oclass)) + { + m_objectClass.AppendElement(oclass); + printf("LDAP : adding objectClass %s\n", oclass.get()); + } + } + + nsCOMPtr<nsILDAPModification> mod = + do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMutableArray> values = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + for (uint32_t i = 0; i < m_objectClass.Length(); ++i) + { + nsCOMPtr<nsILDAPBERValue> value = + do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = value->SetFromUTF8(m_objectClass.ElementAt(i)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = values->AppendElement(value, false); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = mod->SetUpModification(aType, NS_LITERAL_CSTRING("objectClass"), values); + NS_ENSURE_SUCCESS(rv, rv); + + modArray->AppendElement(mod, false); + + // Add card properties + CharPtrArrayGuard props; + rv = aAttributeMap->GetAllCardProperties(props.GetSizeAddr(), + props.GetArrayAddr()); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString attr; + nsCString propvalue; + for (uint32_t i = 0; i < props.GetSize(); ++i) + { + // Skip some attributes that don't map to LDAP. + // + // BirthYear : by default this is mapped to 'birthyear', + // which is not part of mozillaAbPersonAlpha + // + // LastModifiedDate : by default this is mapped to 'modifytimestamp', + // which cannot be modified + // + // PreferMailFormat : by default this is mapped to 'mozillaUseHtmlMail', + // which is a boolean, not plaintext/html/unknown + if (!strcmp(props[i], kBirthYearProperty) || + !strcmp(props[i], kLastModifiedDateProperty) || + !strcmp(props[i], kPreferMailFormatProperty)) + continue; + + rv = aAttributeMap->GetFirstAttribute(nsDependentCString(props[i]), + attr); + NS_ENSURE_SUCCESS(rv, rv); + ToLowerCase(attr); + + // If the property is not mapped to an attribute, skip it. + if (attr.IsEmpty()) + continue; + + nsCOMPtr<nsILDAPModification> mod = + do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + size_t index = m_attributes.IndexOf(attr); + + rv = GetPropertyAsAUTF8String(props[i], propvalue); + + if (NS_SUCCEEDED(rv) &&!propvalue.IsEmpty()) + { + // If the new value is not empty, add/update it + nsCOMPtr<nsILDAPBERValue> value = + do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = value->SetFromUTF8(propvalue); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mod->SetUpModificationOneValue(aType, attr, value); + NS_ENSURE_SUCCESS(rv, rv); + + printf("LDAP : setting attribute %s (%s) to '%s'\n", attr.get(), + props[i], propvalue.get()); + modArray->AppendElement(mod, false); + if (index != m_attributes.NoIndex) + m_attributes.AppendElement(attr); + + } + else if (aType == nsILDAPModification::MOD_REPLACE && + index != m_attributes.NoIndex) + { + // If the new value is empty, we are performing an update + // and the attribute was previously set, clear it + nsCOMPtr<nsIMutableArray> novalues = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mod->SetUpModification(aType, attr, novalues); + NS_ENSURE_SUCCESS(rv, rv); + + printf("LDAP : removing attribute %s (%s)\n", attr.get(), props[i]); + modArray->AppendElement(mod, false); + m_attributes.RemoveElementAt(index); + } + } + + NS_ADDREF(*aLDAPAddMessageInfo = modArray); + + return NS_OK; +} + +NS_IMETHODIMP nsAbLDAPCard::BuildRdn(nsIAbLDAPAttributeMap *aAttributeMap, + const uint32_t aAttrCount, + const char **aAttributes, + nsACString &aRdn) +{ + NS_ENSURE_ARG_POINTER(aAttributeMap); + NS_ENSURE_ARG_POINTER(aAttributes); + + nsresult rv; + nsCString attr; + nsAutoCString prop; + nsCString propvalue; + + aRdn.Truncate(); + for (uint32_t i = 0; i < aAttrCount; ++i) + { + attr.Assign(nsDependentCString(aAttributes[i])); + + // Lookup the property corresponding to the attribute + rv = aAttributeMap->GetProperty(attr, prop); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the property value + rv = GetPropertyAsAUTF8String(prop.get(), propvalue); + + // XXX The case where an attribute needed to build the Relative + // Distinguished Name is not set needs to be handled by the caller, + // so as to let the user know what is missing. + if (NS_FAILED(rv) || propvalue.IsEmpty()) + { + NS_ERROR("nsAbLDAPCard::BuildRdn: a required attribute is not set"); + return NS_ERROR_NOT_INITIALIZED; + } + + aRdn.Append(attr); + aRdn.AppendLiteral("="); + aRdn.Append(propvalue); + if (i < aAttrCount - 1) + aRdn.AppendLiteral("+"); + } + return NS_OK; +} + +NS_IMETHODIMP nsAbLDAPCard::GetDn(nsACString &aDN) +{ + return GetPropertyAsAUTF8String(kDNColumn, aDN); +} + +NS_IMETHODIMP nsAbLDAPCard::SetDn(const nsACString &aDN) +{ + SetLocalId(aDN); + return SetPropertyAsAUTF8String(kDNColumn, aDN); +} + +NS_IMETHODIMP nsAbLDAPCard::SetMetaProperties(nsILDAPMessage *aMessage) +{ + NS_ENSURE_ARG_POINTER(aMessage); + + // Get DN + nsAutoCString dn; + nsresult rv = aMessage->GetDn(dn); + NS_ENSURE_SUCCESS(rv, rv); + + SetDn(dn); + + // Get the list of set attributes + CharPtrArrayGuard attrs; + rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr()); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString attr; + m_attributes.Clear(); + for (uint32_t i = 0; i < attrs.GetSize(); ++i) + { + attr.Assign(nsDependentCString(attrs[i])); + ToLowerCase(attr); + m_attributes.AppendElement(attr); + } + + // Get the objectClass values + m_objectClass.Clear(); + PRUnicharPtrArrayGuard vals; + rv = aMessage->GetValues("objectClass", vals.GetSizeAddr(), + vals.GetArrayAddr()); + + // objectClass is not always included in search result entries and + // nsILDAPMessage::GetValues returns NS_ERROR_LDAP_DECODING_ERROR if the + // requested attribute doesn't exist. + if (rv == NS_ERROR_LDAP_DECODING_ERROR) + return NS_OK; + + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString oclass; + for (uint32_t i = 0; i < vals.GetSize(); ++i) + { + oclass.Assign(NS_LossyConvertUTF16toASCII(nsDependentString(vals[i]))); + ToLowerCase(oclass); + m_objectClass.AppendElement(oclass); + } + + return NS_OK; +} |