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::FilterType::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::FilterType::Email) {
136 result = result.arg(QStringLiteral(
"mail"), query);
137 }
else if (attr == LdapSearchDialog::FilterType::HomeNumber) {
138 result = result.arg(QStringLiteral(
"homePhone"), query);
139 }
else if (attr == LdapSearchDialog::FilterType::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()) {
236 void addContact(
const KLDAPCore::LdapAttrMap &contact,
const QString &server)
239 mContactList.
append(contact);
240 mServerList.
append(server);
244 [[nodiscard]] QPair<KLDAPCore::LdapAttrMap, QString> contact(
const QModelIndex &
index)
const
247 return qMakePair(KLDAPCore::LdapAttrMap(),
QString());
259 return asUtf8(mContactList.
at(
index.
row()).value(QStringLiteral(
"mail")).first()).
trimmed();
268 return asUtf8(mContactList.
at(
index.
row()).value(QStringLiteral(
"cn")).first()).
trimmed();
274 mContactList.
clear();
282 return mContactList.
count();
305 return i18n(
"Full Name");
307 return i18nc(
"@title:column Column containing email addresses",
"Email");
309 return i18n(
"Home Number");
311 return i18n(
"Work Number");
313 return i18n(
"Mobile Number");
315 return i18n(
"Fax Number");
317 return i18n(
"Company");
319 return i18n(
"Organization");
321 return i18n(
"Street");
323 return i18nc(
"@title:column Column containing the residential state of the address",
"State");
325 return i18n(
"Country");
327 return i18n(
"Zip Code");
329 return i18n(
"Postal Address");
333 return i18n(
"Department");
335 return i18n(
"Description");
337 return i18n(
"User ID");
339 return i18nc(
"@title:column Column containing title of the person",
"Title");
355 if (role == ServerRole) {
363 const KLDAPCore::LdapAttrMap
map = mContactList.
at(
index.
row());
367 return join(
map.value(QStringLiteral(
"cn")), QStringLiteral(
", "));
369 return join(
map.value(QStringLiteral(
"mail")), QStringLiteral(
", "));
371 return join(
map.value(QStringLiteral(
"homePhone")), QStringLiteral(
", "));
373 return join(
map.value(QStringLiteral(
"telephoneNumber")), QStringLiteral(
", "));
375 return join(
map.value(QStringLiteral(
"mobile")), QStringLiteral(
", "));
377 return join(
map.value(QStringLiteral(
"facsimileTelephoneNumber")), QStringLiteral(
", "));
379 return join(
map.value(QStringLiteral(
"Company")), QStringLiteral(
", "));
381 return join(
map.value(QStringLiteral(
"o")), QStringLiteral(
", "));
383 return join(
map.value(QStringLiteral(
"street")), QStringLiteral(
", "));
385 return join(
map.value(QStringLiteral(
"st")), QStringLiteral(
", "));
387 return join(
map.value(QStringLiteral(
"co")), QStringLiteral(
", "));
389 return join(
map.value(QStringLiteral(
"postalCode")), QStringLiteral(
", "));
391 return join(
map.value(QStringLiteral(
"postalAddress")), QStringLiteral(
", "));
393 return join(
map.value(QStringLiteral(
"l")), QStringLiteral(
", "));
395 return join(
map.value(QStringLiteral(
"department")), QStringLiteral(
", "));
397 return join(
map.value(QStringLiteral(
"description")), QStringLiteral(
", "));
399 return join(
map.value(QStringLiteral(
"uid")), QStringLiteral(
", "));
401 return join(
map.value(QStringLiteral(
"title")), QStringLiteral(
", "));
424 const QModelIndexList selected = mResultView->selectionModel()->selectedRows();
425 const int numberOfSelectedElement(selected.count());
426 contacts.
reserve(numberOfSelectedElement);
427 for (
int i = 0; i < numberOfSelectedElement; ++i) {
428 contacts.
append(mModel->contact(sortproxy->mapToSource(selected.at(i))));
435 void restoreSettings();
439 void slotSetScope(
bool);
440 void slotStartSearch();
441 void slotStopSearch();
442 void slotSearchDone();
443 void slotError(
const QString &);
444 void slotSelectAll();
445 void slotUnselectAll();
446 void slotSelectionChanged();
453 bool mIsConfigured =
false;
463 ContactListModel *mModel =
nullptr;
472 , d(new LdapSearchDialogPrivate(this))
487 d->user1Button->setDefault(
true);
490 auto page =
new QFrame(
this);
491 mainLayout->addWidget(page);
492 mainLayout->addWidget(buttonBox);
495 topLayout->setContentsMargins({});
497 auto groupBox =
new QGroupBox(
i18n(
"Search for Addresses in Directory"), page);
499 groupBox->setLayout(boxLayout);
500 boxLayout->setColumnStretch(1, 1);
502 auto label =
new QLabel(
i18nc(
"@label:textbox",
"Search for:"), groupBox);
503 boxLayout->addWidget(label, 0, 0);
505 d->mSearchEdit =
new QLineEdit(groupBox);
506 d->mSearchEdit->setClearButtonEnabled(
true);
507 boxLayout->addWidget(d->mSearchEdit, 0, 1);
508 label->setBuddy(d->mSearchEdit);
510 label =
new QLabel(
i18nc(
"In LDAP attribute",
"in"), groupBox);
511 boxLayout->addWidget(label, 0, 2);
513 d->mFilterCombo =
new QComboBox(groupBox);
514 d->mFilterCombo->addItem(
i18nc(
"@item:inlistbox Name of the contact",
"Name"),
QVariant::fromValue(FilterType::Name));
515 d->mFilterCombo->addItem(
i18nc(
"@item:inlistbox email address of the contact",
"Email"),
QVariant::fromValue(FilterType::Email));
518 boxLayout->addWidget(d->mFilterCombo, 0, 3);
519 d->startSearchGuiItem =
KGuiItem(
i18nc(
"@action:button Start searching",
"&Search"), QStringLiteral(
"edit-find"));
526 buttonSize = d->mSearchButton->sizeHint();
527 if (buttonSize.
width() < d->mSearchButton->sizeHint().width()) {
528 buttonSize = d->mSearchButton->sizeHint();
530 d->mSearchButton->setFixedWidth(buttonSize.
width());
532 d->mSearchButton->setDefault(
true);
533 boxLayout->addWidget(d->mSearchButton, 0, 4);
535 d->mRecursiveCheckbox =
new QCheckBox(
i18nc(
"@option:check",
"Recursive search"), groupBox);
536 d->mRecursiveCheckbox->setChecked(
true);
537 boxLayout->addWidget(d->mRecursiveCheckbox, 1, 0, 1, 5);
539 d->mSearchType =
new QComboBox(groupBox);
540 d->mSearchType->addItem(
i18n(
"Contains"));
541 d->mSearchType->addItem(
i18n(
"Starts With"));
542 boxLayout->addWidget(d->mSearchType, 1, 3, 1, 2);
544 topLayout->addWidget(groupBox);
550 d->searchLine->setClearButtonEnabled(
true);
551 d->searchLine->setPlaceholderText(
i18nc(
"@info:placeholder",
"Search in result"));
552 quickSearchLineLayout->addWidget(d->searchLine);
553 topLayout->addLayout(quickSearchLineLayout);
558 d->mModel =
new ContactListModel(d->mResultView);
561 d->sortproxy->setFilterKeyColumn(-1);
562 d->sortproxy->setSourceModel(d->mModel);
566 d->mResultView->setModel(d->sortproxy);
567 d->mResultView->verticalHeader()->hide();
568 d->mResultView->setSortingEnabled(
true);
569 d->mResultView->horizontalHeader()->setSortIndicatorShown(
true);
571 d->slotSelectionChanged();
573 topLayout->addWidget(d->mResultView);
580 topLayout->addLayout(buttonLayout);
583 buttonLayout->addWidget(d->progressIndication);
592 d->slotUnselectAll();
595 buttonLayout->addWidget(buttons);
597 d->user1Button->setText(
i18n(
"Add Selected"));
598 user2Button->setText(
i18n(
"Configure LDAP Servers..."));
601 d->slotSetScope(state);
603 connect(d->mSearchButton, SIGNAL(clicked()),
this, SLOT(slotStartSearch()));
607 d->mSearchEdit->setFocus();
609 d->slotSelectionChanged();
610 d->restoreSettings();
620 d->mSearchEdit->setText(text);
625 return d->mSelectedContacts;
628void LdapSearchDialog::slotCustomContextMenuRequested(
const QPoint &pos)
641void LdapSearchDialog::LdapSearchDialogPrivate::slotSelectionChanged()
646void LdapSearchDialog::LdapSearchDialogPrivate::restoreSettings()
652 qDeleteAll(mLdapClientList);
653 mLdapClientList.clear();
655 KConfig *config = KLDAPCore::LdapClientSearchConfig::config();
657 KConfigGroup searchGroup(config, QStringLiteral(
"LDAPSearch"));
658 mSearchType->setCurrentIndex(searchGroup.readEntry(
"SearchType", 0));
663 mNumHosts = group.readEntry(
"NumSelectedHosts", 0);
665 mIsConfigured =
false;
667 mIsConfigured =
true;
668 auto clientSearchConfig =
new KLDAPCore::LdapClientSearchConfig;
669 for (
int j = 0; j < mNumHosts; ++j) {
671 auto job =
new KLDAPCore::LdapSearchClientReadConfigServerJob(q);
672 job->setCurrentIndex(j);
673 job->setActive(
true);
674 job->setConfig(group);
675 job->setLdapClient(ldapClient);
684 ldapClient->setAttributes(attrs);
689 q->connect(ldapClient, SIGNAL(
done()), q, SLOT(slotSearchDone()));
694 mLdapClientList.append(ldapClient);
696 delete clientSearchConfig;
700 KConfigGroup groupHeader(config, QStringLiteral(
"Headers"));
701 mResultView->horizontalHeader()->restoreState(groupHeader.readEntry(
"HeaderState",
QByteArray()));
704 const QSize dialogSize = groupSize.readEntry(
"Size",
QSize());
706 q->resize(dialogSize);
708 q->resize(
QSize(600, 400).expandedTo(q->minimumSizeHint()));
712void LdapSearchDialog::LdapSearchDialogPrivate::saveSettings()
714 KConfig *config = KLDAPCore::LdapClientSearchConfig::config();
715 KConfigGroup group(config, QStringLiteral(
"LDAPSearch"));
716 group.writeEntry(
"SearchType", mSearchType->currentIndex());
718 KConfigGroup groupHeader(config, QStringLiteral(
"Headers"));
719 groupHeader.writeEntry(
"HeaderState", mResultView->horizontalHeader()->saveState());
723 size.writeEntry(
"Size", q->size());
729void LdapSearchDialog::LdapSearchDialogPrivate::cancelQuery()
732 client->cancelQuery();
741void LdapSearchDialog::LdapSearchDialogPrivate::slotSetScope(
bool rec)
745 client->
setScope(QStringLiteral(
"sub"));
747 client->
setScope(QStringLiteral(
"one"));
752void LdapSearchDialog::LdapSearchDialogPrivate::slotStartSearch()
756 if (!mIsConfigured) {
764 progressIndication->start();
766 q->disconnect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStartSearch()));
767 q->connect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStopSearch()));
769 const bool startsWith = (mSearchType->currentIndex() == 1);
771 const QString filter = makeFilter(mSearchEdit->text().trimmed(), mFilterCombo->currentData().value<FilterType>(), startsWith);
782void LdapSearchDialog::LdapSearchDialogPrivate::slotStopSearch()
788void LdapSearchDialog::LdapSearchDialogPrivate::slotSearchDone()
797 q->disconnect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStopSearch()));
798 q->connect(mSearchButton, SIGNAL(clicked()), q, SLOT(slotStartSearch()));
801 progressIndication->stop();
805void LdapSearchDialog::LdapSearchDialogPrivate::slotError(
const QString &error)
817void LdapSearchDialog::LdapSearchDialogPrivate::slotUnselectAll()
819 mResultView->clearSelection();
820 slotSelectionChanged();
823void LdapSearchDialog::LdapSearchDialogPrivate::slotSelectAll()
825 mResultView->selectAll();
826 slotSelectionChanged();
829void LdapSearchDialog::slotUser1()
833 d->mSelectedContacts.clear();
840 for (
int i = 0; i < items.
count(); ++i) {
844 contact.
setNote(
i18nc(
"arguments are host name, datetime",
845 "Imported from LDAP directory %1 on %2",
849 d->mSelectedContacts.append(contact);
859void LdapSearchDialog::slotUser2()
864 dialog->setWindowTitle(
i18nc(
"@title:window",
"Configure the Address Book LDAP Settings"));
865 dialog->addModule(
KPluginMetaData(QStringLiteral(
"pim6/kcms/kaddressbook/kcm_ldap")));
867 if (dialog->exec()) {
868 d->restoreSettings();
873void LdapSearchDialog::slotCancelClicked()
879#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