diff --git a/CMakeLists.txt b/CMakeLists.txt index 88779cf..6caaca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,59 +1,63 @@ cmake_minimum_required(VERSION 3.5) set(PIM_VERSION "5.10.80") project(MailTransport VERSION ${PIM_VERSION}) # ECM setup set(KF5_MIN_VERSION "5.56.0") find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(GenerateExportHeader) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMQtDeclareLoggingCategory) add_definitions(-DTRANSLATION_DOMAIN=\"libmailtransport5\") set(KMAILTRANSPORT_LIB_VERSION ${PIM_VERSION}) set(KMIME_LIB_VERSION "5.10.80") set(AKONADI_LIB_VERSION "5.10.80") set(AKONADIMIME_LIB_VERSION "5.10.80") set(KSMTP_LIB_VERSION "5.10.80") set(KGAPI_LIB_VERSION "5.10.80") set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5MailTransport") ########### Find packages ########### find_package(KF5KCMUtils ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5ConfigWidgets ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5Wallet ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5I18n ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Akonadi ${AKONADI_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADIMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KPimSMTP ${KSMTP_LIB_VERSION} CONFIG REQUIRED) find_package(KPimGAPI ${KGAPI_LIB_VERSION} CONFIG REQUIRED) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) +if (${KF5Config_VERSION} STRGREATER "5.56.0") + add_definitions(-DQT_NO_FOREACH) + MESSAGE(STATUS "compile without foreach") +endif() if(BUILD_TESTING) add_definitions(-DBUILD_TESTING) endif(BUILD_TESTING) ########### Targets ########### add_subdirectory(src) install( FILES kmailtransport.renamecategories kmailtransport.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/kmailtransport/transport.cpp b/src/kmailtransport/transport.cpp index 3c1a517..ee9f654 100644 --- a/src/kmailtransport/transport.cpp +++ b/src/kmailtransport/transport.cpp @@ -1,344 +1,345 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "transport.h" #include "transport_p.h" #include "mailtransport_defs.h" #include "transportmanager.h" #include "transporttype_p.h" #include #include #include "mailtransport_debug.h" #include #include #include #include using namespace MailTransport; using namespace KWallet; Transport::Transport(const QString &cfgGroup) : TransportBase(cfgGroup) , d(new TransportPrivate) { qCDebug(MAILTRANSPORT_LOG) << cfgGroup; d->passwordLoaded = false; d->passwordDirty = false; d->storePasswordInFile = false; d->needsWalletMigration = false; d->passwordNeedsUpdateFromWallet = false; load(); } Transport::~Transport() { delete d; } bool Transport::isValid() const { return (id() > 0) && !host().isEmpty() && port() <= 65536; } QString Transport::password() { if (!d->passwordLoaded && requiresAuthentication() && storePassword() && d->password.isEmpty()) { readPassword(); } return d->password; } void Transport::setPassword(const QString &passwd) { d->passwordLoaded = true; if (d->password == passwd) { return; } d->passwordDirty = true; d->password = passwd; } void Transport::forceUniqueName() { QStringList existingNames; - foreach (Transport *t, TransportManager::self()->transports()) { + const auto lstTransports = TransportManager::self()->transports(); + for (Transport *t : lstTransports) { if (t->id() != id()) { existingNames << t->name(); } } int suffix = 1; QString origName = name(); while (existingNames.contains(name())) { setName(i18nc("%1: name; %2: number appended to it to make " "it unique among a list of names", "%1 #%2", origName, suffix)); ++suffix; } } void Transport::updatePasswordState() { Transport *original = TransportManager::self()->transportById(id(), false); if (original == this) { qCWarning(MAILTRANSPORT_LOG) << "Tried to update password state of non-cloned transport."; return; } if (original) { d->password = original->d->password; d->passwordLoaded = original->d->passwordLoaded; d->passwordDirty = original->d->passwordDirty; } else { qCWarning(MAILTRANSPORT_LOG) << "Transport with this ID not managed by transport manager."; } } bool Transport::isComplete() const { return !requiresAuthentication() || !storePassword() || d->passwordLoaded; } QString Transport::authenticationTypeString() const { return Transport::authenticationTypeString(authenticationType()); } QString Transport::authenticationTypeString(int type) { switch (type) { case EnumAuthenticationType::LOGIN: return QStringLiteral("LOGIN"); case EnumAuthenticationType::PLAIN: return QStringLiteral("PLAIN"); case EnumAuthenticationType::CRAM_MD5: return QStringLiteral("CRAM-MD5"); case EnumAuthenticationType::DIGEST_MD5: return QStringLiteral("DIGEST-MD5"); case EnumAuthenticationType::NTLM: return QStringLiteral("NTLM"); case EnumAuthenticationType::GSSAPI: return QStringLiteral("GSSAPI"); case EnumAuthenticationType::CLEAR: return i18nc("Authentication method", "Clear text"); case EnumAuthenticationType::APOP: return QStringLiteral("APOP"); case EnumAuthenticationType::ANONYMOUS: return i18nc("Authentication method", "Anonymous"); case EnumAuthenticationType::XOAUTH2: return QStringLiteral("XOAUTH2"); } Q_ASSERT(false); return QString(); } void Transport::usrRead() { TransportBase::usrRead(); setHost(host().trimmed()); if (d->oldName.isEmpty()) { d->oldName = name(); } // Set TransportType. { d->transportType = TransportType(); d->transportType.d->mIdentifier = identifier(); //qCDebug(MAILTRANSPORT_LOG) << "type" << identifier(); // Now we have the type and possibly agentType. Get the name, description // etc. from TransportManager. const TransportType::List &types = TransportManager::self()->types(); int index = types.indexOf(d->transportType); if (index != -1) { d->transportType = types[ index ]; } else { qCWarning(MAILTRANSPORT_LOG) << "Type unknown to manager."; d->transportType.d->mName = i18nc("An unknown transport type", "Unknown"); } } // we have everything we need if (!storePassword()) { return; } if (d->passwordLoaded) { if (d->passwordNeedsUpdateFromWallet) { d->passwordNeedsUpdateFromWallet = false; // read password if wallet is open, defer otherwise if (Wallet::isOpen(Wallet::NetworkWallet())) { // Don't read the password right away because this can lead // to reentrancy problems in KDBusServiceStarter when an application // run in Kontact creates the transports (due to a QEventLoop in the // synchronous KWallet openWallet call). QTimer::singleShot(0, this, &Transport::readPassword); } else { d->passwordLoaded = false; } } return; } // try to find a password in the config file otherwise KConfigGroup group(config(), currentGroup()); if (group.hasKey("password")) { d->password = KStringHandler::obscure(group.readEntry("password")); } else if (group.hasKey("password-kmail")) { //Legacy d->password = KStringHandler::obscure(group.readEntry("password-kmail")); } if (!d->password.isEmpty()) { d->passwordLoaded = true; if (Wallet::isEnabled()) { d->needsWalletMigration = true; } else { d->storePasswordInFile = true; } } } bool Transport::usrSave() { if (requiresAuthentication() && storePassword() && d->passwordDirty) { const QString storePassword = d->password; Wallet *wallet = TransportManager::self()->wallet(); if (!wallet || wallet->writePassword(QString::number(id()), d->password) != 0) { // wallet saving failed, ask if we should store in the config file instead if (d->storePasswordInFile || KMessageBox::warningYesNo( nullptr, i18n("KWallet is not available. It is strongly recommended to use " "KWallet for managing your passwords.\n" "However, the password can be stored in the configuration " "file instead. The password is stored in an obfuscated format, " "but should not be considered secure from decryption efforts " "if access to the configuration file is obtained.\n" "Do you want to store the password for server '%1' in the " "configuration file?", name()), i18n("KWallet Not Available"), KGuiItem(i18n("Store Password")), KGuiItem(i18n("Do Not Store Password"))) == KMessageBox::Yes) { // write to config file KConfigGroup group(config(), currentGroup()); group.writeEntry("password", KStringHandler::obscure(storePassword)); d->storePasswordInFile = true; } } d->passwordDirty = false; } if (!TransportBase::usrSave()) { return false; } TransportManager::self()->emitChangesCommitted(); if (name() != d->oldName) { emit TransportManager::self()->transportRenamed(id(), d->oldName, name()); d->oldName = name(); } return true; } void Transport::readPassword() { // no need to load a password if the account doesn't require auth if (!requiresAuthentication()) { return; } d->passwordLoaded = true; // check whether there is a chance to find our password at all if (Wallet::folderDoesNotExist(Wallet::NetworkWallet(), WALLET_FOLDER) || Wallet::keyDoesNotExist(Wallet::NetworkWallet(), WALLET_FOLDER, QString::number(id()))) { // try migrating password from kmail if (Wallet::folderDoesNotExist(Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER) || Wallet::keyDoesNotExist(Wallet::NetworkWallet(), KMAIL_WALLET_FOLDER, QStringLiteral("transport-%1").arg(id()))) { return; } qCDebug(MAILTRANSPORT_LOG) << "migrating password from kmail wallet"; KWallet::Wallet *wallet = TransportManager::self()->wallet(); if (wallet) { QString pwd; wallet->setFolder(KMAIL_WALLET_FOLDER); if (wallet->readPassword(QStringLiteral("transport-%1").arg(id()), pwd) == 0) { setPassword(pwd); save(); } else { d->password.clear(); d->passwordLoaded = false; } wallet->removeEntry(QStringLiteral("transport-%1").arg(id())); wallet->setFolder(WALLET_FOLDER); } return; } // finally try to open the wallet and read the password KWallet::Wallet *wallet = TransportManager::self()->wallet(); if (wallet) { QString pwd; if (wallet->readPassword(QString::number(id()), pwd) == 0) { setPassword(pwd); } else { d->password.clear(); d->passwordLoaded = false; } } } bool Transport::needsWalletMigration() const { return d->needsWalletMigration; } void Transport::migrateToWallet() { qCDebug(MAILTRANSPORT_LOG) << "migrating" << id() << "to wallet"; d->needsWalletMigration = false; KConfigGroup group(config(), currentGroup()); group.deleteEntry("password"); group.deleteEntry("password-kmail"); d->passwordDirty = true; d->storePasswordInFile = false; save(); } Transport *Transport::clone() const { QString id = currentGroup().mid(10); return new Transport(id); } TransportType Transport::transportType() const { if (!d->transportType.isValid()) { qCWarning(MAILTRANSPORT_LOG) << "Invalid transport type."; } return d->transportType; } QByteArray Transport::toJson() const { //TODO create json info return {}; } diff --git a/src/kmailtransport/transportmanager.cpp b/src/kmailtransport/transportmanager.cpp index 6366183..37bbab3 100644 --- a/src/kmailtransport/transportmanager.cpp +++ b/src/kmailtransport/transportmanager.cpp @@ -1,737 +1,737 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "transportmanager.h" #include "mailtransport_defs.h" #include "transport.h" #include "transport_p.h" #include "transportjob.h" #include "transporttype.h" #include "transporttype_p.h" #include "plugins/transportpluginmanager.h" #include "plugins/transportabstractplugin.h" #include "widgets/addtransportdialogng.h" #include #include #include #include #include #include #include #include #include #include #include "mailtransport_debug.h" #include #include #include #include #include #include using namespace MailTransport; using namespace KWallet; namespace MailTransport { /** * Private class that helps to provide binary compatibility between releases. * @internal */ class TransportManagerPrivate { public: TransportManagerPrivate(TransportManager *parent) : config(nullptr) , wallet(nullptr) , q(parent) { } ~TransportManagerPrivate() { delete config; qDeleteAll(transports); } KConfig *config = nullptr; QList transports; TransportType::List types; bool myOwnChange; bool appliedChange; KWallet::Wallet *wallet = nullptr; bool walletOpenFailed; bool walletAsyncOpen; int defaultTransportId; bool isMainInstance; QList walletQueue; TransportManager *q = nullptr; void readConfig(); void writeConfig(); void fillTypes(); int createId() const; void prepareWallet(); void validateDefault(); void migrateToWallet(); void updatePluginList(); // Slots void slotTransportsChanged(); void slotWalletOpened(bool success); void dbusServiceUnregistered(); void jobResult(KJob *job); }; } class StaticTransportManager : public TransportManager { public: StaticTransportManager() : TransportManager() { } }; StaticTransportManager *sSelf = nullptr; static void destroyStaticTransportManager() { delete sSelf; } TransportManager::TransportManager() : QObject() , d(new TransportManagerPrivate(this)) { Kdelibs4ConfigMigrator migrate(QStringLiteral("transportmanager")); migrate.setConfigFiles(QStringList() << QStringLiteral("mailtransports")); migrate.migrate(); qAddPostRoutine(destroyStaticTransportManager); d->myOwnChange = false; d->appliedChange = false; d->wallet = nullptr; d->walletOpenFailed = false; d->walletAsyncOpen = false; d->defaultTransportId = -1; d->config = new KConfig(QStringLiteral("mailtransports")); QDBusConnection::sessionBus().registerObject(DBUS_OBJECT_PATH, this, QDBusConnection::ExportScriptableSlots |QDBusConnection::ExportScriptableSignals); QDBusServiceWatcher *watcher = new QDBusServiceWatcher(DBUS_SERVICE_NAME, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this); connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() { d->dbusServiceUnregistered(); }); QDBusConnection::sessionBus().connect(QString(), QString(), DBUS_INTERFACE_NAME, DBUS_CHANGE_SIGNAL, this, SLOT(slotTransportsChanged())); d->isMainInstance = QDBusConnection::sessionBus().registerService(DBUS_SERVICE_NAME); d->fillTypes(); } TransportManager::~TransportManager() { qRemovePostRoutine(destroyStaticTransportManager); delete d; } TransportManager *TransportManager::self() { if (!sSelf) { sSelf = new StaticTransportManager; sSelf->d->readConfig(); } return sSelf; } Transport *TransportManager::transportById(int id, bool def) const { for (Transport *t : qAsConst(d->transports)) { if (t->id() == id) { return t; } } if (def || (id == 0 && d->defaultTransportId != id)) { return transportById(d->defaultTransportId, false); } return nullptr; } Transport *TransportManager::transportByName(const QString &name, bool def) const { for (Transport *t : qAsConst(d->transports)) { if (t->name() == name) { return t; } } if (def) { return transportById(0, false); } return nullptr; } QList< Transport * > TransportManager::transports() const { return d->transports; } TransportType::List TransportManager::types() const { return d->types; } Transport *TransportManager::createTransport() const { int id = d->createId(); Transport *t = new Transport(QString::number(id)); t->setId(id); return t; } void TransportManager::addTransport(Transport *transport) { if (d->transports.contains(transport)) { qCDebug(MAILTRANSPORT_LOG) << "Already have this transport."; return; } qCDebug(MAILTRANSPORT_LOG) << "Added transport" << transport; d->transports.append(transport); d->validateDefault(); emitChangesCommitted(); } void TransportManager::schedule(TransportJob *job) { connect(job, &TransportJob::result, this, [this](KJob *job) { d->jobResult(job); }); // check if the job is waiting for the wallet if (!job->transport()->isComplete()) { qCDebug(MAILTRANSPORT_LOG) << "job waits for wallet:" << job; d->walletQueue << job; loadPasswordsAsync(); return; } job->start(); } void TransportManager::createDefaultTransport() { KEMailSettings kes; Transport *t = createTransport(); t->setName(i18n("Default Transport")); t->setHost(kes.getSetting(KEMailSettings::OutServer)); if (t->isValid()) { t->save(); addTransport(t); } else { qCWarning(MAILTRANSPORT_LOG) << "KEMailSettings does not contain a valid transport."; } } bool TransportManager::showTransportCreationDialog(QWidget *parent, ShowCondition showCondition) { if (showCondition == IfNoTransportExists) { if (!isEmpty()) { return true; } const int response = KMessageBox::messageBox(parent, KMessageBox::WarningContinueCancel, i18n("You must create an outgoing account before sending."), i18n("Create Account Now?"), KGuiItem(i18n("Create Account Now"))); if (response != KMessageBox::Continue) { return false; } } QPointer dialog = new AddTransportDialogNG(parent); const bool accepted = (dialog->exec() == QDialog::Accepted); delete dialog; return accepted; } void TransportManager::initializeTransport(const QString &identifier, Transport *transport) { TransportAbstractPlugin *plugin = TransportPluginManager::self()->plugin(identifier); if (plugin) { plugin->initializeTransport(transport, identifier); } } bool TransportManager::configureTransport(const QString &identifier, Transport *transport, QWidget *parent) { TransportAbstractPlugin *plugin = TransportPluginManager::self()->plugin(identifier); if (plugin) { return plugin->configureTransport(identifier, transport, parent); } return false; } TransportJob *TransportManager::createTransportJob(int transportId) { Transport *t = transportById(transportId, false); if (!t) { return nullptr; } t = t->clone(); // Jobs delete their transports. t->updatePasswordState(); TransportAbstractPlugin *plugin = TransportPluginManager::self()->plugin(t->identifier()); if (plugin) { return plugin->createTransportJob(t, t->identifier()); } Q_ASSERT(false); return nullptr; } TransportJob *TransportManager::createTransportJob(const QString &transport) { bool ok = false; Transport *t = nullptr; int transportId = transport.toInt(&ok); if (ok) { t = transportById(transportId); } if (!t) { t = transportByName(transport, false); } if (t) { return createTransportJob(t->id()); } return nullptr; } bool TransportManager::isEmpty() const { return d->transports.isEmpty(); } QVector TransportManager::transportIds() const { QVector rv; rv.reserve(d->transports.count()); for (Transport *t : qAsConst(d->transports)) { rv << t->id(); } return rv; } QStringList TransportManager::transportNames() const { QStringList rv; rv.reserve(d->transports.count()); for (Transport *t : qAsConst(d->transports)) { rv << t->name(); } return rv; } QString TransportManager::defaultTransportName() const { Transport *t = transportById(d->defaultTransportId, false); if (t) { return t->name(); } return QString(); } int TransportManager::defaultTransportId() const { return d->defaultTransportId; } void TransportManager::setDefaultTransport(int id) { if (id == d->defaultTransportId || !transportById(id, false)) { return; } d->defaultTransportId = id; d->writeConfig(); } void TransportManager::removePasswordFromWallet(int id) { Wallet *currentWallet = wallet(); if (currentWallet) { currentWallet->removeEntry(QString::number(id)); } } void TransportManager::removeTransport(int id) { Transport *t = transportById(id, false); if (!t) { return; } auto plugin = MailTransport::TransportPluginManager::self()->plugin(t->identifier()); if (plugin) { plugin->cleanUp(t); } emit transportRemoved(t->id(), t->name()); d->transports.removeAll(t); d->validateDefault(); QString group = t->currentGroup(); if (t->storePassword()) { Wallet *currentWallet = wallet(); if (currentWallet) { currentWallet->removeEntry(QString::number(t->id())); } } delete t; d->config->deleteGroup(group); d->writeConfig(); } void TransportManagerPrivate::readConfig() { QList oldTransports = transports; transports.clear(); QRegularExpression re(QStringLiteral("^Transport (.+)$")); const QStringList groups = config->groupList().filter(re); for (const QString &s : groups) { QRegularExpressionMatch match = re.match(s); if (!match.hasMatch()) { continue; } Transport *t = nullptr; // see if we happen to have that one already - foreach (Transport *old, oldTransports) { + for (Transport *old : oldTransports) { if (old->currentGroup() == QLatin1String("Transport ") + match.captured(1)) { qCDebug(MAILTRANSPORT_LOG) << "reloading existing transport:" << s; t = old; t->d->passwordNeedsUpdateFromWallet = true; t->load(); oldTransports.removeAll(old); break; } } if (!t) { t = new Transport(match.captured(1)); } if (t->id() <= 0) { t->setId(createId()); t->save(); } transports.append(t); } qDeleteAll(oldTransports); oldTransports.clear(); // read default transport KConfigGroup group(config, "General"); defaultTransportId = group.readEntry("default-transport", 0); if (defaultTransportId == 0) { // migrated default transport contains the name instead QString name = group.readEntry("default-transport", QString()); if (!name.isEmpty()) { Transport *t = q->transportByName(name, false); if (t) { defaultTransportId = t->id(); writeConfig(); } } } validateDefault(); migrateToWallet(); q->loadPasswordsAsync(); } void TransportManagerPrivate::writeConfig() { KConfigGroup group(config, "General"); group.writeEntry("default-transport", defaultTransportId); config->sync(); q->emitChangesCommitted(); } void TransportManagerPrivate::fillTypes() { Q_ASSERT(types.isEmpty()); updatePluginList(); QObject::connect(MailTransport::TransportPluginManager::self(), &TransportPluginManager::updatePluginList, q, &TransportManager::updatePluginList); } void TransportManagerPrivate::updatePluginList() { types.clear(); for (MailTransport::TransportAbstractPlugin *plugin : MailTransport::TransportPluginManager::self()->pluginsList()) { if (plugin->names().isEmpty()) { qCDebug(MAILTRANSPORT_LOG) << "Plugin " << plugin << " doesn't provide plugin"; } for (const MailTransport::TransportAbstractPluginInfo &info : plugin->names()) { TransportType type; type.d->mName = info.name; type.d->mDescription = info.description; type.d->mIdentifier = info.identifier; type.d->mIsAkonadiResource = info.isAkonadi; types << type; } } } void TransportManager::updatePluginList() { d->updatePluginList(); } void TransportManager::emitChangesCommitted() { d->myOwnChange = true; // prevent us from reading our changes again d->appliedChange = false; // but we have to read them at least once emit transportsChanged(); emit changesCommitted(); } void TransportManagerPrivate::slotTransportsChanged() { if (myOwnChange && appliedChange) { myOwnChange = false; appliedChange = false; return; } qCDebug(MAILTRANSPORT_LOG); config->reparseConfiguration(); // FIXME: this deletes existing transport objects! readConfig(); appliedChange = true; // to prevent recursion emit q->transportsChanged(); } int TransportManagerPrivate::createId() const { QVector usedIds; usedIds.reserve(1 + transports.count()); for (Transport *t : qAsConst(transports)) { usedIds << t->id(); } usedIds << 0; // 0 is default for unknown int newId; do { newId = KRandom::random(); } while (usedIds.contains(newId)); return newId; } KWallet::Wallet *TransportManager::wallet() { if (d->wallet && d->wallet->isOpen()) { return d->wallet; } if (!Wallet::isEnabled() || d->walletOpenFailed) { return nullptr; } WId window = 0; if (qApp->activeWindow()) { window = qApp->activeWindow()->winId(); } else if (!QApplication::topLevelWidgets().isEmpty()) { window = qApp->topLevelWidgets().first()->winId(); } delete d->wallet; d->wallet = Wallet::openWallet(Wallet::NetworkWallet(), window); if (!d->wallet) { d->walletOpenFailed = true; return nullptr; } d->prepareWallet(); return d->wallet; } void TransportManagerPrivate::prepareWallet() { if (!wallet) { return; } if (!wallet->hasFolder(WALLET_FOLDER)) { wallet->createFolder(WALLET_FOLDER); } wallet->setFolder(WALLET_FOLDER); } void TransportManager::loadPasswords() { for (Transport *t : qAsConst(d->transports)) { t->readPassword(); } // flush the wallet queue const QList copy = d->walletQueue; d->walletQueue.clear(); for (TransportJob *job : copy) { job->start(); } emit passwordsChanged(); } void TransportManager::loadPasswordsAsync() { qCDebug(MAILTRANSPORT_LOG); // check if there is anything to do at all bool found = false; for (Transport *t : qAsConst(d->transports)) { if (!t->isComplete()) { found = true; break; } } if (!found) { return; } // async wallet opening if (!d->wallet && !d->walletOpenFailed) { WId window = 0; if (qApp->activeWindow()) { window = qApp->activeWindow()->winId(); } else if (!QApplication::topLevelWidgets().isEmpty()) { window = qApp->topLevelWidgets().first()->winId(); } d->wallet = Wallet::openWallet(Wallet::NetworkWallet(), window, Wallet::Asynchronous); if (d->wallet) { connect(d->wallet, &KWallet::Wallet::walletOpened, this, [this](bool status) { d->slotWalletOpened(status);}); d->walletAsyncOpen = true; } else { d->walletOpenFailed = true; loadPasswords(); } return; } if (d->wallet && !d->walletAsyncOpen) { loadPasswords(); } } void TransportManagerPrivate::slotWalletOpened(bool success) { qCDebug(MAILTRANSPORT_LOG); walletAsyncOpen = false; if (!success) { walletOpenFailed = true; delete wallet; wallet = nullptr; } else { prepareWallet(); } q->loadPasswords(); } void TransportManagerPrivate::validateDefault() { if (!q->transportById(defaultTransportId, false)) { if (q->isEmpty()) { defaultTransportId = -1; } else { defaultTransportId = transports.first()->id(); writeConfig(); } } } void TransportManagerPrivate::migrateToWallet() { // check if we tried this already static bool firstRun = true; if (!firstRun) { return; } firstRun = false; // check if we are the main instance if (!isMainInstance) { return; } // check if migration is needed QStringList names; for (Transport *t : qAsConst(transports)) { if (t->needsWalletMigration()) { names << t->name(); } } if (names.isEmpty()) { return; } // ask user if he wants to migrate int result = KMessageBox::questionYesNoList( nullptr, i18n("The following mail transports store their passwords in an " "unencrypted configuration file.\nFor security reasons, " "please consider migrating these passwords to KWallet, the " "KDE Wallet management tool,\nwhich stores sensitive data " "for you in a strongly encrypted file.\n" "Do you want to migrate your passwords to KWallet?"), names, i18n("Question"), KGuiItem(i18n("Migrate")), KGuiItem(i18n("Keep")), QStringLiteral("WalletMigrate")); if (result != KMessageBox::Yes) { return; } // perform migration for (Transport *t : qAsConst(transports)) { if (t->needsWalletMigration()) { t->migrateToWallet(); } } } void TransportManagerPrivate::dbusServiceUnregistered() { QDBusConnection::sessionBus().registerService(DBUS_SERVICE_NAME); } void TransportManagerPrivate::jobResult(KJob *job) { walletQueue.removeAll(static_cast(job)); } #include "moc_transportmanager.cpp" diff --git a/src/kmailtransport/widgets/transportlistview.cpp b/src/kmailtransport/widgets/transportlistview.cpp index c8bf5a5..f40e9d9 100644 --- a/src/kmailtransport/widgets/transportlistview.cpp +++ b/src/kmailtransport/widgets/transportlistview.cpp @@ -1,124 +1,125 @@ /* Copyright (c) 2009 Constantin Berzan Based on KMail code by: Copyright (c) 2002 Marc Mutz Copyright (c) 2007 Mathias Soeken This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "transportlistview.h" #include "transport.h" #include "transportmanager.h" #include "transporttype.h" #include #include #include "mailtransport_debug.h" #include using namespace MailTransport; TransportListView::TransportListView(QWidget *parent) : QTreeWidget(parent) { setHeaderLabels(QStringList() << i18nc("@title:column email transport name", "Name") << i18nc("@title:column email transport type", "Type")); setRootIsDecorated(false); header()->setSectionsMovable(false); header()->setSectionResizeMode(QHeaderView::ResizeToContents); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setSortingEnabled(true); sortByColumn(0, Qt::AscendingOrder); setSelectionMode(SingleSelection); fillTransportList(); connect(TransportManager::self(), &TransportManager::transportsChanged, this, &TransportListView::fillTransportList); } void TransportListView::editItem(QTreeWidgetItem *item, int column) { // TODO: is there a nicer way to make only the 'name' column editable? if (column == 0 && item) { Qt::ItemFlags oldFlags = item->flags(); item->setFlags(oldFlags | Qt::ItemIsEditable); QTreeWidget::editItem(item, 0); item->setFlags(oldFlags); const int id = item->data(0, Qt::UserRole).toInt(); Transport *t = TransportManager::self()->transportById(id); if (!t) { qCWarning(MAILTRANSPORT_LOG) << "Transport" << id << "not known by manager."; return; } if (TransportManager::self()->defaultTransportId() == t->id()) { item->setText(0, t->name()); } } } void TransportListView::commitData(QWidget *editor) { if (selectedItems().isEmpty()) { // transport was deleted by someone else??? qCDebug(MAILTRANSPORT_LOG) << "No selected item."; return; } QTreeWidgetItem *item = selectedItems().first(); QLineEdit *edit = dynamic_cast(editor); // krazy:exclude=qclasses Q_ASSERT(edit); // original code had if const int id = item->data(0, Qt::UserRole).toInt(); Transport *t = TransportManager::self()->transportById(id); if (!t) { qCWarning(MAILTRANSPORT_LOG) << "Transport" << id << "not known by manager."; return; } qCDebug(MAILTRANSPORT_LOG) << "Renaming transport" << id << "to" << edit->text(); t->setName(edit->text()); t->forceUniqueName(); t->save(); } void TransportListView::fillTransportList() { // try to preserve the selection int selected = -1; if (currentItem()) { selected = currentItem()->data(0, Qt::UserRole).toInt(); } clear(); - foreach (Transport *t, TransportManager::self()->transports()) { + const auto lstTransports = TransportManager::self()->transports(); + for (Transport *t : lstTransports) { QTreeWidgetItem *item = new QTreeWidgetItem(this); item->setData(0, Qt::UserRole, t->id()); QString name = t->name(); if (TransportManager::self()->defaultTransportId() == t->id()) { name += i18nc("@label the default mail transport", " (Default)"); QFont font(item->font(0)); font.setBold(true); item->setFont(0, font); } item->setText(0, name); item->setText(1, t->transportType().name()); if (t->id() == selected) { setCurrentItem(item); } } }