File indexing completed on 2025-03-30 04:54:33

0001 /*
0002     sievedebugdialog.cpp
0003 
0004     SPDX-FileCopyrightText: 2005 Martijn Klingens <klingens@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only
0007 */
0008 
0009 #include "sievedebugdialog.h"
0010 #include "util/findaccountinfojob.h"
0011 #include "util/util.h"
0012 #include <TextCustomEditor/PlainTextEditor>
0013 #include <TextCustomEditor/PlainTextEditorWidget>
0014 
0015 #include "kmanagesieve/sievejob.h"
0016 #include "libksieveui_debug.h"
0017 #include <KLocalizedString>
0018 #include <KSyntaxHighlighting/Definition>
0019 #include <KSyntaxHighlighting/SyntaxHighlighter>
0020 #include <KSyntaxHighlighting/Theme>
0021 
0022 #include <KConfigGroup>
0023 #include <KSharedConfig>
0024 #include <KWindowConfig>
0025 #include <QDialogButtonBox>
0026 #include <QPushButton>
0027 #include <QTimer>
0028 #include <QVBoxLayout>
0029 #include <QWindow>
0030 
0031 using namespace KSieveUi;
0032 namespace
0033 {
0034 static const char mySieveDebugDialogGroupName[] = "SieveDebugDialog";
0035 }
0036 SieveDebugDialog::SieveDebugDialog(KSieveCore::SieveImapPasswordProvider *passwordProvider, QWidget *parent)
0037     : QDialog(parent)
0038     , mPasswordProvider(passwordProvider)
0039 {
0040     setWindowTitle(i18nc("@title:window", "Sieve Diagnostics"));
0041     auto mainLayout = new QVBoxLayout(this);
0042 
0043     // Collect all accounts
0044     mResourceIdentifier = KSieveCore::Util::sieveImapResourceNames();
0045 
0046     mEdit = new TextCustomEditor::PlainTextEditorWidget(this);
0047     mEdit->setReadOnly(true);
0048     const KSyntaxHighlighting::Definition def = mRepo.definitionForName(QStringLiteral("Sieve"));
0049     if (!def.isValid()) {
0050         qCWarning(LIBKSIEVEUI_LOG) << "Invalid definition name";
0051     }
0052 
0053     auto hl = new KSyntaxHighlighting::SyntaxHighlighter(mEdit->editor()->document());
0054     hl->setTheme((palette().color(QPalette::Base).lightness() < 128) ? mRepo.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
0055                                                                      : mRepo.defaultTheme(KSyntaxHighlighting::Repository::LightTheme));
0056     hl->setDefinition(def);
0057 
0058     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this);
0059     connect(buttonBox, &QDialogButtonBox::rejected, this, &SieveDebugDialog::reject);
0060 
0061     mainLayout->addWidget(mEdit);
0062     mainLayout->addWidget(buttonBox);
0063 
0064     if (!mResourceIdentifier.isEmpty()) {
0065         mEdit->editor()->setPlainText(i18n("Collecting diagnostic information about Sieve support...\n\n"));
0066         QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
0067     } else {
0068         mEdit->editor()->setPlainText(i18n("No IMAP resource found."));
0069     }
0070     readConfig();
0071 }
0072 
0073 SieveDebugDialog::~SieveDebugDialog()
0074 {
0075     if (mSieveJob) {
0076         mSieveJob->kill();
0077         mSieveJob = nullptr;
0078     }
0079     qCDebug(LIBKSIEVEUI_LOG);
0080     writeConfig();
0081 }
0082 
0083 void SieveDebugDialog::readConfig()
0084 {
0085     create(); // ensure a window is created
0086     windowHandle()->resize(QSize(640, 480));
0087     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySieveDebugDialogGroupName));
0088     KWindowConfig::restoreWindowSize(windowHandle(), group);
0089     resize(windowHandle()->size()); // workaround for QTBUG-40584
0090 }
0091 
0092 void SieveDebugDialog::writeConfig()
0093 {
0094     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySieveDebugDialogGroupName));
0095     KWindowConfig::saveWindowSize(windowHandle(), group);
0096     group.sync();
0097 }
0098 
0099 void SieveDebugDialog::slotShutDownJob()
0100 {
0101     disconnect(mSieveJob, &KManageSieve::SieveJob::gotList, this, &SieveDebugDialog::slotGetScriptList);
0102     mSieveJob->kill();
0103     mSieveJob = nullptr;
0104     mEdit->editor()->appendPlainText(i18n("Unable to get the info\n\n"));
0105     mResourceIdentifier.pop_front();
0106     QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
0107 }
0108 
0109 void SieveDebugDialog::slotDiagNextAccount()
0110 {
0111     if (mResourceIdentifier.isEmpty()) {
0112         return;
0113     }
0114     if (!mShutDownJob) {
0115         mShutDownJob = new QTimer(this);
0116         mShutDownJob->setSingleShot(true);
0117         connect(mShutDownJob, &QTimer::timeout, this, &SieveDebugDialog::slotShutDownJob);
0118     }
0119     mShutDownJob->start(30 * 1000); // 30 seconds
0120     const QString ident = mResourceIdentifier.constFirst();
0121 
0122     mEdit->editor()->appendPlainText(i18n("Collecting data for account '%1'...\n", ident));
0123     mEdit->editor()->appendPlainText(i18n("------------------------------------------------------------\n"));
0124 
0125     auto job = new KSieveCore::FindAccountInfoJob(this);
0126     connect(job, &KSieveCore::FindAccountInfoJob::findAccountInfoFinished, this, &SieveDebugDialog::slotFindAccountInfoFinished);
0127     job->setIdentifier(ident);
0128     job->setProvider(mPasswordProvider);
0129     job->start();
0130 }
0131 
0132 void SieveDebugDialog::slotFindAccountInfoFinished(const KSieveCore::Util::AccountInfo &info)
0133 {
0134     // Detect URL for this IMAP account
0135     const QUrl url = info.sieveUrl;
0136     if (!url.isValid()) {
0137         mEdit->editor()->appendPlainText(i18n("(Account does not support Sieve)\n\n"));
0138     } else {
0139         mUrl = url;
0140 
0141         mSieveJob = KManageSieve::SieveJob::list(mUrl);
0142 
0143         // Laurent: not necessary as it's a readonly dialog
0144         // mSieveJob->setProperty("sieveimapaccountsettings", QVariant::fromValue(info.sieveImapAccountSettings));
0145         connect(mSieveJob, &KManageSieve::SieveJob::gotList, this, &SieveDebugDialog::slotGetScriptList);
0146 
0147         // Bypass the singleShot timer -- it's fired when we get our data
0148         return;
0149     }
0150 
0151     // Handle next account async
0152     mResourceIdentifier.pop_front();
0153     QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
0154 }
0155 
0156 void SieveDebugDialog::slotDiagNextScript()
0157 {
0158     if (mScriptList.isEmpty()) {
0159         // Continue handling accounts instead
0160         mScriptList.clear();
0161         mResourceIdentifier.pop_front();
0162         QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
0163         return;
0164     }
0165 
0166     const QString scriptFile = mScriptList.constFirst();
0167     mScriptList.pop_front();
0168 
0169     mEdit->editor()->appendPlainText(i18n("Contents of script '%1':\n", scriptFile));
0170 
0171     auto job = new KSieveCore::FindAccountInfoJob(this);
0172     connect(job, &KSieveCore::FindAccountInfoJob::findAccountInfoFinished, this, &SieveDebugDialog::slotFindAccountInfoForScriptFinished);
0173     job->setIdentifier(mResourceIdentifier.constFirst());
0174     job->setProvider(mPasswordProvider);
0175     job->setProperty("scriptfile", scriptFile);
0176     job->start();
0177 }
0178 
0179 void SieveDebugDialog::slotFindAccountInfoForScriptFinished(const KSieveCore::Util::AccountInfo &info)
0180 {
0181     mUrl = info.sieveUrl;
0182 
0183     mUrl = mUrl.adjusted(QUrl::RemoveFilename);
0184     const QString scriptFile = sender()->property("scriptfile").toString();
0185     mUrl.setPath(mUrl.path() + QLatin1Char('/') + scriptFile);
0186 
0187     mSieveJob = KManageSieve::SieveJob::get(mUrl);
0188 
0189     connect(mSieveJob, &KManageSieve::SieveJob::gotScript, this, &SieveDebugDialog::slotGetScript);
0190 }
0191 
0192 void SieveDebugDialog::slotGetScript(KManageSieve::SieveJob *job, bool success, const QString &script, bool active)
0193 {
0194     qCDebug(LIBKSIEVEUI_LOG) << "( ??," << success << ", ?," << active << ")" << Qt::endl << "script:" << Qt::endl << script;
0195     mSieveJob = nullptr; // job deletes itself after returning from this slot!
0196 
0197     if (!success) {
0198         mEdit->editor()->appendPlainText(
0199             i18n("Retrieving the script failed.\n"
0200                  "The server responded:\n%1",
0201                  job->errorString()));
0202     } else if (script.isEmpty()) {
0203         mEdit->editor()->appendPlainText(i18n("(This script is empty)\n\n"));
0204     } else {
0205         mEdit->editor()->appendPlainText(
0206             i18n("------------------------------------------------------------\n"
0207                  "%1\n"
0208                  "------------------------------------------------------------\n\n",
0209                  script));
0210     }
0211 
0212     // Fetch next script
0213     QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextScript);
0214 }
0215 
0216 void SieveDebugDialog::slotGetScriptList(KManageSieve::SieveJob *job, bool success, const QStringList &scriptList, const QString &activeScript)
0217 {
0218     if (mShutDownJob->isActive()) {
0219         mShutDownJob->stop();
0220     }
0221     qCDebug(LIBKSIEVEUI_LOG) << "Success:" << success << ", List:" << scriptList.join(QLatin1Char(',')) << ", active:" << activeScript;
0222     mSieveJob = nullptr; // job deletes itself after returning from this slot!
0223 
0224     mEdit->editor()->appendPlainText(i18n("Sieve capabilities:\n"));
0225     const QStringList caps = job->sieveCapabilities();
0226     if (caps.isEmpty()) {
0227         mEdit->editor()->appendPlainText(i18n("(No special capabilities available)"));
0228     } else {
0229         for (const auto &str : caps) {
0230             mEdit->editor()->appendPlainText(QLatin1StringView("* ") + str + QLatin1Char('\n'));
0231         }
0232         mEdit->editor()->appendPlainText(QStringLiteral("\n"));
0233     }
0234 
0235     mEdit->editor()->appendPlainText(i18n("Available Sieve scripts:\n"));
0236 
0237     if (scriptList.isEmpty()) {
0238         mEdit->editor()->appendPlainText(i18n("(No Sieve scripts available on this server)\n\n"));
0239     } else {
0240         mScriptList = scriptList;
0241         for (const auto &str : scriptList) {
0242             mEdit->editor()->appendPlainText(QLatin1StringView("* ") + str + QLatin1Char('\n'));
0243         }
0244         mEdit->editor()->appendPlainText(QStringLiteral("\n"));
0245         mEdit->editor()->appendPlainText(i18n("Active script: '%1'\n\n", activeScript));
0246     }
0247 
0248     // Handle next job: dump scripts for this server
0249     QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextScript);
0250 }
0251 
0252 #include "moc_sievedebugdialog.cpp"