KLDAP Library
ldapsearch.cpp
00001 /* 00002 This file is part of libkldap. 00003 Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "ldapsearch.h" 00022 #include "ldapdn.h" 00023 #include "ldapdefs.h" 00024 00025 #include <QtCore/QEventLoop> 00026 #include <QtCore/QTimer> 00027 00028 #include <kdebug.h> 00029 #include <KLocale> 00030 using namespace KLDAP; 00031 00032 //blocking the GUI for xxx milliseconds 00033 #define LDAPSEARCH_BLOCKING_TIMEOUT 10 00034 00035 class LdapSearch::Private 00036 { 00037 public: 00038 Private( LdapSearch *parent ) 00039 : mParent( parent ) 00040 { 00041 } 00042 00043 void result(); 00044 bool connect(); 00045 void closeConnection(); 00046 bool startSearch( const LdapDN &base, LdapUrl::Scope scope, 00047 const QString &filter, const QStringList &attributes, 00048 int pagesize, int count ); 00049 00050 LdapSearch *mParent; 00051 LdapConnection *mConn; 00052 LdapOperation mOp; 00053 bool mOwnConnection, mAbandoned; 00054 int mId, mPageSize; 00055 LdapDN mBase; 00056 QString mFilter; 00057 QStringList mAttributes; 00058 LdapUrl::Scope mScope; 00059 00060 QString mErrorString; 00061 int mError; 00062 int mCount, mMaxCount; 00063 bool mFinished; 00064 }; 00065 00066 void LdapSearch::Private::result() 00067 { 00068 if ( mAbandoned ) { 00069 mOp.abandon( mId ); 00070 return; 00071 } 00072 int res = mOp.waitForResult( mId, LDAPSEARCH_BLOCKING_TIMEOUT ); 00073 00074 kDebug() << "LDAP result:" << res; 00075 00076 if ( res != 0 && 00077 ( res == -1 || 00078 ( mConn->ldapErrorCode() != KLDAP_SUCCESS && 00079 mConn->ldapErrorCode() != KLDAP_SASL_BIND_IN_PROGRESS ) ) ) { 00080 //error happened, but no timeout 00081 mError = mConn->ldapErrorCode(); 00082 mErrorString = mConn->ldapErrorString(); 00083 emit mParent->result( mParent ); 00084 return; 00085 } 00086 00087 //binding 00088 if ( res == LdapOperation::RES_BIND ) { 00089 00090 QByteArray servercc; 00091 servercc = mOp.serverCred(); 00092 00093 kDebug() << "LdapSearch RES_BIND"; 00094 if ( mConn->ldapErrorCode() == KLDAP_SUCCESS ) { //bind succeeded 00095 kDebug() << "bind succeeded"; 00096 LdapControls savedctrls = mOp.serverControls(); 00097 if ( mPageSize ) { 00098 LdapControls ctrls = savedctrls; 00099 LdapControl::insert( ctrls, LdapControl::createPageControl( mPageSize ) ); 00100 mOp.setServerControls( ctrls ); 00101 } 00102 00103 mId = mOp.search( mBase, mScope, mFilter, mAttributes ); 00104 mOp.setServerControls( savedctrls ); 00105 } else { //next bind step 00106 kDebug() << "bind next step"; 00107 mId = mOp.bind( servercc ); 00108 } 00109 if ( mId < 0 ) { 00110 if ( mId == KLDAP_SASL_ERROR ) { 00111 mError = mId; 00112 mErrorString = mConn->saslErrorString(); 00113 } else { 00114 mError = mConn->ldapErrorCode(); 00115 mErrorString = mConn->ldapErrorString(); 00116 } 00117 emit mParent->result( mParent ); 00118 return; 00119 } 00120 QTimer::singleShot( 0, mParent, SLOT(result()) ); 00121 return; 00122 } 00123 00124 //End of entries 00125 if ( res == LdapOperation::RES_SEARCH_RESULT ) { 00126 if ( mPageSize ) { 00127 QByteArray cookie; 00128 int estsize = -1; 00129 for ( int i = 0; i < mOp.controls().count(); ++i ) { 00130 estsize = mOp.controls()[i].parsePageControl( cookie ); 00131 if ( estsize != -1 ) { 00132 break; 00133 } 00134 } 00135 kDebug() << " estimated size:" << estsize; 00136 if ( estsize != -1 && !cookie.isEmpty() ) { 00137 LdapControls ctrls, savedctrls; 00138 savedctrls = mOp.serverControls(); 00139 ctrls = savedctrls; 00140 LdapControl::insert( ctrls, LdapControl::createPageControl ( mPageSize, cookie ) ); 00141 mOp.setServerControls( ctrls ); 00142 mId = mOp.search( mBase, mScope, mFilter, mAttributes ); 00143 mOp.setServerControls( savedctrls ); 00144 if ( mId == -1 ) { 00145 mError = mConn->ldapErrorCode(); 00146 mErrorString = mConn->ldapErrorString(); 00147 emit mParent->result( mParent ); 00148 return; 00149 } 00150 //continue with the next page 00151 QTimer::singleShot( 0, mParent, SLOT(result()) ); 00152 return; 00153 } 00154 } 00155 mFinished = true; 00156 emit mParent->result( mParent ); 00157 return; 00158 } 00159 00160 //Found an entry 00161 if ( res == LdapOperation::RES_SEARCH_ENTRY ) { 00162 emit mParent->data( mParent, mOp.object() ); 00163 mCount++; 00164 } 00165 00166 //If not reached the requested entries, continue 00167 if ( mMaxCount <= 0 || mCount < mMaxCount ) { 00168 QTimer::singleShot( 0, mParent, SLOT(result()) ); 00169 } 00170 //If reached the requested entries, indicate it 00171 if ( mMaxCount > 0 && mCount == mMaxCount ) { 00172 kDebug() << mCount << " entries reached"; 00173 emit mParent->result( mParent ); 00174 } 00175 } 00176 00177 bool LdapSearch::Private::connect() 00178 { 00179 int ret = mConn->connect(); 00180 if ( ret != KLDAP_SUCCESS ) { 00181 mError = ret; 00182 mErrorString = mConn->connectionError(); 00183 closeConnection(); 00184 return false; 00185 } 00186 return true; 00187 } 00188 00189 void LdapSearch::Private::closeConnection() 00190 { 00191 if ( mOwnConnection && mConn ) { 00192 delete mConn; 00193 mConn = 0; 00194 } 00195 } 00196 00197 //This starts the real job 00198 bool LdapSearch::Private::startSearch( const LdapDN &base, LdapUrl::Scope scope, 00199 const QString &filter, 00200 const QStringList &attributes, int pagesize, int count ) 00201 { 00202 kDebug() << "search: base=" << base.toString() << "scope=" << (int)scope 00203 << "filter=" << filter << "attributes=" << attributes 00204 << "pagesize=" << pagesize; 00205 mAbandoned = false; 00206 mError = 0; 00207 mErrorString.clear(); 00208 mOp.setConnection( *mConn ); 00209 mPageSize = pagesize; 00210 mBase = base; 00211 mScope = scope; 00212 mFilter = filter; 00213 mAttributes = attributes; 00214 mMaxCount = count; 00215 mCount = 0; 00216 mFinished = false; 00217 00218 LdapControls savedctrls = mOp.serverControls(); 00219 if ( pagesize ) { 00220 LdapControls ctrls = savedctrls; 00221 mConn->setOption( 0x0008, NULL ); // Disable referals or paging won't work 00222 LdapControl::insert( ctrls, LdapControl::createPageControl( pagesize ) ); 00223 mOp.setServerControls( ctrls ); 00224 } 00225 00226 mId = mOp.bind(); 00227 if ( mId < 0 ) { 00228 if ( mId == KLDAP_SASL_ERROR ) { 00229 mError = mId; 00230 mErrorString = mConn->saslErrorString(); 00231 } else { 00232 mError = mConn->ldapErrorCode(); 00233 mErrorString = mConn->ldapErrorString(); 00234 if ( mError == -1 && mErrorString.isEmpty() ) { 00235 mErrorString = i18n( "Cannot access to server. Please reconfigure it." ); 00236 } 00237 } 00238 return false; 00239 } 00240 kDebug() << "startSearch msg id=" << mId; 00241 00242 //maybe do this with threads?- need thread-safe client libs!!! 00243 QTimer::singleShot( 0, mParent, SLOT(result()) ); 00244 00245 return true; 00246 } 00247 00249 00250 LdapSearch::LdapSearch() 00251 : d( new Private( this ) ) 00252 { 00253 d->mOwnConnection = true; 00254 d->mConn = 0; 00255 } 00256 00257 LdapSearch::LdapSearch( LdapConnection &connection ) 00258 : d( new Private( this ) ) 00259 { 00260 d->mOwnConnection = false; 00261 d->mConn = &connection; 00262 } 00263 00264 LdapSearch::~LdapSearch() 00265 { 00266 d->closeConnection(); 00267 delete d; 00268 } 00269 00270 void LdapSearch::setConnection( LdapConnection &connection ) 00271 { 00272 d->closeConnection(); 00273 d->mOwnConnection = false; 00274 d->mConn = &connection; 00275 } 00276 00277 void LdapSearch::setClientControls( const LdapControls &ctrls ) 00278 { 00279 d->mOp.setClientControls( ctrls ); 00280 } 00281 00282 void LdapSearch::setServerControls( const LdapControls &ctrls ) 00283 { 00284 d->mOp.setServerControls( ctrls ); 00285 } 00286 00287 bool LdapSearch::search( const LdapServer &server, 00288 const QStringList &attributes, int count ) 00289 { 00290 if ( d->mOwnConnection ) { 00291 d->closeConnection(); 00292 d->mConn = new LdapConnection( server ); 00293 if ( !d->connect() ) { 00294 return false; 00295 } 00296 } 00297 return d->startSearch( server.baseDn(), server.scope(), server.filter(), 00298 attributes, server.pageSize(), count ); 00299 } 00300 00301 bool LdapSearch::search( const LdapUrl &url, int count ) 00302 { 00303 if ( d->mOwnConnection ) { 00304 d->closeConnection(); 00305 d->mConn = new LdapConnection( url ); 00306 if ( !d->connect() ) { 00307 return false; 00308 } 00309 } 00310 bool critical; 00311 int pagesize = url.extension( QLatin1String( "x-pagesize" ), critical ).toInt(); 00312 return d->startSearch( url.dn(), url.scope(), url.filter(), 00313 url.attributes(), pagesize, count ); 00314 } 00315 00316 bool LdapSearch::search( const LdapDN &base, LdapUrl::Scope scope, 00317 const QString &filter, const QStringList &attributes, 00318 int pagesize, int count ) 00319 { 00320 Q_ASSERT( !d->mOwnConnection ); 00321 return d->startSearch( base, scope, filter, attributes, pagesize, count ); 00322 } 00323 00324 void LdapSearch::continueSearch() 00325 { 00326 Q_ASSERT( !d->mFinished ); 00327 d->mCount = 0; 00328 QTimer::singleShot( 0, this, SLOT(result()) ); 00329 } 00330 00331 bool LdapSearch::isFinished() 00332 { 00333 return d->mFinished; 00334 } 00335 00336 void LdapSearch::abandon() 00337 { 00338 d->mAbandoned = true; 00339 } 00340 00341 int LdapSearch::error() const 00342 { 00343 return d->mError; 00344 } 00345 00346 QString LdapSearch::errorString() const 00347 { 00348 return d->mErrorString; 00349 } 00350 00351 #include "ldapsearch.moc"