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