/* This file is part of libkldap. Copyright (c) 2004-2006 Szombathelyi György This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ldapsearch.h" #include "ldapdn.h" #include "ldapdefs.h" #include #include #include #include using namespace KLDAP; //blocking the GUI for xxx milliseconds #define LDAPSEARCH_BLOCKING_TIMEOUT 10 class LdapSearch::Private { public: Private( LdapSearch *parent ) : mParent( parent ) { } void result(); bool connect(); void closeConnection(); bool startSearch( const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count ); LdapSearch *mParent; LdapConnection *mConn; LdapOperation mOp; bool mOwnConnection, mAbandoned; int mId, mPageSize; LdapDN mBase; QString mFilter; QStringList mAttributes; LdapUrl::Scope mScope; QString mErrorString; int mError; int mCount, mMaxCount; bool mFinished; }; void LdapSearch::Private::result() { if ( mAbandoned ) { mOp.abandon( mId ); return; } int res = mOp.waitForResult( mId, LDAPSEARCH_BLOCKING_TIMEOUT ); kDebug() << "LDAP result:" << res; if ( res != 0 && ( res == -1 || ( mConn->ldapErrorCode() != KLDAP_SUCCESS && mConn->ldapErrorCode() != KLDAP_SASL_BIND_IN_PROGRESS ) ) ) { //error happened, but no timeout mError = mConn->ldapErrorCode(); mErrorString = mConn->ldapErrorString(); emit mParent->result( mParent ); return; } //binding if ( res == LdapOperation::RES_BIND ) { QByteArray servercc; servercc = mOp.serverCred(); kDebug() << "LdapSearch RES_BIND"; if ( mConn->ldapErrorCode() == KLDAP_SUCCESS ) { //bind succeeded kDebug() << "bind succeeded"; LdapControls savedctrls = mOp.serverControls(); if ( mPageSize ) { LdapControls ctrls = savedctrls; LdapControl::insert( ctrls, LdapControl::createPageControl( mPageSize ) ); mOp.setServerControls( ctrls ); } mId = mOp.search( mBase, mScope, mFilter, mAttributes ); mOp.setServerControls( savedctrls ); } else { //next bind step kDebug() << "bind next step"; mId = mOp.bind( servercc ); } if ( mId < 0 ) { if ( mId == KLDAP_SASL_ERROR ) { mError = mId; mErrorString = mConn->saslErrorString(); } else { mError = mConn->ldapErrorCode(); mErrorString = mConn->ldapErrorString(); } emit mParent->result( mParent ); return; } QTimer::singleShot( 0, mParent, SLOT(result()) ); return; } //End of entries if ( res == LdapOperation::RES_SEARCH_RESULT ) { if ( mPageSize ) { QByteArray cookie; int estsize = -1; const int numberOfControls( mOp.controls().count() ); for ( int i = 0; i < numberOfControls; ++i ) { estsize = mOp.controls()[i].parsePageControl( cookie ); if ( estsize != -1 ) { break; } } kDebug() << " estimated size:" << estsize; if ( estsize != -1 && !cookie.isEmpty() ) { LdapControls ctrls, savedctrls; savedctrls = mOp.serverControls(); ctrls = savedctrls; LdapControl::insert( ctrls, LdapControl::createPageControl ( mPageSize, cookie ) ); mOp.setServerControls( ctrls ); mId = mOp.search( mBase, mScope, mFilter, mAttributes ); mOp.setServerControls( savedctrls ); if ( mId == -1 ) { mError = mConn->ldapErrorCode(); mErrorString = mConn->ldapErrorString(); emit mParent->result( mParent ); return; } //continue with the next page QTimer::singleShot( 0, mParent, SLOT(result()) ); return; } } mFinished = true; emit mParent->result( mParent ); return; } //Found an entry if ( res == LdapOperation::RES_SEARCH_ENTRY ) { emit mParent->data( mParent, mOp.object() ); mCount++; } //If not reached the requested entries, continue if ( mMaxCount <= 0 || mCount < mMaxCount ) { QTimer::singleShot( 0, mParent, SLOT(result()) ); } //If reached the requested entries, indicate it if ( mMaxCount > 0 && mCount == mMaxCount ) { kDebug() << mCount << " entries reached"; emit mParent->result( mParent ); } } bool LdapSearch::Private::connect() { int ret = mConn->connect(); if ( ret != KLDAP_SUCCESS ) { mError = ret; mErrorString = mConn->connectionError(); closeConnection(); return false; } return true; } void LdapSearch::Private::closeConnection() { if ( mOwnConnection && mConn ) { delete mConn; mConn = 0; } } //This starts the real job bool LdapSearch::Private::startSearch( const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count ) { kDebug() << "search: base=" << base.toString() << "scope=" << (int)scope << "filter=" << filter << "attributes=" << attributes << "pagesize=" << pagesize; mAbandoned = false; mError = 0; mErrorString.clear(); mOp.setConnection( *mConn ); mPageSize = pagesize; mBase = base; mScope = scope; mFilter = filter; mAttributes = attributes; mMaxCount = count; mCount = 0; mFinished = false; LdapControls savedctrls = mOp.serverControls(); if ( pagesize ) { LdapControls ctrls = savedctrls; mConn->setOption( 0x0008, NULL ); // Disable referals or paging won't work LdapControl::insert( ctrls, LdapControl::createPageControl( pagesize ) ); mOp.setServerControls( ctrls ); } mId = mOp.bind(); if ( mId < 0 ) { if ( mId == KLDAP_SASL_ERROR ) { mError = mId; mErrorString = mConn->saslErrorString(); } else { mError = mConn->ldapErrorCode(); mErrorString = mConn->ldapErrorString(); if ( mError == -1 && mErrorString.isEmpty() ) { mErrorString = i18n( "Cannot access to server. Please reconfigure it." ); } } return false; } kDebug() << "startSearch msg id=" << mId; //maybe do this with threads?- need thread-safe client libs!!! QTimer::singleShot( 0, mParent, SLOT(result()) ); return true; } /////////////////////////////////////////////// LdapSearch::LdapSearch() : d( new Private( this ) ) { d->mOwnConnection = true; d->mConn = 0; } LdapSearch::LdapSearch( LdapConnection &connection ) : d( new Private( this ) ) { d->mOwnConnection = false; d->mConn = &connection; } LdapSearch::~LdapSearch() { d->closeConnection(); delete d; } void LdapSearch::setConnection( LdapConnection &connection ) { d->closeConnection(); d->mOwnConnection = false; d->mConn = &connection; } void LdapSearch::setClientControls( const LdapControls &ctrls ) { d->mOp.setClientControls( ctrls ); } void LdapSearch::setServerControls( const LdapControls &ctrls ) { d->mOp.setServerControls( ctrls ); } bool LdapSearch::search( const LdapServer &server, const QStringList &attributes, int count ) { if ( d->mOwnConnection ) { d->closeConnection(); d->mConn = new LdapConnection( server ); if ( !d->connect() ) { return false; } } return d->startSearch( server.baseDn(), server.scope(), server.filter(), attributes, server.pageSize(), count ); } bool LdapSearch::search( const LdapUrl &url, int count ) { if ( d->mOwnConnection ) { d->closeConnection(); d->mConn = new LdapConnection( url ); if ( !d->connect() ) { return false; } } bool critical = true; int pagesize = url.extension( QLatin1String( "x-pagesize" ), critical ).toInt(); return d->startSearch( url.dn(), url.scope(), url.filter(), url.attributes(), pagesize, count ); } bool LdapSearch::search( const LdapDN &base, LdapUrl::Scope scope, const QString &filter, const QStringList &attributes, int pagesize, int count ) { Q_ASSERT( !d->mOwnConnection ); return d->startSearch( base, scope, filter, attributes, pagesize, count ); } void LdapSearch::continueSearch() { Q_ASSERT( !d->mFinished ); d->mCount = 0; QTimer::singleShot( 0, this, SLOT(result()) ); } bool LdapSearch::isFinished() { return d->mFinished; } void LdapSearch::abandon() { d->mAbandoned = true; } int LdapSearch::error() const { return d->mError; } QString LdapSearch::errorString() const { return d->mErrorString; } #include "moc_ldapsearch.cpp"