File indexing completed on 2024-12-22 05:01:01

0001 /*
0002   SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004   SPDX-License-Identifier: GPL-2.0-only
0005 */
0006 
0007 #include "configureaccountpage.h"
0008 #include "configagentdelegate.h"
0009 #include "kmkernel.h"
0010 #include "newmailnotifierinterface.h"
0011 #include "settings/kmailsettings.h"
0012 #include "undosend/undosendcombobox.h"
0013 #include <MailCommon/AccountConfigOrderDialog>
0014 #include <MessageComposer/MessageComposerSettings>
0015 #include <PimCommon/ConfigureImmutableWidgetUtils>
0016 using namespace PimCommon::ConfigureImmutableWidgetUtils;
0017 #include <MailTransport/TransportManagementWidget>
0018 using MailTransport::TransportManagementWidget;
0019 #include <MailCommon/MailUtil>
0020 
0021 #include "identity/identitypage.h"
0022 #include "kmail_debug.h"
0023 #include <Akonadi/AgentConfigurationDialog>
0024 #include <Akonadi/AgentManager>
0025 #include <Akonadi/AgentType>
0026 #include <Akonadi/AgentTypeDialog>
0027 #include <KConfigGroup>
0028 #include <KLDAPWidgets/LdapConfigureWidget>
0029 #include <KLocalizedString>
0030 #include <KMessageBox>
0031 #include <QComboBox>
0032 
0033 #include <QAbstractItemView>
0034 #include <QFormLayout>
0035 #include <QLabel>
0036 #include <QMenu>
0037 #include <QProcess>
0038 
0039 #include <memory>
0040 
0041 QString AccountsPage::helpAnchor() const
0042 {
0043     return QStringLiteral("configure-accounts");
0044 }
0045 
0046 AccountsPage::AccountsPage(QObject *parent, const KPluginMetaData &data)
0047     : ConfigModuleWithTabs(parent, data)
0048 {
0049     // Identity Tab:
0050     auto identityTab = new KMail::IdentityPage();
0051     addTab(identityTab, i18nc("@title:tab Tab page where the user configures identities", "Identities"));
0052 
0053     //
0054     // "Receiving" tab:
0055     //
0056     auto receivingTab = new AccountsPageReceivingTab();
0057     addTab(receivingTab, i18nc("@title:tab Tab page where the user configures accounts to receive mail", "Receiving"));
0058     connect(receivingTab, &AccountsPageReceivingTab::accountListChanged, this, &AccountsPage::accountListChanged);
0059 
0060     //
0061     // "Sending" tab:
0062     //
0063     auto sendingTab = new AccountsPageSendingTab();
0064     addTab(sendingTab, i18nc("@title:tab Tab page where the user configures accounts to send mail", "Sending"));
0065 
0066     //
0067     // "Sending" tab:
0068     //
0069     auto ldapCompletionTab = new LdapCompetionTab();
0070     addTab(ldapCompletionTab, i18nc("@title:tab Tab page where the user configures ldap server", "LDAP server"));
0071 }
0072 
0073 AccountsPageSendingTab::~AccountsPageSendingTab() = default;
0074 
0075 QString AccountsPageSendingTab::helpAnchor() const
0076 {
0077     return QStringLiteral("configure-accounts-sending");
0078 }
0079 
0080 AccountsPageSendingTab::AccountsPageSendingTab(QWidget *parent)
0081     : ConfigModuleTab(parent)
0082 {
0083     auto formLayout = new QFormLayout(this);
0084     // label: zero stretch ### FIXME more
0085     formLayout->addRow(new QLabel(i18n("Outgoing accounts (add at least one):"), this));
0086 
0087     auto tmw = new TransportManagementWidget(this);
0088     tmw->layout()->setContentsMargins({});
0089     formLayout->addRow(tmw);
0090 
0091     // "confirm before send" check box:
0092     mConfirmSendCheck = new QCheckBox(i18n("&Confirm action"), this);
0093     formLayout->addRow(i18n("Before sending:"), mConfirmSendCheck);
0094     connect(mConfirmSendCheck, &QCheckBox::stateChanged, this, &AccountsPageSendingTab::slotEmitChanged);
0095 
0096     mCheckSpellingBeforeSending = new QCheckBox(i18n("Check spelling"), this);
0097     formLayout->addRow(QString(), mCheckSpellingBeforeSending);
0098     connect(mCheckSpellingBeforeSending, &QCheckBox::stateChanged, this, &AccountsPageSendingTab::slotEmitChanged);
0099 
0100     // "send on check" combo:
0101     mSendOnCheckCombo = new QComboBox(this);
0102     mSendOnCheckCombo->setEditable(false);
0103     mSendOnCheckCombo->addItems(QStringList() << i18n("Never Automatically") << i18n("On Manual Mail Checks") << i18n("On All Mail Checks"));
0104     mSendOnCheckCombo->setWhatsThis(i18n(KMailSettings::self()->sendOnCheckItem()->whatsThis().toUtf8().constData()));
0105     formLayout->addRow(i18n("Send &messages in outbox folder:"), mSendOnCheckCombo);
0106     connect(mSendOnCheckCombo, &QComboBox::activated, this, &AccountsPageSendingTab::slotEmitChanged);
0107 
0108     // "default send method" combo:
0109     mSendMethodCombo = new QComboBox(this);
0110     mSendMethodCombo->setEditable(false);
0111     mSendMethodCombo->addItems(QStringList() << i18n("Send Now") << i18n("Send Later"));
0112     formLayout->addRow(i18n("Defa&ult send method:"), mSendMethodCombo);
0113     connect(mSendMethodCombo, &QComboBox::activated, this, &AccountsPageSendingTab::slotEmitChanged);
0114 
0115     auto hLayout = new QHBoxLayout;
0116     mUndoSend = new QCheckBox(i18n("Enable Undo Send"), this);
0117     hLayout->addWidget(mUndoSend);
0118     connect(mUndoSend, &QCheckBox::toggled, this, [this](bool state) {
0119         mUndoSendComboBox->setEnabled(state);
0120         slotEmitChanged();
0121     });
0122 
0123     mUndoSendComboBox = new UndoSendCombobox(this);
0124     mUndoSendComboBox->setEnabled(false);
0125     hLayout->addWidget(mUndoSendComboBox);
0126     formLayout->addRow(QString(), hLayout);
0127     connect(mUndoSendComboBox, &QComboBox::activated, this, &AccountsPageSendingTab::slotEmitChanged);
0128 }
0129 
0130 void AccountsPageSendingTab::doLoadFromGlobalSettings()
0131 {
0132     mSendOnCheckCombo->setCurrentIndex(KMailSettings::self()->sendOnCheck());
0133     loadWidget(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem());
0134     loadWidget(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem());
0135     loadWidget(mUndoSend, KMailSettings::self()->enabledUndoSendItem());
0136     mUndoSendComboBox->setDelay(KMailSettings::self()->undoSendDelay());
0137 }
0138 
0139 void AccountsPageSendingTab::doLoadOther()
0140 {
0141     mSendMethodCombo->setCurrentIndex(MessageComposer::MessageComposerSettings::self()->sendImmediate() ? 0 : 1);
0142     loadWidget(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem());
0143     loadWidget(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem());
0144     loadWidget(mUndoSend, KMailSettings::self()->enabledUndoSendItem());
0145     mUndoSendComboBox->setDelay(KMailSettings::self()->undoSendDelay());
0146 }
0147 
0148 void AccountsPageSendingTab::save()
0149 {
0150     KMailSettings::self()->setSendOnCheck(mSendOnCheckCombo->currentIndex());
0151     saveCheckBox(mConfirmSendCheck, KMailSettings::self()->confirmBeforeSendItem());
0152     saveCheckBox(mCheckSpellingBeforeSending, KMailSettings::self()->checkSpellingBeforeSendItem());
0153     saveCheckBox(mUndoSend, KMailSettings::self()->enabledUndoSendItem());
0154     MessageComposer::MessageComposerSettings::self()->setSendImmediate(mSendMethodCombo->currentIndex() == 0);
0155     KMailSettings::self()->setUndoSendDelay(mUndoSendComboBox->delay());
0156 }
0157 
0158 QString AccountsPageReceivingTab::helpAnchor() const
0159 {
0160     return QStringLiteral("configure-accounts-receiving");
0161 }
0162 
0163 AccountsPageReceivingTab::AccountsPageReceivingTab(QWidget *parent)
0164     : ConfigModuleTab(parent)
0165 {
0166     const auto service = Akonadi::ServerManager::self()->agentServiceName(Akonadi::ServerManager::Agent, QStringLiteral("akonadi_newmailnotifier_agent"));
0167     mNewMailNotifierInterface =
0168         new OrgFreedesktopAkonadiNewMailNotifierInterface(service, QStringLiteral("/NewMailNotifierAgent"), QDBusConnection::sessionBus(), this);
0169     if (!mNewMailNotifierInterface->isValid()) {
0170         qCDebug(KMAIL_LOG) << " org.freedesktop.Akonadi.NewMailNotifierAgent not found. Please verify your installation";
0171         delete mNewMailNotifierInterface;
0172         mNewMailNotifierInterface = nullptr;
0173     }
0174     mAccountsReceiving.setupUi(this);
0175 
0176     mAccountsReceiving.mAccountsReceiving->setMimeTypeFilter(QStringList() << KMime::Message::mimeType());
0177     mAccountsReceiving.mAccountsReceiving->setCapabilityFilter(QStringList() << QStringLiteral("Resource"));
0178     mAccountsReceiving.mAccountsReceiving->setExcludeCapabilities(QStringList()
0179                                                                   << QStringLiteral("MailTransport") << QStringLiteral("Notes") << QStringLiteral("Autostart"));
0180 
0181     KConfig specialMailCollection(QStringLiteral("specialmailcollectionsrc"));
0182     if (specialMailCollection.hasGroup(QStringLiteral("SpecialCollections"))) {
0183         KConfigGroup grp = specialMailCollection.group(QStringLiteral("SpecialCollections"));
0184         mAccountsReceiving.mAccountsReceiving->setSpecialCollectionIdentifier(grp.readEntry(QStringLiteral("DefaultResourceId")));
0185     }
0186     auto configDelegate = new ConfigAgentDelegate(mAccountsReceiving.mAccountsReceiving->view());
0187     mAccountsReceiving.mAccountsReceiving->setItemDelegate(configDelegate);
0188     connect(configDelegate, &ConfigAgentDelegate::optionsClicked, this, &AccountsPageReceivingTab::slotShowMailCheckMenu);
0189 
0190     connect(mAccountsReceiving.mVerboseNotificationCheck, &QCheckBox::stateChanged, this, &ConfigModuleTab::slotEmitChanged);
0191 
0192     connect(mAccountsReceiving.mOtherNewMailActionsButton, &QAbstractButton::clicked, this, &AccountsPageReceivingTab::slotEditNotifications);
0193     connect(mAccountsReceiving.customizeAccountOrder, &QAbstractButton::clicked, this, &AccountsPageReceivingTab::slotCustomizeAccountOrder);
0194     mAccountsReceiving.mAccountsReceiving->disconnectAddAccountButton();
0195     auto accountMenu = new QMenu(this);
0196     accountMenu->addAction(i18n("Add Mail Account..."), this, &AccountsPageReceivingTab::slotAddMailAccount);
0197     accountMenu->addAction(i18n("Custom Account..."), this, &AccountsPageReceivingTab::slotAddCustomAccount);
0198     mAccountsReceiving.mAccountsReceiving->addAccountButton()->setMenu(accountMenu);
0199 }
0200 
0201 AccountsPageReceivingTab::~AccountsPageReceivingTab()
0202 {
0203     delete mNewMailNotifierInterface;
0204     mRetrievalHash.clear();
0205 }
0206 
0207 void AccountsPageReceivingTab::slotAddCustomAccount()
0208 {
0209     mAccountsReceiving.mAccountsReceiving->slotAddAccount();
0210 }
0211 
0212 void AccountsPageReceivingTab::slotAddMailAccount()
0213 {
0214     const QString path = QStandardPaths::findExecutable(QStringLiteral("accountwizard"));
0215     if (path.isEmpty() || !QProcess::startDetached(path, {})) {
0216         KMessageBox::error(this,
0217                            i18n("Could not start the account wizard. "
0218                                 "Please make sure you have AccountWizard properly installed."),
0219                            i18nc("@title:window", "Unable to start account wizard"));
0220     }
0221 }
0222 
0223 void AccountsPageReceivingTab::slotCustomizeAccountOrder()
0224 {
0225     if (KMKernel::self()) {
0226         MailCommon::AccountConfigOrderDialog dlg(KMKernel::self()->mailCommonSettings(), this);
0227         dlg.exec();
0228     }
0229 }
0230 
0231 void AccountsPageReceivingTab::slotShowMailCheckMenu(const QString &ident, const QPoint &pos)
0232 {
0233     QMenu menu(this);
0234 
0235     bool IncludeInManualChecks;
0236     bool OfflineOnShutdown;
0237     bool CheckOnStartup;
0238     if (!mRetrievalHash.contains(ident)) {
0239         const QString resourceGroupPattern(QStringLiteral("Resource %1"));
0240 
0241         KConfigGroup group;
0242         KConfig *conf = nullptr;
0243         if (KMKernel::self()) {
0244             group = KConfigGroup(KMKernel::self()->config(), resourceGroupPattern.arg(ident));
0245         } else {
0246             conf = new KConfig(QStringLiteral("kmail2rc"));
0247             group = KConfigGroup(conf, resourceGroupPattern.arg(ident));
0248         }
0249 
0250         IncludeInManualChecks = group.readEntry("IncludeInManualChecks", true);
0251 
0252         // Keep sync with kmkernel, don't forget to change there.
0253         OfflineOnShutdown = group.readEntry("OfflineOnShutdown", ident.startsWith(QLatin1StringView("akonadi_pop3_resource")) ? true : false);
0254 
0255         CheckOnStartup = group.readEntry("CheckOnStartup", false);
0256         QSharedPointer<RetrievalOptions> opts(new RetrievalOptions(IncludeInManualChecks, OfflineOnShutdown, CheckOnStartup));
0257         mRetrievalHash.insert(ident, opts);
0258         delete conf;
0259     } else {
0260         QSharedPointer<RetrievalOptions> opts = mRetrievalHash.value(ident);
0261         IncludeInManualChecks = opts->IncludeInManualChecks;
0262         OfflineOnShutdown = opts->OfflineOnShutdown;
0263         CheckOnStartup = opts->CheckOnStartup;
0264     }
0265 
0266     if (!MailCommon::Util::isVirtualCollection(ident)) {
0267         auto manualMailCheck = new QAction(i18nc("Label to a checkbox, so is either checked/unchecked", "Include in Manual Mail Check"), &menu);
0268         manualMailCheck->setCheckable(true);
0269         manualMailCheck->setChecked(IncludeInManualChecks);
0270         manualMailCheck->setData(ident);
0271         menu.addAction(manualMailCheck);
0272         connect(manualMailCheck, &QAction::toggled, this, &AccountsPageReceivingTab::slotIncludeInCheckChanged);
0273     }
0274 
0275     auto switchOffline = new QAction(i18nc("Label to a checkbox, so is either checked/unchecked", "Switch offline on KMail Shutdown"), &menu);
0276     switchOffline->setCheckable(true);
0277     switchOffline->setChecked(OfflineOnShutdown);
0278     switchOffline->setData(ident);
0279     menu.addAction(switchOffline);
0280     connect(switchOffline, &QAction::toggled, this, &AccountsPageReceivingTab::slotOfflineOnShutdownChanged);
0281 
0282     auto checkOnStartup = new QAction(i18n("Check mail on startup"), &menu);
0283     checkOnStartup->setCheckable(true);
0284     checkOnStartup->setChecked(CheckOnStartup);
0285     checkOnStartup->setData(ident);
0286     menu.addAction(checkOnStartup);
0287 
0288     connect(checkOnStartup, &QAction::toggled, this, &AccountsPageReceivingTab::slotCheckOnStatupChanged);
0289 
0290     menu.exec(mAccountsReceiving.mAccountsReceiving->view()->mapToGlobal(pos));
0291 }
0292 
0293 void AccountsPageReceivingTab::slotCheckOnStatupChanged(bool checked)
0294 {
0295     auto action = qobject_cast<QAction *>(sender());
0296     const QString ident = action->data().toString();
0297 
0298     QSharedPointer<RetrievalOptions> opts = mRetrievalHash.value(ident);
0299     opts->CheckOnStartup = checked;
0300     slotEmitChanged();
0301 }
0302 
0303 void AccountsPageReceivingTab::slotIncludeInCheckChanged(bool checked)
0304 {
0305     auto action = qobject_cast<QAction *>(sender());
0306     const QString ident = action->data().toString();
0307 
0308     QSharedPointer<RetrievalOptions> opts = mRetrievalHash.value(ident);
0309     opts->IncludeInManualChecks = checked;
0310     slotEmitChanged();
0311 }
0312 
0313 void AccountsPageReceivingTab::slotOfflineOnShutdownChanged(bool checked)
0314 {
0315     auto action = qobject_cast<QAction *>(sender());
0316     const QString ident = action->data().toString();
0317 
0318     QSharedPointer<RetrievalOptions> opts = mRetrievalHash.value(ident);
0319     opts->OfflineOnShutdown = checked;
0320     slotEmitChanged();
0321 }
0322 
0323 void AccountsPageReceivingTab::slotEditNotifications()
0324 {
0325     const auto instance = Akonadi::AgentManager::self()->instance(QStringLiteral("akonadi_newmailnotifier_agent"));
0326     if (instance.isValid()) {
0327         std::make_unique<Akonadi::AgentConfigurationDialog>(instance, this)->exec();
0328     } else {
0329         KMessageBox::error(this, i18n("New Mail Notifier Agent not registered. Please contact your administrator."));
0330     }
0331 }
0332 
0333 void AccountsPageReceivingTab::doLoadFromGlobalSettings()
0334 {
0335     if (mNewMailNotifierInterface) {
0336         mAccountsReceiving.mVerboseNotificationCheck->setChecked(mNewMailNotifierInterface->verboseMailNotification());
0337     }
0338 }
0339 
0340 void AccountsPageReceivingTab::save()
0341 {
0342     // Save Mail notification settings
0343     if (mNewMailNotifierInterface) {
0344         mNewMailNotifierInterface->setVerboseMailNotification(mAccountsReceiving.mVerboseNotificationCheck->isChecked());
0345     }
0346 
0347     const QString resourceGroupPattern(QStringLiteral("Resource %1"));
0348     QHash<QString, QSharedPointer<RetrievalOptions>>::const_iterator it = mRetrievalHash.cbegin();
0349     const QHash<QString, QSharedPointer<RetrievalOptions>>::const_iterator itEnd = mRetrievalHash.cend();
0350     for (; it != itEnd; ++it) {
0351         KConfigGroup group;
0352         KConfig *conf = nullptr;
0353         if (KMKernel::self()) {
0354             group = KConfigGroup(KMKernel::self()->config(), resourceGroupPattern.arg(it.key()));
0355         } else {
0356             conf = new KConfig(QStringLiteral("kmail2rc"));
0357             group = KConfigGroup(conf, resourceGroupPattern.arg(it.key()));
0358         }
0359         QSharedPointer<RetrievalOptions> opts = it.value();
0360         group.writeEntry("IncludeInManualChecks", opts->IncludeInManualChecks);
0361         group.writeEntry("OfflineOnShutdown", opts->OfflineOnShutdown);
0362         group.writeEntry("CheckOnStartup", opts->CheckOnStartup);
0363         delete conf;
0364     }
0365 }
0366 
0367 LdapCompetionTab::LdapCompetionTab(QWidget *parent)
0368     : ConfigModuleTab(parent)
0369     , mLdapConfigureWidget(new KLDAPWidgets::LdapConfigureWidget(this))
0370 {
0371     auto layout = new QVBoxLayout(this);
0372     layout->setContentsMargins({});
0373 
0374     layout->addWidget(mLdapConfigureWidget);
0375 
0376     connect(mLdapConfigureWidget, &KLDAPWidgets::LdapConfigureWidget::changed, this, qOverload<bool>(&LdapCompetionTab::changed));
0377 }
0378 
0379 LdapCompetionTab::~LdapCompetionTab() = default;
0380 
0381 QString LdapCompetionTab::helpAnchor() const
0382 {
0383     return {};
0384 }
0385 
0386 void LdapCompetionTab::save()
0387 {
0388     mLdapConfigureWidget->save();
0389 }
0390 
0391 void LdapCompetionTab::doLoadOther()
0392 {
0393     mLdapConfigureWidget->load();
0394 }
0395 
0396 #include "moc_configureaccountpage.cpp"