diff --git a/directory/xpcom/TODO.txt b/directory/xpcom/TODO.txt index d46888e30ebc..8b5aa232ebd2 100644 --- a/directory/xpcom/TODO.txt +++ b/directory/xpcom/TODO.txt @@ -1,10 +1,5 @@ implementation -------------- - -* finish XPCOMifying nsLDAP{Message,Connection,Operation} in order to allow - XPCOM proxies to be used for thread-crossing operations (side benefit: also - exposes more LDAPy goodness to JS) (in progres: dmose) - * make AsyncRead actually be asynchronous (and probably cause ldapSearch.cpp to be split and moved) by factoring out the lowlevel stuff into another thread (in progress: dmose) @@ -77,6 +72,20 @@ housecleaning * investigate the MOZILLA_CLIENT define as used by the SDK. eg do we still want the reference to "xp_sort.h"? +* does NS_ENSURE_* provide adequate error-checking at interface boundaries + for JS in non-debug builds? + +* does always using this-> for member vars cause inheritance problems? if so, + does it matter in an XPCOM world? + +* shouldn't be casting results of nsILDAPConnection::GetErrorString to void + in ldapSearch + +* finish XPCOMifying nsLDAP{Message,Connection,Operation} and check + thread-safety in order to allow XPCOM proxies to be used for + thread-crossing operations (side benefit: also exposes more LDAPy + goodness to JS) + features -------- diff --git a/directory/xpcom/base/public/MANIFEST_IDL b/directory/xpcom/base/public/MANIFEST_IDL index dfb39a457320..ab2ec53de24d 100644 --- a/directory/xpcom/base/public/MANIFEST_IDL +++ b/directory/xpcom/base/public/MANIFEST_IDL @@ -1,3 +1,4 @@ nsILDAPURI.idl nsILDAPConnection.idl - +nsILDAPOperation.idl +nsILDAPMessage.idl diff --git a/directory/xpcom/base/public/Makefile.in b/directory/xpcom/base/public/Makefile.in index 8080c1765b77..0685994f0504 100644 --- a/directory/xpcom/base/public/Makefile.in +++ b/directory/xpcom/base/public/Makefile.in @@ -42,6 +42,8 @@ MODULE = mozldap XPIDL_MODULE = mozldap XPIDLSRCS = nsILDAPConnection.idl \ + nsILDAPOperation.idl \ + nsILDAPMessage.idl \ nsILDAPURI.idl \ $(NULL) diff --git a/directory/xpcom/base/public/nsILDAPConnection.idl b/directory/xpcom/base/public/nsILDAPConnection.idl index ff4e36069acb..8a408ee9ecb5 100644 --- a/directory/xpcom/base/public/nsILDAPConnection.idl +++ b/directory/xpcom/base/public/nsILDAPConnection.idl @@ -33,6 +33,14 @@ #include "nsISupports.idl" +// for the ldapPtr typedef +// +%{C++ +#include "ldap.h" +%} + +[ptr] native ldapConnectionHandle(LDAP); + [scriptable, uuid(337ad2fe-1dd2-11b2-89f8-aae1221ec86c)] interface nsILDAPConnection : nsISupports { @@ -43,6 +51,11 @@ interface nsILDAPConnection : nsISupports void Init(in string defhost, in short defport); // wrapper for ldap_get_lderrno() - short GetLdErrno(out string matched, out string s); + long GetLdErrno(out string matched, out string s); + + // really only for the internal use of nsLDAPOperation and friends + // + [noscript] readonly attribute ldapConnectionHandle connectionHandle; + }; diff --git a/directory/xpcom/base/public/nsILDAPMessage.idl b/directory/xpcom/base/public/nsILDAPMessage.idl new file mode 100644 index 000000000000..2d5bcb29ad63 --- /dev/null +++ b/directory/xpcom/base/public/nsILDAPMessage.idl @@ -0,0 +1,79 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the mozilla.org LDAP XPCOM component. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Dan Mosedale + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nsISupports.idl" +#include "nsILDAPOperation.idl" + +// for the ldapMsgHandle typedef +// +%{C++ +#include "ldap.h" +%} + +[ptr] native ldapMsgHandle(LDAPMessage); + +[scriptable, uuid(973ff50f-2002-4f0c-b57d-2242156139a2)] +interface nsILDAPMessage : nsISupports +{ + // initialize an operation + // + [noscript] void Init(in nsILDAPOperation operation, + in ldapMsgHandle msgHandle); + + // wrapper for ldap_get_dn + // + // XXX - currently must use ldap_mem_free to free + // + readonly attribute string DN; + + // wrappers for ldap_{first,next}_attribute + // + // XXX - currently must use ldap_mem_free to free the results + // + string firstAttribute(); + string nextAttribute(); + + // wrapper for ldap_get_values + // + // XXX - values must be freed with ldap_value_free + // + void GetValues(in string attr, out unsigned long count, + [retval, array, size_is(count)] out string values); + + + // turn an error condition associated with this message into an LDAP + // errcode (wrapper around ldap_parse_result) + // + long GetErrorCode(); + +}; diff --git a/directory/xpcom/base/public/nsILDAPOperation.idl b/directory/xpcom/base/public/nsILDAPOperation.idl new file mode 100644 index 000000000000..3405247282d4 --- /dev/null +++ b/directory/xpcom/base/public/nsILDAPOperation.idl @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the mozilla.org LDAP XPCOM component. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Dan Mosedale + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nsISupports.idl" +#include "nsILDAPConnection.idl" + +interface nsILDAPMessage; + +[scriptable, uuid(fd3d413b-14b0-49c4-8348-a4fc0edba9ff)] +interface nsILDAPOperation : nsISupports +{ + // the connection this operation is on + // + attribute nsILDAPConnection connection; + + // wrapper for ldap_simple_bind() + // + void SimpleBind(in string binddn, in string passwd); + + // wrapper for ldap_search_url() + // + void URLSearch(in string url, in boolean attrsonly); + + // wrapper for ldap_result() + // XXX - timeout currently ignored + // XXX - should add consts for all param + // + long Result(in long all, in PRTime timeout, out nsILDAPMessage message); +}; diff --git a/directory/xpcom/base/src/ldapSearch.cpp b/directory/xpcom/base/src/ldapSearch.cpp index a1728815a849..502681223c4c 100644 --- a/directory/xpcom/base/src/ldapSearch.cpp +++ b/directory/xpcom/base/src/ldapSearch.cpp @@ -34,40 +34,53 @@ #include #include #include +#include "nspr.h" #include "ldap.h" -#include "nsLDAPConnection.h" -#include "nsLDAPOperation.h" -#include "nsLDAPMessage.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsILDAPConnection.h" +#include "nsILDAPOperation.h" +#include "nsILDAPMessage.h" #include "nsLDAPChannel.h" -void +NS_METHOD lds(class nsLDAPChannel *chan, const char *url) { - class nsLDAPConnection *myConnection; - class nsLDAPMessage *myMessage; - class nsLDAPOperation *myOperation; - struct timeval nullTimeval = {0,0}; - // struct timeval timeout = {10,0}; - int returnCode; - char *errString; - PRInt16 lden; + nsCOMPtr myConnection; + nsCOMPtr myMessage; + nsCOMPtr myOperation; + int returnCode; + char *errString; + PRInt32 lden; + nsresult rv; - myConnection = new nsLDAPConnection(); - if ( !myConnection->Init("nsdirectory.netscape.com", LDAP_PORT) ) { - fprintf(stderr, "main: nsLDAPConnection::Init failed\n"); - exit(-1); - } - myOperation = new nsLDAPOperation(myConnection); + // create an LDAP connection + // + myConnection = do_CreateInstance("mozilla.network.ldapconnection", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // initialize it with the defaults + // XXX should return reasonable err msg, not assert + // + rv = myConnection->Init("nsdirectory.netscape.com", LDAP_PORT); + NS_ENSURE_SUCCESS(rv, rv); + + // create and initialize an LDAP operation on the new connection + // + myOperation = do_CreateInstance("mozilla.network.ldapoperation", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = myOperation->SetConnection(myConnection); + NS_ENSURE_SUCCESS(rv, rv); #ifdef NO_URL_SEARCH fprintf(stderr, "starting bind\n"); - fflush(stderr); if ( !myOperation->SimpleBind(NULL, NULL) ) { (void)myConnection->GetErrorString(&errString); fprintf(stderr, "ldap_simple_bind: %s\n", errString); - exit(-1); + return NS_ERROR_FAILURE; } fprintf(stderr, "waiting for bind to complete"); @@ -92,154 +105,170 @@ lds(class nsLDAPChannel *chan, const char *url) "myOperation->Result() [myOperation->SimpleBind]: %s: errno=%d\n", errString, errno); ldap_memfree(errString); - exit(-1); + return NS_ERROR_FAILURE; break; default: fprintf(stderr, "\nmyOperation->Result() returned unexpected value: %d", returnCode); - exit(-1); + return NS_ERROR_FAILURE; } fprintf(stderr, "bound\n"); - delete myMessage; - delete myOperation; - #endif - // start search - - fprintf(stderr, "starting search\n"); - fflush(stderr); - myOperation = new nsLDAPOperation(myConnection); + // start search + // + PR_fprintf(PR_STDERR, "starting search\n"); - // XXX what about timeouts? - // - returnCode = myOperation->URLSearch(url, 0); - if (returnCode == -1) { - exit(-1); - } + myOperation = do_CreateInstance("mozilla.network.ldapoperation", &rv); + NS_ENSURE_SUCCESS(rv, rv); - // poll for results - // - fprintf(stderr, "polling search operation"); - returnCode = LDAP_SUCCESS; - while ( returnCode != LDAP_RES_SEARCH_RESULT ) { + rv = myOperation->SetConnection(myConnection); + NS_ENSURE_SUCCESS(rv, rv); - char *dn, *attr; - int rc2; + // XXX what about timeouts? + // XXX failure is a reasonable thing; don't assert + // + rv = myOperation->URLSearch(url, PR_FALSE); + NS_ENSURE_SUCCESS(rv,rv); - fputc('.', stderr); + // poll for results + // + fprintf(stderr, "polling search operation"); + returnCode = LDAP_SUCCESS; + while ( returnCode != LDAP_RES_SEARCH_RESULT ) { - myMessage = new nsLDAPMessage(myOperation); - returnCode = myOperation->Result(LDAP_MSG_ONE, &nullTimeval, - myMessage); + char *dn, *attr; + int rc2; - switch (returnCode) { - case -1: // something went wrong - (void)myConnection->GetErrorString(&errString); - fprintf(stderr, - "\nmyOperation->Result() [URLSearch]: %s: errno=%d\n", - errString, errno); - ldap_memfree(errString); - exit(-1); - case 0: // nothing's been returned yet - break; + fputc('.', stderr); - case LDAP_RES_SEARCH_ENTRY: - fprintf(stderr, "\nentry returned!\n"); + // XXX is 0 the right value? + // + rv = myOperation->Result(LDAP_MSG_ONE, (PRTime)0, + getter_AddRefs(myMessage), &returnCode); - // get the DN - dn = myMessage->GetDN(); - if (!dn) { - (void)myConnection->GetErrorString(&errString); - fprintf(stderr, "myMessage->GetDN(): %s\n", errString); - - exit(-1); - } - chan->pipeWrite("dn: "); - chan->pipeWrite(dn); - chan->pipeWrite("\n"); + switch (returnCode) { + case -1: // something went wrong + (void)myConnection->GetErrorString(&errString); + fprintf(stderr, + "\nmyOperation->Result() [URLSearch]: %s: errno=%d\n", + errString, errno); + ldap_memfree(errString); + return NS_ERROR_FAILURE; + case 0: // nothing's been returned yet + break; - ldap_memfree(dn); + case LDAP_RES_SEARCH_ENTRY: + fprintf(stderr, "\nentry returned!\n"); - // fetch the attributesget the first attribute - for (attr = myMessage->FirstAttribute(); - attr != NULL; - attr = myMessage->NextAttribute()) { + // get the DN + // XXX better err handling + // + rv = myMessage->GetDN(&dn); + NS_ENSURE_SUCCESS(rv, rv); - int i; - char **vals; + chan->pipeWrite("dn: "); + chan->pipeWrite(dn); + chan->pipeWrite("\n"); - // get the values of this attribute - vals = myMessage->GetValues(attr); - if (vals == NULL) { - (void)myConnection->GetErrorString(&errString); - fprintf(stderr, "myMessage->GetValues: %s\n", errString); + ldap_memfree(dn); - exit(-1); - } + // fetch the attributes + for (rv = myMessage->FirstAttribute(&attr); + attr != NULL; + rv = myMessage->NextAttribute(&attr)) { - // print all values of this attribute - for ( i=0 ; vals[i] != NULL; i++ ) { - chan->pipeWrite(attr); - chan->pipeWrite(": "); - chan->pipeWrite(vals[i]); - chan->pipeWrite("\n"); - } + if ( NS_FAILED(rv) ) { + PR_fprintf(PR_STDERR, "failure getting attribute\n"); + return rv; + } - ldap_value_free(vals); - ldap_memfree(attr); - } + int i; + char **vals; + PRUint32 attrCount; + + // get the values of this attribute + // XXX better failure handling + // + rv = myMessage->GetValues(attr, &attrCount, &vals); + if (NS_FAILED(rv)) { + (void)myConnection->GetErrorString(&errString); + PR_fprintf(PR_STDERR, "myMessage->GetValues: %s\n", + errString); + return rv;; + } + + // print all values of this attribute + for ( i=0 ; vals[i] != NULL; i++ ) { + chan->pipeWrite(attr); + chan->pipeWrite(": "); + chan->pipeWrite(vals[i]); + chan->pipeWrite("\n"); + } + + ldap_value_free(vals); + ldap_memfree(attr); + } - // did we reach this statement because of an error? - (void)myConnection->GetLdErrno(NULL, NULL, &lden); - if ( lden != LDAP_SUCCESS ) { + // did we reach this statement because of an error? + (void)myConnection->GetLdErrno(NULL, NULL, &lden); + if ( lden != LDAP_SUCCESS ) { - (void)myConnection->GetErrorString(&errString); - fprintf(stderr, "myMessage: error getting attribute: %s\n", - errString); + (void)myConnection->GetErrorString(&errString); + fprintf(stderr, "myMessage: error getting attribute: %s\n", + errString); + return NS_ERROR_FAILURE; + } - exit(-1); - } + // separate this entry from the next + chan->pipeWrite("\n"); - // separate this entry from the next - chan->pipeWrite("\n"); + // continue polling +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "polling search operation"); +#endif + break; - // continue polling - fprintf(stderr, "polling search operation"); - break; + case LDAP_RES_SEARCH_REFERENCE: // referral + fprintf(stderr, + "LDAP_RES_SEARCH_REFERENCE returned; not implemented!"); + return NS_ERROR_FAILURE; + break; - case LDAP_RES_SEARCH_REFERENCE: // referral - fprintf(stderr, - "LDAP_RES_SEARCH_REFERENCE returned; not implemented!"); - exit(-1); - break; + case LDAP_RES_SEARCH_RESULT: // all done (the while condition sees this) + fprintf(stderr, "\nresult returned: \n"); - case LDAP_RES_SEARCH_RESULT: // all done (the while condition sees this) - fprintf(stderr, "\nresult returned: \n"); - - rc2 = myMessage->GetErrorCode(); - if ( rc2 != LDAP_SUCCESS ) { - fprintf(stderr, " %s\n", - ldap_err2string(rc2)); - exit(-1); - } - fprintf(stderr, "success\n"); - break; + // XXX should use GetErrorString here? + // + rv = myMessage->GetErrorCode(&rc2); + if ( NS_FAILED(rv) ) { + PR_fprintf(PR_STDERR, " %s\n", ldap_err2string(rc2)); + return NS_ERROR_FAILURE; + } + PR_fprintf(PR_STDERR, "success\n"); + break; - default: - fprintf(stderr,"unexpected result returned"); - exit(-1); - break; - } + default: + PR_fprintf(PR_STDERR, "unexpected result returned"); + return NS_ERROR_FAILURE; + break; + } + myMessage = 0; - delete myMessage; + usleep(200); + } - usleep(200); - } +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR,"unbinding\n"); +#endif - fprintf(stderr,"unbinding\n"); - delete myConnection; - fprintf(stderr,"unbound\n"); + myConnection = 0; + +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR,"unbound\n"); +#endif + + return NS_OK; } diff --git a/directory/xpcom/base/src/nsLDAPChannel.cpp b/directory/xpcom/base/src/nsLDAPChannel.cpp index 999ecc7cb01f..f50fecab0ddf 100644 --- a/directory/xpcom/base/src/nsLDAPChannel.cpp +++ b/directory/xpcom/base/src/nsLDAPChannel.cpp @@ -45,7 +45,7 @@ static NS_DEFINE_CID(kLDAPServiceCID, NS_LDAPSERVICE_CID); #include "nspr.h" #endif -void lds(class nsLDAPChannel *chan, const char *); +NS_METHOD lds(class nsLDAPChannel *chan, const char *); NS_IMPL_ISUPPORTS2(nsLDAPChannel, nsIChannel, nsIRequest); diff --git a/directory/xpcom/base/src/nsLDAPConnection.cpp b/directory/xpcom/base/src/nsLDAPConnection.cpp index fedfa7c047fc..7d0ba11cc863 100644 --- a/directory/xpcom/base/src/nsLDAPConnection.cpp +++ b/directory/xpcom/base/src/nsLDAPConnection.cpp @@ -34,7 +34,7 @@ #include #include "nsLDAPConnection.h" -NS_IMPL_ISUPPORTS1(nsLDAPConnection, nsILDAPConnection); +NS_IMPL_THREADSAFE_ISUPPORTS1(nsLDAPConnection, nsILDAPConnection); // constructor // @@ -50,7 +50,7 @@ nsLDAPConnection::~nsLDAPConnection() { int rc; - rc = ldap_unbind_s(this->connectionHandle); + rc = ldap_unbind_s(this->mConnectionHandle); if (rc != LDAP_SUCCESS) { fprintf(stderr, "nsLDAPConnection::~nsLDAPConnection: %s\n", ldap_err2string(rc)); @@ -60,20 +60,26 @@ nsLDAPConnection::~nsLDAPConnection() // wrapper for ldap_init() // NS_IMETHODIMP -nsLDAPConnection::Init(const char *defhost, PRInt16 defport) +nsLDAPConnection::Init(const char *aDefHost, PRInt16 aDefPort) { - this->connectionHandle = ldap_init(defhost, defport); - return (this->connectionHandle == NULL ? NS_ERROR_FAILURE : NS_OK); + NS_ENSURE_ARG(aDefHost); + NS_ENSURE_ARG(aDefPort); + + this->mConnectionHandle = ldap_init(aDefHost, aDefPort); + return (this->mConnectionHandle == NULL ? NS_ERROR_FAILURE : NS_OK); } // wrapper for ldap_get_lderrno // NS_IMETHODIMP nsLDAPConnection::GetLdErrno(char **matched, char **errString, - PRInt16 *_retval) + PRInt32 *_retval) { - *_retval = ldap_get_lderrno(this->connectionHandle, matched, errString); - return NS_OK; + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = ldap_get_lderrno(this->mConnectionHandle, matched, errString); + + return NS_OK; } // return the error string corresponding to GetLdErrno. @@ -84,7 +90,23 @@ nsLDAPConnection::GetLdErrno(char **matched, char **errString, NS_IMETHODIMP nsLDAPConnection::GetErrorString(char **_retval) { - *_retval = ldap_err2string(ldap_get_lderrno(this->connectionHandle, - NULL, NULL)); - return NS_OK; + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = ldap_err2string(ldap_get_lderrno(this->mConnectionHandle, + NULL, NULL)); + return NS_OK; +} + +// really only for the internal use of nsLDAPOperation and friends +// +// [ptr] native ldapPtr(LDAP); +// [noscript] readonly attribute ldapPtr connection; +// +NS_IMETHODIMP +nsLDAPConnection::GetConnectionHandle(LDAP* *aConnectionHandle) +{ + NS_ENSURE_ARG_POINTER(aConnectionHandle); + + *aConnectionHandle = mConnectionHandle; + return NS_OK; } diff --git a/directory/xpcom/base/src/nsLDAPConnection.h b/directory/xpcom/base/src/nsLDAPConnection.h index 22b413099d69..bc1f9966b0c5 100644 --- a/directory/xpcom/base/src/nsLDAPConnection.h +++ b/directory/xpcom/base/src/nsLDAPConnection.h @@ -37,6 +37,12 @@ #include "nsILDAPConnection.h" #include "ldap.h" +// 0d871e30-1dd2-11b2-8ea9-831778c78e93 +// +#define NS_LDAPCONNECTION_CID \ +{ 0x0d871e30, 0x1dd2, 0x11b2, \ + { 0x8e, 0xa9, 0x83, 0x17, 0x78, 0xc7, 0x8e, 0x93 }} + class nsLDAPConnection : public nsILDAPConnection { friend class nsLDAPOperation; @@ -54,7 +60,7 @@ class nsLDAPConnection : public nsILDAPConnection { protected: // the LDAP SDK's struct for the connection - LDAP *connectionHandle; + LDAP *mConnectionHandle; }; diff --git a/directory/xpcom/base/src/nsLDAPMessage.cpp b/directory/xpcom/base/src/nsLDAPMessage.cpp index 8fc68385f8ec..93a17e4047a7 100644 --- a/directory/xpcom/base/src/nsLDAPMessage.cpp +++ b/directory/xpcom/base/src/nsLDAPMessage.cpp @@ -31,15 +31,24 @@ * GPL. */ -#include "nsLDAPMessage.h" #include +#include "nsLDAPMessage.h" + +#ifdef DEBUG +#include "nspr.h" +#endif + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsLDAPMessage, nsILDAPMessage); // constructor -nsLDAPMessage::nsLDAPMessage(class nsLDAPOperation *op) +// +nsLDAPMessage::nsLDAPMessage() { - this->operation = op; - this->message = NULL; - this->position = NULL; + NS_INIT_ISUPPORTS(); + + mMsgHandle = NULL; + mConnectionHandle = NULL; + mPosition = NULL; } // destructor @@ -47,66 +56,94 @@ nsLDAPMessage::nsLDAPMessage(class nsLDAPOperation *op) // nsLDAPMessage::~nsLDAPMessage(void) { - int rc; + int rc; - if (this->message != NULL) { - rc = ldap_msgfree(this->message); + if (mMsgHandle != NULL) { + rc = ldap_msgfree(mMsgHandle); - switch(rc) { - case LDAP_RES_BIND: - case LDAP_RES_SEARCH_ENTRY: - case LDAP_RES_SEARCH_RESULT: - case LDAP_RES_MODIFY: - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODRDN: - case LDAP_RES_COMPARE: - case LDAP_RES_SEARCH_REFERENCE: - case LDAP_RES_EXTENDED: - case LDAP_RES_ANY: - // success - break; - case LDAP_SUCCESS: - // timed out (dunno why LDAP_SUCESS is used to indicate this) - fprintf(stderr, - "nsLDAPMessage::~nsLDAPMessage: ldap_msgfree() timed out.\n"); - fflush(stderr); - break; - default: - // other failure - // XXX - might errno conceivably be useful here? - fprintf(stderr,"nsLDAPMessage::~nsLDAPMessage: ldap_msgfree: %s\n", - ldap_err2string(rc)); - fflush(stderr); - break; + switch(rc) { + case LDAP_RES_BIND: + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_RESULT: + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODRDN: + case LDAP_RES_COMPARE: + case LDAP_RES_SEARCH_REFERENCE: + case LDAP_RES_EXTENDED: + case LDAP_RES_ANY: + // success + break; + case LDAP_SUCCESS: + // timed out (dunno why LDAP_SUCCESS is used to indicate this) + fprintf(stderr, + "nsLDAPMessage::~nsLDAPMessage: ldap_msgfree() timed out.\n"); + break; + default: + // other failure + // XXX - might errno conceivably be useful here? + fprintf(stderr,"nsLDAPMessage::~nsLDAPMessage: ldap_msgfree: %s\n", + ldap_err2string(rc)); + break; + } } - } - if ( this->position != NULL ) { - ldap_ber_free(this->position, 0); - } + if ( mPosition != NULL ) { + ldap_ber_free(mPosition, 0); + } } +// associate this message with an existing operation +// +NS_IMETHODIMP +nsLDAPMessage::Init(nsILDAPOperation *aOperation, LDAPMessage *aMsgHandle) +{ + nsresult rv; + nsCOMPtr connection; + + NS_ENSURE_ARG_POINTER(aOperation); + NS_ENSURE_ARG_POINTER(aMsgHandle); + + // initialize the appropriate member vars + // + mOperation = aOperation; + mMsgHandle = aMsgHandle; + + // cache the connection handle associated with this operation + // + rv = mOperation->GetConnection(getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = connection->GetConnectionHandle(&mConnectionHandle); + NS_ENSURE_SUCCESS(rv,rv); + + return NS_OK; +} + // XXX - both this and GetErrorString should be based on a separately // broken out ldap_parse_result // -int -nsLDAPMessage::GetErrorCode(void) +NS_IMETHODIMP +nsLDAPMessage::GetErrorCode(PRInt32 *aErrCode) { - int errcode; - int rc; + PRInt32 rc; - rc = ldap_parse_result(this->operation->connection->connectionHandle, - this->message, &errcode, NULL, NULL, - NULL, NULL, 0); - if (rc != LDAP_SUCCESS) { - fprintf(stderr, "nsLDAPMessage::ErrorToString: ldap_parse_result: %s\n", - ldap_err2string(rc)); - exit(-1); - } + rc = ldap_parse_result(mConnectionHandle, mMsgHandle, aErrCode, + NULL, NULL, NULL, NULL, 0); - return(errcode); + if (rc != LDAP_SUCCESS) { + +#ifdef DEBUG + PR_fprintf(PR_STDERR, + "nsLDAPMessage::ErrorToString: ldap_parse_result: %s\n", + ldap_err2string(rc)); +#endif + return NS_ERROR_FAILURE; + } + + return NS_OK; } // XXX deal with extra params (make client not have to use ldap_memfree() on @@ -124,9 +161,8 @@ nsLDAPMessage::GetErrorString(void) int rc; - rc = ldap_parse_result(this->operation->connection->connectionHandle, - this->message, &errcode, &matcheddn, &errmsg, - &referrals, &serverctrls, 0); + rc = ldap_parse_result(mConnectionHandle, mMsgHandle, &errcode, &matcheddn, + &errmsg, &referrals, &serverctrls, 0); if (rc != LDAP_SUCCESS) { fprintf(stderr, "nsLDAPMessage::ErrorToString: ldap_parse_result: %s\n", ldap_err2string(rc)); @@ -143,20 +179,34 @@ nsLDAPMessage::GetErrorString(void) // wrapper for ldap_first_attribute // -char * -nsLDAPMessage::FirstAttribute(void) +NS_IMETHODIMP +nsLDAPMessage::FirstAttribute(char* *aAttribute) { - return ldap_first_attribute(this->operation->connection->connectionHandle, - this->message, &(this->position)); + NS_ENSURE_ARG_POINTER(aAttribute); + + *aAttribute = ldap_first_attribute(mConnectionHandle, mMsgHandle, + &mPosition); + if (*aAttribute) { + return NS_OK; + } else { + return NS_ERROR_FAILURE; + } } // wrapper for ldap_next_attribute() // -char * -nsLDAPMessage::NextAttribute(void) +NS_IMETHODIMP +nsLDAPMessage::NextAttribute(char* *aAttribute) { - return ldap_next_attribute(this->operation->connection->connectionHandle, - this->message, this->position); + NS_ENSURE_ARG_POINTER(aAttribute); + + *aAttribute = ldap_next_attribute(mConnectionHandle, mMsgHandle, + mPosition); + if (*aAttribute) { + return NS_OK; + } else { + return NS_ERROR_FAILURE; + } } // wrapper for ldap_msgtype() @@ -164,23 +214,50 @@ nsLDAPMessage::NextAttribute(void) int nsLDAPMessage::Type(void) { - return (ldap_msgtype(this->message)); + return (ldap_msgtype(mMsgHandle)); } // wrapper for ldap_get_dn // -char * -nsLDAPMessage::GetDN(void) +NS_IMETHODIMP +nsLDAPMessage::GetDN(char* *aDN) { - return ldap_get_dn(this->operation->connection->connectionHandle, - this->message); + NS_ENSURE_ARG_POINTER(aDN); + + *aDN = ldap_get_dn(mConnectionHandle, mMsgHandle); + + if (*aDN) { + return NS_OK; + } else { + return NS_ERROR_FAILURE; + } + } // wrapper for ldap_get_values() // -char ** -nsLDAPMessage::GetValues(const char *attr) +NS_IMETHODIMP +nsLDAPMessage::GetValues(const char *aAttr, PRUint32 *aCount, + char** *aValues) { - return ldap_get_values(this->operation->connection->connectionHandle, - this->message, attr); + PRUint32 i; + char **values; + + values = ldap_get_values(mConnectionHandle, mMsgHandle, aAttr); + + // bail out if there was a problem + // XXX - better err handling + // + if (!values) { + return NS_ERROR_FAILURE; + } + + // count the values + // + for ( i=0 ; values[i] != NULL; i++ ) { + } + + *aCount = i + 1; // include the NULL-terminator in our count + *aValues = values; + return NS_OK; } diff --git a/directory/xpcom/base/src/nsLDAPMessage.h b/directory/xpcom/base/src/nsLDAPMessage.h index 9c296556e09b..2d640c29daa8 100644 --- a/directory/xpcom/base/src/nsLDAPMessage.h +++ b/directory/xpcom/base/src/nsLDAPMessage.h @@ -35,45 +35,42 @@ #define _nsLDAPMessage_h_ #include "ldap.h" -#include "nsLDAPOperation.h" +#include "nsILDAPMessage.h" +#include "nsILDAPOperation.h" +#include "nsILDAPConnection.h" +#include "nsCOMPtr.h" -class nsLDAPMessage { - friend class nsLDAPOperation; +// 76e061ad-a59f-43b6-b812-ee6e8e69423f +// +#define NS_LDAPMESSAGE_CID \ +{ 0x76e061ad, 0xa59f, 0x43b6, \ + { 0xb8, 0x12, 0xee, 0x6e, 0x8e, 0x69, 0x42, 0x3f }} - public: +class nsLDAPMessage : public nsILDAPMessage +{ + friend class nsLDAPOperation; - // constructor - // - nsLDAPMessage(class nsLDAPOperation *op); + public: - // destructor - // - ~nsLDAPMessage(void); + NS_DECL_ISUPPORTS; + NS_DECL_NSILDAPMESSAGE; - // turn an error condition associated with this message into an LDAP - // errcode - int GetErrorCode(void); + // constructor & destructor + // + nsLDAPMessage(); + virtual ~nsLDAPMessage(); - // turn an error condition associated with this message into a string - char *GetErrorString(void); + // turn an error condition associated with this message into a string + char *GetErrorString(void); - // wrapper for ldap_msgtype() - int Type(void); + // wrapper for ldap_msgtype() + int Type(void); - // wrapper for ldap_get_dn() - char *GetDN(void); - - // wrapper for ldap_{first,next}_attribute() - char *FirstAttribute(void); - char *NextAttribute(void); - - // wrapper for ldap_get_values - char **GetValues(const char *attr); - - protected: - LDAPMessage *message; // the message we're wrapping - BerElement *position; // position in the associated attr list - class nsLDAPOperation *operation; // the connection this msg is related to + protected: + LDAPMessage *mMsgHandle; // the message we're wrapping + BerElement *mPosition; // position in the associated attr list + nsCOMPtr mOperation; // operation this msg relates to + LDAP *mConnectionHandle; // cached connection handle }; #endif /* _nsLDAPMessage_h */ diff --git a/directory/xpcom/base/src/nsLDAPOperation.cpp b/directory/xpcom/base/src/nsLDAPOperation.cpp index 1edb758d87c2..08b50b13957b 100644 --- a/directory/xpcom/base/src/nsLDAPOperation.cpp +++ b/directory/xpcom/base/src/nsLDAPOperation.cpp @@ -33,13 +33,15 @@ #include "ldap.h" #include "nsLDAPOperation.h" -#include "nsLDAPConnection.h" -#include "nsLDAPMessage.h" +#include "nsILDAPMessage.h" +#include "nsIComponentManager.h" + +struct timeval nsLDAPOperation::sNullTimeval = {0, 0}; // constructor -nsLDAPOperation::nsLDAPOperation(class nsLDAPConnection *c) +nsLDAPOperation::nsLDAPOperation() { - this->connection = c; + NS_INIT_ISUPPORTS(); } // destructor @@ -47,28 +49,99 @@ nsLDAPOperation::~nsLDAPOperation() { } +NS_IMPL_THREADSAFE_ISUPPORTS1(nsLDAPOperation, nsILDAPOperation); + +// the connection this operation is on +// +// attribute nsILDAPConnection connection; +// +NS_IMETHODIMP +nsLDAPOperation::SetConnection(nsILDAPConnection *aConnection) +{ + nsresult rv; + + // set the connection + // + mConnection = aConnection; + + // get and cache the connection handle + // + rv = this->mConnection->GetConnectionHandle(&this->mConnectionHandle); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +NS_IMETHODIMP +nsLDAPOperation::GetConnection(nsILDAPConnection* *aConnection) +{ + NS_ENSURE_ARG_POINTER(aConnection); + + *aConnection = mConnection; + NS_IF_ADDREF(*aConnection); + + return NS_OK; +} + // wrapper for ldap_simple_bind() // -bool +NS_IMETHODIMP nsLDAPOperation::SimpleBind(const char *who, const char *passwd) { - this->msgId = ldap_simple_bind(this->connection->connectionHandle, who, - passwd); + NS_ENSURE_ARG(who); + NS_ENSURE_ARG(passwd); - if (this->msgId == -1) { - return false; - } else { - return true; - } + this->mMsgId = ldap_simple_bind(this->mConnectionHandle, who, + passwd); + + if (this->mMsgId == -1) { + return NS_ERROR_FAILURE; + } else { + return NS_OK; + } } // wrapper for ldap_result -int -nsLDAPOperation::Result(int all, struct timeval *timeout, - class nsLDAPMessage *msg) +NS_IMETHODIMP +nsLDAPOperation::Result(PRInt32 aAll, + PRTime timeout, + nsILDAPMessage* *aMessage, + PRInt32 *_retval) { - return ( ldap_result(this->connection->connectionHandle, this->msgId, - all, timeout, &(msg->message)) ); + LDAPMessage *msgHandle; + nsCOMPtr msg; + + nsresult rv; + + NS_ENSURE_ARG_POINTER(aMessage); + NS_ENSURE_ARG_POINTER(_retval); + + // make the call + // + *_retval = ldap_result(mConnectionHandle, mMsgId, + aAll, &sNullTimeval, &msgHandle); + + // if we didn't error or timeout, create an nsILDAPMessage + // + if (*_retval != 0 && *_retval != -1) { + + // create the message + // + msg = do_CreateInstance("mozilla.network.ldapmessage", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // initialize it + // + rv = msg->Init(this, msgHandle); + NS_ENSURE_SUCCESS(rv, rv); + + } + + *aMessage = msg; + NS_IF_ADDREF(*aMessage); + + return NS_OK; } // wrappers for ldap_search_ext @@ -84,9 +157,9 @@ nsLDAPOperation::SearchExt(const char *base, // base DN to search struct timeval *timeoutp, // how long to wait int sizelimit) // max # of entries to return { - return ldap_search_ext(this->connection->connectionHandle, base, scope, + return ldap_search_ext(this->mConnectionHandle, base, scope, filter, attrs, attrsOnly, serverctrls, - clientctrls, timeoutp, sizelimit, &(this->msgId)); + clientctrls, timeoutp, sizelimit, &(this->mMsgId)); } int @@ -97,16 +170,22 @@ nsLDAPOperation::SearchExt(const char *base, // base DN to search int sizelimit) // max # of entries to return { return nsLDAPOperation::SearchExt(base, scope, filter, NULL, 0, NULL, - NULL, timeoutp, sizelimit); + NULL, timeoutp, sizelimit); } // wrapper for ldap_url_search // -int -nsLDAPOperation::URLSearch(const char *URL, // the search URL - int attrsonly) // skip attribute names? +NS_IMETHODIMP +nsLDAPOperation::URLSearch(const char *aURL, // the search URL + PRBool aAttrsOnly) // skip attribute names? { - this->msgId = ldap_url_search(this->connection->connectionHandle, URL, - attrsonly); - return this->msgId; + NS_ENSURE_ARG(aURL); + + this->mMsgId = ldap_url_search(this->mConnectionHandle, aURL, + aAttrsOnly); + if (this->mMsgId == -1) { + return NS_ERROR_FAILURE; + } + + return NS_OK; } diff --git a/directory/xpcom/base/src/nsLDAPOperation.h b/directory/xpcom/base/src/nsLDAPOperation.h index e0d576ea7382..a55d4d69881c 100644 --- a/directory/xpcom/base/src/nsLDAPOperation.h +++ b/directory/xpcom/base/src/nsLDAPOperation.h @@ -35,55 +35,50 @@ #define _nsLDAPOperation_h_ #include "ldap.h" -#include "nsLDAPConnection.h" +#include "nsCOMPtr.h" +#include "nsILDAPConnection.h" +#include "nsILDAPOperation.h" -class nsLDAPOperation { +// 97a479d0-9a44-47c6-a17a-87f9b00294bb +#define NS_LDAPOPERATION_CID \ +{ 0x97a479d0, 0x9a44, 0x47c6, \ + { 0xa1, 0x7a, 0x87, 0xf9, 0xb0, 0x02, 0x94, 0xbb}} - friend class nsLDAPMessage; +class nsLDAPOperation : public nsILDAPOperation +{ + public: - public: + NS_DECL_ISUPPORTS; + NS_DECL_NSILDAPOPERATION; - // constructor - // - nsLDAPOperation(class nsLDAPConnection *c); + // constructor & destructor + // + nsLDAPOperation(); + virtual ~nsLDAPOperation(); - // destructor - // - ~nsLDAPOperation(); + // wrappers for ldap_search_ext + // + int SearchExt(const char *base, // base DN to search + int scope, // LDAP_SCOPE_{BASE,ONELEVEL,SUBTREE} + const char* filter, // search filter + char **attrs, // attribute types to be returned + int attrsOnly, // attrs only, or values too? + LDAPControl **serverctrls, + LDAPControl **clientctrls, + struct timeval *timeoutp, // how long to wait + int sizelimit); // max # of entries to return - // wrapper for ldap_simple_bind() - // - bool SimpleBind(const char *who, const char *passwd); - - // wrapper for ldap_result() - // XXX - should this really be part of the nsLDAPMessage class? - int Result(int all, struct timeval *timeout, class nsLDAPMessage *m); + int SearchExt(const char *base, // base DN to search + int scope, // LDAP_SCOPE_{BASE,ONELEVEL,SUBTREE} + const char* filter, // search filter + struct timeval *timeoutp, // how long to wait + int sizelimit); // max # of entries to return - // wrappers for ldap_search_ext - // - int SearchExt(const char *base, // base DN to search - int scope, // LDAP_SCOPE_{BASE,ONELEVEL,SUBTREE} - const char* filter, // search filter - char **attrs, // attribute types to be returned - int attrsOnly, // attrs only, or values too? - LDAPControl **serverctrls, - LDAPControl **clientctrls, - struct timeval *timeoutp, // how long to wait - int sizelimit); // max # of entries to return - - int SearchExt(const char *base, // base DN to search - int scope, // LDAP_SCOPE_{BASE,ONELEVEL,SUBTREE} - const char* filter, // search filter - struct timeval *timeoutp, // how long to wait - int sizelimit); // max # of entries to return - - // wrapper for ldap_search_url. returns msg id #; -1 is an error. - // - int URLSearch(const char *URL, // the URL to search - int attrsonly); // skip the attr names? - protected: - int msgId; - class nsLDAPConnection *connection; // connection this op is happening on. + protected: + PRInt32 mMsgId; + nsCOMPtr mConnection; + LDAP *mConnectionHandle; // cached from mConnection->GetConnectionHandle() + static struct timeval sNullTimeval; }; #endif /* _nsLDAPOperation_h */ diff --git a/directory/xpcom/base/src/nsLDAPProtocolModule.cpp b/directory/xpcom/base/src/nsLDAPProtocolModule.cpp index 76ba3e5a9acc..33b16a32f1a1 100644 --- a/directory/xpcom/base/src/nsLDAPProtocolModule.cpp +++ b/directory/xpcom/base/src/nsLDAPProtocolModule.cpp @@ -35,22 +35,33 @@ #include "nsLDAPProtocolHandler.h" #include "nsLDAPChannel.h" #include "nsLDAPService.h" +#include "nsLDAPConnection.h" +#include "nsLDAPOperation.h" +#include "nsLDAPMessage.h" // use the default constructor // NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPProtocolHandler); NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLDAPService, Init); +NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPConnection); +NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPOperation); +NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPMessage); // a table of the CIDs implemented by this module (in this case, just one) // static nsModuleComponentInfo components[] = { - { "LDAP Protocol Handler", NS_LDAPPROTOCOLHANDLER_CID, - NS_NETWORK_PROTOCOL_PROGID_PREFIX "ldap", nsLDAPProtocolHandlerConstructor - }, - { "LDAP Service", NS_LDAPSERVICE_CID, - "mozilla.network.ldapservice", nsLDAPServiceConstructor - } + { "LDAP Protocol Handler", NS_LDAPPROTOCOLHANDLER_CID, + NS_NETWORK_PROTOCOL_PROGID_PREFIX "ldap", + nsLDAPProtocolHandlerConstructor }, + { "LDAP Service", NS_LDAPSERVICE_CID, "mozilla.network.ldapservice", + nsLDAPServiceConstructor }, + { "LDAP Connection", NS_LDAPCONNECTION_CID, + "mozilla.network.ldapconnection", nsLDAPConnectionConstructor }, + { "LDAP Operation", NS_LDAPOPERATION_CID, + "mozilla.network.ldapoperation", nsLDAPOperationConstructor }, + { "LDAP Message", NS_LDAPMESSAGE_CID, + "mozilla.network.ldapmessage", nsLDAPMessageConstructor } }; // implement the NSGetModule() exported function