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 <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
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 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
00209
00210
00211
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
00220
00221 KConfig* config = KABC::AddressLineEdit::config();
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
00331
00332
00333
00334
00335
00336 QString result( "&(|(objectclass=person)(objectclass=groupofnames)(mail=*))(" );
00337 if( query.isEmpty() )
00338
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
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
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
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
00476 addr.setNameFromString( asUtf8( cli->mAttrs["cn"].first() ) );
00477
00478
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
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
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
00547 addr.setNameFromString( asUtf8( cli->mAttrs["cn"].first() ) );
00548
00549
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"