File indexing completed on 2025-01-26 04:52:15
0001 /* kldapclient.cpp - LDAP access 0002 * SPDX-FileCopyrightText: 2002 Klarälvdalens Datakonsult AB 0003 * SPDX-FileContributor: Steffen Hansen <hansen@kde.org> 0004 * 0005 * Ported to KABC by Daniel Molkentin <molkentin@kde.org> 0006 * 0007 * SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "ldapclient.h" 0011 #include "ldapclient_debug.h" 0012 0013 #include "kldapcore/ldapobject.h" 0014 #include "kldapcore/ldapserver.h" 0015 #include "kldapcore/ldapurl.h" 0016 #include "kldapcore/ldif.h" 0017 0018 #include <KIO/TransferJob> 0019 0020 #include <QPointer> 0021 0022 using namespace KLDAPCore; 0023 using namespace KLDAPWidgets; 0024 class Q_DECL_HIDDEN LdapClient::LdapClientPrivate 0025 { 0026 public: 0027 LdapClientPrivate(LdapClient *qq) 0028 : q(qq) 0029 { 0030 } 0031 0032 ~LdapClientPrivate() 0033 { 0034 cancelQuery(); 0035 } 0036 0037 void cancelQuery(); 0038 0039 void startParseLDIF(); 0040 void parseLDIF(const QByteArray &data); 0041 void endParseLDIF(); 0042 void finishCurrentObject(); 0043 0044 void slotData(KIO::Job *, const QByteArray &data); 0045 void slotInfoMessage(KJob *, const QString &info); 0046 void slotDone(); 0047 0048 LdapClient *const q; 0049 0050 KLDAPCore::LdapServer mServer; 0051 QString mScope; 0052 QStringList mAttrs; 0053 0054 QPointer<KJob> mJob = nullptr; 0055 bool mActive = false; 0056 0057 KLDAPCore::LdapObject mCurrentObject; 0058 KLDAPCore::Ldif mLdif; 0059 int mClientNumber = 0; 0060 int mCompletionWeight = 0; 0061 }; 0062 0063 LdapClient::LdapClient(int clientNumber, QObject *parent) 0064 : QObject(parent) 0065 , d(new LdapClientPrivate(this)) 0066 { 0067 d->mClientNumber = clientNumber; 0068 d->mCompletionWeight = 50 - d->mClientNumber; 0069 } 0070 0071 LdapClient::~LdapClient() = default; 0072 0073 bool LdapClient::isActive() const 0074 { 0075 return d->mActive; 0076 } 0077 0078 void LdapClient::setServer(const KLDAPCore::LdapServer &server) 0079 { 0080 d->mServer = server; 0081 } 0082 0083 const KLDAPCore::LdapServer LdapClient::server() const 0084 { 0085 return d->mServer; 0086 } 0087 0088 void LdapClient::setAttributes(const QStringList &attrs) 0089 { 0090 d->mAttrs = attrs; 0091 d->mAttrs << QStringLiteral("objectClass"); // via objectClass we detect distribution lists 0092 } 0093 0094 QStringList LdapClient::attributes() const 0095 { 0096 return d->mAttrs; 0097 } 0098 0099 void LdapClient::setScope(const QString &scope) 0100 { 0101 d->mScope = scope; 0102 } 0103 0104 void LdapClient::startQuery(const QString &filter) 0105 { 0106 cancelQuery(); 0107 KLDAPCore::LdapUrl url{d->mServer.url()}; 0108 0109 url.setAttributes(d->mAttrs); 0110 url.setScope(d->mScope == QLatin1StringView("one") ? KLDAPCore::LdapUrl::One : KLDAPCore::LdapUrl::Sub); 0111 const QString userFilter = url.filter(); 0112 QString finalFilter = filter; 0113 // combine the filter set by the user in the config dialog (url.filter()) and the filter from this query 0114 if (!userFilter.isEmpty()) { 0115 finalFilter = QLatin1StringView("&(") + finalFilter + QLatin1StringView(")(") + userFilter + QLatin1Char(')'); 0116 } 0117 url.setFilter(QLatin1Char('(') + finalFilter + QLatin1Char(')')); 0118 0119 qCDebug(LDAPCLIENT_LOG) << "LdapClient: Doing query:" << url.toDisplayString(); 0120 0121 d->startParseLDIF(); 0122 d->mActive = true; 0123 KIO::TransferJob *transfertJob = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); 0124 d->mJob = transfertJob; 0125 connect(transfertJob, &KIO::TransferJob::data, this, [this](KIO::Job *job, const QByteArray &data) { 0126 d->slotData(job, data); 0127 }); 0128 connect(d->mJob.data(), &KIO::TransferJob::infoMessage, this, [this](KJob *job, const QString &message) { 0129 d->slotInfoMessage(job, message); 0130 }); 0131 connect(d->mJob.data(), &KIO::TransferJob::result, this, [this]() { 0132 d->slotDone(); 0133 }); 0134 } 0135 0136 void LdapClient::cancelQuery() 0137 { 0138 d->cancelQuery(); 0139 } 0140 0141 void LdapClient::LdapClientPrivate::cancelQuery() 0142 { 0143 if (mJob) { 0144 mJob->kill(); 0145 mJob = nullptr; 0146 } 0147 0148 mActive = false; 0149 } 0150 0151 void LdapClient::LdapClientPrivate::slotData(KIO::Job *, const QByteArray &data) 0152 { 0153 parseLDIF(data); 0154 } 0155 0156 void LdapClient::LdapClientPrivate::slotInfoMessage(KJob *, const QString &info) 0157 { 0158 qCDebug(LDAPCLIENT_LOG) << "Job said :" << info; 0159 } 0160 0161 void LdapClient::LdapClientPrivate::slotDone() 0162 { 0163 endParseLDIF(); 0164 mActive = false; 0165 if (!mJob) { 0166 return; 0167 } 0168 int err = mJob->error(); 0169 if (err && err != KIO::ERR_USER_CANCELED) { 0170 Q_EMIT q->error(mJob->errorString()); 0171 } 0172 Q_EMIT q->done(); 0173 } 0174 0175 void LdapClient::LdapClientPrivate::startParseLDIF() 0176 { 0177 mCurrentObject.clear(); 0178 mLdif.startParsing(); 0179 } 0180 0181 void LdapClient::LdapClientPrivate::endParseLDIF() 0182 { 0183 } 0184 0185 void LdapClient::LdapClientPrivate::finishCurrentObject() 0186 { 0187 mCurrentObject.setDn(mLdif.dn()); 0188 KLDAPCore::LdapAttrValue objectclasses; 0189 const KLDAPCore::LdapAttrMap::ConstIterator end = mCurrentObject.attributes().constEnd(); 0190 for (KLDAPCore::LdapAttrMap::ConstIterator it = mCurrentObject.attributes().constBegin(); it != end; ++it) { 0191 if (it.key().toLower() == QLatin1StringView("objectclass")) { 0192 objectclasses = it.value(); 0193 break; 0194 } 0195 } 0196 0197 bool groupofnames = false; 0198 const KLDAPCore::LdapAttrValue::ConstIterator endValue(objectclasses.constEnd()); 0199 for (KLDAPCore::LdapAttrValue::ConstIterator it = objectclasses.constBegin(); it != endValue; ++it) { 0200 const QByteArray sClass = (*it).toLower(); 0201 if (sClass == "groupofnames" || sClass == "kolabgroupofnames") { 0202 groupofnames = true; 0203 } 0204 } 0205 0206 if (groupofnames) { 0207 KLDAPCore::LdapAttrMap::ConstIterator it = mCurrentObject.attributes().find(QStringLiteral("mail")); 0208 if (it == mCurrentObject.attributes().end()) { 0209 // No explicit mail address found so far? 0210 // Fine, then we use the address stored in the DN. 0211 QString sMail; 0212 const QStringList lMail = mCurrentObject.dn().toString().split(QStringLiteral(",dc="), Qt::SkipEmptyParts); 0213 const int n = lMail.count(); 0214 if (n) { 0215 if (lMail.first().startsWith(QLatin1StringView("cn="), Qt::CaseInsensitive)) { 0216 sMail = lMail.first().simplified().mid(3); 0217 if (1 < n) { 0218 sMail.append(QLatin1Char('@')); 0219 } 0220 for (int i = 1; i < n; ++i) { 0221 sMail.append(lMail.at(i)); 0222 if (i < n - 1) { 0223 sMail.append(QLatin1Char('.')); 0224 } 0225 } 0226 mCurrentObject.addValue(QStringLiteral("mail"), sMail.toUtf8()); 0227 } 0228 } 0229 } 0230 } 0231 Q_EMIT q->result(*q, mCurrentObject); 0232 mCurrentObject.clear(); 0233 } 0234 0235 void LdapClient::LdapClientPrivate::parseLDIF(const QByteArray &data) 0236 { 0237 // qCDebug(LDAPCLIENT_LOG) <<"LdapClient::parseLDIF(" << QCString(data.data(), data.size()+1) <<" )"; 0238 if (!data.isEmpty()) { 0239 mLdif.setLdif(data); 0240 } else { 0241 mLdif.endLdif(); 0242 } 0243 KLDAPCore::Ldif::ParseValue ret; 0244 QString name; 0245 do { 0246 ret = mLdif.nextItem(); 0247 switch (ret) { 0248 case KLDAPCore::Ldif::Item: { 0249 name = mLdif.attr(); 0250 const QByteArray value = mLdif.value(); 0251 mCurrentObject.addValue(name, value); 0252 break; 0253 } 0254 case KLDAPCore::Ldif::EndEntry: 0255 finishCurrentObject(); 0256 break; 0257 default: 0258 break; 0259 } 0260 } while (ret != KLDAPCore::Ldif::MoreData); 0261 } 0262 0263 int LdapClient::clientNumber() const 0264 { 0265 return d->mClientNumber; 0266 } 0267 0268 int LdapClient::completionWeight() const 0269 { 0270 return d->mCompletionWeight; 0271 } 0272 0273 void LdapClient::setCompletionWeight(int weight) 0274 { 0275 d->mCompletionWeight = weight; 0276 } 0277 0278 #include "moc_ldapclient.cpp"