File indexing completed on 2025-02-02 05:08:37
0001 /* 0002 SPDX-FileCopyrightText: 2010 Omat Holding B.V. <info@omat.nl> 0003 SPDX-FileCopyrightText: 2014 Sandro Knauß <knauss@kolabsys.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "ispdb.h" 0009 #include "accountwizard_debug.h" 0010 #include <KLocalizedString> 0011 #include <kio/jobclasses.h> 0012 0013 #include <QDomDocument> 0014 0015 Ispdb::Ispdb(QObject *parent) 0016 : QObject(parent) 0017 { 0018 } 0019 0020 Ispdb::~Ispdb() = default; 0021 0022 QString Ispdb::email() const 0023 { 0024 return mEmail; 0025 } 0026 0027 void Ispdb::setEmail(const QString &address) 0028 { 0029 if (mEmail == address) { 0030 return; 0031 } 0032 mEmail = address; 0033 KMime::Types::Mailbox box; 0034 box.fromUnicodeString(address); 0035 mAddr = box.addrSpec(); 0036 Q_EMIT emailChanged(); 0037 } 0038 0039 QString Ispdb::password() const 0040 { 0041 return mPassword; 0042 } 0043 0044 void Ispdb::setPassword(const QString &password) 0045 { 0046 if (mPassword == password) { 0047 return; 0048 } 0049 mPassword = password; 0050 Q_EMIT passwordChanged(); 0051 } 0052 0053 void Ispdb::start() 0054 { 0055 qCDebug(ACCOUNTWIZARD_LOG) << mAddr.asString(); 0056 // we should do different things in here. But lets focus in the db first. 0057 lookupInDb(false, false); 0058 } 0059 0060 void Ispdb::lookupInDb(bool auth, bool crypt) 0061 { 0062 setServerType(mServerType); 0063 startJob(lookupUrl(QStringLiteral("mail"), QStringLiteral("1.1"), auth, crypt)); 0064 } 0065 0066 void Ispdb::startJob(const QUrl &url) 0067 { 0068 mData.clear(); 0069 QMap<QString, QVariant> map; 0070 map[QStringLiteral("errorPage")] = false; 0071 0072 KIO::TransferJob *job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); 0073 job->setMetaData(map); 0074 connect(job, &KIO::TransferJob::result, this, &Ispdb::slotResult); 0075 connect(job, &KIO::TransferJob::data, this, &Ispdb::dataArrived); 0076 } 0077 0078 QUrl Ispdb::lookupUrl(const QString &type, const QString &version, bool auth, bool crypt) 0079 { 0080 QUrl url; 0081 const QString path = type + QStringLiteral("/config-v") + version + QStringLiteral(".xml"); 0082 switch (mServerType) { 0083 case IspAutoConfig: 0084 url = QUrl(QStringLiteral("http://autoconfig.") + mAddr.domain.toLower() + QLatin1Char('/') + path); 0085 break; 0086 case IspWellKnow: 0087 url = QUrl(QStringLiteral("http://") + mAddr.domain.toLower() + QStringLiteral("/.well-known/autoconfig/") + path); 0088 break; 0089 case DataBase: 0090 url = QUrl(QStringLiteral("https://autoconfig.thunderbird.net/v1.1/") + mAddr.domain.toLower()); 0091 break; 0092 } 0093 if (mServerType != DataBase) { 0094 if (crypt) { 0095 url.setScheme(QStringLiteral("https")); 0096 } 0097 0098 if (auth) { 0099 url.setUserName(mAddr.asString()); 0100 url.setPassword(mPassword); 0101 } 0102 } 0103 return url; 0104 } 0105 0106 void Ispdb::slotResult(KJob *job) 0107 { 0108 if (job->error()) { 0109 qCDebug(ACCOUNTWIZARD_LOG) << "Fetching failed" << job->errorString(); 0110 bool lookupFinished = false; 0111 0112 switch (mServerType) { 0113 case IspAutoConfig: 0114 mServerType = IspWellKnow; 0115 break; 0116 case IspWellKnow: 0117 lookupFinished = true; 0118 break; 0119 case DataBase: 0120 mServerType = IspAutoConfig; 0121 break; 0122 } 0123 0124 if (lookupFinished) { 0125 Q_EMIT finished(false); 0126 return; 0127 } 0128 lookupInDb(false, false); 0129 return; 0130 } 0131 0132 // qCDebug(ACCOUNTWIZARD_LOG) << mData; 0133 QDomDocument document; 0134 bool ok = document.setContent(mData); 0135 if (!ok) { 0136 qCDebug(ACCOUNTWIZARD_LOG) << "Could not parse xml" << mData; 0137 Q_EMIT finished(false); 0138 return; 0139 } 0140 0141 parseResult(document); 0142 } 0143 0144 void Ispdb::parseResult(const QDomDocument &document) 0145 { 0146 QDomElement docElem = document.documentElement(); 0147 QDomNodeList l = docElem.elementsByTagName(QStringLiteral("emailProvider")); 0148 0149 if (l.isEmpty()) { 0150 Q_EMIT finished(false); 0151 return; 0152 } 0153 0154 // only handle the first emailProvider entry 0155 QDomNode firstProvider = l.at(0); 0156 QDomNode n = firstProvider.firstChild(); 0157 while (!n.isNull()) { 0158 QDomElement e = n.toElement(); 0159 if (!e.isNull()) { 0160 // qCDebug(ACCOUNTWIZARD_LOG) << qPrintable(e.tagName()); 0161 const QString tagName(e.tagName()); 0162 if (tagName == QLatin1StringView("domain")) { 0163 mDomains << e.text(); 0164 } else if (tagName == QLatin1StringView("displayName")) { 0165 mDisplayName = e.text(); 0166 } else if (tagName == QLatin1StringView("displayShortName")) { 0167 mDisplayShortName = e.text(); 0168 } else if (tagName == QLatin1StringView("incomingServer") && e.attribute(QStringLiteral("type")) == QLatin1StringView("imap")) { 0169 Server s = createServer(e); 0170 if (s.isValid()) { 0171 mImapServers.append(s); 0172 } 0173 } else if (tagName == QLatin1StringView("incomingServer") && e.attribute(QStringLiteral("type")) == QLatin1StringView("pop3")) { 0174 Server s = createServer(e); 0175 if (s.isValid()) { 0176 mPop3Servers.append(s); 0177 } 0178 } else if (tagName == QLatin1StringView("outgoingServer") && e.attribute(QStringLiteral("type")) == QLatin1StringView("smtp")) { 0179 Server s = createServer(e); 0180 if (s.isValid()) { 0181 mSmtpServers.append(s); 0182 } 0183 } else if (tagName == QLatin1StringView("identity")) { 0184 Identity i = createIdentity(e); 0185 if (i.isValid()) { 0186 mIdentities.append(i); 0187 if (i.isDefault()) { 0188 mDefaultIdentity = mIdentities.count() - 1; 0189 } 0190 } 0191 } 0192 } 0193 n = n.nextSibling(); 0194 } 0195 0196 // comment this section out when you are tired of it... 0197 qCDebug(ACCOUNTWIZARD_LOG) << "------------------ summary --------------"; 0198 qCDebug(ACCOUNTWIZARD_LOG) << "Domains" << mDomains; 0199 qCDebug(ACCOUNTWIZARD_LOG) << "Name" << mDisplayName << "(" << mDisplayShortName << ")"; 0200 qCDebug(ACCOUNTWIZARD_LOG) << "Imap servers:"; 0201 for (const Server &s : std::as_const(mImapServers)) { 0202 qCDebug(ACCOUNTWIZARD_LOG) << s.hostname << s.port << s.socketType << s.username << s.authentication; 0203 } 0204 qCDebug(ACCOUNTWIZARD_LOG) << "pop3 servers:"; 0205 for (const Server &s : std::as_const(mPop3Servers)) { 0206 qCDebug(ACCOUNTWIZARD_LOG) << s.hostname << s.port << s.socketType << s.username << s.authentication; 0207 } 0208 qCDebug(ACCOUNTWIZARD_LOG) << "smtp servers:"; 0209 for (const Server &s : std::as_const(mSmtpServers)) { 0210 qCDebug(ACCOUNTWIZARD_LOG) << s.hostname << s.port << s.socketType << s.username << s.authentication; 0211 } 0212 // end section. 0213 0214 Q_EMIT finished(true); 0215 } 0216 0217 Server Ispdb::createServer(const QDomElement &n) 0218 { 0219 QDomNode o = n.firstChild(); 0220 Server s; 0221 while (!o.isNull()) { 0222 QDomElement f = o.toElement(); 0223 if (!f.isNull()) { 0224 const QString tagName(f.tagName()); 0225 if (tagName == QLatin1StringView("hostname")) { 0226 s.hostname = replacePlaceholders(f.text()); 0227 } else if (tagName == QLatin1StringView("port")) { 0228 s.port = f.text().toInt(); 0229 } else if (tagName == QLatin1StringView("socketType")) { 0230 const QString type(f.text()); 0231 if (type == QLatin1StringView("plain")) { 0232 s.socketType = None; 0233 } else if (type == QLatin1StringView("SSL")) { 0234 s.socketType = SSL; 0235 } 0236 if (type == QLatin1StringView("STARTTLS")) { 0237 s.socketType = StartTLS; 0238 } 0239 } else if (tagName == QLatin1StringView("username")) { 0240 s.username = replacePlaceholders(f.text()); 0241 } else if (tagName == QLatin1StringView("authentication") && s.authentication == 0) { 0242 const QString type(f.text()); 0243 if (type == QLatin1StringView("password-cleartext") || type == QLatin1StringView("plain")) { 0244 s.authentication = Plain; 0245 } else if (type == QLatin1StringView("password-encrypted") || type == QLatin1StringView("secure")) { 0246 s.authentication = CramMD5; 0247 } else if (type == QLatin1StringView("NTLM")) { 0248 s.authentication = NTLM; 0249 } else if (type == QLatin1StringView("GSSAPI")) { 0250 s.authentication = GSSAPI; 0251 } else if (type == QLatin1StringView("client-ip-based")) { 0252 s.authentication = ClientIP; 0253 } else if (type == QLatin1StringView("none")) { 0254 s.authentication = NoAuth; 0255 } else if (type == QLatin1StringView("OAuth2")) { 0256 s.authentication = OAuth2; 0257 } 0258 } 0259 } 0260 o = o.nextSibling(); 0261 } 0262 return s; 0263 } 0264 0265 Identity Ispdb::createIdentity(const QDomElement &n) 0266 { 0267 QDomNode o = n.firstChild(); 0268 Identity i; 0269 0270 // type="kolab" version="1.0" is the only identity that is defined 0271 if (n.attribute(QStringLiteral("type")) != QLatin1StringView("kolab") || n.attribute(QStringLiteral("version")) != QLatin1StringView("1.0")) { 0272 qCDebug(ACCOUNTWIZARD_LOG) << "unknown type of identity element."; 0273 } 0274 0275 while (!o.isNull()) { 0276 QDomElement f = o.toElement(); 0277 if (!f.isNull()) { 0278 const QString tagName(f.tagName()); 0279 if (tagName == QLatin1StringView("default")) { 0280 i.mDefault = f.text().toLower() == QLatin1StringView("true"); 0281 } else if (tagName == QLatin1StringView("email")) { 0282 i.email = f.text(); 0283 } else if (tagName == QLatin1StringView("name")) { 0284 i.name = f.text(); 0285 } else if (tagName == QLatin1StringView("organization")) { 0286 i.organization = f.text(); 0287 } else if (tagName == QLatin1StringView("signature")) { 0288 QTextStream stream(&i.signature); 0289 f.save(stream, 0); 0290 i.signature = i.signature.trimmed(); 0291 if (i.signature.startsWith(QLatin1StringView("<signature>"))) { 0292 i.signature = i.signature.mid(11, i.signature.length() - 23); 0293 i.signature = i.signature.trimmed(); 0294 } 0295 } 0296 } 0297 o = o.nextSibling(); 0298 } 0299 0300 return i; 0301 } 0302 0303 QString Ispdb::replacePlaceholders(const QString &in) 0304 { 0305 QString out(in); 0306 out.replace(QLatin1StringView("%EMAILLOCALPART%"), mAddr.localPart); 0307 out.replace(QLatin1StringView("%EMAILADDRESS%"), mAddr.asString()); 0308 out.replace(QLatin1StringView("%EMAILDOMAIN%"), mAddr.domain); 0309 return out; 0310 } 0311 0312 void Ispdb::dataArrived(KIO::Job *, const QByteArray &data) 0313 { 0314 mData.append(data); 0315 } 0316 0317 // The getters 0318 0319 QStringList Ispdb::relevantDomains() const 0320 { 0321 return mDomains; 0322 } 0323 0324 QString Ispdb::name(Length l) const 0325 { 0326 if (l == Long) { 0327 return mDisplayName; 0328 } else if (l == Short) { 0329 return mDisplayShortName; 0330 } else { 0331 return {}; // make compiler happy. Not me. 0332 } 0333 } 0334 0335 QList<Server> Ispdb::imapServers() const 0336 { 0337 return mImapServers; 0338 } 0339 0340 QList<Server> Ispdb::pop3Servers() const 0341 { 0342 return mPop3Servers; 0343 } 0344 0345 QList<Server> Ispdb::smtpServers() const 0346 { 0347 return mSmtpServers; 0348 } 0349 0350 int Ispdb::defaultIdentity() const 0351 { 0352 return mDefaultIdentity; 0353 } 0354 0355 QList<Identity> Ispdb::identities() const 0356 { 0357 return mIdentities; 0358 } 0359 0360 void Ispdb::setServerType(Ispdb::SearchServerType type) 0361 { 0362 if (type != mServerType || mStart) { 0363 mServerType = type; 0364 mStart = false; 0365 switch (mServerType) { 0366 case IspAutoConfig: 0367 Q_EMIT searchType(i18n("Lookup configuration: Email provider")); 0368 break; 0369 case IspWellKnow: 0370 Q_EMIT searchType(i18n("Lookup configuration: Trying common server name")); 0371 break; 0372 case DataBase: 0373 Q_EMIT searchType(i18n("Lookup configuration: Mozilla database")); 0374 break; 0375 } 0376 } 0377 } 0378 0379 Ispdb::SearchServerType Ispdb::serverType() const 0380 { 0381 return mServerType; 0382 } 0383 0384 QDebug operator<<(QDebug d, const Server &t) 0385 { 0386 d << "authentication " << t.authentication; 0387 d << "socketType " << t.socketType; 0388 d << "hostname " << t.hostname; 0389 d << "username " << t.username; 0390 d << "port " << t.port; 0391 return d; 0392 } 0393 0394 QDebug operator<<(QDebug d, const Identity &t) 0395 { 0396 d << " email " << t.email; 0397 d << " name " << t.name; 0398 d << " organization " << t.organization; 0399 d << " signature " << t.signature; 0400 d << " isDefault " << t.mDefault; 0401 return d; 0402 } 0403 0404 #include "moc_ispdb.cpp"