00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "ldapsearchdialog.h"
00022 #include "ldapclient.h"
00023
00024 #include <qcheckbox.h>
00025 #include <qgroupbox.h>
00026 #include <qheader.h>
00027 #include <qlabel.h>
00028 #include <qlayout.h>
00029 #include <qlistview.h>
00030 #include <qpushbutton.h>
00031
00032 #include <kabc/addresslineedit.h>
00033 #include <kapplication.h>
00034 #include <kcombobox.h>
00035 #include <kconfig.h>
00036 #include <klineedit.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039
00040 using namespace KPIM;
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
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 namespace KPIM {
00098
00099 class ContactListItem : public QListViewItem
00100 {
00101 public:
00102 ContactListItem( QListView* parent, const KPIM::LdapAttrMap& attrs )
00103 : QListViewItem( parent ), mAttrs( attrs )
00104 {
00105 const KPIM::LdapAttrValue &mailAttrs = attrs[ "mail" ];
00106 if ( mailAttrs.isEmpty() ) {
00107 setSelectable( false );
00108 setEnabled( false );
00109 }
00110 }
00111
00112 KPIM::LdapAttrMap mAttrs;
00113
00114 virtual QString text( int col ) const
00115 {
00116
00117 const QString colName = listView()->columnText( col );
00118 const QString ldapAttrName = adrbookattr2ldap()[ colName ];
00119 return join( mAttrs[ ldapAttrName ], ", " );
00120 }
00121 };
00122
00123 }
00124
00125 LDAPSearchDialog::LDAPSearchDialog( QWidget* parent, const char* name )
00126 : KDialogBase( Plain, i18n( "Search for Addresses in Directory" ), Help | User1 |
00127 User2 | User3 | Cancel, Default, parent, name, false, true )
00128 {
00129 setButtonCancel( KStdGuiItem::close() );
00130 QFrame *page = plainPage();
00131 QVBoxLayout *topLayout = new QVBoxLayout( page, marginHint(), spacingHint() );
00132
00133 QGroupBox *groupBox = new QGroupBox( i18n( "Search for Addresses in Directory" ),
00134 page );
00135 groupBox->setFrameShape( QGroupBox::Box );
00136 groupBox->setFrameShadow( QGroupBox::Sunken );
00137 groupBox->setColumnLayout( 0, Qt::Vertical );
00138 QGridLayout *boxLayout = new QGridLayout( groupBox->layout(), 2,
00139 5, spacingHint() );
00140 boxLayout->setColStretch( 1, 1 );
00141
00142 QLabel *label = new QLabel( i18n( "Search for:" ), groupBox );
00143 boxLayout->addWidget( label, 0, 0 );
00144
00145 mSearchEdit = new KLineEdit( groupBox );
00146 boxLayout->addWidget( mSearchEdit, 0, 1 );
00147 label->setBuddy( mSearchEdit );
00148
00149 label = new QLabel( i18n( "in" ), groupBox );
00150 boxLayout->addWidget( label, 0, 2 );
00151
00152 mFilterCombo = new KComboBox( groupBox );
00153 mFilterCombo->insertItem( i18n( "Name" ) );
00154 mFilterCombo->insertItem( i18n( "Email" ) );
00155 mFilterCombo->insertItem( i18n( "Home Number" ) );
00156 mFilterCombo->insertItem( i18n( "Work Number" ) );
00157 boxLayout->addWidget( mFilterCombo, 0, 3 );
00158
00159 QSize buttonSize;
00160 mSearchButton = new QPushButton( i18n( "Stop" ), groupBox );
00161 buttonSize = mSearchButton->sizeHint();
00162 mSearchButton->setText( i18n( "Search" ) );
00163 if ( buttonSize.width() < mSearchButton->sizeHint().width() )
00164 buttonSize = mSearchButton->sizeHint();
00165 mSearchButton->setFixedWidth( buttonSize.width() );
00166
00167 mSearchButton->setDefault( true );
00168 boxLayout->addWidget( mSearchButton, 0, 4 );
00169
00170 mRecursiveCheckbox = new QCheckBox( i18n( "Recursive search" ), groupBox );
00171 mRecursiveCheckbox->setChecked( true );
00172 boxLayout->addMultiCellWidget( mRecursiveCheckbox, 1, 1, 0, 4 );
00173
00174 mSearchType = new KComboBox( groupBox );
00175 mSearchType->insertItem( i18n( "Contains" ) );
00176 mSearchType->insertItem( i18n( "Starts With" ) );
00177 boxLayout->addMultiCellWidget( mSearchType, 1, 1, 3, 4 );
00178
00179 topLayout->addWidget( groupBox );
00180
00181 mResultListView = new QListView( page );
00182 mResultListView->setSelectionMode( QListView::Multi );
00183 mResultListView->setAllColumnsShowFocus( true );
00184 mResultListView->setShowSortIndicator( true );
00185 topLayout->addWidget( mResultListView );
00186
00187 resize( QSize( 600, 400).expandedTo( minimumSizeHint() ) );
00188
00189 setButtonText( User1, i18n( "Unselect All" ) );
00190 setButtonText( User2, i18n( "Select All" ) );
00191 setButtonText( User3, i18n( "Add Selected" ) );
00192
00193 mNumHosts = 0;
00194 mIsOK = false;
00195
00196 connect( mRecursiveCheckbox, SIGNAL( toggled( bool ) ),
00197 this, SLOT( slotSetScope( bool ) ) );
00198 connect( mSearchButton, SIGNAL( clicked() ),
00199 this, SLOT( slotStartSearch() ) );
00200
00201 setTabOrder(mSearchEdit, mFilterCombo);
00202 setTabOrder(mFilterCombo, mSearchButton);
00203 mSearchEdit->setFocus();
00204
00205 restoreSettings();
00206 }
00207
00208 LDAPSearchDialog::~LDAPSearchDialog()
00209 {
00210 saveSettings();
00211 }
00212
00213 void LDAPSearchDialog::restoreSettings()
00214 {
00215
00216
00217
00218
00219 mLdapClientList.setAutoDelete( true );
00220 mLdapClientList.clear();
00221
00222 KConfig kabConfig( "kaddressbookrc" );
00223 kabConfig.setGroup( "LDAPSearch" );
00224 mSearchType->setCurrentItem( kabConfig.readNumEntry( "SearchType", 0 ) );
00225
00226
00227
00228 KConfig* config = KABC::AddressLineEdit::config();
00229 KConfigGroupSaver saver( config, "LDAP" );
00230 mNumHosts = config->readUnsignedNumEntry( "NumSelectedHosts" );
00231 if ( !mNumHosts ) {
00232 KMessageBox::error( this, i18n( "You must select a LDAP server before searching.\nYou can do this from the menu Settings/Configure KAddressBook." ) );
00233 mIsOK = false;
00234 } else {
00235 mIsOK = true;
00236 for ( int j = 0; j < mNumHosts; ++j ) {
00237 KPIM::LdapServer ldapServer;
00238
00239 QString host = config->readEntry( QString( "SelectedHost%1" ).arg( j ), "" );
00240 if ( !host.isEmpty() )
00241 ldapServer.setHost( host );
00242
00243 int port = config->readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) );
00244 if ( port )
00245 ldapServer.setPort( port );
00246
00247 QString base = config->readEntry( QString( "SelectedBase%1" ).arg( j ), "" );
00248 if ( !base.isEmpty() )
00249 ldapServer.setBaseDN( base );
00250
00251 QString bindDN = config->readEntry( QString( "SelectedBind%1" ).arg( j ), "" );
00252 if ( !bindDN.isEmpty() )
00253 ldapServer.setBindDN( bindDN );
00254
00255 QString pwdBindDN = config->readEntry( QString( "SelectedPwdBind%1" ).arg( j ), "" );
00256 if ( !pwdBindDN.isEmpty() )
00257 ldapServer.setPwdBindDN( pwdBindDN );
00258
00259 KPIM::LdapClient* ldapClient = new KPIM::LdapClient( 0, this, "ldapclient" );
00260 ldapClient->setServer( ldapServer );
00261
00262 QStringList attrs;
00263
00264 for ( QMap<QString,QString>::Iterator it = adrbookattr2ldap().begin(); it != adrbookattr2ldap().end(); ++it )
00265 attrs << *it;
00266
00267 ldapClient->setAttrs( attrs );
00268
00269 connect( ldapClient, SIGNAL( result( const KPIM::LdapObject& ) ),
00270 this, SLOT( slotAddResult( const KPIM::LdapObject& ) ) );
00271 connect( ldapClient, SIGNAL( done() ),
00272 this, SLOT( slotSearchDone() ) );
00273 connect( ldapClient, SIGNAL( error( const QString& ) ),
00274 this, SLOT( slotError( const QString& ) ) );
00275
00276 mLdapClientList.append( ldapClient );
00277 }
00278
00280 while ( mResultListView->header()->count() > 0 ) {
00281 mResultListView->removeColumn(0);
00282 }
00283
00284 mResultListView->addColumn( i18n( "Full Name" ) );
00285 mResultListView->addColumn( i18n( "Email" ) );
00286 mResultListView->addColumn( i18n( "Home Number" ) );
00287 mResultListView->addColumn( i18n( "Work Number" ) );
00288 mResultListView->addColumn( i18n( "Mobile Number" ) );
00289 mResultListView->addColumn( i18n( "Fax Number" ) );
00290 mResultListView->addColumn( i18n( "Company" ) );
00291 mResultListView->addColumn( i18n( "Organization" ) );
00292 mResultListView->addColumn( i18n( "Street" ) );
00293 mResultListView->addColumn( i18n( "State" ) );
00294 mResultListView->addColumn( i18n( "Country" ) );
00295 mResultListView->addColumn( i18n( "Zip Code" ) );
00296 mResultListView->addColumn( i18n( "Postal Address" ) );
00297 mResultListView->addColumn( i18n( "City" ) );
00298 mResultListView->addColumn( i18n( "Department" ) );
00299 mResultListView->addColumn( i18n( "Description" ) );
00300 mResultListView->addColumn( i18n( "User ID" ) );
00301 mResultListView->addColumn( i18n( "Title" ) );
00302
00303 mResultListView->clear();
00304 }
00305 }
00306
00307 void LDAPSearchDialog::saveSettings()
00308 {
00309 KConfig config( "kaddressbookrc" );
00310 config.setGroup( "LDAPSearch" );
00311 config.writeEntry( "SearchType", mSearchType->currentItem() );
00312 config.sync();
00313 }
00314
00315 void LDAPSearchDialog::cancelQuery()
00316 {
00317 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00318 client->cancelQuery();
00319 }
00320 }
00321
00322 void LDAPSearchDialog::slotAddResult( const KPIM::LdapObject& obj )
00323 {
00324 new ContactListItem( mResultListView, obj.attrs );
00325 }
00326
00327 void LDAPSearchDialog::slotSetScope( bool rec )
00328 {
00329 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00330 if ( rec )
00331 client->setScope( "sub" );
00332 else
00333 client->setScope( "one" );
00334 }
00335 }
00336
00337 QString LDAPSearchDialog::makeFilter( const QString& query, const QString& attr,
00338 bool startsWith )
00339 {
00340
00341
00342
00343
00344
00345
00346 QString result( "&(|(objectclass=person)(objectclass=groupofnames)(mail=*))(" );
00347 if( query.isEmpty() )
00348
00349 return result + "|(cn=*)(sn=*)" + ")";
00350
00351 if ( attr == i18n( "Name" ) ) {
00352 result += startsWith ? "|(cn=%1*)(sn=%2*)" : "|(cn=*%1*)(sn=*%2*)";
00353 result = result.arg( query ).arg( query );
00354 } else {
00355 result += (startsWith ? "%1=%2*" : "%1=*%2*");
00356 if ( attr == i18n( "Email" ) ) {
00357 result = result.arg( "mail" ).arg( query );
00358 } else if ( attr == i18n( "Home Number" ) ) {
00359 result = result.arg( "homePhone" ).arg( query );
00360 } else if ( attr == i18n( "Work Number" ) ) {
00361 result = result.arg( "telephoneNumber" ).arg( query );
00362 } else {
00363
00364 result = QString::null;
00365 return result;
00366 }
00367 }
00368 result += ")";
00369 return result;
00370 }
00371
00372 void LDAPSearchDialog::slotStartSearch()
00373 {
00374 cancelQuery();
00375
00376 QApplication::setOverrideCursor( Qt::waitCursor );
00377 mSearchButton->setText( i18n( "Stop" ) );
00378
00379 disconnect( mSearchButton, SIGNAL( clicked() ),
00380 this, SLOT( slotStartSearch() ) );
00381 connect( mSearchButton, SIGNAL( clicked() ),
00382 this, SLOT( slotStopSearch() ) );
00383
00384 bool startsWith = (mSearchType->currentItem() == 1);
00385
00386 QString filter = makeFilter( mSearchEdit->text().stripWhiteSpace(), mFilterCombo->currentText(), startsWith );
00387
00388
00389 mResultListView->clear();
00390 for( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00391 client->startQuery( filter );
00392 }
00393
00394 saveSettings();
00395 }
00396
00397 void LDAPSearchDialog::slotStopSearch()
00398 {
00399 cancelQuery();
00400 slotSearchDone();
00401 }
00402
00403 void LDAPSearchDialog::slotSearchDone()
00404 {
00405
00406 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00407 if ( client->isActive() )
00408 return;
00409 }
00410
00411 disconnect( mSearchButton, SIGNAL( clicked() ),
00412 this, SLOT( slotStopSearch() ) );
00413 connect( mSearchButton, SIGNAL( clicked() ),
00414 this, SLOT( slotStartSearch() ) );
00415
00416 mSearchButton->setText( i18n( "Search" ) );
00417 QApplication::restoreOverrideCursor();
00418 }
00419
00420 void LDAPSearchDialog::slotError( const QString& error )
00421 {
00422 QApplication::restoreOverrideCursor();
00423 KMessageBox::error( this, error );
00424 }
00425
00426 void LDAPSearchDialog::closeEvent( QCloseEvent* e )
00427 {
00428 slotStopSearch();
00429 e->accept();
00430 }
00431
00436 QString LDAPSearchDialog::selectedEMails() const
00437 {
00438 QStringList result;
00439 ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00440 while ( cli ) {
00441 if ( cli->isSelected() ) {
00442 QString email = asUtf8( cli->mAttrs[ "mail" ].first() ).stripWhiteSpace();
00443 if ( !email.isEmpty() ) {
00444 QString name = asUtf8( cli->mAttrs[ "cn" ].first() ).stripWhiteSpace();
00445 if ( name.isEmpty() ) {
00446 result << email;
00447 } else {
00448 result << name + " <" + email + ">";
00449 }
00450 }
00451 }
00452 cli = static_cast<ContactListItem*>( cli->nextSibling() );
00453 }
00454
00455 return result.join( ", " );
00456 }
00457
00458 void LDAPSearchDialog::slotHelp()
00459 {
00460 kapp->invokeHelp( "ldap-queries" );
00461 }
00462
00463 void LDAPSearchDialog::slotUser1()
00464 {
00465 mResultListView->selectAll( false );
00466 }
00467
00468 void LDAPSearchDialog::slotUser2()
00469 {
00470 mResultListView->selectAll( true );
00471 }
00472
00473 void LDAPSearchDialog::slotUser3()
00474 {
00475 emit addresseesAdded();
00476 }
00477
00478 #include "ldapsearchdialog.moc"