Libksieve

sievedebugdialog.cpp
1/*
2 sievedebugdialog.cpp
3
4 SPDX-FileCopyrightText: 2005 Martijn Klingens <klingens@kde.org>
5
6 SPDX-License-Identifier: GPL-2.0-only
7*/
8
9#include "sievedebugdialog.h"
10#include "util/findaccountinfojob.h"
11#include "util/util.h"
12#include <TextCustomEditor/PlainTextEditor>
13#include <TextCustomEditor/PlainTextEditorWidget>
14
15#include "kmanagesieve/sievejob.h"
16#include "libksieveui_debug.h"
17#include <KLocalizedString>
18#include <KSyntaxHighlighting/Definition>
19#include <KSyntaxHighlighting/SyntaxHighlighter>
20#include <KSyntaxHighlighting/Theme>
21
22#include <KConfigGroup>
23#include <KSharedConfig>
24#include <KWindowConfig>
25#include <QDialogButtonBox>
26#include <QPushButton>
27#include <QTimer>
28#include <QVBoxLayout>
29#include <QWindow>
30
31using namespace KSieveUi;
32namespace
33{
34static const char mySieveDebugDialogGroupName[] = "SieveDebugDialog";
35}
36SieveDebugDialog::SieveDebugDialog(KSieveCore::SieveImapPasswordProvider *passwordProvider, QWidget *parent)
37 : QDialog(parent)
38 , mPasswordProvider(passwordProvider)
39{
40 setWindowTitle(i18nc("@title:window", "Sieve Diagnostics"));
41 auto mainLayout = new QVBoxLayout(this);
42
43 // Collect all accounts
44 mResourceIdentifier = KSieveCore::Util::sieveImapResourceNames();
45
46 mEdit = new TextCustomEditor::PlainTextEditorWidget(this);
47 mEdit->setReadOnly(true);
48 const KSyntaxHighlighting::Definition def = mRepo.definitionForName(QStringLiteral("Sieve"));
49 if (!def.isValid()) {
50 qCWarning(LIBKSIEVEUI_LOG) << "Invalid definition name";
51 }
52
53 auto hl = new KSyntaxHighlighting::SyntaxHighlighter(mEdit->editor()->document());
54 hl->setTheme((palette().color(QPalette::Base).lightness() < 128) ? mRepo.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
55 : mRepo.defaultTheme(KSyntaxHighlighting::Repository::LightTheme));
56 hl->setDefinition(def);
57
58 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this);
59 connect(buttonBox, &QDialogButtonBox::rejected, this, &SieveDebugDialog::reject);
60
61 mainLayout->addWidget(mEdit);
62 mainLayout->addWidget(buttonBox);
63
64 if (!mResourceIdentifier.isEmpty()) {
65 mEdit->editor()->setPlainText(i18n("Collecting diagnostic information about Sieve support...\n\n"));
66 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
67 } else {
68 mEdit->editor()->setPlainText(i18n("No IMAP resource found."));
69 }
70 readConfig();
71}
72
73SieveDebugDialog::~SieveDebugDialog()
74{
75 if (mSieveJob) {
76 mSieveJob->kill();
77 mSieveJob = nullptr;
78 }
79 qCDebug(LIBKSIEVEUI_LOG);
80 writeConfig();
81}
82
83void SieveDebugDialog::readConfig()
84{
85 create(); // ensure a window is created
86 windowHandle()->resize(QSize(640, 480));
87 KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySieveDebugDialogGroupName));
89 resize(windowHandle()->size()); // workaround for QTBUG-40584
90}
91
92void SieveDebugDialog::writeConfig()
93{
94 KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySieveDebugDialogGroupName));
96 group.sync();
97}
98
99void SieveDebugDialog::slotShutDownJob()
100{
101 disconnect(mSieveJob, &KManageSieve::SieveJob::gotList, this, &SieveDebugDialog::slotGetScriptList);
102 mSieveJob->kill();
103 mSieveJob = nullptr;
104 mEdit->editor()->appendPlainText(i18n("Unable to get the info\n\n"));
105 mResourceIdentifier.pop_front();
106 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
107}
108
109void SieveDebugDialog::slotDiagNextAccount()
110{
111 if (mResourceIdentifier.isEmpty()) {
112 return;
113 }
114 if (!mShutDownJob) {
115 mShutDownJob = new QTimer(this);
116 mShutDownJob->setSingleShot(true);
117 connect(mShutDownJob, &QTimer::timeout, this, &SieveDebugDialog::slotShutDownJob);
118 }
119 mShutDownJob->start(30 * 1000); // 30 seconds
120 const QString ident = mResourceIdentifier.constFirst();
121
122 mEdit->editor()->appendPlainText(i18n("Collecting data for account '%1'...\n", ident));
123 mEdit->editor()->appendPlainText(i18n("------------------------------------------------------------\n"));
124
125 auto job = new KSieveCore::FindAccountInfoJob(this);
126 connect(job, &KSieveCore::FindAccountInfoJob::findAccountInfoFinished, this, &SieveDebugDialog::slotFindAccountInfoFinished);
127 job->setIdentifier(ident);
128 job->setProvider(mPasswordProvider);
129 job->start();
130}
131
132void SieveDebugDialog::slotFindAccountInfoFinished(const KSieveCore::Util::AccountInfo &info)
133{
134 // Detect URL for this IMAP account
135 const QUrl url = info.sieveUrl;
136 if (!url.isValid()) {
137 mEdit->editor()->appendPlainText(i18n("(Account does not support Sieve)\n\n"));
138 } else {
139 mUrl = url;
140
141 mSieveJob = KManageSieve::SieveJob::list(mUrl);
142
143 // Laurent: not necessary as it's a readonly dialog
144 // mSieveJob->setProperty("sieveimapaccountsettings", QVariant::fromValue(info.sieveImapAccountSettings));
145 connect(mSieveJob, &KManageSieve::SieveJob::gotList, this, &SieveDebugDialog::slotGetScriptList);
146
147 // Bypass the singleShot timer -- it's fired when we get our data
148 return;
149 }
150
151 // Handle next account async
152 mResourceIdentifier.pop_front();
153 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
154}
155
156void SieveDebugDialog::slotDiagNextScript()
157{
158 if (mScriptList.isEmpty()) {
159 // Continue handling accounts instead
160 mScriptList.clear();
161 mResourceIdentifier.pop_front();
162 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextAccount);
163 return;
164 }
165
166 const QString scriptFile = mScriptList.constFirst();
167 mScriptList.pop_front();
168
169 mEdit->editor()->appendPlainText(i18n("Contents of script '%1':\n", scriptFile));
170
171 auto job = new KSieveCore::FindAccountInfoJob(this);
172 connect(job, &KSieveCore::FindAccountInfoJob::findAccountInfoFinished, this, &SieveDebugDialog::slotFindAccountInfoForScriptFinished);
173 job->setIdentifier(mResourceIdentifier.constFirst());
174 job->setProvider(mPasswordProvider);
175 job->setProperty("scriptfile", scriptFile);
176 job->start();
177}
178
179void SieveDebugDialog::slotFindAccountInfoForScriptFinished(const KSieveCore::Util::AccountInfo &info)
180{
181 mUrl = info.sieveUrl;
182
183 mUrl = mUrl.adjusted(QUrl::RemoveFilename);
184 const QString scriptFile = sender()->property("scriptfile").toString();
185 mUrl.setPath(mUrl.path() + QLatin1Char('/') + scriptFile);
186
187 mSieveJob = KManageSieve::SieveJob::get(mUrl);
188
189 connect(mSieveJob, &KManageSieve::SieveJob::gotScript, this, &SieveDebugDialog::slotGetScript);
190}
191
192void SieveDebugDialog::slotGetScript(KManageSieve::SieveJob *job, bool success, const QString &script, bool active)
193{
194 qCDebug(LIBKSIEVEUI_LOG) << "( ??," << success << ", ?," << active << ")" << Qt::endl << "script:" << Qt::endl << script;
195 mSieveJob = nullptr; // job deletes itself after returning from this slot!
196
197 if (!success) {
198 mEdit->editor()->appendPlainText(
199 i18n("Retrieving the script failed.\n"
200 "The server responded:\n%1",
201 job->errorString()));
202 } else if (script.isEmpty()) {
203 mEdit->editor()->appendPlainText(i18n("(This script is empty)\n\n"));
204 } else {
205 mEdit->editor()->appendPlainText(
206 i18n("------------------------------------------------------------\n"
207 "%1\n"
208 "------------------------------------------------------------\n\n",
209 script));
210 }
211
212 // Fetch next script
213 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextScript);
214}
215
216void SieveDebugDialog::slotGetScriptList(KManageSieve::SieveJob *job, bool success, const QStringList &scriptList, const QString &activeScript)
217{
218 if (mShutDownJob->isActive()) {
219 mShutDownJob->stop();
220 }
221 qCDebug(LIBKSIEVEUI_LOG) << "Success:" << success << ", List:" << scriptList.join(QLatin1Char(',')) << ", active:" << activeScript;
222 mSieveJob = nullptr; // job deletes itself after returning from this slot!
223
224 mEdit->editor()->appendPlainText(i18n("Sieve capabilities:\n"));
225 const QStringList caps = job->sieveCapabilities();
226 if (caps.isEmpty()) {
227 mEdit->editor()->appendPlainText(i18n("(No special capabilities available)"));
228 } else {
229 for (const auto &str : caps) {
230 mEdit->editor()->appendPlainText(QLatin1StringView("* ") + str + QLatin1Char('\n'));
231 }
232 mEdit->editor()->appendPlainText(QStringLiteral("\n"));
233 }
234
235 mEdit->editor()->appendPlainText(i18n("Available Sieve scripts:\n"));
236
237 if (scriptList.isEmpty()) {
238 mEdit->editor()->appendPlainText(i18n("(No Sieve scripts available on this server)\n\n"));
239 } else {
240 mScriptList = scriptList;
241 for (const auto &str : scriptList) {
242 mEdit->editor()->appendPlainText(QLatin1StringView("* ") + str + QLatin1Char('\n'));
243 }
244 mEdit->editor()->appendPlainText(QStringLiteral("\n"));
245 mEdit->editor()->appendPlainText(i18n("Active script: '%1'\n\n", activeScript));
246 }
247
248 // Handle next job: dump scripts for this server
249 QTimer::singleShot(0, this, &SieveDebugDialog::slotDiagNextScript);
250}
251
252#include "moc_sievedebugdialog.cpp"
A job to manage sieve scripts.
Definition sievejob.h:31
void kill(KJob::KillVerbosity verbosity=KJob::Quietly)
Kills the sieve job.
Definition sievejob.cpp:246
QString errorString() const
A human-readable error message.
Definition sievejob.cpp:268
QStringList sieveCapabilities() const
Returns the sieve capabilities of the IMAP server.
Definition sievejob.cpp:254
static SieveJob * list(const QUrl &url)
Lists all available scripts at the given sieve url.
Definition sievejob.cpp:314
static SieveJob * get(const QUrl &source)
Gets a sieve script from an IMAP server.
Definition sievejob.cpp:300
void gotList(KManageSieve::SieveJob *job, bool success, const QStringList &scriptList, const QString &activeScript)
This signal is emitted when a list job has finished.
void gotScript(KManageSieve::SieveJob *job, bool success, const QString &script, bool active)
This signal is emitted when a get job has finished.
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
The SieveImapPasswordProvider class.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KCONFIGGUI_EXPORT void saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
KCONFIGGUI_EXPORT void restoreWindowSize(QWindow *window, const KConfigGroup &config)
void clear()
const T & constFirst() const const
bool isEmpty() const const
void pop_front()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QVariant property(const char *name) const const
QObject * sender() const const
bool isEmpty() const const
QString join(QChar separator) const const
QTextStream & endl(QTextStream &stream)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isActive() const const
void start()
void stop()
void timeout()
RemoveFilename
QUrl adjusted(FormattingOptions options) const const
bool isValid() const const
QString path(ComponentFormattingOptions options) const const
void setPath(const QString &path, ParsingMode mode)
QString toString() const const
void create(WId window, bool initializeWindow, bool destroyOldWindow)
void resize(const QSize &)
QWindow * windowHandle() const const
void resize(const QSize &newSize)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:19 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.