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"