diff options
Diffstat (limited to 'mailnews/addrbook/src/nsAbLDAPDirectoryModify.cpp')
-rw-r--r-- | mailnews/addrbook/src/nsAbLDAPDirectoryModify.cpp | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbLDAPDirectoryModify.cpp b/mailnews/addrbook/src/nsAbLDAPDirectoryModify.cpp new file mode 100644 index 000000000..95af79c04 --- /dev/null +++ b/mailnews/addrbook/src/nsAbLDAPDirectoryModify.cpp @@ -0,0 +1,372 @@ +/* -*- 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 "nsAbLDAPDirectoryModify.h" +#include "nsILDAPMessage.h" +#include "nsILDAPConnection.h" +#include "nsILDAPErrors.h" +#include "nsILDAPModification.h" +#include "nsIServiceManager.h" +#include "nsIAbLDAPDirectory.h" +#include "nsIMutableArray.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" + +#include <stdio.h> + +using namespace mozilla; + +class nsAbModifyLDAPMessageListener : public nsAbLDAPListenerBase +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + nsAbModifyLDAPMessageListener(const int32_t type, + const nsACString &cardDN, + nsIArray* modArray, + const nsACString &newRDN, + const nsACString &newBaseDN, + nsILDAPURL* directoryUrl, + nsILDAPConnection* connection, + nsIMutableArray* serverSearchControls, + nsIMutableArray* clientSearchControls, + const nsACString &login, + const int32_t timeOut = 0); + // nsILDAPMessageListener + NS_IMETHOD OnLDAPMessage(nsILDAPMessage *aMessage) override; + +protected: + virtual ~nsAbModifyLDAPMessageListener(); + + nsresult Cancel(); + virtual void InitFailed(bool aCancelled = false) override; + virtual nsresult DoTask() override; + nsresult DoMainTask(); + nsresult OnLDAPMessageModifyResult(nsILDAPMessage *aMessage); + nsresult OnLDAPMessageRenameResult(nsILDAPMessage *aMessage); + + int32_t mType; + nsCString mCardDN; + nsCOMPtr<nsIArray> mModification; + nsCString mNewRDN; + nsCString mNewBaseDN; + + bool mFinished; + bool mCanceled; + bool mFlagRename; + + nsCOMPtr<nsILDAPOperation> mModifyOperation; + nsCOMPtr<nsIMutableArray> mServerSearchControls; + nsCOMPtr<nsIMutableArray> mClientSearchControls; +}; + + +NS_IMPL_ISUPPORTS(nsAbModifyLDAPMessageListener, nsILDAPMessageListener) + +nsAbModifyLDAPMessageListener::nsAbModifyLDAPMessageListener( + const int32_t type, + const nsACString &cardDN, + nsIArray* modArray, + const nsACString &newRDN, + const nsACString &newBaseDN, + nsILDAPURL* directoryUrl, + nsILDAPConnection* connection, + nsIMutableArray* serverSearchControls, + nsIMutableArray* clientSearchControls, + const nsACString &login, + const int32_t timeOut) : + nsAbLDAPListenerBase(directoryUrl, connection, login, timeOut), + mType(type), + mCardDN(cardDN), + mModification(modArray), + mNewRDN(newRDN), + mNewBaseDN(newBaseDN), + mFinished(false), + mCanceled(false), + mFlagRename(false), + mServerSearchControls(serverSearchControls), + mClientSearchControls(clientSearchControls) +{ + if (mType == nsILDAPModification::MOD_REPLACE && + !mNewRDN.IsEmpty() && !mNewBaseDN.IsEmpty()) + mFlagRename = true; +} + +nsAbModifyLDAPMessageListener::~nsAbModifyLDAPMessageListener () +{ +} + +nsresult nsAbModifyLDAPMessageListener::Cancel () +{ + nsresult rv = Initiate(); + NS_ENSURE_SUCCESS(rv, rv); + + MutexAutoLock lock(mLock); + + if (mFinished || mCanceled) + return NS_OK; + + mCanceled = true; + + return NS_OK; +} + +NS_IMETHODIMP nsAbModifyLDAPMessageListener::OnLDAPMessage(nsILDAPMessage *aMessage) +{ + nsresult rv = Initiate(); + NS_ENSURE_SUCCESS(rv, rv); + + int32_t messageType; + rv = aMessage->GetType(&messageType); + NS_ENSURE_SUCCESS(rv, rv); + + bool cancelOperation = false; + + // Enter lock + { + MutexAutoLock lock (mLock); + + if (mFinished) + return NS_OK; + + // for these messages, no matter the outcome, we're done + if ((messageType == nsILDAPMessage::RES_ADD) || + (messageType == nsILDAPMessage::RES_DELETE) || + (messageType == nsILDAPMessage::RES_MODIFY)) + mFinished = true; + else if (mCanceled) + { + mFinished = true; + cancelOperation = true; + } + } + // Leave lock + + // nsCOMPtr<nsIAbDirectoryQueryResult> queryResult; + if (!cancelOperation) + { + switch (messageType) + { + case nsILDAPMessage::RES_BIND: + rv = OnLDAPMessageBind(aMessage); + if (NS_FAILED(rv)) + // We know the bind failed and hence the message has an error, so we + // can just call ModifyResult with the message and that'll sort it out + // for us. + rv = OnLDAPMessageModifyResult(aMessage); + break; + case nsILDAPMessage::RES_ADD: + case nsILDAPMessage::RES_MODIFY: + case nsILDAPMessage::RES_DELETE: + rv = OnLDAPMessageModifyResult(aMessage); + break; + case nsILDAPMessage::RES_MODDN: + mFlagRename = false; + rv = OnLDAPMessageRenameResult(aMessage); + if (NS_FAILED(rv)) + // Rename failed, so we stop here + mFinished = true; + break; + default: + break; + } + } + else + { + if (mModifyOperation) + rv = mModifyOperation->AbandonExt(); + + // reset because we might re-use this listener...except don't do this + // until the search is done, so we'll ignore results from a previous + // search. + mCanceled = mFinished = false; + } + + return rv; +} + +void nsAbModifyLDAPMessageListener::InitFailed(bool aCancelled) +{ + // XXX Just cancel the operation for now + // we'll need to review this when we've got the proper listeners in place. + Cancel(); +} + +nsresult nsAbModifyLDAPMessageListener::DoTask() +{ + nsresult rv; + mCanceled = mFinished = false; + + mModifyOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mModifyOperation->Init (mConnection, this, nullptr); + NS_ENSURE_SUCCESS(rv, rv); + + // XXX do we need the search controls? + rv = mModifyOperation->SetServerControls(mServerSearchControls); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mModifyOperation->SetClientControls(mClientSearchControls); + NS_ENSURE_SUCCESS(rv, rv); + + if (mFlagRename) + return mModifyOperation->Rename(mCardDN, mNewRDN, mNewBaseDN, true); + + switch (mType) + { + case nsILDAPModification::MOD_ADD: + return mModifyOperation->AddExt(mCardDN, mModification); + case nsILDAPModification::MOD_DELETE: + return mModifyOperation->DeleteExt(mCardDN); + case nsILDAPModification::MOD_REPLACE: + return mModifyOperation->ModifyExt(mCardDN, mModification); + default: + NS_ERROR("Bad LDAP modification requested"); + return NS_ERROR_UNEXPECTED; + } +} + +nsresult nsAbModifyLDAPMessageListener::OnLDAPMessageModifyResult(nsILDAPMessage *aMessage) +{ + nsresult rv; + NS_ENSURE_ARG_POINTER(aMessage); + + int32_t errCode; + rv = aMessage->GetErrorCode(&errCode); + NS_ENSURE_SUCCESS(rv, rv); + + if (errCode != nsILDAPErrors::SUCCESS) + { + nsAutoCString errMessage; + rv = aMessage->GetErrorMessage(errMessage); + NS_ENSURE_SUCCESS(rv, rv); + + printf("LDAP modification failed (code: %i, message: %s)\n", + errCode, errMessage.get()); + return NS_ERROR_FAILURE; + } + + printf("LDAP modification succeeded\n"); + return NS_OK; +} + +nsresult nsAbModifyLDAPMessageListener::OnLDAPMessageRenameResult(nsILDAPMessage *aMessage) +{ + nsresult rv; + NS_ENSURE_ARG_POINTER(aMessage); + + int32_t errCode; + rv = aMessage->GetErrorCode(&errCode); + NS_ENSURE_SUCCESS(rv, rv); + + if (errCode != nsILDAPErrors::SUCCESS) + { + nsAutoCString errMessage; + rv = aMessage->GetErrorMessage(errMessage); + NS_ENSURE_SUCCESS(rv, rv); + + printf("LDAP rename failed (code: %i, message: %s)\n", + errCode, errMessage.get()); + return NS_ERROR_FAILURE; + } + + // Rename succeeded, now update the card DN and + // process the main task + mCardDN.Assign(mNewRDN); + mCardDN.AppendLiteral(","); + mCardDN.Append(mNewBaseDN); + + printf("LDAP rename succeeded\n"); + return DoTask(); +} + +nsAbLDAPDirectoryModify::nsAbLDAPDirectoryModify() +{ +} + +nsAbLDAPDirectoryModify::~nsAbLDAPDirectoryModify() +{ +} + +nsresult nsAbLDAPDirectoryModify::DoModify(nsIAbLDAPDirectory *directory, + const int32_t &updateType, + const nsACString &cardDN, + nsIArray* modArray, + const nsACString &newRDN, + const nsACString &newBaseDN) +{ + NS_ENSURE_ARG_POINTER(directory); + // modArray may be null in the delete operation case. + if (!modArray && + (updateType == nsILDAPModification::MOD_ADD || + updateType == nsILDAPModification::MOD_REPLACE)) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + + // it's an error if we don't have a dn + if (cardDN.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr<nsILDAPURL> currentUrl; + rv = directory->GetLDAPURL(getter_AddRefs(currentUrl)); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the ldap connection + nsCOMPtr<nsILDAPConnection> ldapConnection = + do_CreateInstance(NS_LDAPCONNECTION_CONTRACTID, &rv); + + nsCOMPtr<nsIMutableArray> serverSearchControls; + rv = directory->GetSearchServerControls(getter_AddRefs(serverSearchControls)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMutableArray> clientSearchControls; + rv = directory->GetSearchClientControls(getter_AddRefs(clientSearchControls)); + NS_ENSURE_SUCCESS(rv, rv); + + /* + // XXX we need to fix how this all works - specifically, see the first patch + // on bug 124553 for how the query equivalent did this + // too soon? Do we need a new listener? + if (alreadyInitialized) + { + nsAbQueryLDAPMessageListener *msgListener = + NS_STATIC_CAST(nsAbQueryLDAPMessageListener *, + NS_STATIC_CAST(nsILDAPMessageListener *, mListener.get())); + if (msgListener) + { + msgListener->mUrl = url; + return msgListener->DoSearch(); + } + }*/ + + nsCString login; + rv = directory->GetAuthDn(login); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t protocolVersion; + rv = directory->GetProtocolVersion(&protocolVersion); + NS_ENSURE_SUCCESS(rv, rv); + + // Initiate LDAP message listener + nsAbModifyLDAPMessageListener* _messageListener = + new nsAbModifyLDAPMessageListener(updateType, cardDN, modArray, + newRDN, newBaseDN, + currentUrl, + ldapConnection, + serverSearchControls, + clientSearchControls, + login, + 0); + if (_messageListener == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + // Now lets initialize the LDAP connection properly. We'll kick + // off the bind operation in the callback function, |OnLDAPInit()|. + return ldapConnection->Init(currentUrl, login, + _messageListener, nullptr, protocolVersion); +} + |