kaddressbook Library API Documentation

ldapsearchdialog.cpp

00001 /* ldapsearchdialogimpl.cpp - LDAP access
00002  *      Copyright (C) 2002 Klar�vdalens Datakonsult AB
00003  *
00004  *      Author: Steffen Hansen <hansen@kde.org>
00005  *
00006  * This file is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This file is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00019  */
00020 
00021 
00022 #include <qcheckbox.h>
00023 #include <qgroupbox.h>
00024 #include <qheader.h>
00025 #include <qlabel.h>
00026 #include <qlayout.h>
00027 #include <qlistview.h>
00028 #include <qpushbutton.h>
00029 
00030 #include <kabc/addresslineedit.h>
00031 #include <kapplication.h>
00032 #include <kcombobox.h>
00033 #include <kconfig.h>
00034 #include <klineedit.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.h>
00037 
00038 #include "kabcore.h"
00039 #include "ldapsearchdialog.h"
00040 #include "kablock.h"
00041 
00042 static QString asUtf8( const QByteArray &val )
00043 {
00044   if ( val.isEmpty() )
00045     return QString::null;
00046 
00047   const char *data = val.data();
00048 
00049   //QString::fromUtf8() bug workaround
00050   if ( data[ val.size() - 1 ] == '\0' )
00051     return QString::fromUtf8( data, val.size() - 1 );
00052   else
00053     return QString::fromUtf8( data, val.size() );
00054 }
00055 
00056 static QString join( const KPIM::LdapAttrValue& lst, const QString& sep )
00057 {
00058   QString res;
00059   bool alredy = false;
00060   for ( KPIM::LdapAttrValue::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
00061     if ( alredy )
00062       res += sep;
00063     alredy = TRUE;
00064     res += asUtf8( *it );
00065   }
00066   return res;
00067 }
00068 
00069 static QMap<QString, QString>& adrbookattr2ldap()
00070 {
00071   static QMap<QString, QString> keys;
00072 
00073   if ( keys.isEmpty() ) {
00074     keys[ i18n( "Title" ) ] = "title";
00075     keys[ i18n( "Full Name" ) ] = "cn";
00076     keys[ i18n( "Email" ) ] = "mail";
00077     keys[ i18n( "Home Number" ) ] = "homePhone";
00078     keys[ i18n( "Work Number" ) ] = "telephoneNumber";
00079     keys[ i18n( "Mobile Number" ) ] = "mobile";
00080     keys[ i18n( "Fax Number" ) ] = "facsimileTelephoneNumber";
00081     keys[ i18n( "Pager" ) ] = "pager";
00082     keys[ i18n( "Street") ] = "street";
00083     keys[ i18n( "State" ) ] = "st";
00084     keys[ i18n( "Country" ) ] = "co";
00085     keys[ i18n( "City" ) ] = "l";
00086     keys[ i18n( "Organization" ) ] = "o";
00087     keys[ i18n( "Company" ) ] = "Company";
00088     keys[ i18n( "Department" ) ] = "department";
00089     keys[ i18n( "Zip Code" ) ] = "postalCode";
00090     keys[ i18n( "Postal Address" ) ] = "postalAddress";
00091     keys[ i18n( "Description" ) ] = "description";
00092     keys[ i18n( "User ID" ) ] = "uid";
00093   }
00094   return keys;
00095 }
00096 
00097 class ContactListItem : public QListViewItem
00098 {
00099   public:
00100     ContactListItem( QListView* parent, const KPIM::LdapAttrMap& attrs )
00101       : QListViewItem( parent ), mAttrs( attrs )
00102     { }
00103 
00104     KPIM::LdapAttrMap mAttrs;
00105 
00106     virtual QString text( int col ) const
00107     {
00108       // Look up a suitable attribute for column col
00109       const QString colName = listView()->columnText( col );
00110       const QString ldapAttrName = adrbookattr2ldap()[ colName ];
00111       return join( mAttrs[ ldapAttrName ], ", " );
00112     }
00113 };
00114 
00115 LDAPSearchDialog::LDAPSearchDialog( KABC::AddressBook *ab, KABCore *core,
00116                                     QWidget* parent, const char* name )
00117   : KDialogBase( Plain, i18n( "Search for Addresses in Directory" ), Help | Default | User1 |
00118     User2 | User3 |  Cancel, Default, parent, name, false, true ),
00119     mAddressBook( ab ), mCore( core )
00120 {
00121   setButtonCancel( KStdGuiItem::close() );
00122   QFrame *page = plainPage();
00123   QVBoxLayout *topLayout = new QVBoxLayout( page, marginHint(), spacingHint() );
00124 
00125   QGroupBox *groupBox = new QGroupBox( i18n( "Search for Addresses in Directory" ),
00126                                        page );
00127   groupBox->setFrameShape( QGroupBox::Box );
00128   groupBox->setFrameShadow( QGroupBox::Sunken );
00129   groupBox->setColumnLayout( 0, Qt::Vertical );
00130   QGridLayout *boxLayout = new QGridLayout( groupBox->layout(), 2,
00131                                             5, spacingHint() );
00132   boxLayout->setColStretch( 1, 1 );
00133 
00134   QLabel *label = new QLabel( i18n( "Search for:" ), groupBox );
00135   boxLayout->addWidget( label, 0, 0 );
00136 
00137   mSearchEdit = new KLineEdit( groupBox );
00138   boxLayout->addWidget( mSearchEdit, 0, 1 );
00139   label->setBuddy( mSearchEdit );
00140 
00141   label = new QLabel( i18n( "in" ), groupBox );
00142   boxLayout->addWidget( label, 0, 2 );
00143 
00144   mFilterCombo = new KComboBox( groupBox );
00145   mFilterCombo->insertItem( i18n( "Name" ) );
00146   mFilterCombo->insertItem( i18n( "Email" ) );
00147   mFilterCombo->insertItem( i18n( "Home Number" ) );
00148   mFilterCombo->insertItem( i18n( "Work Number" ) );
00149   boxLayout->addWidget( mFilterCombo, 0, 3 );
00150 
00151   QSize buttonSize;
00152   mSearchButton = new QPushButton( i18n( "Stop" ), groupBox );
00153   buttonSize = mSearchButton->sizeHint();
00154   mSearchButton->setText( i18n( "Search" ) );
00155   if ( buttonSize.width() < mSearchButton->sizeHint().width() )
00156     buttonSize = mSearchButton->sizeHint();
00157   mSearchButton->setFixedWidth( buttonSize.width() );
00158 
00159   mSearchButton->setDefault( true );
00160   boxLayout->addWidget( mSearchButton, 0, 4 );
00161 
00162   mRecursiveCheckbox = new QCheckBox( i18n( "Recursive search" ), groupBox  );
00163   mRecursiveCheckbox->setChecked( true );
00164   boxLayout->addMultiCellWidget( mRecursiveCheckbox, 1, 1, 0, 4 );
00165 
00166   mSearchType = new KComboBox( groupBox );
00167   mSearchType->insertItem( i18n( "Contains" ) );
00168   mSearchType->insertItem( i18n( "Starts With" ) );
00169   boxLayout->addMultiCellWidget( mSearchType, 1, 1, 3, 4 );
00170 
00171   topLayout->addWidget( groupBox );
00172 
00173   mResultListView = new QListView( page );
00174   mResultListView->setSelectionMode( QListView::Multi );
00175   mResultListView->setAllColumnsShowFocus( true );
00176   mResultListView->setShowSortIndicator( true );
00177   topLayout->addWidget( mResultListView );
00178 
00179   resize( QSize( 600, 400).expandedTo( minimumSizeHint() ) );
00180 
00181   setButtonText( User1, i18n( "Unselect All" ) );
00182   setButtonText( User2, i18n( "Select All" ) );
00183   setButtonText( User3, i18n( "Add Selected" ) );
00184   setButtonText( Default, i18n( "Email Selected" ) );
00185 
00186   mNumHosts = 0;
00187   mIsOK = false;
00188 
00189   connect( mRecursiveCheckbox, SIGNAL( toggled( bool ) ),
00190        this, SLOT( slotSetScope( bool ) ) );
00191   connect( mSearchButton, SIGNAL( clicked() ),
00192        this, SLOT( slotStartSearch() ) );
00193 
00194   setTabOrder(mSearchEdit, mFilterCombo);
00195   setTabOrder(mFilterCombo, mSearchButton);
00196   mSearchEdit->setFocus();
00197 
00198   restoreSettings();
00199 }
00200 
00201 LDAPSearchDialog::~LDAPSearchDialog()
00202 {
00203   saveSettings();
00204 }
00205 
00206 void LDAPSearchDialog::restoreSettings()
00207 {
00208   // Create one KPIM::LdapClient per selected server and configure it.
00209 
00210   // First clean the list to make sure it is empty at
00211   // the beginning of the process
00212   mLdapClientList.setAutoDelete( true );
00213   mLdapClientList.clear();
00214 
00215   KConfig kabConfig( "kaddressbookrc" );
00216   kabConfig.setGroup( "LDAPSearch" );
00217   mSearchType->setCurrentItem( kabConfig.readNumEntry( "SearchType", 0 ) );
00218 
00219   // then read the config file and register all selected
00220   // server in the list
00221   KConfig* config = KABC::AddressLineEdit::config(); // singleton kabldaprc config object
00222   KConfigGroupSaver saver( config, "LDAP" );
00223   mNumHosts = config->readUnsignedNumEntry( "NumSelectedHosts" );
00224   if ( !mNumHosts ) {
00225     KMessageBox::error( this, i18n( "You must select a LDAP server before searching.\nYou can do this from the menu Settings/Configure KAddressBook." ) );
00226     mIsOK = false;
00227   } else {
00228     mIsOK = true;
00229     for ( int j = 0; j < mNumHosts; ++j ) {
00230       KPIM::LdapClient* ldapClient = new KPIM::LdapClient( 0, this, "ldapclient" );
00231 
00232       QString host = config->readEntry( QString( "SelectedHost%1" ).arg( j ), "" );
00233       if ( !host.isEmpty() )
00234         ldapClient->setHost( host );
00235 
00236       QString port = QString::number( config->readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) ) );
00237       if ( !port.isEmpty() )
00238         ldapClient->setPort( port );
00239 
00240       QString base = config->readEntry( QString( "SelectedBase%1" ).arg( j ), "" );
00241       if ( !base.isEmpty() )
00242         ldapClient->setBase( base );
00243 
00244       QString bindDN = config->readEntry( QString( "SelectedBind%1" ).arg( j ), "" );
00245       if ( !bindDN.isEmpty() )
00246         ldapClient->setBindDN( bindDN );
00247 
00248       QString pwdBindDN = config->readEntry( QString( "SelectedPwdBind%1" ).arg( j ), "" );
00249       if ( !pwdBindDN.isEmpty() )
00250         ldapClient->setPwdBindDN( pwdBindDN );
00251 
00252       QStringList attrs;
00253 
00254       for ( QMap<QString,QString>::Iterator it = adrbookattr2ldap().begin(); it != adrbookattr2ldap().end(); ++it )
00255         attrs << *it;
00256 
00257       ldapClient->setAttrs( attrs );
00258 
00259       connect( ldapClient, SIGNAL( result( const KPIM::LdapObject& ) ),
00260            this, SLOT( slotAddResult( const KPIM::LdapObject& ) ) );
00261       connect( ldapClient, SIGNAL( done() ),
00262            this, SLOT( slotSearchDone() ) );
00263       connect( ldapClient, SIGNAL( error( const QString& ) ),
00264            this, SLOT( slotError( const QString& ) ) );
00265 
00266       mLdapClientList.append( ldapClient );
00267     }
00268 
00270     while ( mResultListView->header()->count() > 0 ) {
00271       mResultListView->removeColumn(0);
00272     }
00273 
00274     mResultListView->addColumn( i18n( "Full Name" ) );
00275     mResultListView->addColumn( i18n( "Email" ) );
00276     mResultListView->addColumn( i18n( "Home Number" ) );
00277     mResultListView->addColumn( i18n( "Work Number" ) );
00278     mResultListView->addColumn( i18n( "Mobile Number" ) );
00279     mResultListView->addColumn( i18n( "Fax Number" ) );
00280     mResultListView->addColumn( i18n( "Company" ) );
00281     mResultListView->addColumn( i18n( "Organization" ) );
00282     mResultListView->addColumn( i18n( "Street" ) );
00283     mResultListView->addColumn( i18n( "State" ) );
00284     mResultListView->addColumn( i18n( "Country" ) );
00285     mResultListView->addColumn( i18n( "Zip Code" ) );
00286     mResultListView->addColumn( i18n( "Postal Address" ) );
00287     mResultListView->addColumn( i18n( "City" ) );
00288     mResultListView->addColumn( i18n( "Department" ) );
00289     mResultListView->addColumn( i18n( "Description" ) );
00290     mResultListView->addColumn( i18n( "User ID" ) );
00291     mResultListView->addColumn( i18n( "Title" ) );
00292 
00293     mResultListView->clear();
00294   }
00295 }
00296 
00297 void LDAPSearchDialog::saveSettings()
00298 {
00299   KConfig config( "kaddressbookrc" );
00300   config.setGroup( "LDAPSearch" );
00301   config.writeEntry( "SearchType", mSearchType->currentItem() );
00302   config.sync();
00303 }
00304 
00305 void LDAPSearchDialog::cancelQuery()
00306 {
00307   for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00308     client->cancelQuery();
00309   }
00310 }
00311 
00312 void LDAPSearchDialog::slotAddResult( const KPIM::LdapObject& obj )
00313 {
00314   new ContactListItem( mResultListView, obj.attrs );
00315 }
00316 
00317 void LDAPSearchDialog::slotSetScope( bool rec )
00318 {
00319   for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00320     if ( rec )
00321       client->setScope( "sub" );
00322     else
00323       client->setScope( "one" );
00324   }
00325 }
00326 
00327 QString LDAPSearchDialog::makeFilter( const QString& query, const QString& attr,
00328                                       bool startsWith )
00329 {
00330   /* The reasoning behind this filter is:
00331    * If it's a person, or a distlist, show it, even if it doesn't have an email address.
00332    * If it's not a person, or a distlist, only show it if it has an email attribute.
00333    * This allows both resource accounts with an email address which are not a person and
00334    * person entries without an email address to show up, while still not showing things
00335    * like structural entries in the ldap tree. */
00336   QString result( "&(|(objectclass=person)(objectclass=groupofnames)(mail=*))(" );
00337   if( query.isEmpty() )
00338     // Return a filter that matches everything
00339     return result + "|(cn=*)(sn=*)" + ")";
00340 
00341   if ( attr == i18n( "Name" ) ) {
00342     result += startsWith ? "|(cn=%1*)(sn=%2*)" : "|(cn=*%1*)(sn=*%2*)";
00343     result = result.arg( query ).arg( query );
00344   } else {
00345     result += (startsWith ? "%1=%2*" : "%1=*%2*");
00346     if ( attr == i18n( "Email" ) ) {
00347       result = result.arg( "mail" ).arg( query );
00348     } else if ( attr == i18n( "Home Number" ) ) {
00349       result = result.arg( "homePhone" ).arg( query );
00350     } else if ( attr == i18n( "Work Number" ) ) {
00351       result = result.arg( "telephoneNumber" ).arg( query );
00352     } else {
00353       // Error?
00354       result = QString::null;
00355       return result;
00356     }
00357   }
00358   result += ")";
00359   return result;
00360 }
00361 
00362 void LDAPSearchDialog::slotStartSearch()
00363 {
00364   cancelQuery();
00365 
00366   QApplication::setOverrideCursor( Qt::waitCursor );
00367   mSearchButton->setText( i18n( "Stop" ) );
00368 
00369   disconnect( mSearchButton, SIGNAL( clicked() ),
00370               this, SLOT( slotStartSearch() ) );
00371   connect( mSearchButton, SIGNAL( clicked() ),
00372            this, SLOT( slotStopSearch() ) );
00373 
00374   bool startsWith = (mSearchType->currentItem() == 1);
00375 
00376   QString filter = makeFilter( mSearchEdit->text().stripWhiteSpace(), mFilterCombo->currentText(), startsWith );
00377 
00378    // loop in the list and run the KPIM::LdapClients
00379   mResultListView->clear();
00380   for( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00381     client->startQuery( filter );
00382   }
00383 
00384   saveSettings();
00385 }
00386 
00387 void LDAPSearchDialog::slotStopSearch()
00388 {
00389   cancelQuery();
00390   slotSearchDone();
00391 }
00392 
00393 void LDAPSearchDialog::slotSearchDone()
00394 {
00395   // If there are no more active clients, we are done.
00396   for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00397     if ( client->isActive() )
00398       return;
00399   }
00400 
00401   disconnect( mSearchButton, SIGNAL( clicked() ),
00402               this, SLOT( slotStopSearch() ) );
00403   connect( mSearchButton, SIGNAL( clicked() ),
00404            this, SLOT( slotStartSearch() ) );
00405 
00406   mSearchButton->setText( i18n( "Search" ) );
00407   QApplication::restoreOverrideCursor();
00408 }
00409 
00410 void LDAPSearchDialog::slotError( const QString& error )
00411 {
00412   QApplication::restoreOverrideCursor();
00413   KMessageBox::error( this, error );
00414 }
00415 
00416 void LDAPSearchDialog::closeEvent( QCloseEvent* e )
00417 {
00418   slotStopSearch();
00419   e->accept();
00420 }
00421 
00426 QString LDAPSearchDialog::selectedEMails() const
00427 {
00428   QStringList result;
00429   ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00430   while ( cli ) {
00431     if ( cli->isSelected() ) {
00432       QString email = asUtf8( cli->mAttrs[ "mail" ].first() ).stripWhiteSpace();
00433       if ( !email.isEmpty() ) {
00434         QString name = asUtf8( cli->mAttrs[ "cn" ].first() ).stripWhiteSpace();
00435         if ( name.isEmpty() ) {
00436           result << email;
00437         } else {
00438           result << name + " <" + email + ">";
00439         }
00440       }
00441     }
00442     cli = static_cast<ContactListItem*>( cli->nextSibling() );
00443   }
00444 
00445   return result.join( ", " );
00446 }
00447 
00448 void LDAPSearchDialog::slotHelp()
00449 {
00450   kapp->invokeHelp( "ldap-queries" );
00451 }
00452 
00453 void LDAPSearchDialog::slotUser1()
00454 {
00455   mResultListView->selectAll( false );
00456 }
00457 
00458 void LDAPSearchDialog::slotUser2()
00459 {
00460   mResultListView->selectAll( true );
00461 }
00462 
00463 void LDAPSearchDialog::slotUser3()
00464 {
00465 
00466   KABC::Resource *resource = mCore->requestResource( this );
00467   if ( !resource ) return;
00468   KABLock::self( mAddressBook )->lock( resource );
00469 
00470   ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00471   while ( cli ) {
00472     if ( cli->isSelected() ) {
00473       KABC::Addressee addr;
00474 
00475       // name
00476       addr.setNameFromString( asUtf8( cli->mAttrs["cn"].first() ) );
00477 
00478       // email
00479       KPIM::LdapAttrValue lst = cli->mAttrs["mail"];
00480       KPIM::LdapAttrValue::ConstIterator it = lst.begin();
00481       bool pref = true;
00482       if ( it != lst.end() ) {
00483         addr.insertEmail( asUtf8( *it ), pref );
00484         pref = false;
00485         ++it;
00486       }
00487 
00488       addr.setOrganization( asUtf8( cli->mAttrs[ "o" ].first() ) );
00489       if ( addr.organization().isEmpty() )
00490          addr.setOrganization( asUtf8( cli->mAttrs[ "Company" ].first() ) );
00491 
00492       addr.insertCustom("KADDRESSBOOK", "X-Department", asUtf8( cli->mAttrs[ "department" ].first() ) );
00493 
00494       // Address
00495       KABC::Address workAddr( KABC::Address::Work );
00496 
00497       workAddr.setStreet( asUtf8( cli->mAttrs[ "street" ].first()) );
00498       workAddr.setLocality( asUtf8( cli->mAttrs[ "l" ].first()) );
00499       workAddr.setRegion( asUtf8( cli->mAttrs[ "st" ].first()));
00500       workAddr.setPostalCode( asUtf8( cli->mAttrs[ "postalCode" ].first()) );
00501       workAddr.setCountry( asUtf8( cli->mAttrs[ "co" ].first()) );
00502 
00503       if ( !workAddr.isEmpty() )
00504         addr.insertAddress( workAddr );
00505 
00506       // phone
00507       KABC::PhoneNumber homeNr = asUtf8( cli->mAttrs[  "homePhone" ].first() );
00508       homeNr.setType( KABC::PhoneNumber::Home );
00509       addr.insertPhoneNumber( homeNr );
00510 
00511       KABC::PhoneNumber workNr = asUtf8( cli->mAttrs[  "telephoneNumber" ].first() );
00512       workNr.setType( KABC::PhoneNumber::Work );
00513       addr.insertPhoneNumber( workNr );
00514 
00515       KABC::PhoneNumber faxNr = asUtf8( cli->mAttrs[  "facsimileTelephoneNumber" ].first() );
00516       faxNr.setType( KABC::PhoneNumber::Fax );
00517       addr.insertPhoneNumber( faxNr );
00518 
00519       KABC::PhoneNumber cellNr = asUtf8( cli->mAttrs[  "mobile" ].first() );
00520       cellNr.setType( KABC::PhoneNumber::Cell );
00521       addr.insertPhoneNumber( cellNr );
00522 
00523       KABC::PhoneNumber pagerNr = asUtf8( cli->mAttrs[  "pager" ].first() );
00524       pagerNr.setType( KABC::PhoneNumber::Pager );
00525       addr.insertPhoneNumber( pagerNr );
00526 
00527       if ( mAddressBook ) {
00528         addr.setResource( resource );
00529         mAddressBook->insertAddressee( addr );
00530       }
00531     }
00532     cli = static_cast<ContactListItem*>( cli->nextSibling() );
00533   }
00534 
00535   KABLock::self( mAddressBook )->unlock( resource );
00536   emit addresseesAdded();
00537 }
00538 
00539 void LDAPSearchDialog::slotDefault()
00540 {
00541   QStringList emails;
00542   ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00543   while ( cli ) {
00544     if ( cli->isSelected() ) {
00545       KABC::Addressee addr;
00546       // name
00547       addr.setNameFromString( asUtf8( cli->mAttrs["cn"].first() ) );
00548 
00549       // email
00550       KPIM::LdapAttrValue lst = cli->mAttrs["mail"];
00551       addr.insertEmail( asUtf8( *(lst.begin()) ), true );
00552       emails << addr.fullEmail();
00553     }
00554     cli = static_cast<ContactListItem*>( cli->nextSibling() );
00555   }
00556   mCore->sendMail( emails.join( ", " ) );
00557 }
00558 
00559 #include "ldapsearchdialog.moc"
KDE Logo
This file is part of the documentation for kaddressbook Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 25 11:19:26 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003