10#include "ldapsearchdialog.h"
12#include <KLDAPCore/LdapClient>
14#include <KLDAPCore/LdapClientSearchConfig>
15#include <KLDAPCore/LdapSearchClientReadConfigServerJob>
16#include <KLineEditEventHandler>
17#include <Libkdepim/ProgressIndicatorLabel>
19#include <QApplication>
32#include <QSortFilterProxyModel>
36#include <KCMultiDialog>
38#include <KConfigGroup>
40#include <KPluginMetaData>
42#include <QDialogButtonBox>
44#include <kldapcore/ldapobject.h>
45#include <kldapcore/ldapserver.h>
47#include <KConfigGroup>
49#include <KLocalizedString>
50#include <QDialogButtonBox>
60 const char *data = val.
data();
63 if (data[val.
size() - 1] ==
'\0') {
70static QString join(
const KLDAPCore::LdapAttrValue &lst,
const QString &sep)
74 KLDAPCore::LdapAttrValue::ConstIterator
end(lst.constEnd());
75 for (KLDAPCore::LdapAttrValue::ConstIterator it = lst.constBegin(); it != end; ++it) {
92 keys[
i18nc(
"@item LDAP search key",
"Title")] = QStringLiteral(
"title");
93 keys[
i18n(
"Full Name")] = QStringLiteral(
"cn");
94 keys[
i18nc(
"@item LDAP search key",
"Email")] = QStringLiteral(
"mail");
95 keys[
i18n(
"Home Number")] = QStringLiteral(
"homePhone");
96 keys[
i18n(
"Work Number")] = QStringLiteral(
"telephoneNumber");
97 keys[
i18n(
"Mobile Number")] = QStringLiteral(
"mobile");
98 keys[
i18n(
"Fax Number")] = QStringLiteral(
"facsimileTelephoneNumber");
99 keys[
i18n(
"Pager")] = QStringLiteral(
"pager");
100 keys[
i18n(
"Street")] = QStringLiteral(
"street");
101 keys[
i18nc(
"@item LDAP search key",
"State")] = QStringLiteral(
"st");
102 keys[
i18n(
"Country")] = QStringLiteral(
"co");
103 keys[
i18n(
"City")] = QStringLiteral(
"l");
104 keys[
i18n(
"Organization")] = QStringLiteral(
"o");
105 keys[
i18n(
"Company")] = QStringLiteral(
"Company");
106 keys[
i18n(
"Department")] = QStringLiteral(
"department");
107 keys[
i18n(
"Zip Code")] = QStringLiteral(
"postalCode");
108 keys[
i18n(
"Postal Address")] = QStringLiteral(
"postalAddress");
109 keys[
i18n(
"Description")] = QStringLiteral(
"description");
110 keys[
i18n(
"User ID")] = QStringLiteral(
"uid");
116static QString makeFilter(
const QString &query, LdapSearchDialog::FilterType attr,
bool startsWith)
124 QString result(QStringLiteral(
"&(|(objectclass=person)(objectclass=groupofnames)(mail=*))("));
127 return result + QStringLiteral(
"|(cn=*)(sn=*)") +
QLatin1Char(
')');
130 if (attr == LdapSearchDialog::Name) {
131 result += startsWith ? QStringLiteral(
"|(cn=%1*)(sn=%2*)") : QStringLiteral(
"|(cn=*%1*)(sn=*%2*)");
132 result = result.arg(query, query);
134 result += startsWith ? QStringLiteral(
"%1=%2*") : QStringLiteral(
"%1=*%2*");
135 if (attr == LdapSearchDialog::Email) {
136 result = result.arg(QStringLiteral(
"mail"), query);
137 }
else if (attr == LdapSearchDialog::HomeNumber) {
138 result = result.arg(QStringLiteral(
"homePhone"), query);
139 }
else if (attr == LdapSearchDialog::WorkNumber) {
140 result = result.arg(QStringLiteral(
"telephoneNumber"), query);
151static KContacts::Addressee convertLdapAttributesToAddressee(
const KLDAPCore::LdapAttrMap &attrs)
156 if (!attrs.value(QStringLiteral(
"cn")).isEmpty()) {
161 KLDAPCore::LdapAttrValue lst = attrs[QStringLiteral(
"mail")];
162 KLDAPCore::LdapAttrValue::ConstIterator it = lst.constBegin();
164 while (it != lst.constEnd()) {
166 email.setPreferred(pref);
172 if (!attrs.value(QStringLiteral(
"o")).isEmpty()) {
176 addr.
setOrganization(asUtf8(attrs[QStringLiteral(
"Company")].first()));
182 if (!attrs.value(QStringLiteral(
"department")).isEmpty()) {
183 addr.
setDepartment(asUtf8(attrs[QStringLiteral(
"department")].first()));
186 if (!workAddr.isEmpty()) {
191 if (!attrs.value(QStringLiteral(
"homePhone")).isEmpty()) {
197 if (!attrs.value(QStringLiteral(
"telephoneNumber")).isEmpty()) {
203 if (!attrs.value(QStringLiteral(
"facsimileTelephoneNumber")).isEmpty()) {
209 if (!attrs.value(QStringLiteral(
"mobile")).isEmpty()) {
215 if (!attrs.value(QStringLiteral(
"pager")).isEmpty()) {
234 void addContact(
const KLDAPCore::LdapAttrMap &contact,
const QString &server)
237 mContactList.
append(contact);
238 mServerList.
append(server);
242 [[nodiscard]] QPair<KLDAPCore::LdapAttrMap, QString> contact(
const QModelIndex &
index)
const
245 return qMakePair(KLDAPCore::LdapAttrMap(),
QString());
257 return asUtf8(mContactList.
at(
index.
row()).value(QStringLiteral(
"mail")).first()).
trimmed();
266 return asUtf8(mContactList.
at(
index.
row()).value(QStringLiteral(
"cn")).first()).
trimmed();
272 mContactList.
clear();
280 return mContactList.
count();
303 return i18n(
"Full Name");
305 return i18nc(
"@title:column Column containing email addresses",
"Email");
307 return i18n(
"Home Number");
309 return i18n(
"Work Number");
311 return i18n(
"Mobile Number");
313 return i18n(
"Fax Number");
315 return i18n(
"Company");
317 return i18n(
"Organization");
319 return i18n(
"Street");
321 return i18nc(
"@title:column Column containing the residential state of the address",
"State");
323 return i18n(
"Country");
325 return i18n(
"Zip Code");
327 return i18n(
"Postal Address");
331 return i18n(
"Department");
333 return i18n(
"Description");
335 return i18n(
"User ID");
337 return i18nc(
"@title:column Column containing title of the person",
"Title");
353 if (role == ServerRole) {
361 const KLDAPCore::LdapAttrMap
map = mContactList.
at(
index.
row());
365 return join(
map.value(QStringLiteral(
"cn")), QStringLiteral(
", "));
367 return join(
map.value(QStringLiteral(
"mail")), QStringLiteral(
", "));
369 return join(
map.value(QStringLiteral(
"homePhone")), QStringLiteral(
", "));
371 return join(
map.value(QStringLiteral(
"telephoneNumber")), QStringLiteral(
", "));
373 return join(
map.value(QStringLiteral(
"mobile")), QStringLiteral(
", "));
375 return join(
map.value(QStringLiteral(
"facsimileTelephoneNumber")), QStringLiteral(
", "));
377 return join(
map.value(QStringLiteral(
"Company")), QStringLiteral(
", "));
379 return join(
map.value(QStringLiteral(
"o")), QStringLiteral(
", "));
381 return join(
map.value(QStringLiteral(
"street")), QStringLiteral(
", "));
383 return join(
map.value(QStringLiteral(
"st")), QStringLiteral(
", "));
385 return join(
map.value(QStringLiteral(
"co")), QStringLiteral(
", "));
387 return join(
map.value(QStringLiteral(
"postalCode")), QStringLiteral(
", "));
389 return join(
map.value(QStringLiteral(
"postalAddress")), QStringLiteral(
", "));
391 return join(
map.value(QStringLiteral(
"l")), QStringLiteral(
", "));
393 return join(
map.value(QStringLiteral(
"department")), QStringLiteral(
", "));
395 return join(
map.value(QStringLiteral(
"description")), QStringLiteral(
", "));
397 return join(
map.value(QStringLiteral(
"uid")), QStringLiteral(
", "));
399 return join(
map.value(QStringLiteral(
"title")), QStringLiteral(
", "));
422 const QModelIndexList selected = mResultView->selectionModel()->selectedRows();
423 const int numberOfSelectedElement(selected.count());
424 contacts.
reserve(numberOfSelectedElement);
425 for (
int i = 0; i < numberOfSelectedElement; ++i) {
426 contacts.
append(mModel->contact(sortproxy->mapToSource(selected.at(i))));
433 void restoreSettings();
437 void slotSetScope(
bool);
438 void slotStartSearch();
439 void slotStopSearch();
440 void slotSearchDone();
441 void slotError(
const QString &);
442 void slotSelectAll();
443 void slotUnselectAll();
444 void slotSelectionChanged();
451 bool mIsConfigured =
false;
461 ContactListModel *mModel =
nullptr;
470 , d(new LdapSearchDialogPrivate(this))
485 d->user1Button->setDefault(
true);
488 auto page =
new QFrame(
this);
489 mainLayout->addWidget(page);
490 mainLayout->addWidget(buttonBox);
493 topLayout->setContentsMargins({});
495 auto groupBox =
new QGroupBox(
i18n(
"Search for Addresses in Directory"), page);
497 groupBox->setLayout(boxLayout);
498 boxLayout->setColumnStretch(1, 1);
500 auto label =
new QLabel(
i18nc(
"@label:textbox",
"Search for:"), groupBox);
501 boxLayout->addWidget(label, 0, 0);
503 d->mSearchEdit =
new QLineEdit(groupBox);
504 d->mSearchEdit->setClearButtonEnabled(
true);
505 boxLayout->addWidget(d->mSearchEdit, 0, 1);
506 label->setBuddy(d->mSearchEdit);
508 label =
new QLabel(
i18nc(
"In LDAP attribute",
"in"), groupBox);
509 boxLayout->addWidget(label, 0, 2);
511 d->mFilterCombo =
new QComboBox(groupBox);
513 d->mFilterCombo->addItem(
i18nc(
"@item:inlistbox email address of the contact",
"Email"),
QVariant::fromValue(Email));
516 boxLayout->addWidget(d->mFilterCombo, 0, 3);
517 d->startSearchGuiItem =
KGuiItem(
i18nc(
"@action:button Start searching",
"&Search"), QStringLiteral(
"edit-find"));
524 buttonSize = d->mSearchButton->sizeHint();
525 if (buttonSize.
width() < d->mSearchButton->sizeHint().width()) {
526 buttonSize = d->mSearchButton->sizeHint();
528 d->mSearchButton->setFixedWidth(buttonSize.
width());
530 d->mSearchButton->setDefault(
true);
531 boxLayout->addWidget(d->mSearchButton, 0, 4);
533 d->mRecursiveCheckbox =
new QCheckBox(
i18nc(
"@option:check",
"Recursive search"), groupBox);
534 d->mRecursiveCheckbox->setChecked(
true);
535 boxLayout->addWidget(d->mRecursiveCheckbox, 1, 0, 1, 5);
537 d->mSearchType =
new QComboBox(groupBox);
538 d->mSearchType->addItem(
i18n(
"Contains"));
539 d->mSearchType->addItem(
i18n(
"Starts With"));
540 boxLayout->addWidget(d->mSearchType, 1, 3, 1, 2);
542 topLayout->addWidget(groupBox);
548 d->searchLine->setClearButtonEnabled(
true);
549 d->searchLine->setPlaceholderText(
i18nc(
"@info:placeholder",
"Search in result"));
550 quickSearchLineLayout->addWidget(d->searchLine);
551 topLayout->addLayout(quickSearchLineLayout);
556 d->mModel =
new ContactListModel(d->mResultView);
559 d->sortproxy->setFilterKeyColumn(-1);
560 d->sortproxy->setSourceModel(d->mModel);
564 d->mResultView->setModel(d->sortproxy);
565 d->mResultView->verticalHeader()->hide();
566 d->mResultView->setSortingEnabled(
true);
567 d->mResultView->horizontalHeader()->setSortIndicatorShown(
true);
569 d->slotSelectionChanged();
571 topLayout->addWidget(d->mResultView);
578 topLayout->addLayout(buttonLayout);
581 buttonLayout->addWidget(d->progressIndication);
590 d->slotUnselectAll();
593 buttonLayout->addWidget(buttons);
595 d->user1Button->setText(
i18n(
"Add Selected"));
596 user2Button->setText(
i18n(
"Configure LDAP Servers..."));
599 d->slotSetScope(state);
601 connect(d->mSearchButton, SIGNAL(clicked()),
this, SLOT(slotStartSearch()));
605 d->mSearchEdit->setFocus();
607 d->slotSelectionChanged();
608 d->restoreSettings();
618 d->mSearchEdit->setText(text);
623 return d->mSelectedContacts;
626void LdapSearchDialog::slotCustomContextMenuRequested(
const QPoint &pos)
639void LdapSearchDialog::LdapSearchDialogPrivate::slotSelectionChanged()
644void LdapSearchDialog::LdapSearchDialogPrivate::restoreSettings()
650 qDeleteAll(mLdapClientList);
651 mLdapClientList.clear();
653 KConfig *config = KLDAPCore::LdapClientSearchConfig::config();
655 KConfigGroup searchGroup(config, QStringLiteral(
"LDAPSearch"));
656 mSearchType->setCurrentIndex(searchGroup.readEntry(
"SearchType", 0));
661 mNumHosts = group.readEntry(
"NumSelectedHosts", 0);
663 mIsConfigured =
false;
665 mIsConfigured =
true;
666 auto clientSearchConfig =
new KLDAPCore::LdapClientSearchConfig;
667 for (
int j = 0; j < mNumHosts; ++j) {
669 auto job =
new KLDAPCore::LdapSearchClientReadConfigServerJob(q);
670 job->setCurrentIndex(j);
671 job->setActive(
true);
672 job->setConfig(group);
673 job->setLdapClient(ldapClient);
682 ldapClient->setAttributes(attrs);
687 q->connect(ldapClient, SIGNAL(
done()), q, SLOT(slotSearchDone()));
692 mLdapClientList.append(ldapClient);
694 delete clientSearchConfig;
698 KConfigGroup groupHeader(config, QStringLiteral(
"Headers"));
699 mResultView->horizontalHeader()->restoreState(groupHeader.readEntry(
"HeaderState",
QByteArray()));
702 const QSize dialogSize = groupSize.readEntry(
"Size",
QSize());
704 q->resize(dialogSize);
706 q->resize(
QSize(600, 400).expandedTo(q->minimumSizeHint()));
710void LdapSearchDialog::LdapSearchDialogPrivate::saveSettings()
712 KConfig *config = KLDAPCore::LdapClientSearchConfig::config();
713 KConfigGroup group(config, QStringLiteral(
"LDAPSearch"));
714 group.writeEntry(
"SearchType", mSearchType->currentIndex());
716 KConfigGroup groupHeader(config, QStringLiteral(
"Headers"));
717 groupHeader.writeEntry(
"HeaderState", mResultView->horizontalHeader()->saveState());
721 size.writeEntry(
"Size", q->size());
727void LdapSearchDialog::LdapSearchDialogPrivate::cancelQuery()
730 client->cancelQuery();
739void LdapSearchDialog::LdapSearchDialogPrivate::slotSetScope(
bool rec)
743 client->
setScope(QStringLiteral(
"sub"));
745 client->
setScope(QStringLiteral(
"one"));
750void LdapSearchDialog::LdapSearchDialogPrivate::slotStartSearch()
754 if (!mIsConfigured) {
762 progressIndication->start();
764 q->disconnect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStartSearch()));
765 q->connect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStopSearch()));
767 const bool startsWith = (mSearchType->currentIndex() == 1);
769 const QString filter = makeFilter(mSearchEdit->text().trimmed(), mFilterCombo->currentData().value<FilterType>(), startsWith);
780void LdapSearchDialog::LdapSearchDialogPrivate::slotStopSearch()
786void LdapSearchDialog::LdapSearchDialogPrivate::slotSearchDone()
795 q->disconnect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStopSearch()));
796 q->connect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStartSearch()));
799 progressIndication->stop();
803void LdapSearchDialog::LdapSearchDialogPrivate::slotError(
const QString &error)
815void LdapSearchDialog::LdapSearchDialogPrivate::slotUnselectAll()
817 mResultView->clearSelection();
818 slotSelectionChanged();
821void LdapSearchDialog::LdapSearchDialogPrivate::slotSelectAll()
823 mResultView->selectAll();
824 slotSelectionChanged();
827void LdapSearchDialog::slotUser1()
831 d->mSelectedContacts.clear();
838 for (
int i = 0; i < items.
count(); ++i) {
842 contact.
setNote(
i18nc(
"arguments are host name, datetime",
843 "Imported from LDAP directory %1 on %2",
847 d->mSelectedContacts.append(contact);
857void LdapSearchDialog::slotUser2()
862 dialog->setWindowTitle(
i18nc(
"@title:window",
"Configure the Address Book LDAP Settings"));
863 dialog->addModule(
KPluginMetaData(QStringLiteral(
"pim6/kcms/kaddressbook/kcm_ldap")));
865 if (dialog->exec()) {
866 d->restoreSettings();
871void LdapSearchDialog::slotCancelClicked()
877#include "moc_ldapsearchdialog.cpp"
static void assign(QPushButton *button, const KGuiItem &item)
void startQuery(const QString &filter)
const KLDAPCore::LdapServer server() const
void error(const QString &message)
void setScope(const QString &scope)
const LdapAttrMap & attributes() const
A dialog to search contacts in a LDAP directory.
void contactsAdded()
This signal is emitted whenever the user clicked the 'Add Selected' button.
LdapSearchDialog(QWidget *parent=nullptr)
Creates a new ldap search dialog.
KContacts::Addressee::List selectedContacts() const
Returns a list of contacts that have been selected in the LDAP search.
void setSearchText(const QString &text)
Sets the text in the search line edit.
~LdapSearchDialog() override
Destroys the ldap search dialog.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void catchReturnKey(QObject *lineEdit)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & end()
void clicked(const QModelIndex &index)
QItemSelectionModel * selectionModel() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
void addStretch(int stretch)
bool isEmpty() const const
qsizetype size() const const
void setText(const QString &text, Mode mode)
QDateTime currentDateTime()
void setModal(bool modal)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
bool hasSelection() const const
void setContentsMargins(const QMargins &margins)
void textChanged(const QString &text)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
void reserve(qsizetype size)
bool isEmpty() const const
QVariant data(int role) const const
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
bool isValid() const const
void setFilterFixedString(const QString &pattern)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString trimmed() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QVariant fromValue(T &&value)
QString toString() const const