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