diff options
Diffstat (limited to 'ldap/xpcom/src/nsLDAPSyncQuery.cpp')
-rw-r--r-- | ldap/xpcom/src/nsLDAPSyncQuery.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/ldap/xpcom/src/nsLDAPSyncQuery.cpp b/ldap/xpcom/src/nsLDAPSyncQuery.cpp new file mode 100644 index 0000000000..e1f70ee7fa --- /dev/null +++ b/ldap/xpcom/src/nsLDAPSyncQuery.cpp @@ -0,0 +1,386 @@ +/* -*- 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 "nsLDAPSyncQuery.h" +#include "nsIServiceManager.h" +#include "nsILDAPErrors.h" +#include "nsThreadUtils.h" +#include "nsILDAPMessage.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsMemory.h" + +// nsISupports Implementation + +NS_IMPL_ISUPPORTS(nsLDAPSyncQuery, nsILDAPSyncQuery, nsILDAPMessageListener) + +// Constructor +// +nsLDAPSyncQuery::nsLDAPSyncQuery() : + mFinished(false), // This is a control variable for event loop + mProtocolVersion(nsILDAPConnection::VERSION3) +{ +} + +// Destructor +// +nsLDAPSyncQuery::~nsLDAPSyncQuery() +{ +} + + +// Messages received are passed back via this function. +// void OnLDAPMessage (in nsILDAPMessage aMessage) +// +NS_IMETHODIMP +nsLDAPSyncQuery::OnLDAPMessage(nsILDAPMessage *aMessage) +{ + int32_t messageType; + + // just in case. + // + if (!aMessage) { + return NS_OK; + } + + // figure out what sort of message was returned + // + nsresult rv = aMessage->GetType(&messageType); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected " + "error in aMessage->GetType()"); + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + switch (messageType) { + + case nsILDAPMessage::RES_BIND: + + // a bind has completed + // + return OnLDAPBind(aMessage); + + case nsILDAPMessage::RES_SEARCH_ENTRY: + + // a search entry has been returned + // + return OnLDAPSearchEntry(aMessage); + + case nsILDAPMessage::RES_SEARCH_RESULT: + + // the search is finished; we're all done + // + return OnLDAPSearchResult(aMessage); + + default: + + // Given the LDAP operations nsLDAPSyncQuery uses, we should + // never get here. If we do get here in a release build, it's + // probably a bug, but maybe it's the LDAP server doing something + // weird. Might as well try and continue anyway. The session should + // eventually get reaped by the timeout code, if necessary. + // + NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected " + "LDAP message received"); + return NS_OK; + } +} + +// void onLDAPInit (in nsresult aStatus); +// +NS_IMETHODIMP +nsLDAPSyncQuery::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus) +{ + nsresult rv; // temp for xpcom return values + // create and initialize an LDAP operation (to be used for the bind) + // + mOperation = do_CreateInstance("@mozilla.org/network/ldap-operation;1", + &rv); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + // our OnLDAPMessage accepts all result callbacks + // + rv = mOperation->Init(mConnection, this, nullptr); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; // this should never happen + } + + // kick off a bind operation + // + rv = mOperation->SimpleBind(EmptyCString()); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +nsLDAPSyncQuery::OnLDAPBind(nsILDAPMessage *aMessage) +{ + + int32_t errCode; + + mOperation = nullptr; // done with bind op; make nsCOMPtr release it + + // get the status of the bind + // + nsresult rv = aMessage->GetErrorCode(&errCode); + if (NS_FAILED(rv)) { + + NS_ERROR("nsLDAPSyncQuery::OnLDAPBind(): couldn't get " + "error code from aMessage"); + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + + // check to be sure the bind succeeded + // + if (errCode != nsILDAPErrors::SUCCESS) { + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + // ok, we're starting a search + // + return StartLDAPSearch(); +} + +nsresult +nsLDAPSyncQuery::OnLDAPSearchEntry(nsILDAPMessage *aMessage) +{ + uint32_t attrCount; + char** attributes; + nsresult rv = aMessage->GetAttributes(&attrCount, &attributes); + if (NS_FAILED(rv)) + { + NS_WARNING("nsLDAPSyncQuery:OnLDAPSearchEntry(): " + "aMessage->GetAttributes() failed"); + FinishLDAPQuery(); + return rv; + } + + // Iterate through the attributes received in this message + for (uint32_t i = 0; i < attrCount; i++) + { + char16_t **vals; + uint32_t valueCount; + + // Get the values of this attribute. + // XXX better failure handling + rv = aMessage->GetValues(attributes[i], &valueCount, &vals); + if (NS_FAILED(rv)) + { + NS_WARNING("nsLDAPSyncQuery:OnLDAPSearchEntry(): " + "aMessage->GetValues() failed\n"); + FinishLDAPQuery(); + break; + } + + // Store all values of this attribute in the mResults. + for (uint32_t j = 0; j < valueCount; j++) { + mResults.Append(char16_t('\n')); + mResults.AppendASCII(attributes[i]); + mResults.Append(char16_t('=')); + mResults.Append(vals[j]); + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(valueCount, vals); + } + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(attrCount, attributes); + + return rv; +} + + +nsresult +nsLDAPSyncQuery::OnLDAPSearchResult(nsILDAPMessage *aMessage) +{ + // We are done with the LDAP search. + // Release the control variable for the eventloop and other members + // + FinishLDAPQuery(); + return NS_OK; +} + +nsresult +nsLDAPSyncQuery::StartLDAPSearch() +{ + nsresult rv; + // create and initialize an LDAP operation (to be used for the search + // + mOperation = + do_CreateInstance("@mozilla.org/network/ldap-operation;1", &rv); + + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't " + "create @mozilla.org/network/ldap-operation;1"); + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + // initialize the LDAP operation object + // + rv = mOperation->Init(mConnection, this, nullptr); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't " + "initialize LDAP operation"); + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + // get the search filter associated with the directory server url; + // + nsAutoCString urlFilter; + rv = mServerURL->GetFilter(urlFilter); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + // get the base dn to search + // + nsAutoCString dn; + rv = mServerURL->GetDn(dn); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + // and the scope + // + int32_t scope; + rv = mServerURL->GetScope(&scope); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + nsAutoCString attributes; + rv = mServerURL->GetAttributes(attributes); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; + } + + // time to kick off the search. + rv = mOperation->SearchExt(dn, scope, urlFilter, attributes, 0, 0); + + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +// void initConnection (); +// +nsresult nsLDAPSyncQuery::InitConnection() +{ + // Because mConnection->Init proxies back to the main thread, this + // better be the main thread. + NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_FAILURE); + nsresult rv; // temp for xpcom return values + // create an LDAP connection + // + mConnection = do_CreateInstance("@mozilla.org/network/ldap-connection;1", + &rv); + if (NS_FAILED(rv)) { + NS_ERROR("nsLDAPSyncQuery::InitConnection(): could " + "not create @mozilla.org/network/ldap-connection;1"); + FinishLDAPQuery(); + return NS_ERROR_FAILURE; + } + + // have we been properly initialized? + // + if (!mServerURL) { + NS_ERROR("nsLDAPSyncQuery::InitConnection(): mServerURL " + "is NULL"); + FinishLDAPQuery(); + return NS_ERROR_NOT_INITIALIZED; + } + rv = mConnection->Init(mServerURL, EmptyCString(), this, + nullptr, mProtocolVersion); + if (NS_FAILED(rv)) { + FinishLDAPQuery(); + return NS_ERROR_UNEXPECTED; // this should never happen + } + + return NS_OK; +} + +void +nsLDAPSyncQuery::FinishLDAPQuery() +{ + // We are done with the LDAP operation. + // Release the Control variable for the eventloop + // + mFinished = true; + + // Release member variables + // + mConnection = nullptr; + mOperation = nullptr; + mServerURL = nullptr; + +} + +/* wstring getQueryResults (in nsILDAPURL aServerURL, in unsigned long aVersion); */ +NS_IMETHODIMP nsLDAPSyncQuery::GetQueryResults(nsILDAPURL *aServerURL, + uint32_t aProtocolVersion, + char16_t **_retval) +{ + nsresult rv; + + if (!aServerURL) { + NS_ERROR("nsLDAPSyncQuery::GetQueryResults() called without LDAP URL"); + return NS_ERROR_FAILURE; + } + mServerURL = aServerURL; + mProtocolVersion = aProtocolVersion; + + nsCOMPtr<nsIThread> currentThread = do_GetCurrentThread(); + + // Start an LDAP query. + // InitConnection will bind to the ldap server and post a OnLDAPMessage + // event. This event will trigger a search and the whole operation will + // be carried out by chain of events + // + rv = InitConnection(); + if (NS_FAILED(rv)) + return rv; + + // We want this LDAP query to be synchronous while the XPCOM LDAP is + // async in nature. So this eventQueue handling will wait for the + // LDAP operation to be finished. + // mFinished controls the state of the LDAP opertion. + // It will be released in any case (success/failure) + + + // Run the event loop, + // mFinished is a control variable + // + while (!mFinished) + NS_ENSURE_STATE(NS_ProcessNextEvent(currentThread)); + + // Return results + // + if (!mResults.IsEmpty()) { + *_retval = ToNewUnicode(mResults); + if (!_retval) + rv = NS_ERROR_OUT_OF_MEMORY; + } + return rv; + +} |