Back to index

lightning-sunbird  0.9+nobinonly
nsLDAPSyncQuery.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mitesh Shah <mitesh@netscape.com>
00024  *   Dan Mosedale <dmose@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #if defined(MOZ_LDAP_XPCOM)
00041 
00042 #include "nsLDAPSyncQuery.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsIProxyObjectManager.h"
00045 #include "nsXPIDLString.h"
00046 #include "nsILDAPErrors.h"
00047 #include "nsIEventQueueService.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsILDAPMessage.h"
00050 
00051 // nsISupports Implementation
00052 
00053 NS_IMPL_THREADSAFE_ISUPPORTS2(nsLDAPSyncQuery, nsILDAPSyncQuery, nsILDAPMessageListener)
00054 
00055 // Constructor
00056 //
00057 nsLDAPSyncQuery::nsLDAPSyncQuery() :
00058     mFinished(PR_FALSE), // This is a control variable for event loop
00059     mAttrCount(0), mAttrs(0), mProtocolVersion(nsILDAPConnection::VERSION3)
00060 {
00061 }
00062 
00063 // Destructor
00064 //
00065 nsLDAPSyncQuery::~nsLDAPSyncQuery()
00066 {
00067 }
00068 
00069 
00070 // Messages received are passed back via this function.
00071 // void OnLDAPMessage (in nsILDAPMessage aMessage) 
00072 //
00073 NS_IMETHODIMP 
00074 nsLDAPSyncQuery::OnLDAPMessage(nsILDAPMessage *aMessage)
00075 {
00076     PRInt32 messageType;
00077 
00078     // just in case.
00079     //
00080     if (!aMessage) {
00081         return NS_OK;
00082     }
00083 
00084     // figure out what sort of message was returned
00085     //
00086     nsresult rv = aMessage->GetType(&messageType);
00087     if (NS_FAILED(rv)) {
00088         NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected "
00089                  "error in aMessage->GetType()");
00090         FinishLDAPQuery();
00091         return NS_ERROR_UNEXPECTED;
00092     }
00093 
00094     switch (messageType) {
00095 
00096     case nsILDAPMessage::RES_BIND:
00097 
00098         // a bind has completed
00099         //
00100         return OnLDAPBind(aMessage);
00101 
00102     case nsILDAPMessage::RES_SEARCH_ENTRY:
00103         
00104         // a search entry has been returned
00105         //
00106         return OnLDAPSearchEntry(aMessage);
00107 
00108     case nsILDAPMessage::RES_SEARCH_RESULT:
00109 
00110         // the search is finished; we're all done
00111         //  
00112         return OnLDAPSearchResult(aMessage);
00113 
00114     default:
00115         
00116         // Given the LDAP operations nsLDAPSyncQuery uses, we should
00117         // never get here.  If we do get here in a release build, it's
00118         // probably a bug, but maybe it's the LDAP server doing something
00119         // weird.  Might as well try and continue anyway.  The session should
00120         // eventually get reaped by the timeout code, if necessary.
00121         //
00122         NS_ERROR("nsLDAPSyncQuery::OnLDAPMessage(): unexpected "
00123                  "LDAP message received");
00124         return NS_OK;
00125     }
00126 }
00127 
00128 // void onLDAPInit (in nsresult aStatus);
00129 //
00130 NS_IMETHODIMP
00131 nsLDAPSyncQuery::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
00132 {
00133     nsresult rv;        // temp for xpcom return values
00134     nsCOMPtr<nsILDAPMessageListener> selfProxy;
00135 
00136     // create and initialize an LDAP operation (to be used for the bind)
00137     //  
00138     mOperation = do_CreateInstance("@mozilla.org/network/ldap-operation;1", 
00139                                    &rv);
00140     if (NS_FAILED(rv)) {
00141         FinishLDAPQuery();
00142         return NS_ERROR_FAILURE;
00143     }
00144 
00145     // get a proxy object so the callback happens on the main thread
00146     //
00147     rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ,
00148                               NS_GET_IID(nsILDAPMessageListener), 
00149                               NS_STATIC_CAST(nsILDAPMessageListener *, this),
00150                               PROXY_ASYNC | PROXY_ALWAYS, 
00151                               getter_AddRefs(selfProxy));
00152     if (NS_FAILED(rv)) {
00153         FinishLDAPQuery();
00154         return NS_ERROR_FAILURE;
00155     }
00156 
00157     // our OnLDAPMessage accepts all result callbacks
00158     //
00159     rv = mOperation->Init(mConnection, selfProxy, nsnull);
00160     if (NS_FAILED(rv)) {
00161         FinishLDAPQuery();
00162         return NS_ERROR_UNEXPECTED; // this should never happen
00163     }
00164 
00165     // kick off a bind operation 
00166     // 
00167     rv = mOperation->SimpleBind(EmptyCString()); 
00168     if (NS_FAILED(rv)) {
00169         FinishLDAPQuery();
00170         return NS_ERROR_FAILURE;
00171     }
00172     
00173     return NS_OK;
00174 }
00175 
00176 nsresult
00177 nsLDAPSyncQuery::OnLDAPBind(nsILDAPMessage *aMessage)
00178 {
00179 
00180     PRInt32 errCode;
00181 
00182     mOperation = 0;  // done with bind op; make nsCOMPtr release it
00183 
00184     // get the status of the bind
00185     //
00186     nsresult rv = aMessage->GetErrorCode(&errCode);
00187     if (NS_FAILED(rv)) {
00188         
00189         NS_ERROR("nsLDAPSyncQuery::OnLDAPBind(): couldn't get "
00190                  "error code from aMessage");
00191         FinishLDAPQuery();
00192         return NS_ERROR_FAILURE;
00193     }
00194 
00195 
00196     // check to be sure the bind succeeded
00197     //
00198     if (errCode != nsILDAPErrors::SUCCESS) {
00199         FinishLDAPQuery();
00200         return NS_ERROR_FAILURE;
00201     }
00202 
00203     // ok, we're starting a search
00204     //
00205     return StartLDAPSearch();
00206 }
00207 
00208 nsresult
00209 nsLDAPSyncQuery::OnLDAPSearchEntry(nsILDAPMessage *aMessage)
00210 {
00211     nsresult rv;       
00212 
00213     // Attributes are retrived in StartLDAPSearch
00214     // iterate through them
00215     //
00216     for (PRUint32 i = 0; i < mAttrCount; i++) {
00217 
00218         PRUnichar **vals;
00219         PRUint32 valueCount;
00220 
00221         // get the values of this attribute
00222         // XXX better failure handling
00223         //
00224         rv = aMessage->GetValues(mAttrs[i], &valueCount, &vals);
00225         if (NS_FAILED(rv)) {
00226             NS_WARNING("nsLDAPSyncQuery:OnLDAPSearchEntry(): "
00227                        "aMessage->GetValues() failed\n");
00228             FinishLDAPQuery();
00229             return rv;;
00230         }
00231 
00232         // store  all values of this attribute in the mResults.
00233         //
00234         for (PRUint32 j = 0; j < valueCount; j++) {
00235             mResults.Append(PRUnichar('\n'));
00236             mResults.AppendASCII(mAttrs[i]);
00237             mResults.Append(PRUnichar('='));
00238             mResults.Append(vals[j]);
00239         }
00240         
00241         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(valueCount, vals);
00242 
00243     }
00244 
00245     return NS_OK;
00246 }
00247 
00248 
00249 nsresult
00250 nsLDAPSyncQuery::OnLDAPSearchResult(nsILDAPMessage *aMessage)
00251 {
00252     // We are done with the LDAP search.
00253     // Release the control variable for the eventloop and other members
00254     // 
00255     FinishLDAPQuery();
00256     
00257     // Release memory allocated for mAttrs
00258     
00259     if (mAttrCount > 0)
00260         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mAttrCount, mAttrs);
00261 
00262     return NS_OK;
00263 }
00264 
00265 nsresult
00266 nsLDAPSyncQuery::StartLDAPSearch()
00267 {
00268     nsresult rv; 
00269     nsCOMPtr<nsILDAPMessageListener> selfProxy; // for callback
00270 
00271 
00272     // create and initialize an LDAP operation (to be used for the search
00273     //  
00274     mOperation = 
00275         do_CreateInstance("@mozilla.org/network/ldap-operation;1", &rv);
00276 
00277     if (NS_FAILED(rv)) {
00278         NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't "
00279                  "create @mozilla.org/network/ldap-operation;1");
00280         FinishLDAPQuery();
00281         return NS_ERROR_FAILURE;
00282     }
00283 
00284     // get a proxy object so the callback happens on the main thread
00285     //
00286     rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ, 
00287                               NS_GET_IID(nsILDAPMessageListener),
00288                               NS_STATIC_CAST(nsILDAPMessageListener *, this),
00289                               PROXY_ASYNC | PROXY_ALWAYS,
00290                               getter_AddRefs(selfProxy));
00291     if (NS_FAILED(rv)) {
00292         NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't "
00293                  "create proxy to this object for callback");
00294         FinishLDAPQuery();
00295         return NS_ERROR_FAILURE;
00296     }
00297 
00298     // initialize the LDAP operation object
00299     //
00300     rv = mOperation->Init(mConnection, selfProxy, nsnull);
00301     if (NS_FAILED(rv)) {
00302         NS_ERROR("nsLDAPSyncQuery::StartLDAPSearch(): couldn't "
00303                  "initialize LDAP operation");
00304         FinishLDAPQuery();
00305         return NS_ERROR_UNEXPECTED;
00306     }
00307 
00308     // get the search filter associated with the directory server url; 
00309     //
00310     nsCAutoString urlFilter;
00311     rv = mServerURL->GetFilter(urlFilter);
00312     if (NS_FAILED(rv)) {
00313         FinishLDAPQuery();
00314         return NS_ERROR_UNEXPECTED;
00315     }
00316 
00317     // get the base dn to search
00318     //
00319     nsCAutoString dn;
00320     rv = mServerURL->GetDn(dn);
00321     if (NS_FAILED(rv)) {
00322         FinishLDAPQuery();
00323         return NS_ERROR_UNEXPECTED;
00324     }
00325 
00326     // and the scope
00327     //
00328     PRInt32 scope;
00329     rv = mServerURL->GetScope(&scope);
00330     if (NS_FAILED(rv)) {
00331         FinishLDAPQuery();
00332         return NS_ERROR_UNEXPECTED;
00333     }
00334 
00335     
00336     rv = mServerURL->GetAttributes(&mAttrCount, &mAttrs);
00337     if (NS_FAILED(rv)) {
00338         FinishLDAPQuery();
00339         return NS_ERROR_UNEXPECTED;
00340     }
00341 
00342 
00343     // time to kick off the search.
00344     //
00345     rv = mOperation->SearchExt(dn, scope, urlFilter, mAttrCount,
00346                                NS_CONST_CAST(const char **, mAttrs), 0, 0);
00347 
00348     if (NS_FAILED(rv)) {
00349         FinishLDAPQuery();
00350         return NS_ERROR_FAILURE;
00351     }
00352 
00353     return NS_OK;
00354 }
00355 
00356 // void initConnection (); 
00357 //
00358 nsresult nsLDAPSyncQuery::InitConnection()
00359 {
00360     nsCOMPtr<nsILDAPMessageListener> selfProxy;
00361     nsresult rv;        // temp for xpcom return values
00362     
00363     // create an LDAP connection
00364     //
00365     mConnection = do_CreateInstance("@mozilla.org/network/ldap-connection;1",
00366                                     &rv);
00367     if (NS_FAILED(rv)) {
00368         NS_ERROR("nsLDAPSyncQuery::InitConnection(): could "
00369                  "not create @mozilla.org/network/ldap-connection;1");
00370         FinishLDAPQuery();
00371         return NS_ERROR_FAILURE;
00372     }
00373 
00374     // have we been properly initialized?
00375     //
00376     if (!mServerURL) {
00377         NS_ERROR("nsLDAPSyncQuery::InitConnection(): mServerURL "
00378                  "is NULL");
00379         FinishLDAPQuery();
00380         return NS_ERROR_NOT_INITIALIZED;
00381     }
00382 
00383     // host to connect to
00384     //
00385     nsCAutoString host;
00386     rv = mServerURL->GetAsciiHost(host);
00387     if (NS_FAILED(rv)) {
00388         FinishLDAPQuery();
00389         return NS_ERROR_FAILURE;
00390     }
00391 
00392     // on which port
00393     //
00394     PRInt32 port;
00395     rv = mServerURL->GetPort(&port);
00396     if (NS_FAILED(rv)) {
00397         FinishLDAPQuery();
00398         return NS_ERROR_FAILURE;
00399     }
00400         
00401     PRUint32 options;
00402     rv = mServerURL->GetOptions(&options);
00403     if (NS_FAILED(rv)) {
00404         FinishLDAPQuery();
00405         return NS_ERROR_FAILURE;
00406     }
00407 
00408     // get a proxy object so the callback happens on the main thread
00409     //
00410     rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ,
00411                               NS_GET_IID(nsILDAPMessageListener), 
00412                               NS_STATIC_CAST(nsILDAPMessageListener *, this), 
00413                               PROXY_ASYNC | PROXY_ALWAYS, 
00414                               getter_AddRefs(selfProxy));
00415     if (NS_FAILED(rv)) {
00416         FinishLDAPQuery();
00417         NS_ERROR("nsLDAPSyncQuery::InitConnection(): couldn't "
00418                  "create proxy to this object for callback");
00419         return NS_ERROR_FAILURE;
00420     }
00421 
00422     rv = mConnection->Init(host.get(), port, 
00423                            (options & nsILDAPURL::OPT_SECURE) 
00424                            ? PR_TRUE : PR_FALSE, EmptyCString(), selfProxy,
00425                            nsnull, mProtocolVersion);
00426     if (NS_FAILED(rv)) {
00427         FinishLDAPQuery();
00428         return NS_ERROR_UNEXPECTED; // this should never happen
00429     }
00430 
00431     return NS_OK;
00432 }
00433 
00434 void
00435 nsLDAPSyncQuery::FinishLDAPQuery()
00436 {
00437     // We are done with the LDAP operation. 
00438     // Release the Control variable for the eventloop
00439     //
00440     mFinished = PR_TRUE;
00441     
00442     // Release member variables
00443     //
00444     mConnection = 0;
00445     mOperation = 0;
00446     mServerURL = 0;
00447  
00448 }
00449 
00450 /* wstring getQueryResults (in nsILDAPURL aServerURL, in unsigned long aVersion); */
00451 NS_IMETHODIMP nsLDAPSyncQuery::GetQueryResults(nsILDAPURL *aServerURL,
00452                                                PRUint32 aProtocolVersion,
00453                                                PRUnichar **_retval)
00454 {
00455     nsresult rv;
00456     
00457     if (!aServerURL) {
00458         NS_ERROR("nsLDAPSyncQuery::GetQueryResults() called without LDAP URL");
00459         return NS_ERROR_FAILURE;
00460     }
00461     mServerURL = aServerURL;
00462     mProtocolVersion = aProtocolVersion;
00463 
00464     nsCOMPtr<nsIEventQueue> currentThreadQ;
00465     nsCOMPtr<nsIEventQueueService> service;
00466 
00467     // Get the eventQueue Service
00468     //
00469     service = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00470     if (NS_FAILED(rv)) {
00471         return rv;
00472     }
00473 
00474     // Get the eventQ for the Current Thread
00475     //
00476     rv = service->PushThreadEventQueue(getter_AddRefs(currentThreadQ));
00477     if (NS_FAILED(rv)) {
00478         return rv;
00479     }
00480 
00481     // Start an LDAP query. 
00482     // InitConnection will bind to the ldap server and post a OnLDAPMessage 
00483     // event. This event will trigger a search and the whole operation will 
00484     // be carried out by chain of events
00485     //
00486     rv = InitConnection();
00487     if (NS_FAILED(rv)) {
00488         service->PopThreadEventQueue(currentThreadQ);
00489         return rv;
00490     }   
00491     
00492     // We want this LDAP query to be synchronous while the XPCOM LDAP is 
00493     // async in nature. So this eventQueue handling will wait for the 
00494     // LDAP operation to be finished. 
00495     // mFinished controls the state of the LDAP opertion. 
00496     // It will be released in any case (success/failure)
00497     
00498     
00499     // Run the event loop, 
00500     // mFinished is a control variable
00501     //
00502     while (!mFinished) {
00503 
00504         PRBool isEventPending;
00505         rv = currentThreadQ->PendingEvents(&isEventPending);
00506         if (NS_FAILED(rv)) {
00507             service->PopThreadEventQueue(currentThreadQ);
00508             return rv;
00509         }
00510         if (isEventPending) {
00511             rv = currentThreadQ->ProcessPendingEvents();
00512             if (NS_FAILED(rv)) {
00513                 service->PopThreadEventQueue(currentThreadQ);
00514                 return rv;
00515             }
00516         }
00517       
00518     }
00519     rv = service->PopThreadEventQueue(currentThreadQ);
00520     if (NS_FAILED(rv))
00521         return rv;
00522 
00523     // Return results
00524     //
00525     if (!mResults.IsEmpty()) {
00526         *_retval = ToNewUnicode(mResults);
00527         if (!_retval)
00528           rv = NS_ERROR_OUT_OF_MEMORY;
00529     }
00530     return rv;
00531 
00532 }
00533 #endif