00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 <addresseelineedit.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
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
00109 QString colName = listView()->columnText( col );
00110 return join( mAttrs[ adrbookattr2ldap()[ colName ] ], ", " );
00111 }
00112 };
00113
00114 LDAPSearchDialog::LDAPSearchDialog( KABC::AddressBook *ab, KABCore *core,
00115 QWidget* parent, const char* name )
00116 : KDialogBase( Plain, i18n( "Search for Addresses in Directory" ), Help | User1 |
00117 User2 | User3 | Cancel, Default, parent, name, false, true ),
00118 mAddressBook( ab ), mCore( core )
00119 {
00120 setButtonCancel( KStdGuiItem::close() );
00121 QFrame *page = plainPage();
00122 QVBoxLayout *topLayout = new QVBoxLayout( page, marginHint(), spacingHint() );
00123
00124 QGroupBox *groupBox = new QGroupBox( i18n( "Search for Addresses in Directory" ),
00125 page );
00126 groupBox->setFrameShape( QGroupBox::Box );
00127 groupBox->setFrameShadow( QGroupBox::Sunken );
00128 groupBox->setColumnLayout( 0, Qt::Vertical );
00129 QGridLayout *boxLayout = new QGridLayout( groupBox->layout(), 2,
00130 5, spacingHint() );
00131 boxLayout->setColStretch( 1, 1 );
00132
00133 QLabel *label = new QLabel( i18n( "Search for:" ), groupBox );
00134 boxLayout->addWidget( label, 0, 0 );
00135
00136 mSearchEdit = new KLineEdit( groupBox );
00137 boxLayout->addWidget( mSearchEdit, 0, 1 );
00138 label->setBuddy( mSearchEdit );
00139
00140 label = new QLabel( i18n( "in" ), groupBox );
00141 boxLayout->addWidget( label, 0, 2 );
00142
00143 mFilterCombo = new KComboBox( groupBox );
00144 mFilterCombo->insertItem( i18n( "Name" ) );
00145 mFilterCombo->insertItem( i18n( "Email" ) );
00146 mFilterCombo->insertItem( i18n( "Home Number" ) );
00147 mFilterCombo->insertItem( i18n( "Work Number" ) );
00148 boxLayout->addWidget( mFilterCombo, 0, 3 );
00149
00150 QSize buttonSize;
00151 mSearchButton = new QPushButton( i18n( "Stop" ), groupBox );
00152 buttonSize = mSearchButton->sizeHint();
00153 mSearchButton->setText( i18n( "Search" ) );
00154 if ( buttonSize.width() < mSearchButton->sizeHint().width() )
00155 buttonSize = mSearchButton->sizeHint();
00156 mSearchButton->setFixedWidth( buttonSize.width() );
00157
00158 mSearchButton->setDefault( true );
00159 boxLayout->addWidget( mSearchButton, 0, 4 );
00160
00161 mRecursiveCheckbox = new QCheckBox( i18n( "Recursive search" ), groupBox );
00162 mRecursiveCheckbox->setChecked( true );
00163 boxLayout->addMultiCellWidget( mRecursiveCheckbox, 1, 1, 0, 4 );
00164
00165 mSearchType = new KComboBox( groupBox );
00166 mSearchType->insertItem( i18n( "Contains" ) );
00167 mSearchType->insertItem( i18n( "Starts With" ) );
00168 boxLayout->addMultiCellWidget( mSearchType, 1, 1, 3, 4 );
00169
00170 topLayout->addWidget( groupBox );
00171
00172 mResultListView = new QListView( page );
00173 mResultListView->setSelectionMode( QListView::Multi );
00174 mResultListView->setAllColumnsShowFocus( true );
00175 mResultListView->setShowSortIndicator( true );
00176 topLayout->addWidget( mResultListView );
00177
00178 resize( QSize( 600, 400).expandedTo( minimumSizeHint() ) );
00179
00180 setButtonText( User1, i18n( "Unselect All" ) );
00181 setButtonText( User2, i18n( "Select All" ) );
00182 setButtonText( User3, i18n( "Add Selected" ) );
00183
00184 mNumHosts = 0;
00185 mIsOK = false;
00186
00187 connect( mRecursiveCheckbox, SIGNAL( toggled( bool ) ),
00188 this, SLOT( slotSetScope( bool ) ) );
00189 connect( mSearchButton, SIGNAL( clicked() ),
00190 this, SLOT( slotStartSearch() ) );
00191
00192 setTabOrder(mSearchEdit, mFilterCombo);
00193 setTabOrder(mFilterCombo, mSearchButton);
00194 mSearchEdit->setFocus();
00195
00196 restoreSettings();
00197 }
00198
00199 LDAPSearchDialog::~LDAPSearchDialog()
00200 {
00201 saveSettings();
00202 }
00203
00204 void LDAPSearchDialog::restoreSettings()
00205 {
00206
00207
00208
00209
00210 mLdapClientList.setAutoDelete( true );
00211 mLdapClientList.clear();
00212
00213 KConfig kabConfig( "kaddressbookrc" );
00214 kabConfig.setGroup( "LDAPSearch" );
00215 mSearchType->setCurrentItem( kabConfig.readNumEntry( "SearchType", 0 ) );
00216
00217
00218
00219 KConfig* config = KPIM::AddresseeLineEdit::config();
00220 KConfigGroupSaver saver( config, "LDAP" );
00221 mNumHosts = config->readUnsignedNumEntry( "NumSelectedHosts" );
00222 if ( !mNumHosts ) {
00223 KMessageBox::error( this, i18n( "You must select a LDAP server before searching.\nYou can do this from the menu Settings/Configure KAddressBook." ) );
00224 mIsOK = false;
00225 } else {
00226 mIsOK = true;
00227 for ( int j = 0; j < mNumHosts; ++j ) {
00228 KPIM::LdapClient* ldapClient = new KPIM::LdapClient( 0, this, "ldapclient" );
00229
00230 QString host = config->readEntry( QString( "SelectedHost%1" ).arg( j ), "" );
00231 if ( !host.isEmpty() )
00232 ldapClient->setHost( host );
00233
00234 QString port = QString::number( config->readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) ) );
00235 if ( !port.isEmpty() )
00236 ldapClient->setPort( port );
00237
00238 QString base = config->readEntry( QString( "SelectedBase%1" ).arg( j ), "" );
00239 if ( !base.isEmpty() )
00240 ldapClient->setBase( base );
00241
00242 QString bindDN = config->readEntry( QString( "SelectedBind%1" ).arg( j ), "" );
00243 if ( !bindDN.isEmpty() )
00244 ldapClient->setBindDN( bindDN );
00245
00246 QString pwdBindDN = config->readEntry( QString( "SelectedPwdBind%1" ).arg( j ), "" );
00247 if ( !pwdBindDN.isEmpty() )
00248 ldapClient->setPwdBindDN( pwdBindDN );
00249
00250 QStringList attrs;
00251
00252 for ( QMap<QString,QString>::Iterator it = adrbookattr2ldap().begin(); it != adrbookattr2ldap().end(); ++it )
00253 attrs << *it;
00254
00255 ldapClient->setAttrs( attrs );
00256
00257 connect( ldapClient, SIGNAL( result( const KPIM::LdapObject& ) ),
00258 this, SLOT( slotAddResult( const KPIM::LdapObject& ) ) );
00259 connect( ldapClient, SIGNAL( done() ),
00260 this, SLOT( slotSearchDone() ) );
00261 connect( ldapClient, SIGNAL( error( const QString& ) ),
00262 this, SLOT( slotError( const QString& ) ) );
00263
00264 mLdapClientList.append( ldapClient );
00265 }
00266
00268 while ( mResultListView->header()->count() > 0 ) {
00269 mResultListView->removeColumn(0);
00270 }
00271
00272 mResultListView->addColumn( i18n( "Full Name" ) );
00273 mResultListView->addColumn( i18n( "Email" ) );
00274 mResultListView->addColumn( i18n( "Home Number" ) );
00275 mResultListView->addColumn( i18n( "Work Number" ) );
00276 mResultListView->addColumn( i18n( "Mobile Number" ) );
00277 mResultListView->addColumn( i18n( "Fax Number" ) );
00278 mResultListView->addColumn( i18n( "Company" ) );
00279 mResultListView->addColumn( i18n( "Organization" ) );
00280 mResultListView->addColumn( i18n( "Street" ) );
00281 mResultListView->addColumn( i18n( "State" ) );
00282 mResultListView->addColumn( i18n( "Country" ) );
00283 mResultListView->addColumn( i18n( "Zip Code" ) );
00284 mResultListView->addColumn( i18n( "Postal Address" ) );
00285 mResultListView->addColumn( i18n( "City" ) );
00286 mResultListView->addColumn( i18n( "Department" ) );
00287 mResultListView->addColumn( i18n( "Description" ) );
00288 mResultListView->addColumn( i18n( "User ID" ) );
00289 mResultListView->addColumn( i18n( "Title" ) );
00290
00291 mResultListView->clear();
00292 }
00293 }
00294
00295 void LDAPSearchDialog::saveSettings()
00296 {
00297 KConfig config( "kaddressbookrc" );
00298 config.setGroup( "LDAPSearch" );
00299 config.writeEntry( "SearchType", mSearchType->currentItem() );
00300 config.sync();
00301 }
00302
00303 void LDAPSearchDialog::cancelQuery()
00304 {
00305 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00306 client->cancelQuery();
00307 }
00308 }
00309
00310 void LDAPSearchDialog::slotAddResult( const KPIM::LdapObject& obj )
00311 {
00312 new ContactListItem( mResultListView, obj.attrs );
00313 }
00314
00315 void LDAPSearchDialog::slotSetScope( bool rec )
00316 {
00317 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00318 if ( rec )
00319 client->setScope( "sub" );
00320 else
00321 client->setScope( "one" );
00322 }
00323 }
00324
00325 QString LDAPSearchDialog::makeFilter( const QString& query, const QString& attr,
00326 bool startsWith )
00327 {
00328 if( query.isEmpty() )
00329
00330 return QString( "|(cn=*)(sn=*)" );
00331
00332 if ( attr == i18n( "Name" ) ) {
00333 QString result( (startsWith ? "|(cn=%1*)(sn=%2*)" : "|(cn=*%1*)(sn=*%2*)") );
00334
00335 result = result.arg( query ).arg( query );
00336
00337 return result;
00338 } else {
00339 QString result( (startsWith ? "%1=%2*" : "%1=*%2*") );
00340
00341 if ( attr == i18n( "Email" ) ) {
00342 result = result.arg( "mail" ).arg( query );
00343 } else if ( attr == i18n( "Home Number" ) ) {
00344 result = result.arg( "homePhone" ).arg( query );
00345 } else if ( attr == i18n( "Work Number" ) ) {
00346 result = result.arg( "telephoneNumber" ).arg( query );
00347 } else {
00348
00349 result = QString::null;
00350 }
00351
00352 return result;
00353 }
00354 }
00355
00356 void LDAPSearchDialog::slotStartSearch()
00357 {
00358 cancelQuery();
00359
00360 QApplication::setOverrideCursor( Qt::waitCursor );
00361 mSearchButton->setText( i18n( "Stop" ) );
00362
00363 disconnect( mSearchButton, SIGNAL( clicked() ),
00364 this, SLOT( slotStartSearch() ) );
00365 connect( mSearchButton, SIGNAL( clicked() ),
00366 this, SLOT( slotStopSearch() ) );
00367
00368 bool startsWith = (mSearchType->currentItem() == 1);
00369
00370 QString filter = makeFilter( mSearchEdit->text().stripWhiteSpace(), mFilterCombo->currentText(), startsWith );
00371
00372
00373 mResultListView->clear();
00374 for( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00375 client->startQuery( filter );
00376 }
00377
00378 saveSettings();
00379 }
00380
00381 void LDAPSearchDialog::slotStopSearch()
00382 {
00383 cancelQuery();
00384 slotSearchDone();
00385 }
00386
00387 void LDAPSearchDialog::slotSearchDone()
00388 {
00389
00390 for ( KPIM::LdapClient* client = mLdapClientList.first(); client; client = mLdapClientList.next() ) {
00391 if ( client->isActive() )
00392 return;
00393 }
00394
00395 disconnect( mSearchButton, SIGNAL( clicked() ),
00396 this, SLOT( slotStopSearch() ) );
00397 connect( mSearchButton, SIGNAL( clicked() ),
00398 this, SLOT( slotStartSearch() ) );
00399
00400 mSearchButton->setText( i18n( "Search" ) );
00401 QApplication::restoreOverrideCursor();
00402 }
00403
00404 void LDAPSearchDialog::slotError( const QString& error )
00405 {
00406 QApplication::restoreOverrideCursor();
00407 KMessageBox::error( this, error );
00408 }
00409
00410 void LDAPSearchDialog::closeEvent( QCloseEvent* e )
00411 {
00412 slotStopSearch();
00413 e->accept();
00414 }
00415
00420 QString LDAPSearchDialog::selectedEMails() const
00421 {
00422 QStringList result;
00423 ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00424 while ( cli ) {
00425 if ( cli->isSelected() ) {
00426 QString email = asUtf8( cli->mAttrs[ "mail" ].first() ).stripWhiteSpace();
00427 if ( !email.isEmpty() ) {
00428 QString name = asUtf8( cli->mAttrs[ "cn" ].first() ).stripWhiteSpace();
00429 if ( name.isEmpty() ) {
00430 result << email;
00431 } else {
00432 result << name + " <" + email + ">";
00433 }
00434 }
00435 }
00436 cli = static_cast<ContactListItem*>( cli->nextSibling() );
00437 }
00438
00439 return result.join( ", " );
00440 }
00441
00442 void LDAPSearchDialog::slotHelp()
00443 {
00444 kapp->invokeHelp( "ldap-queries" );
00445 }
00446
00447 void LDAPSearchDialog::slotUser1()
00448 {
00449 mResultListView->selectAll( false );
00450 }
00451
00452 void LDAPSearchDialog::slotUser2()
00453 {
00454 mResultListView->selectAll( true );
00455 }
00456
00457 void LDAPSearchDialog::slotUser3()
00458 {
00459
00460 KABC::Resource *resource = mCore->requestResource( this );
00461 if ( !resource ) return;
00462 KABLock::self( mAddressBook )->lock( resource );
00463
00464 ContactListItem* cli = static_cast<ContactListItem*>( mResultListView->firstChild() );
00465 while ( cli ) {
00466 if ( cli->isSelected() ) {
00467 KABC::Addressee addr;
00468
00469
00470 addr.setNameFromString( asUtf8( cli->mAttrs["cn"].first() ) );
00471
00472
00473 KPIM::LdapAttrValue lst = cli->mAttrs["mail"];
00474 KPIM::LdapAttrValue::ConstIterator it = lst.begin();
00475 bool pref = true;
00476 if ( it != lst.end() ) {
00477 addr.insertEmail( asUtf8( *it ), pref );
00478 pref = false;
00479 ++it;
00480 }
00481
00482 addr.setOrganization( asUtf8( cli->mAttrs[ "o" ].first() ) );
00483 if ( addr.organization().isEmpty() )
00484 addr.setOrganization( asUtf8( cli->mAttrs[ "Company" ].first() ) );
00485
00486 addr.insertCustom("KADDRESSBOOK", "X-Department", asUtf8( cli->mAttrs[ "department" ].first() ) );
00487
00488
00489 KABC::Address workAddr( KABC::Address::Work );
00490
00491 workAddr.setStreet( asUtf8( cli->mAttrs[ "street" ].first()) );
00492 workAddr.setLocality( asUtf8( cli->mAttrs[ "l" ].first()) );
00493 workAddr.setRegion( asUtf8( cli->mAttrs[ "st" ].first()));
00494 workAddr.setPostalCode( asUtf8( cli->mAttrs[ "postalCode" ].first()) );
00495 workAddr.setCountry( asUtf8( cli->mAttrs[ "co" ].first()) );
00496
00497 if ( !workAddr.isEmpty() )
00498 addr.insertAddress( workAddr );
00499
00500
00501 KABC::PhoneNumber homeNr = asUtf8( cli->mAttrs[ "homePhone" ].first() );
00502 homeNr.setType( KABC::PhoneNumber::Home );
00503 addr.insertPhoneNumber( homeNr );
00504
00505 KABC::PhoneNumber workNr = asUtf8( cli->mAttrs[ "telephoneNumber" ].first() );
00506 workNr.setType( KABC::PhoneNumber::Work );
00507 addr.insertPhoneNumber( workNr );
00508
00509 KABC::PhoneNumber faxNr = asUtf8( cli->mAttrs[ "facsimileTelephoneNumber" ].first() );
00510 faxNr.setType( KABC::PhoneNumber::Fax );
00511 addr.insertPhoneNumber( faxNr );
00512
00513 KABC::PhoneNumber cellNr = asUtf8( cli->mAttrs[ "mobile" ].first() );
00514 cellNr.setType( KABC::PhoneNumber::Cell );
00515 addr.insertPhoneNumber( cellNr );
00516
00517 KABC::PhoneNumber pagerNr = asUtf8( cli->mAttrs[ "pager" ].first() );
00518 pagerNr.setType( KABC::PhoneNumber::Pager );
00519 addr.insertPhoneNumber( pagerNr );
00520
00521 if ( mAddressBook ) {
00522 addr.setResource( resource );
00523 mAddressBook->insertAddressee( addr );
00524 }
00525 }
00526 cli = static_cast<ContactListItem*>( cli->nextSibling() );
00527 }
00528
00529 KABLock::self( mAddressBook )->unlock( resource );
00530 emit addresseesAdded();
00531 }
00532
00533 #include "ldapsearchdialog.moc"