File indexing completed on 2024-12-15 04:55:36
0001 /* 0002 SPDX-FileCopyrightText: 2016-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "importimapsettingsthunderbirdcheckjob.h" 0008 #include "sieveeditor_debug.h" 0009 #include <KConfig> 0010 #include <KConfigGroup> 0011 #include <KLocalizedString> 0012 #include <QDir> 0013 #include <QFile> 0014 #include <QRegularExpression> 0015 0016 LIBSIEVEEDITOR_EXPORT QString sieveeditor_thunderbird_default_toplevel_path = QDir::homePath() + QLatin1StringView("/.thunderbird/"); 0017 0018 ImportImapSettingsThunderbirdCheckJob::ImportImapSettingsThunderbirdCheckJob(QObject *parent) 0019 : AbstractImapSettingsCheckJob(parent) 0020 { 0021 } 0022 0023 ImportImapSettingsThunderbirdCheckJob::~ImportImapSettingsThunderbirdCheckJob() = default; 0024 0025 // Copy from mailimporter 0026 QMap<QString, QString> ImportImapSettingsThunderbirdCheckJob::listProfile(QString ¤tProfile, const QString &defaultSettingPath) 0027 { 0028 const QString thunderbirdPath = defaultSettingPath + QLatin1StringView("/profiles.ini"); 0029 QMap<QString, QString> lstProfile; 0030 if (QFileInfo::exists(thunderbirdPath)) { 0031 // ini file. 0032 KConfig config(thunderbirdPath); 0033 const QStringList profileList = config.groupList().filter(QRegularExpression(QStringLiteral("Profile\\d+"))); 0034 const bool uniqProfile = (profileList.count() == 1); 0035 if (uniqProfile) { 0036 KConfigGroup group = config.group(profileList.at(0)); 0037 const QString path = group.readEntry("Path"); 0038 const QString name = group.readEntry(QStringLiteral("Name")); 0039 currentProfile = path; 0040 lstProfile.insert(name, path); 0041 return lstProfile; 0042 } else { 0043 for (const QString &profileName : profileList) { 0044 KConfigGroup group = config.group(profileName); 0045 const QString path = group.readEntry("Path"); 0046 const QString name = group.readEntry(QStringLiteral("Name")); 0047 if (group.hasKey("Default") && (group.readEntry("Default", 0) == 1)) { 0048 currentProfile = path; 0049 } 0050 lstProfile.insert(name, path); 0051 } 0052 } 0053 } 0054 return lstProfile; 0055 } 0056 0057 void ImportImapSettingsThunderbirdCheckJob::start() 0058 { 0059 mSettingsWereImported = false; 0060 QString currentProfile; 0061 const QMap<QString, QString> lstProfile = listProfile(currentProfile, defaultPath()); 0062 const int numberLstProfileCount = lstProfile.count(); 0063 if (numberLstProfileCount > 0) { 0064 if (numberLstProfileCount == 1) { 0065 mSettingsWereImported = importSettings(defaultPath(), lstProfile.first()); 0066 } else { 0067 QMap<QString, QString>::const_iterator i = lstProfile.constBegin(); 0068 while (i != lstProfile.constEnd()) { 0069 const bool imported = importSettings(defaultPath(), i.value()); 0070 if (imported) { 0071 mSettingsWereImported = true; 0072 } 0073 ++i; 0074 } 0075 } 0076 } 0077 checkNoSettingsImported(); 0078 } 0079 0080 bool ImportImapSettingsThunderbirdCheckJob::importSettings(const QString &directory, const QString &defaultProfile) 0081 { 0082 const QString filePath = directory + QLatin1Char('/') + defaultProfile + QStringLiteral("/prefs.js"); 0083 // qCDebug(SIEVEEDITOR_LOG) << "importSettings filename:" << filePath; 0084 QFile file(filePath); 0085 if (!file.open(QIODevice::ReadOnly)) { 0086 qCWarning(SIEVEEDITOR_LOG) << "Unable to open file " << filePath; 0087 return false; 0088 } 0089 QTextStream stream(&file); 0090 while (!stream.atEnd()) { 0091 const QString line = stream.readLine(); 0092 if (line.startsWith(QLatin1StringView("user_pref"))) { 0093 if (line.contains(QLatin1StringView("mail.server.")) || line.contains(QLatin1StringView("mail.account.")) 0094 || line.contains(QLatin1StringView("mail.accountmanager.")) || line.contains(QLatin1StringView("extensions.sieve.account."))) { 0095 insertIntoMap(line); 0096 } 0097 } else { 0098 if (!line.startsWith(QLatin1Char('#')) && line.isEmpty() && line.startsWith(QLatin1StringView("/*")) && line.startsWith(QLatin1StringView(" */")) 0099 && line.startsWith(QLatin1StringView(" *"))) { 0100 qCDebug(SIEVEEDITOR_LOG) << " unstored line :" << line; 0101 } 0102 } 0103 } 0104 const QString mailAccountPreference = mHashConfig.value(QStringLiteral("mail.accountmanager.accounts")).toString(); 0105 if (mailAccountPreference.isEmpty()) { 0106 qCDebug(SIEVEEDITOR_LOG) << "No account found"; 0107 return false; 0108 } 0109 const QStringList accountList = mailAccountPreference.split(QLatin1Char(',')); 0110 0111 bool atLeastAnAccountFound = false; 0112 for (const QString &account : accountList) { 0113 const QString serverName = mHashConfig.value(QStringLiteral("mail.account.%1").arg(account) + QStringLiteral(".server")).toString(); 0114 const QString accountName = QStringLiteral("mail.server.%1").arg(serverName); 0115 const QString type = mHashConfig.value(accountName + QStringLiteral(".type")).toString(); 0116 if (type == QLatin1StringView("imap")) { 0117 // Sieve settings == username@account 0118 0119 const QString imapServerName = mHashConfig.value(accountName + QStringLiteral(".hostname")).toString(); 0120 QString userName = mHashConfig.value(accountName + QStringLiteral(".userName")).toString(); 0121 // Convert @ in username in %40 0122 QString userNameSieveConverted = userName; 0123 userNameSieveConverted.replace(QLatin1Char('@'), QStringLiteral("%40")); 0124 const QString sieveKeyServerUserName = QLatin1StringView("extensions.sieve.account.") + userNameSieveConverted + QLatin1Char('@') + imapServerName; 0125 // user_pref("extensions.sieve.account.<username>@<server>.enabled", true); 0126 if (mHashConfig.value(sieveKeyServerUserName + QStringLiteral(".enabled"), false).toBool()) { 0127 // TODO 0128 // user_pref("extensions.sieve.account.<username>@<server>.TLS", true); 0129 // user_pref("extensions.sieve.account.<username>@<server>.TLS.forced", true); 0130 // user_pref("extensions.sieve.account.<username>@<server>.activeAuthorization", 1); 0131 // user_pref("extensions.sieve.account.<username>@<server>.activeHost", 1); 0132 // user_pref("extensions.sieve.account.<username>@<server>.activeLogin", 1); 0133 SieveEditorUtil::SieveServerConfig config; 0134 // 0 4190 0135 // 1 2000 0136 // 2 custom 0137 // Default == 4190 0138 // user_pref("extensions.sieve.account.<username>@<server>.port", 1255); 0139 config.sieveSettings.port = mHashConfig.value(sieveKeyServerUserName + QStringLiteral(".port"), 4190).toInt(); 0140 // not necessary to import this one : user_pref("extensions.sieve.account.<username>@<server>.port.type", 1); 0141 0142 // user_pref("extensions.sieve.account.<username>@<server>.hostname", "sdfsfsqsdf"); 0143 const QString sieveHostName = mHashConfig.value(sieveKeyServerUserName + QStringLiteral(".hostname")).toString(); 0144 if (sieveHostName.isEmpty()) { 0145 config.sieveSettings.serverName = imapServerName; 0146 } else { 0147 config.sieveSettings.serverName = sieveHostName; 0148 } 0149 0150 const QString sieveUserName = mHashConfig.value(sieveKeyServerUserName + QStringLiteral(".login.username")).toString(); 0151 // user_pref("extensions.sieve.account.<username>@<server>.login.username", "newuser"); 0152 if (sieveUserName.isEmpty()) { 0153 config.sieveSettings.userName = userName; 0154 } else { 0155 config.sieveSettings.userName = sieveUserName; 0156 } 0157 0158 // not necessary to import this one : user_pref("extensions.sieve.account.<username>@<server>.proxy.type", 1); 0159 0160 // qCDebug(SIEVEEDITOR_LOG) << "imap account " << accountName; 0161 const QString name = mHashConfig.value(accountName + QStringLiteral(".name")).toString(); 0162 bool found; 0163 const int sievePort = mHashConfig.value(accountName + QStringLiteral(".port")).toInt(&found); 0164 if (found) { 0165 config.sieveImapAccountSettings.setPort(sievePort); 0166 } 0167 encryption(config, accountName); 0168 addAuth(config, accountName); 0169 config.sieveImapAccountSettings.setUserName(userName); 0170 config.sieveImapAccountSettings.setServerName(imapServerName); 0171 0172 if (config.isValid()) { 0173 atLeastAnAccountFound = true; 0174 Q_EMIT importSetting(name, config); 0175 } 0176 } 0177 } else { 0178 // qCDebug(SIEVEEDITOR_LOG) << "Account " << accountName << " is not a imap account. Skip it."; 0179 } 0180 } 0181 return atLeastAnAccountFound; 0182 } 0183 0184 // Stolen from import-wizard 0185 void ImportImapSettingsThunderbirdCheckJob::encryption(SieveEditorUtil::SieveServerConfig &config, const QString &accountName) 0186 { 0187 bool found; 0188 const int socketType = mHashConfig.value(accountName + QStringLiteral(".socketType")).toInt(&found); 0189 if (found) { 0190 switch (socketType) { 0191 case 0: 0192 // None 0193 config.sieveImapAccountSettings.setEncryptionMode(KSieveCore::SieveImapAccountSettings::EncryptionMode::Unencrypted); 0194 break; 0195 case 2: 0196 // STARTTLS 0197 config.sieveImapAccountSettings.setEncryptionMode(KSieveCore::SieveImapAccountSettings::EncryptionMode::STARTTLS); 0198 break; 0199 case 3: 0200 // SSL/TLS 0201 config.sieveImapAccountSettings.setEncryptionMode(KSieveCore::SieveImapAccountSettings::EncryptionMode::SSLorTLS); 0202 break; 0203 default: 0204 qCDebug(SIEVEEDITOR_LOG) << "Unknown encryption mode " << socketType; 0205 } 0206 } else { 0207 qCDebug(SIEVEEDITOR_LOG) << "Invalid encryption mode settings"; 0208 } 0209 } 0210 0211 void ImportImapSettingsThunderbirdCheckJob::addAuth(SieveEditorUtil::SieveServerConfig &config, const QString &accountName) 0212 { 0213 bool found = false; 0214 if (mHashConfig.contains(accountName + QStringLiteral(".authMethod"))) { 0215 const int authMethod = mHashConfig.value(accountName + QStringLiteral(".authMethod")).toInt(&found); 0216 if (found) { 0217 switch (authMethod) { 0218 case 0: 0219 config.sieveImapAccountSettings.setAuthenticationType(KSieveCore::SieveImapAccountSettings::Plain); 0220 break; 0221 case 4: // Encrypted password ??? 0222 config.sieveImapAccountSettings.setAuthenticationType(KSieveCore::SieveImapAccountSettings::Login); 0223 qCDebug(SIEVEEDITOR_LOG) << " authmethod == encrypt password"; 0224 break; 0225 case 5: // GSSAPI 0226 config.sieveImapAccountSettings.setAuthenticationType(KSieveCore::SieveImapAccountSettings::GSSAPI); 0227 break; 0228 case 6: // NTLM 0229 config.sieveImapAccountSettings.setAuthenticationType(KSieveCore::SieveImapAccountSettings::NTLM); 0230 break; 0231 case 7: // TLS 0232 qCDebug(SIEVEEDITOR_LOG) << " authmethod method == TLS"; //???? 0233 break; 0234 case 10: // OAuth2 0235 config.sieveImapAccountSettings.setAuthenticationType(KSieveCore::SieveImapAccountSettings::XOAuth2); 0236 qCDebug(SIEVEEDITOR_LOG) << " authmethod method == OAuth2"; //???? 0237 break; 0238 default: 0239 qCDebug(SIEVEEDITOR_LOG) << " ImportImapSettingsThunderbirdCheckJob::addAuth unknown :" << authMethod; 0240 break; 0241 } 0242 } else { 0243 qCDebug(SIEVEEDITOR_LOG) << " ImportImapSettingsThunderbirdCheckJob::addAuth undefine value"; 0244 } 0245 } 0246 } 0247 0248 void ImportImapSettingsThunderbirdCheckJob::insertIntoMap(const QString &line) 0249 { 0250 QString newLine = line; 0251 newLine.remove(QStringLiteral("user_pref(\"")); 0252 newLine.remove(QStringLiteral(");")); 0253 const int pos = newLine.indexOf(QLatin1Char(',')); 0254 QString key = newLine.left(pos); 0255 key.remove(key.length() - 1, 1); 0256 QString valueStr = newLine.right(newLine.length() - pos - 2); 0257 if (valueStr.at(0) == QLatin1Char('"')) { 0258 valueStr.remove(0, 1); 0259 const int pos(valueStr.length() - 1); 0260 if (valueStr.at(pos) == QLatin1Char('"')) { 0261 valueStr.remove(pos, 1); 0262 } 0263 // Store as String 0264 mHashConfig.insert(key, valueStr); 0265 } else { 0266 if (valueStr == QLatin1StringView("true")) { 0267 mHashConfig.insert(key, true); 0268 } else if (valueStr == QLatin1StringView("false")) { 0269 mHashConfig.insert(key, false); 0270 } else { 0271 // Store as integer 0272 const int value = valueStr.toInt(); 0273 mHashConfig.insert(key, value); 0274 } 0275 } 0276 } 0277 0278 QString ImportImapSettingsThunderbirdCheckJob::defaultPath() const 0279 { 0280 return sieveeditor_thunderbird_default_toplevel_path; 0281 } 0282 0283 bool ImportImapSettingsThunderbirdCheckJob::settingsCanBeImported() const 0284 { 0285 const QDir dir(defaultPath()); 0286 return dir.exists(); 0287 } 0288 0289 QString ImportImapSettingsThunderbirdCheckJob::name() const 0290 { 0291 return i18n("Thunderbird IMAP Settings"); 0292 } 0293 0294 #include "moc_importimapsettingsthunderbirdcheckjob.cpp"