1 /*
2   SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3 
4   SPDX-License-Identifier: GPL-2.0-only
5 */
6 
7 #include "parseuserscriptjob.h"
8 #include "ksieveui/scriptsparsing/parsingutil.h"
9 #include <KLocalizedString>
10 #include <QXmlStreamReader>
11 #include <kmanagesieve/sievejob.h>
12 
13 using namespace KSieveUi;
ParseUserScriptJob(const QUrl & url,QObject * parent)14 ParseUserScriptJob::ParseUserScriptJob(const QUrl &url, QObject *parent)
15     : QObject(parent)
16     , mCurrentUrl(url)
17 {
18 }
19 
~ParseUserScriptJob()20 ParseUserScriptJob::~ParseUserScriptJob()
21 {
22     kill();
23     delete mStreamReader;
24 }
25 
kill()26 void ParseUserScriptJob::kill()
27 {
28     if (mSieveJob) {
29         mSieveJob->kill();
30     }
31     mSieveJob = nullptr;
32 }
33 
scriptUrl() const34 QUrl ParseUserScriptJob::scriptUrl() const
35 {
36     return mCurrentUrl;
37 }
38 
start()39 void ParseUserScriptJob::start()
40 {
41     if (mCurrentUrl.isEmpty()) {
42         emitError(i18n("Path is not specified."));
43         return;
44     }
45     if (mSieveJob) {
46         mSieveJob->kill();
47     }
48     mActiveScripts = QStringList();
49     mError = QString();
50     mSieveJob = KManageSieve::SieveJob::get(mCurrentUrl);
51     connect(mSieveJob, &KManageSieve::SieveJob::result, this, &ParseUserScriptJob::slotGetResult);
52 }
53 
setAutoDelete(bool deleteMe)54 void ParseUserScriptJob::setAutoDelete(bool deleteMe)
55 {
56     mAutoDelete = deleteMe;
57 }
58 
slotGetResult(KManageSieve::SieveJob * job,bool success,const QString & script,bool)59 void ParseUserScriptJob::slotGetResult(KManageSieve::SieveJob *job, bool success, const QString &script, bool)
60 {
61     mSieveJob = nullptr;
62     if (!success) {
63         emitError(
64             i18n("Retrieving the script failed.\n"
65                  "The server responded:\n%1",
66                  job->errorString()));
67         return;
68     }
69     if (script.isEmpty()) {
70         emitError(i18n("Script is empty. (%1)", mCurrentUrl.fileName()));
71         return;
72     }
73     bool result;
74     const QStringList lst = parsescript(script, result);
75     if (result) {
76         emitSuccess(lst);
77     } else {
78         emitError(i18n("Script parsing error."));
79     }
80 }
81 
emitError(const QString & msgError)82 void ParseUserScriptJob::emitError(const QString &msgError)
83 {
84     mError = msgError;
85     Q_EMIT finished(this);
86     if (mAutoDelete) {
87         deleteLater();
88     }
89 }
90 
emitSuccess(const QStringList & activeScriptList)91 void ParseUserScriptJob::emitSuccess(const QStringList &activeScriptList)
92 {
93     mActiveScripts = activeScriptList;
94     Q_EMIT finished(this);
95     if (mAutoDelete) {
96         deleteLater();
97     }
98 }
99 
parsescript(const QString & script,bool & result)100 QStringList ParseUserScriptJob::parsescript(const QString &script, bool &result)
101 {
102     QStringList lst;
103     const QString doc = ParsingUtil::parseScript(script, result);
104     if (result) {
105         lst = extractActiveScript(doc);
106     }
107     return lst;
108 }
109 
activeScriptList() const110 QStringList ParseUserScriptJob::activeScriptList() const
111 {
112     return mActiveScripts;
113 }
114 
error() const115 QString ParseUserScriptJob::error() const
116 {
117     return mError;
118 }
119 
extractActiveScript(const QString & doc)120 QStringList ParseUserScriptJob::extractActiveScript(const QString &doc)
121 {
122     mStreamReader = new QXmlStreamReader(doc);
123     QStringList lstScript;
124     if (mStreamReader->readNextStartElement()) {
125         while (mStreamReader->readNextStartElement()) {
126             const QStringRef tagname = mStreamReader->name();
127             if (tagname == QLatin1String("action")) {
128                 if (mStreamReader->attributes().hasAttribute(QLatin1String("name"))) {
129                     const QString actionName = mStreamReader->attributes().value(QLatin1String("name")).toString();
130                     if (actionName == QLatin1String("include")) {
131                         // Load includes
132                         const QString str = loadInclude();
133                         if (!str.isEmpty()) {
134                             if (!lstScript.contains(str)) {
135                                 lstScript.append(str);
136                             }
137                         }
138                     } else {
139                         mStreamReader->skipCurrentElement();
140                     }
141                 }
142             } else {
143                 mStreamReader->skipCurrentElement();
144             }
145         }
146     }
147     return lstScript;
148 }
149 
loadInclude()150 QString ParseUserScriptJob::loadInclude()
151 {
152     QString scriptName;
153     while (mStreamReader->readNextStartElement()) {
154         if (mStreamReader->name() == QLatin1String("str")) {
155             scriptName = mStreamReader->readElementText();
156         } else {
157             mStreamReader->skipCurrentElement();
158         }
159     }
160     return scriptName;
161 }
162