Index: libksieve/ksieve/scriptbuilder.h =================================================================== --- libksieve/ksieve/scriptbuilder.h +++ libksieve/ksieve/scriptbuilder.h @@ -51,8 +51,8 @@ virtual void stringListEntry( const QString & string, bool multiLine, const QString & embeddedHashComment ) = 0; virtual void stringListArgumentEnd() = 0; - virtual void commandStart( const QString & identifier ) = 0; - virtual void commandEnd() = 0; + virtual void commandStart( const QString & identifier, int lineNumber ) = 0; + virtual void commandEnd(int lineNumber) = 0; virtual void testStart( const QString & identifier ) = 0; virtual void testEnd() = 0; @@ -60,8 +60,8 @@ virtual void testListStart() = 0; virtual void testListEnd() = 0; - virtual void blockStart() = 0; - virtual void blockEnd() = 0; + virtual void blockStart(int lineNumber) = 0; + virtual void blockEnd(int lineNumber) = 0; /** A hash comment always includes an implicit lineFeed() at it's end. */ virtual void hashComment( const QString & comment ) = 0; Index: libksieve/ksieveui/CMakeLists.txt =================================================================== --- libksieve/ksieveui/CMakeLists.txt +++ libksieve/ksieveui/CMakeLists.txt @@ -153,6 +153,7 @@ widgets/managesievewidget.cpp debug/sievedebugdialog.cpp util/util.cpp + managescriptsjob/checkkep14supportjob.cpp managescriptsjob/generateglobalscriptjob.cpp managescriptsjob/parseuserscriptjob.cpp templates/sievetemplatewidget.cpp Index: libksieve/ksieveui/managescriptsjob/checkkep14supportjob.h =================================================================== --- libksieve/ksieveui/managescriptsjob/checkkep14supportjob.h +++ libksieve/ksieveui/managescriptsjob/checkkep14supportjob.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, 2014 Montel Laurent + Copyright (c) 2015 Sandro Knauß This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -15,10 +15,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef VACATIONCREATESCRIPTJOB_H -#define VACATIONCREATESCRIPTJOB_H +#ifndef CHECKKEP14SUPPORTJOB_H +#define CHECKKEP14SUPPORTJOB_H #include +#include #include "ksieveui_export.h" @@ -29,37 +30,36 @@ } namespace KSieveUi { -class KSIEVEUI_EXPORT VacationCreateScriptJob : public QObject +class KSIEVEUI_EXPORT CheckKep14SupportJob : public QObject { Q_OBJECT public: - explicit VacationCreateScriptJob(QObject *parent=0); - ~VacationCreateScriptJob(); + explicit CheckKep14SupportJob(QObject *parent=0); + ~CheckKep14SupportJob(); void start(); void setServerUrl(const KUrl &url); - void setScript(const QString &script); - void setServerName(const QString &servername); - void setStatus(bool activate, bool wasActive); + void setServerName(const QString &name); + QString serverName(); -Q_SIGNALS: - void result(bool); - void scriptActive(bool activated, const QString &serverName); + QStringList availableScripts(); + bool hasKep14Support(); + KUrl serverUrl(); -private slots: - void slotPutActiveResult(KManageSieve::SieveJob *job, bool success); - void slotPutInactiveResult(KManageSieve::SieveJob *job, bool success); +Q_SIGNALS: + void result(CheckKep14SupportJob*, bool); private: - void handlePutResult(KManageSieve::SieveJob *, bool success, bool activated); KUrl mUrl; - QString mScript; - QString mServerName; - bool mActivate; - bool mWasActive; KManageSieve::SieveJob *mSieveJob; + QStringList mAvailableScripts; + bool mKep14Support; + QString mServerName; + +private slots: + void slotCheckKep14Support(KManageSieve::SieveJob *job, bool success, const QStringList &availableScripts, const QString &activeScript); }; } -#endif // VACATIONCREATESCRIPTJOB_H +#endif // CHECKKEP14SUPPORTJOB_H Index: libksieve/ksieveui/managescriptsjob/checkkep14supportjob.cpp =================================================================== --- /dev/null +++ libksieve/ksieveui/managescriptsjob/checkkep14supportjob.cpp @@ -0,0 +1,93 @@ +/* + Copyright (c) 2015 Sandro Knauß + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "checkkep14supportjob.h" +#include +#include + +#include +#include +#include + +using namespace KSieveUi; + +CheckKep14SupportJob::CheckKep14SupportJob(QObject *parent) + : QObject(parent), + mSieveJob(0) +{ + +} + +CheckKep14SupportJob::~CheckKep14SupportJob() +{ + +} + +void CheckKep14SupportJob::start() +{ + if (mUrl.isEmpty()) { + qDebug() << " server url is empty"; + deleteLater(); + return; + } + mSieveJob = KManageSieve::SieveJob::list(mUrl); + connect(mSieveJob, SIGNAL(gotList(KManageSieve::SieveJob*,bool,QStringList,QString)), + this, SLOT(slotCheckKep14Support(KManageSieve::SieveJob*,bool,QStringList,QString))); +} + +void CheckKep14SupportJob::setServerUrl(const KUrl &url) +{ + mUrl = url; +} + +KUrl CheckKep14SupportJob::serverUrl() +{ + return mUrl; +} + +void CheckKep14SupportJob::setServerName(const QString &name) +{ + mServerName = name; +} + +QString CheckKep14SupportJob::serverName() +{ + return mServerName; +} + + +QStringList CheckKep14SupportJob::availableScripts() +{ + return mAvailableScripts; +} + +bool CheckKep14SupportJob::hasKep14Support() +{ + return mKep14Support; +} + +void CheckKep14SupportJob::slotCheckKep14Support(KManageSieve::SieveJob *job, bool success, const QStringList &availableScripts, const QString &activeScript) +{ + if (!success) { + emit result(this, false); + return; + } + + mKep14Support = Util::hasKep14Support(job->sieveCapabilities(), availableScripts, activeScript); + mAvailableScripts = availableScripts; + emit result(this, true); +} Index: libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.h =================================================================== --- libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.h +++ libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.h @@ -33,6 +33,7 @@ ~GenerateGlobalScriptJob(); void start(); + void kill(); void addUserActiveScripts(const QStringList &lstScript); @@ -50,7 +51,7 @@ void writeUserScript(); QStringList mListUserActiveScripts; KUrl mCurrentUrl; - KManageSieve::SieveJob *mMasterjob; + KManageSieve::SieveJob *mMasterJob; KManageSieve::SieveJob *mUserJob; }; } Index: libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.cpp =================================================================== --- libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.cpp +++ libksieve/ksieveui/managescriptsjob/generateglobalscriptjob.cpp @@ -25,19 +25,30 @@ GenerateGlobalScriptJob::GenerateGlobalScriptJob(const KUrl &url, QObject *parent) : QObject(parent), mCurrentUrl(url), - mMasterjob(0), + mMasterJob(0), mUserJob(0) { } GenerateGlobalScriptJob::~GenerateGlobalScriptJob() { - if (mMasterjob) - mMasterjob->kill(); - if (mUserJob) + kill(); +} + +void GenerateGlobalScriptJob::kill() +{ + if (mMasterJob) { + mMasterJob->kill(); + } + mMasterJob = 0; + + if (mUserJob) { mUserJob->kill(); + } + mUserJob = 0; } + void GenerateGlobalScriptJob::addUserActiveScripts(const QStringList &lstScript) { mListUserActiveScripts = lstScript; @@ -49,7 +60,7 @@ Q_EMIT error(i18n("Path is not specified.")); return; } - writeMasterScript(); + writeUserScript(); } void GenerateGlobalScriptJob::writeMasterScript() @@ -79,8 +90,8 @@ KUrl url(mCurrentUrl); url.setFileName(QLatin1String("MASTER")); - mMasterjob = KManageSieve::SieveJob::put(url, masterScript, true, true ); - connect( mMasterjob, SIGNAL(result(KManageSieve::SieveJob*,bool,QString,bool)), + mMasterJob = KManageSieve::SieveJob::put(url, masterScript, true, true ); + connect( mMasterJob, SIGNAL(result(KManageSieve::SieveJob*,bool,QString,bool)), this, SLOT(slotPutMasterResult(KManageSieve::SieveJob*,bool)) ); } @@ -90,7 +101,7 @@ Q_EMIT error(i18n("Error when we wrote \"MASTER\" script on server.")); return; } - mMasterjob = 0; + mMasterJob = 0; writeUserScript(); } @@ -107,7 +118,7 @@ "require [\"include\"];\n"); Q_FOREACH (const QString &activeScript, mListUserActiveScripts) { - userScript += QString::fromLatin1("\ninclude :personal \"%1\"").arg(activeScript); + userScript += QString::fromLatin1("\ninclude :personal \"%1\";").arg(activeScript); } KUrl url(mCurrentUrl); Index: libksieve/ksieveui/managescriptsjob/parseuserscriptjob.h =================================================================== --- libksieve/ksieveui/managescriptsjob/parseuserscriptjob.h +++ libksieve/ksieveui/managescriptsjob/parseuserscriptjob.h @@ -19,6 +19,7 @@ #define PARSEUSERSCRIPTJOB_H #include +#include #include #include "ksieveui_export.h" class QDomDocument; @@ -31,28 +32,36 @@ class KSIEVEUI_EXPORT ParseUserScriptJob : public QObject { Q_OBJECT + + friend class ParseUserJobTest; public: - explicit ParseUserScriptJob(QObject *parent=0); + explicit ParseUserScriptJob(const KUrl &url,QObject *parent=0); ~ParseUserScriptJob(); void start(); - void scriptUrl(const KUrl &url); - static QStringList parsescript(const QString &script, bool &result); + KUrl scriptUrl() const; + QStringList activeScriptList() const; + QString error() const; + void kill(); private Q_SLOTS: void slotGetResult( KManageSieve::SieveJob *, bool, const QString &, bool ); Q_SIGNALS: - void success(const QStringList &activeScriptList); - void error(const QString &msgError); + void finished(ParseUserScriptJob* job); private: + void emitSuccess(const QStringList &activeScriptList); + void emitError(const QString &msgError); static QString loadInclude(const QDomElement &element); static QStringList extractActiveScript(const QDomDocument &doc); + static QStringList parsescript(const QString &script, bool &result); KUrl mCurrentUrl; KManageSieve::SieveJob *mSieveJob; + QStringList mActiveScripts; + QString mError; }; } Index: libksieve/ksieveui/managescriptsjob/parseuserscriptjob.cpp =================================================================== --- libksieve/ksieveui/managescriptsjob/parseuserscriptjob.cpp +++ libksieve/ksieveui/managescriptsjob/parseuserscriptjob.cpp @@ -24,32 +24,33 @@ using namespace KSieveUi; -ParseUserScriptJob::ParseUserScriptJob(QObject *parent) +ParseUserScriptJob::ParseUserScriptJob(const KUrl &url, QObject *parent) : QObject(parent), mSieveJob(0) + , mCurrentUrl(url) { } ParseUserScriptJob::~ParseUserScriptJob() { - if ( mSieveJob ) - mSieveJob->kill(); - mSieveJob = 0; + kill(); } -void ParseUserScriptJob::scriptUrl(const KUrl &url) +KUrl ParseUserScriptJob::scriptUrl() const { - mCurrentUrl = url; + return mCurrentUrl; } void ParseUserScriptJob::start() { if (mCurrentUrl.isEmpty()) { - Q_EMIT error(i18n("Path is not specified.")); + emitError(i18n("Path is not specified.")); return; } if ( mSieveJob ) mSieveJob->kill(); + mActiveScripts = QStringList(); + mError = QString(); mSieveJob = KManageSieve::SieveJob::get( mCurrentUrl ); connect( mSieveJob, SIGNAL(result(KManageSieve::SieveJob*,bool,QString,bool)), this, SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool)) ); @@ -59,15 +60,27 @@ { mSieveJob = 0; if (script.isEmpty()) { - Q_EMIT error(i18n("Script is empty.")); + emitError(i18n("Script is empty.")); return; } bool result; const QStringList lst = parsescript(script, result); if (result) - Q_EMIT success(lst); + emitSuccess(lst); else - Q_EMIT error(i18n("Script parsing error")); + emitError(i18n("Script parsing error")); +} + +void ParseUserScriptJob::emitError(const QString &msgError) +{ + mError = msgError; + emit finished(this); +} + +void ParseUserScriptJob::emitSuccess(const QStringList &activeScriptList) +{ + mActiveScripts = activeScriptList; + emit finished(this); } QStringList ParseUserScriptJob::parsescript(const QString &script, bool &result) @@ -80,6 +93,24 @@ return lst; } +QStringList ParseUserScriptJob::activeScriptList() const +{ + return mActiveScripts; +} + +QString ParseUserScriptJob::error() const +{ + return mError; +} + +void ParseUserScriptJob::kill() +{ + if ( mSieveJob ) + mSieveJob->kill(); + mSieveJob = 0; +} + + QStringList ParseUserScriptJob::extractActiveScript(const QDomDocument &doc) { QStringList lstScript; Index: libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.h =================================================================== --- libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.h +++ libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.h @@ -19,7 +19,9 @@ #define PARSEUSERJOBTEST_H #include -class ParseUserTest : public QObject + +namespace KSieveUi { +class ParseUserJobTest : public QObject { Q_OBJECT private Q_SLOTS: @@ -29,5 +31,5 @@ void testParseUserDuplicateActiveScriptJob(); void testParseUserErrorScriptJob(); }; - +} #endif // PARSEUSERJOBTEST_H Index: libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.cpp =================================================================== --- libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.cpp +++ libksieve/ksieveui/managescriptsjob/tests/parseuserjobtest.cpp @@ -18,19 +18,20 @@ #include "ksieveui/managescriptsjob/parseuserscriptjob.h" #include +using namespace KSieveUi; -QTEST_KDEMAIN( ParseUserTest, NoGUI ) +QTEST_KDEMAIN( ParseUserJobTest, NoGUI ) -void ParseUserTest::testParseEmptyUserJob() +void ParseUserJobTest::testParseEmptyUserJob() { const QString script; bool result; - const QStringList lst = KSieveUi::ParseUserScriptJob::parsescript(script, result); + const QStringList lst = ParseUserScriptJob::parsescript(script, result); QCOMPARE(lst.count(), 0); QCOMPARE(result, true); } -void ParseUserTest::testParseUserTwoActiveScriptJob() +void ParseUserJobTest::testParseUserTwoActiveScriptJob() { const QString script = QLatin1String("# USER Management Script\n" "#\n" @@ -44,12 +45,12 @@ "include :personal \"file1\";\n" "include :personal \"file2\";\n"); bool result; - const QStringList lst = KSieveUi::ParseUserScriptJob::parsescript(script, result); + const QStringList lst = ParseUserScriptJob::parsescript(script, result); QCOMPARE(lst.count(), 2); QCOMPARE(result, true); } -void ParseUserTest::testParseUserNoActiveScriptJob() +void ParseUserJobTest::testParseUserNoActiveScriptJob() { const QString script = QLatin1String("# USER Management Script\n" "#\n" @@ -61,12 +62,12 @@ "\n" "require [\"include\"];\n"); bool result; - const QStringList lst = KSieveUi::ParseUserScriptJob::parsescript(script, result); + const QStringList lst = ParseUserScriptJob::parsescript(script, result); QCOMPARE(lst.count(), 0); QCOMPARE(result, true); } -void ParseUserTest::testParseUserDuplicateActiveScriptJob() +void ParseUserJobTest::testParseUserDuplicateActiveScriptJob() { const QString script = QLatin1String("# USER Management Script\n" "#\n" @@ -80,12 +81,12 @@ "include :personal \"file1\";\n" "include :personal \"file1\";\n"); bool result; - const QStringList lst = KSieveUi::ParseUserScriptJob::parsescript(script, result); + const QStringList lst = ParseUserScriptJob::parsescript(script, result); QCOMPARE(lst.count(), 1); QCOMPARE(result, true); } -void ParseUserTest::testParseUserErrorScriptJob() +void ParseUserJobTest::testParseUserErrorScriptJob() { const QString script = QLatin1String("# USER Management Script\n" "#\n" @@ -97,7 +98,7 @@ "\n" "errorscript\n"); bool result; - const QStringList lst = KSieveUi::ParseUserScriptJob::parsescript(script, result); + const QStringList lst = ParseUserScriptJob::parsescript(script, result); QCOMPARE(lst.count(), 0); QCOMPARE(result, false); } Index: libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.h =================================================================== --- libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.h +++ libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.h @@ -33,14 +33,14 @@ void taggedArgument( const QString &tag ); void stringArgument( const QString &string, bool multiLine, const QString & /*fixme*/ ); void numberArgument( unsigned long number, char quantifier ); - void commandStart( const QString &identifier ); - void commandEnd(); + void commandStart( const QString &identifier, int lineNumber); + void commandEnd(int lineNumber); void testStart( const QString &identifier ); void testEnd(); void testListStart(); void testListEnd(); - void blockStart(); - void blockEnd(); + void blockStart(int lineNumber); + void blockEnd(int lineNumber); void stringListArgumentStart(); void stringListArgumentEnd(); void stringListEntry( const QString &string, bool multiline, const QString &hashComment ); Index: libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.cpp =================================================================== --- libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.cpp +++ libksieve/ksieveui/scriptsparsing/xmlprintingscriptbuilder.cpp @@ -50,7 +50,7 @@ write( QLatin1String("num"), ( quantifier ? QString::fromLatin1("quantifier=\"%1\"").arg( quantifier ) : QString()) , QString::number( number ) ); } -void XMLPrintingScriptBuilder::commandStart( const QString &identifier ) +void XMLPrintingScriptBuilder::commandStart( const QString &identifier, int lineNumber ) { if ( identifier == QLatin1String("else") || identifier == QLatin1String("break") || @@ -66,7 +66,7 @@ } } -void XMLPrintingScriptBuilder::commandEnd() +void XMLPrintingScriptBuilder::commandEnd(int lineNumber) { if (mIsAction) { write( QLatin1String("") ); @@ -96,12 +96,12 @@ write( QLatin1String("") ); } -void XMLPrintingScriptBuilder::blockStart() +void XMLPrintingScriptBuilder::blockStart(int lineNumber) { write( QLatin1String("") ); } -void XMLPrintingScriptBuilder::blockEnd() +void XMLPrintingScriptBuilder::blockEnd(int lineNumber) { write( QLatin1String("") ); } Index: libksieve/ksieveui/util/util.h =================================================================== --- libksieve/ksieveui/util/util.h +++ libksieve/ksieveui/util/util.h @@ -45,6 +45,7 @@ class KUrl; class QString; +class QStringList; namespace KSieveUi { @@ -75,6 +76,17 @@ * be available at all. */ KSIEVEUI_EXPORT bool allowOutOfOfficeSettings(); + + /** + * Checks if a server has KEP:14 support + */ + bool hasKep14Support(const QStringList &sieveCapabilities, const QStringList &availableScripts, const QString &activeScript); + + /** + * Is the given scriptName a protected KEP:14 name, that a normal user should not touch directly. + * it tests against MASTER, USER and MANAGEMENT script + */ + bool isKep14ProtectedName(const QString &scriptName); } } Index: libksieve/ksieveui/util/util.cpp =================================================================== --- libksieve/ksieveui/util/util.cpp +++ libksieve/ksieveui/util/util.cpp @@ -166,3 +166,45 @@ { return VacationSettings::self()->allowOutOfOfficeSettings(); } + +bool Util::hasKep14Support(const QStringList &sieveCapabilities, const QStringList &availableScripts, const QString &activeScript) +{ + const bool hasIncludeCapability = sieveCapabilities.contains(QLatin1String("include")); + if (!hasIncludeCapability) { + return false; + } + + bool masterIsActive = !activeScript.isEmpty(); + if (masterIsActive) { + const QString scriptName = activeScript.split(QLatin1Char('.')).first().toLower(); + masterIsActive = (scriptName == QLatin1String("master") || scriptName == QLatin1String("user")); + } + if (!masterIsActive) { + return false; + } + + bool hasUserScript = false; + foreach(const QString &script, availableScripts) { + if (script.isEmpty()) { + continue; + } + const QString name = script.split(QLatin1Char('.')).first().toLower(); + if (name == QLatin1String("user")) { + hasUserScript = true; + break; + } + } + + return hasIncludeCapability && masterIsActive && hasUserScript; +} + +bool Util::isKep14ProtectedName(const QString &name) +{ + QString n = name.split(QLatin1Char('.')).first().toLower(); + if (n == QLatin1String("master") || + n == QLatin1String("user") || + n == QLatin1String("management")) { + return true; + } + return false; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/multiimapvacationdialog.h =================================================================== --- libksieve/ksieveui/vacation/multiimapvacationdialog.h +++ libksieve/ksieveui/vacation/multiimapvacationdialog.h @@ -26,11 +26,12 @@ class QStackedWidget; namespace KSieveUi { class VacationCreateScriptJob; +class MultiImapVacationManager; class KSIEVEUI_EXPORT MultiImapVacationDialog : public KDialog { Q_OBJECT public: - explicit MultiImapVacationDialog(QWidget *parent=0); + explicit MultiImapVacationDialog(MultiImapVacationManager *manager, QWidget *parent=0); ~MultiImapVacationDialog(); QList listCreateJob() const; @@ -49,6 +50,7 @@ QList mListCreateJob; KTabWidget *mTabWidget; QStackedWidget *mStackedWidget; + MultiImapVacationManager* mVacationManager; }; } Index: libksieve/ksieveui/vacation/multiimapvacationdialog.cpp =================================================================== --- libksieve/ksieveui/vacation/multiimapvacationdialog.cpp +++ libksieve/ksieveui/vacation/multiimapvacationdialog.cpp @@ -18,6 +18,7 @@ #include "multiimapvacationdialog.h" #include "vacationpagewidget.h" +#include "multiimapvacationmanager.h" #include "ksieveui/util/util.h" #include @@ -34,8 +35,9 @@ using namespace KSieveUi; -MultiImapVacationDialog::MultiImapVacationDialog(QWidget *parent) +MultiImapVacationDialog::MultiImapVacationDialog(MultiImapVacationManager *manager, QWidget *parent) : KDialog(parent) + , mVacationManager(manager) { setCaption( i18n("Configure \"Out of Office\" Replies") ); @@ -87,17 +89,12 @@ void MultiImapVacationDialog::init() { bool foundOneImap = false; - const Akonadi::AgentInstance::List instances = KSieveUi::Util::imapAgentInstances(); - foreach ( const Akonadi::AgentInstance &instance, instances ) { - if ( instance.status() == Akonadi::AgentInstance::Broken ) - continue; - - const KUrl url = KSieveUi::Util::findSieveUrlForAccount( instance.identifier() ); - if ( !url.isEmpty() ) { - const QString serverName = instance.name(); - createPage(serverName, url); - foundOneImap = true; - } + + QMap list = mVacationManager->serverList(); + foreach (const QString &serverName, list.keys()) { + const KUrl url = list.value(serverName); + createPage(serverName, url); + foundOneImap = true; } if (foundOneImap) { setButtons( Ok | Cancel | Default ); @@ -115,6 +112,7 @@ VacationPageWidget *page = new VacationPageWidget; page->setServerUrl(url); page->setServerName(serverName); + page->setVacationManager(mVacationManager); mTabWidget->addTab(page,serverName); } Index: libksieve/ksieveui/vacation/multiimapvacationmanager.h =================================================================== --- libksieve/ksieveui/vacation/multiimapvacationmanager.h +++ libksieve/ksieveui/vacation/multiimapvacationmanager.h @@ -19,10 +19,15 @@ #define MULTIIMAPVACATIONMANAGER_H #include +#include #include "ksieveui_export.h" +class KUrl; + namespace KSieveUi { +class CheckKep14SupportJob; +class VacationCheckJob; class KSIEVEUI_EXPORT MultiImapVacationManager : public QObject { Q_OBJECT @@ -31,18 +36,24 @@ ~MultiImapVacationManager(); void checkVacation(); + QMap serverList(); + void checkVacation(const QString &serverName, const KUrl &url); + + bool kep14Support(QString serverName); Q_SIGNALS: void scriptActive(bool active, const QString &serverName); - void requestEditVacation(); + void scriptAvailable(const QString &serverName, const QStringList &sieveCapabilities, const QString &scriptName, const QString &script, bool active); private slots: - void slotScriptActive(bool active, const QString &serverName); + void slotScriptActive(VacationCheckJob* job, QString scriptName, bool active); + void slotCheckKep14Ended(CheckKep14SupportJob *job, bool success); private: int mNumberOfJobs; - bool mQuestionAsked; bool mCheckInProgress; + + QMap mKep14Support; //if the server has KEP:14 support }; } #endif // MULTIIMAPVACATIONMANAGER_H Index: libksieve/ksieveui/vacation/multiimapvacationmanager.cpp =================================================================== --- libksieve/ksieveui/vacation/multiimapvacationmanager.cpp +++ libksieve/ksieveui/vacation/multiimapvacationmanager.cpp @@ -18,17 +18,21 @@ #include "multiimapvacationmanager.h" #include "vacationcheckjob.h" #include "util/util.h" +#include +#include +#include #include #include #include +#include + using namespace KSieveUi; MultiImapVacationManager::MultiImapVacationManager(QObject *parent) : QObject(parent), mNumberOfJobs(0), - mQuestionAsked(false), mCheckInProgress(false) { } @@ -38,14 +42,9 @@ } -void MultiImapVacationManager::checkVacation() +QMap MultiImapVacationManager::serverList() { - if (mCheckInProgress) - return; - mNumberOfJobs = 0; - mCheckInProgress = true; - mQuestionAsked = false; - + QMap list; const Akonadi::AgentInstance::List instances = KSieveUi::Util::imapAgentInstances(); foreach ( const Akonadi::AgentInstance &instance, instances ) { if ( instance.status() == Akonadi::AgentInstance::Broken ) @@ -53,32 +52,84 @@ const KUrl url = KSieveUi::Util::findSieveUrlForAccount( instance.identifier() ); if ( !url.isEmpty() ) { - const QString serverName = instance.name(); - ++mNumberOfJobs; - VacationCheckJob *job = new VacationCheckJob(url, serverName, this); - connect(job, SIGNAL(scriptActive(bool,QString)), this, SLOT(slotScriptActive(bool,QString))); + list.insert(instance.name(), url); } } + return list; } -void MultiImapVacationManager::slotScriptActive(bool active, const QString &serverName) +void MultiImapVacationManager::checkVacation(const QString &serverName, const KUrl &url) { - --mNumberOfJobs; - Q_EMIT scriptActive(active, serverName); - - if (active) { - if (!mQuestionAsked) { - mQuestionAsked = true; - if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n" - "Do you want to edit it?"), i18n("Out-of-office reply still active"), - KGuiItem( i18n( "Edit"), QLatin1String("document-properties") ), - KGuiItem( i18n("Ignore"), QLatin1String("dialog-cancel") ) ) - == KMessageBox::Yes ) { - Q_EMIT requestEditVacation(); - } - } + ++mNumberOfJobs; + if (!mKep14Support.contains(serverName)) { + CheckKep14SupportJob *checkKep14Job = new CheckKep14SupportJob(this); + checkKep14Job->setProperty(QLatin1String("triggerScript").latin1(), true); + checkKep14Job->setServerName(serverName); + checkKep14Job->setServerUrl(url); + connect(checkKep14Job, SIGNAL(result(CheckKep14SupportJob*,bool)), SLOT(slotCheckKep14Ended(CheckKep14SupportJob*,bool))); + checkKep14Job->start(); + } + + VacationCheckJob *job = new VacationCheckJob(url, serverName, this); + job->setKep14Support(mKep14Support[serverName]); + connect(job, SIGNAL(scriptActive(VacationCheckJob*,QString,bool)), this, SLOT(slotScriptActive(VacationCheckJob*,QString,bool))); + job->start(); +} + +void MultiImapVacationManager::checkVacation() +{ + if (mCheckInProgress) + return; + mNumberOfJobs = 0; + mCheckInProgress = true; + + QMap list = serverList(); + foreach ( const QString &serverName, list.keys() ) { + const KUrl url = list.value(serverName); + checkVacation(serverName, url); } +} - if (mNumberOfJobs == 0) +void MultiImapVacationManager::slotScriptActive(VacationCheckJob* job, QString scriptName, bool active) +{ + --mNumberOfJobs; + if (mNumberOfJobs == 0) { mCheckInProgress = false; + } + + job->deleteLater(); + + if (job->noScriptFound()) { + emit scriptActive(false, job->serverName()); + return; + } + emit scriptActive(active, job->serverName()); + emit scriptAvailable(job->serverName(), job->sieveCapabilities(), scriptName, job->script(), active); +} + +void MultiImapVacationManager::slotCheckKep14Ended(CheckKep14SupportJob *job, bool success) +{ + job->deleteLater(); + if (!success) { + --mNumberOfJobs; + return; + } + + mKep14Support.insert(job->serverName(), job->hasKep14Support()); + + VacationCheckJob *checkJob = new VacationCheckJob(job->serverUrl(), job->serverName(), this); + checkJob->setKep14Support(job->hasKep14Support()); + connect(checkJob, SIGNAL(scriptActive(VacationCheckJob*,QString,bool)), + SLOT(slotScriptActive(VacationCheckJob*,QString,bool))); + checkJob->start(); +} + +bool MultiImapVacationManager::kep14Support(QString serverName) +{ + if (mKep14Support.contains(serverName)) { + return mKep14Support[serverName]; + } else { + kWarning() << "We don't know the KEP:14 support for this server." << serverName; + } + return false; } Index: libksieve/ksieveui/vacation/tests/CMakeLists.txt =================================================================== --- libksieve/ksieveui/vacation/tests/CMakeLists.txt +++ libksieve/ksieveui/vacation/tests/CMakeLists.txt @@ -1,5 +1,7 @@ include_directories(${CMAKE_SOURCE_DIR}/libksieve ${CMAKE_SOURCE_DIR}/libksieve/ksieveui + ${CMAKE_BINARY_DIR}/libksieve + ${CMAKE_BINARY_DIR}/libksieve/ksieveui ) @@ -10,3 +12,25 @@ KDE4_ADD_EXECUTABLE(vacationmultiservertest ${vacation_multi_server_SRCS} ) TARGET_LINK_LIBRARIES(vacationmultiservertest ${KDE4_KDEUI_LIBS} ksieveui ksieve) +set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) + +macro( add_vacation_test _source ) + set( _test ${_source}test.cpp + ../${_source}.cpp + ../vacationscriptextractor.cpp + ${CMAKE_BINARY_DIR}/libksieve/ksieveui/sieve-vacation.cpp + ${CMAKE_SOURCE_DIR}/libksieve/parser/lexer.cpp + ${CMAKE_SOURCE_DIR}/libksieve/parser/parser.cpp + ${CMAKE_SOURCE_DIR}/libksieve/parser/utf8validator.cpp + ) + get_filename_component( _name ${_source} NAME_WE ) + kde4_add_unit_test( ${_name} TESTNAME vacation-${_name} ${_test} ) + set_target_properties(${_name} PROPERTIES COMPILE_FLAGS -DVACATIONTESTDATADIR="\\"${CMAKE_CURRENT_SOURCE_DIR}/data/\\"") + target_link_libraries( ${_name} + ksieveui + kmanagesieve + ksieve + ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} ${KDEPIMLIBS_KMIME_LIBS} ${KDEPIMLIBS_KPIMIDENTITIES_LIBS}) +endmacro() + +add_vacation_test( vacationutils ) \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-complex.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-complex.siv @@ -0,0 +1,8 @@ +require ["date","relational","vacation"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if allof (currentdate :zone "+0100" :value "ge" "date" "2015-01-02", currentdate :zone "+0100" :value "le" "date" "2015-03-04", not header :contains "X-Spam-Flag" "YES") +{ + vacation :days 7 :addresses "test@test.de" :subject "XXX" "dsfgsdfgsdfg"; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-deactivate-complex.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-deactivate-complex.siv @@ -0,0 +1,8 @@ +require ["date","relational","vacation"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if false # allof (currentdate :zone "+0100" :value "ge" "date" "2015-01-02", currentdate :zone "+0100" :value "le" "date" "2015-03-04", not header :contains "X-Spam-Flag" "YES") +{ + vacation :days 7 :addresses "test@test.de" :subject "XXX" "dsfgsdfgsdfg"; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-deactivate-multiple.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-deactivate-multiple.siv @@ -0,0 +1,19 @@ +require ["vacation"]; + +if true +{ + testcommand; +} + +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if false # true +{ + vacation :subject "XXX" "dsfgsdfgsdfg"; +} + +if true +{ + testcommand; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-deactivate.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-deactivate.siv @@ -0,0 +1,9 @@ +require ["vacation"]; + +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if false # true +{ + vacation :subject "XXX" "dsfgsdfgsdfg"; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-multiple.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-multiple.siv @@ -0,0 +1,16 @@ +require ["vacation"]; + +if false +{ + testcommand; +} + +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +vacation :subject "XXX" "dsfgsdfgsdfg"; + +if false +{ + testcommand; +} Index: libksieve/ksieveui/vacation/tests/data/vacation-notfound.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-notfound.siv @@ -0,0 +1,15 @@ +#blabla + +testcommand; + +if true { + testcmd2; +} + +if false { + testcmd3; +} + +if true { + testcmd4; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/data/vacation-simple.siv =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/data/vacation-simple.siv @@ -0,0 +1,6 @@ +require ["vacation"]; + +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +vacation :subject "XXX" "dsfgsdfgsdfg"; \ No newline at end of file Index: libksieve/ksieveui/vacation/tests/main.cpp =================================================================== --- libksieve/ksieveui/vacation/tests/main.cpp +++ libksieve/ksieveui/vacation/tests/main.cpp @@ -20,6 +20,7 @@ #include #include "vacation/multiimapvacationdialog.h" +#include #include @@ -30,7 +31,8 @@ KApplication app; app.setQuitOnLastWindowClosed( false ); - KSieveUi::MultiImapVacationDialog dlg; + KSieveUi::MultiImapVacationManager manager; + KSieveUi::MultiImapVacationDialog dlg(&manager); dlg.show(); app.exec(); Index: libksieve/ksieveui/vacation/tests/vacationutilstest.h =================================================================== --- libksieve/ksieveui/vacation/tests/vacationutilstest.h +++ libksieve/ksieveui/vacation/tests/vacationutilstest.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2013, 2014 Montel Laurent + Copyright (c) 2015 Sandro Knauß This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as @@ -15,19 +15,27 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef PARSEUSERJOBTEST_H -#define PARSEUSERJOBTEST_H +#ifndef VACATIONUTILSTEST_H +#define VACATIONUTILSTEST_H #include -class ParseUserTest : public QObject + +namespace KSieveUi { +class VacationUtilsTest : public QObject { Q_OBJECT private Q_SLOTS: - void testParseEmptyUserJob(); - void testParseUserTwoActiveScriptJob(); - void testParseUserNoActiveScriptJob(); - void testParseUserDuplicateActiveScriptJob(); - void testParseUserErrorScriptJob(); + void testParseEmptyScript(); + void testParseOnlyComment(); + void testParseActivate_data(); + void testParseActivate(); + void testParseScript_data(); + void testParseScript(); + void testParseScriptComplex(); + void testWriteScript(); + void testWriteSimpleScript(); + void testUpdateVacationBlock(); + void testMergeRequireLine(); }; - -#endif // PARSEUSERJOBTEST_H +} +#endif // VACATIONUTILSTEST_H Index: libksieve/ksieveui/vacation/tests/vacationutilstest.cpp =================================================================== --- /dev/null +++ libksieve/ksieveui/vacation/tests/vacationutilstest.cpp @@ -0,0 +1,303 @@ +/* + Copyright (c) 2015 Sandro Knauß + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "vacationutilstest.h" +#include "vacation/vacationutils.h" + +#include + +#include +#include +#include + +using namespace KSieveUi; + +QTEST_KDEMAIN( VacationUtilsTest, NoGUI ) + +void VacationUtilsTest::testParseEmptyScript() +{ + const QString script; + QCOMPARE(VacationUtils::foundVacationScript(script), false); +} + +void VacationUtilsTest::testParseOnlyComment() +{ + QString script(QLatin1String("#comment")); + QCOMPARE(VacationUtils::foundVacationScript(script), false); + script = QLatin1String("#comment\n\n#comment\n"); + QCOMPARE(VacationUtils::foundVacationScript(script), false); +} + +void VacationUtilsTest::testParseActivate_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("found"); + QTest::addColumn("active"); + + QTest::newRow("notfound") << QString::fromLatin1("vacation-notfound.siv") << false << false; + QTest::newRow("simple") << QString::fromLatin1("vacation-simple.siv") << true << true; + QTest::newRow("multile if") << QString::fromLatin1("vacation-multiple.siv") << true << true; + QTest::newRow("deactivate") << QString::fromLatin1("vacation-deactivate.siv") << true << false; + QTest::newRow("deactivate-multiple if") << QString::fromLatin1("vacation-deactivate-multiple.siv") << true << false; + QTest::newRow("deactivate-complex") << QString::fromLatin1("vacation-deactivate-complex.siv") << true << false; +} + + +void VacationUtilsTest::testParseActivate() +{ + QFETCH(QString, filename); + QFETCH(bool, found); + QFETCH(bool, active); + + QFile file(QLatin1String(VACATIONTESTDATADIR)+filename); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + QCOMPARE(VacationUtils::foundVacationScript(script), found); + + QString messageText; + QString subject; + int notificationInterval; + QStringList aliases; + bool sendForSpam; + QString domainName; + QDate startDate; + QDate endDate; + bool scriptActive = !active; + + bool ret = VacationUtils::parseScript(script, scriptActive, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate); + QCOMPARE(ret, found); + QCOMPARE(scriptActive, active); +} + +void VacationUtilsTest::testParseScript_data() +{ + QTest::addColumn("activate"); + QTest::addColumn("deactivate"); + + QTest::newRow("simple") << QString::fromLatin1("vacation-simple.siv") << QString::fromLatin1("vacation-deactivate.siv"); + QTest::newRow("complex") << QString::fromLatin1("vacation-complex.siv") << QString::fromLatin1("vacation-deactivate-complex.siv"); +} + + +void VacationUtilsTest::testParseScript() +{ + QFETCH(QString, activate); + QFETCH(QString, deactivate); + QFile fileA(QLatin1String(VACATIONTESTDATADIR) + activate); + QVERIFY(fileA.open(QIODevice::ReadOnly)); + QString scriptA = QString::fromUtf8(fileA.readAll()); + QFile fileD(QLatin1String(VACATIONTESTDATADIR) + deactivate); + QVERIFY(fileD.open(QIODevice::ReadOnly)); + QString scriptD = QString::fromUtf8(fileD.readAll()); + + QString messageTextA, messageTextD; + QString subjectA, subjectD; + int notificationIntervalA, notificationIntervalD; + QStringList aliasesA, aliasesD; + bool sendForSpamA, sendForSpamD; + QString domainNameA, domainNameD; + QDate startDateA, startDateD; + QDate endDateA, endDateD; + bool scriptActiveA, scriptActiveD; + VacationUtils::parseScript(scriptA, scriptActiveA, messageTextA, subjectA, notificationIntervalA, aliasesA, sendForSpamA, domainNameA, startDateA, endDateA); + VacationUtils::parseScript(scriptD, scriptActiveD, messageTextD, subjectD, notificationIntervalD, aliasesD, sendForSpamD, domainNameD, startDateD, endDateD); + QCOMPARE(scriptActiveA, true); + QCOMPARE(scriptActiveD, false); + QCOMPARE(messageTextD, messageTextA); + QCOMPARE(subjectD, subjectA); + QCOMPARE(notificationIntervalD, notificationIntervalA); + QCOMPARE(aliasesD, aliasesA); + QCOMPARE(sendForSpamD, sendForSpamA); + QCOMPARE(domainNameD, domainNameA); + QCOMPARE(startDateD, startDateA); + QCOMPARE(endDateD, endDateA); +} + +void VacationUtilsTest::testParseScriptComplex() +{ + QFile file(QLatin1String(VACATIONTESTDATADIR "vacation-complex.siv")); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + + QString messageText; + QString subject; + int notificationInterval; + QStringList aliases; + bool sendForSpam; + QString domainName; + QDate startDate; + QDate endDate; + bool scriptActive; + VacationUtils::parseScript(script, scriptActive, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate); + QCOMPARE(scriptActive, true); + QCOMPARE(messageText, QLatin1String("dsfgsdfgsdfg")); + QCOMPARE(subject, QLatin1String("XXX")); + QCOMPARE(notificationInterval, 7); + QCOMPARE(aliases, QStringList() << QLatin1String("test@test.de")); + QCOMPARE(sendForSpam, false); + QCOMPARE(domainName, QString()); + QCOMPARE(startDate, QDate(2015, 01, 02)); + QCOMPARE(endDate, QDate(2015, 03, 04)); +} + +void VacationUtilsTest::testWriteScript() +{ + QString messageText(QLatin1String("dsfgsdfgsdfg")); + QString subject(QLatin1String("XXX")); + int notificationInterval(7); + QStringList aliases = QStringList() << QLatin1String("test@test.de"); + QList addesses; + bool sendForSpam(false); + QString domainName(QLatin1String("example.org")); + QDate startDate(2015, 01, 02); + QDate endDate(2015, 03, 04); + bool scriptActive(true); + + QString messageTextA; + QString subjectA; + int notificationIntervalA; + QStringList aliasesA; + bool sendForSpamA; + QString domainNameA; + QDate startDateA; + QDate endDateA; + bool scriptActiveA; + + foreach(const QString &alias, aliases) { + KMime::Types::Mailbox a; + a.fromUnicodeString(alias); + addesses.append(a.addrSpec()); + } + + QString script = VacationUtils::composeScript(messageText, scriptActive, subject, notificationInterval, addesses, sendForSpam, domainName, startDate, endDate); + bool ret = VacationUtils::parseScript(script, scriptActiveA, messageTextA, subjectA, notificationIntervalA, aliasesA, sendForSpamA, domainNameA, startDateA, endDateA); + QCOMPARE(ret, true); + QCOMPARE(scriptActiveA, scriptActive); + QCOMPARE(messageTextA, messageText); + QCOMPARE(subjectA, subject); + QCOMPARE(notificationIntervalA, notificationInterval); + QCOMPARE(aliasesA, aliases); + QCOMPARE(sendForSpamA, sendForSpam); + QCOMPARE(domainNameA, domainName); + QCOMPARE(startDateA, startDate); + QCOMPARE(endDateA, endDate); + + scriptActive = false; + script = VacationUtils::composeScript(messageText, scriptActive, subject, notificationInterval, addesses, sendForSpam, domainName, startDate, endDate); + ret = VacationUtils::parseScript(script, scriptActiveA, messageTextA, subjectA, notificationIntervalA, aliasesA, sendForSpamA, domainNameA, startDateA, endDateA); + QCOMPARE(ret, true); + QCOMPARE(scriptActiveA, scriptActive); + QCOMPARE(messageTextA, messageText); + QCOMPARE(subjectA, subject); + QCOMPARE(notificationIntervalA, notificationInterval); + QCOMPARE(aliasesA, aliases); + QCOMPARE(sendForSpamA, sendForSpam); + QCOMPARE(domainNameA, domainName); + QCOMPARE(startDateA, startDate); + QCOMPARE(endDateA, endDate); +} + + +void VacationUtilsTest::testWriteSimpleScript() +{ + QString messageText(QLatin1String("dsfgsdfgsdfg")); + QString subject(QLatin1String("XXX")); + int notificationInterval(7); + bool scriptActive(true); + + QString messageTextA; + QString subjectA; + int notificationIntervalA; + QStringList aliasesA; + bool sendForSpamA; + QString domainNameA; + QDate startDateA; + QDate endDateA; + bool scriptActiveA; + + QString script = VacationUtils::composeScript(messageText, scriptActive, subject, notificationInterval, QList(), true, QString(), QDate(), QDate()); + bool ret = VacationUtils::parseScript(script, scriptActiveA, messageTextA, subjectA, notificationIntervalA, aliasesA, sendForSpamA, domainNameA, startDateA, endDateA); + QCOMPARE(ret, true); + QCOMPARE(scriptActiveA, scriptActive); + QCOMPARE(messageTextA, messageText); + QCOMPARE(subjectA, subject); + QCOMPARE(notificationIntervalA, notificationInterval); + + scriptActive = false; + script = VacationUtils::composeScript(messageText, scriptActive, subject, notificationInterval, QList(), true, QString(), QDate(), QDate()); + ret = VacationUtils::parseScript(script, scriptActiveA, messageTextA, subjectA, notificationIntervalA, aliasesA, sendForSpamA, domainNameA, startDateA, endDateA); + QCOMPARE(ret, true); + QCOMPARE(scriptActiveA, scriptActive); + QCOMPARE(messageTextA, messageText); + QCOMPARE(subjectA, subject); + QCOMPARE(notificationIntervalA, notificationInterval); +} + +void VacationUtilsTest::testUpdateVacationBlock() +{ + QFile fileA(QLatin1String(VACATIONTESTDATADIR "vacation-simple.siv")); + QVERIFY(fileA.open(QIODevice::ReadOnly)); + QString scriptA = QString::fromUtf8(fileA.readAll()); + + QFile fileB(QLatin1String(VACATIONTESTDATADIR "vacation-deactivate.siv")); + QVERIFY(fileB.open(QIODevice::ReadOnly)); + QString scriptB = QString::fromUtf8(fileB.readAll()); + + const QString attend = QLatin1String("if true\n{\ntestcmd;\n}\n"); + const QString require = QLatin1String("require [\"date\", \"test\"];"); + const QString scriptAattend = scriptA + QLatin1String("\n") + attend; + const QString scriptBattend = scriptB + QLatin1String("\n") + attend; + + QStringList linesA = scriptA.split(QLatin1Char('\n')); + QStringList header; + for(int i=0; i<5;i++ ){ + header.append(linesA.at(i)); + } + + QStringList vacation; + for(int i=5; isetActivateVacation( active ); + mDialog->setActivateVacation( active && sActive ); mDialog->setSubject(subject); mDialog->setMessageText( messageText ); mDialog->setNotificationInterval( notificationInterval ); @@ -161,7 +163,8 @@ void Vacation::slotDialogOk() { kDebug(); // compose a new script: - const QString script = VacationUtils::composeScript( mDialog->messageText(), + const bool active = mDialog->activateVacation(); + const QString script = VacationUtils::composeScript( mDialog->messageText(), active, mDialog->subject(), mDialog->notificationInterval(), mDialog->mailAliases(), @@ -169,7 +172,6 @@ mDialog->domainName(), mDialog->startDate(), mDialog->endDate() ); - const bool active = mDialog->activateVacation(); emit scriptActive( active, mServerName); kDebug() << "script:" << endl << script; Index: libksieve/ksieveui/vacation/vacationcheckjob.h =================================================================== --- libksieve/ksieveui/vacation/vacationcheckjob.h +++ libksieve/ksieveui/vacation/vacationcheckjob.h @@ -19,6 +19,7 @@ #define VACATIONCHECKJOB_H #include +#include #include namespace KManageSieve { @@ -26,23 +27,46 @@ } namespace KSieveUi { +class ParseUserScriptJob; class VacationCheckJob : public QObject { Q_OBJECT public: explicit VacationCheckJob(const KUrl &url, const QString &serverName, QObject *parent=0); ~VacationCheckJob(); + void setKep14Support(bool kep14Support); + void start(); + void kill(); + bool noScriptFound(); + QString script(); + QStringList sieveCapabilities(); + QString serverName(); Q_SIGNALS: - void scriptActive(bool active, const QString &serverName); + void scriptActive(VacationCheckJob* job, const QString &sscriptName, bool active); private slots: void slotGetResult(KManageSieve::SieveJob *job, bool success, const QString &script, bool active); + void slotGotActiveScripts(ParseUserScriptJob *job); + void slotGotList(KManageSieve::SieveJob *job, bool success, const QStringList &availableScripts, const QString &activeScript); + void emitError(const QString &errorMessage); + void searchVacationScript(); + void getNextScript(); + bool isVacationScipt(const QString &script) const; + bool isLastScript() const; private: QString mServerName; KUrl mUrl; KManageSieve::SieveJob * mSieveJob; + ParseUserScriptJob *mParseJob; + bool mKep14Support; + QStringList mAvailableScripts; + QStringList mActiveScripts; + int mScriptPos; + bool mNoScriptFound; + QString mScript; + QStringList mSieveCapabilities; }; } Index: libksieve/ksieveui/vacation/vacationcheckjob.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationcheckjob.cpp +++ libksieve/ksieveui/vacation/vacationcheckjob.cpp @@ -16,32 +16,196 @@ */ #include "vacationcheckjob.h" +#include "vacationutils.h" +#include +#include #include +#include + using namespace KSieveUi; VacationCheckJob::VacationCheckJob(const KUrl &url, const QString &serverName, QObject *parent) : QObject(parent), mServerName(serverName), mUrl(url) + , mKep14Support(false) + , mSieveJob(0) + , mParseJob(0) + , mNoScriptFound(0) { - mSieveJob = KManageSieve::SieveJob::get( mUrl ); - mSieveJob->setInteractive( false ); - connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), - SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool)) ); } VacationCheckJob::~VacationCheckJob() { + kill(); +} + +void VacationCheckJob::kill() +{ if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0; + + if (mParseJob) { + mParseJob->kill(); + } + mParseJob = 0; +} + + +void VacationCheckJob::setKep14Support(bool kep14Support) +{ + mKep14Support = kep14Support; } -void VacationCheckJob::slotGetResult(KManageSieve::SieveJob */*job*/, bool success, const QString &/*script*/, bool active) +void VacationCheckJob::start() { + if (mKep14Support) { + KUrl url = mUrl; + url.setFileName(QLatin1String("USER")); + mParseJob = new ParseUserScriptJob(url); + connect(mParseJob, SIGNAL(finished(ParseUserScriptJob*)), SLOT(slotGotActiveScripts(ParseUserScriptJob*))); + mParseJob->start(); + mSieveJob = KManageSieve::SieveJob::list(url); + connect(mSieveJob, SIGNAL(gotList(KManageSieve::SieveJob*,bool,QStringList,QString)), + this, SLOT(slotGotList(KManageSieve::SieveJob*,bool,QStringList,QString))); + } else { + mSieveJob = KManageSieve::SieveJob::get(mUrl); + mSieveJob->setInteractive(false); + connect(mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), + SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool))); + } +} + +void VacationCheckJob::slotGetResult(KManageSieve::SieveJob */*job*/, bool success, const QString &script, bool active) +{ + mScript = script; + mSieveCapabilities = mSieveJob->sieveCapabilities(); mSieveJob = 0; - if ( !success ) - active = false; // default to inactive - emit scriptActive( active, mServerName ); + + if (mKep14Support) { + if (isVacationScipt(script)) { + const QString &scriptName = mAvailableScripts[mScriptPos-1]; + emit scriptActive(this, scriptName, mActiveScripts.contains(scriptName) && VacationUtils::vacationScriptActive(script)); + kDebug() << "vacation script found :)"; + } else if (isLastScript()) { + mNoScriptFound = true; + emit scriptActive(this, QString(), false); + kDebug() << "no vacation script found :("; + } else { + getNextScript(); + } + } else { + if ( !success ) { + active = false; // default to inactive + mNoScriptFound = true; + } + if (active) { + mActiveScripts << mUrl.fileName(); + } + emit scriptActive(this, mUrl.fileName(), active); + } } + +void VacationCheckJob::slotGotActiveScripts(ParseUserScriptJob *job) +{ + mParseJob = 0; + if (!job->error().isEmpty()) { + emitError(QLatin1String("ParseUserScriptJob failed:")+job->error()); + return; + } + mActiveScripts = job->activeScriptList(); + + if (!mSieveJob) { + searchVacationScript(); + } +} + +void VacationCheckJob::slotGotList(KManageSieve::SieveJob *job, bool success, const QStringList &availableScripts, const QString &activeScript) +{ + mSieveJob = 0; + if (!success) { + emitError(QLatin1String("SieveJob list failed.")); + return; + } + + mAvailableScripts = availableScripts; + + if (!mParseJob) { + searchVacationScript(); + } +} + +void VacationCheckJob::emitError(const QString &errorMessage) +{ + qWarning() << errorMessage; + //TODO: emit error +} + +void VacationCheckJob::searchVacationScript() +{ + QStringList scriptList = mActiveScripts; + + // Reorder script list + foreach(const QString &script, mAvailableScripts) { + if (!scriptList.contains(script)) { + scriptList.append(script); + } + } + + mAvailableScripts = scriptList; + mScriptPos = 0; + getNextScript(); +} + +void VacationCheckJob::getNextScript() +{ + if (isLastScript()) { + //TODO: no script found + mNoScriptFound = true; + emit scriptActive(this, QString(), false); + kDebug() << "no vacation script found :("; + } + KUrl url = mUrl; + url.setFileName(mAvailableScripts[mScriptPos]); + mScriptPos += 1; + if (Util::isKep14ProtectedName(url.fileName())) { + getNextScript(); + } + mSieveJob = KManageSieve::SieveJob::get(url); + mSieveJob->setInteractive(false); + connect(mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), + SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool))); +} + +bool VacationCheckJob::isLastScript() const +{ + return mScriptPos >= mAvailableScripts.count(); +} + +bool VacationCheckJob::isVacationScipt(const QString &script) const +{ + return KSieveUi::VacationUtils::foundVacationScript(script); +} + +bool VacationCheckJob::noScriptFound() +{ + return mNoScriptFound; +} + +QString VacationCheckJob::serverName() +{ + return mServerName; +} + +QString VacationCheckJob::script() +{ + return mScript; +} + +QStringList VacationCheckJob::sieveCapabilities() +{ + return mSieveCapabilities; +} + Index: libksieve/ksieveui/vacation/vacationcreatescriptjob.h =================================================================== --- libksieve/ksieveui/vacation/vacationcreatescriptjob.h +++ libksieve/ksieveui/vacation/vacationcreatescriptjob.h @@ -29,6 +29,8 @@ } namespace KSieveUi { +class ParseUserScriptJob; +class GenerateGlobalScriptJob; class KSIEVEUI_EXPORT VacationCreateScriptJob : public QObject { Q_OBJECT @@ -37,28 +39,39 @@ ~VacationCreateScriptJob(); void start(); + void kill(); void setServerUrl(const KUrl &url); void setScript(const QString &script); void setServerName(const QString &servername); + const QString &serverName() const; void setStatus(bool activate, bool wasActive); + void setKep14Support(bool kep14Support); Q_SIGNALS: void result(bool); void scriptActive(bool activated, const QString &serverName); private slots: - void slotPutActiveResult(KManageSieve::SieveJob *job, bool success); - void slotPutInactiveResult(KManageSieve::SieveJob *job, bool success); + void slotPutResult(KManageSieve::SieveJob *job, bool success); + void slotGetScript(KManageSieve::SieveJob *job, bool success, const QString &oldScript, bool active); + void slotGotActiveScripts(ParseUserScriptJob *job); + void slotGenerateDone(const QString &error=QString()); private: - void handlePutResult(KManageSieve::SieveJob *, bool success, bool activated); + void handleResult(); KUrl mUrl; QString mScript; QString mServerName; bool mActivate; - bool mWasActive; + bool mScriptActive; + bool mKep14Support; + bool mUserJobRunning; + bool mScriptJobRunning; + bool mSuccess; KManageSieve::SieveJob *mSieveJob; + ParseUserScriptJob *mParseUserJob; + GenerateGlobalScriptJob *mCreateJob; }; } Index: libksieve/ksieveui/vacation/vacationcreatescriptjob.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationcreatescriptjob.cpp +++ libksieve/ksieveui/vacation/vacationcreatescriptjob.cpp @@ -16,6 +16,9 @@ */ #include "vacationcreatescriptjob.h" +#include "vacationutils.h" +#include +#include #include #include @@ -27,21 +30,46 @@ VacationCreateScriptJob::VacationCreateScriptJob(QObject *parent) : QObject(parent), mActivate(false), - mWasActive(false), - mSieveJob(0) + mScriptActive(false) + , mKep14Support(false) + , mUserJobRunning(false) + , mScriptJobRunning(false) + , mSuccess(true) + , mSieveJob(0) + , mParseUserJob(0) + , mCreateJob(0) { } VacationCreateScriptJob::~VacationCreateScriptJob() { + kill(); +} + +void VacationCreateScriptJob::kill() +{ + if (mSieveJob) { + mSieveJob->kill(); + } + mSieveJob = 0; + + if (mParseUserJob) { + mParseUserJob->kill(); + } + mParseUserJob = 0; + if (mCreateJob) { + mCreateJob->kill(); + } + mParseUserJob = 0; } + void VacationCreateScriptJob::setStatus(bool activate, bool wasActive) { mActivate = activate; - mWasActive = wasActive; + mScriptActive = wasActive; } void VacationCreateScriptJob::setServerName(const QString &servername) @@ -49,20 +77,14 @@ mServerName = servername; } -void VacationCreateScriptJob::start() +const QString &VacationCreateScriptJob::serverName() const { - if (mUrl.isEmpty()) { - qDebug()<<" server url is empty"; - deleteLater(); - return; - } - mSieveJob = KManageSieve::SieveJob::put( mUrl, mScript, mActivate, mWasActive ); - if ( mActivate ) - connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), - SLOT(slotPutActiveResult(KManageSieve::SieveJob*,bool)) ); - else - connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), - SLOT(slotPutInactiveResult(KManageSieve::SieveJob*,bool)) ); + return mServerName; +} + +void VacationCreateScriptJob::setKep14Support(bool kep14Support) +{ + mKep14Support = kep14Support; } void VacationCreateScriptJob::setServerUrl(const KUrl &url) @@ -75,28 +97,104 @@ mScript = script; } -void VacationCreateScriptJob::slotPutActiveResult( KManageSieve::SieveJob * job, bool success ) +void VacationCreateScriptJob::start() +{ + if (mUrl.isEmpty()) { + qDebug()<<" server url is empty"; + deleteLater(); + return; + } + + mUserJobRunning = false; + mScriptJobRunning = true; + mSieveJob = KManageSieve::SieveJob::get(mUrl); + mSieveJob->setInteractive(false); + connect(mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), + SLOT(slotGetScript(KManageSieve::SieveJob*,bool,QString,bool))); + + if (mKep14Support && mActivate && !mScriptActive) { + mUserJobRunning = true; + KUrl url = mUrl; + url.setFileName(QLatin1String("USER")); + mParseUserJob = new ParseUserScriptJob(url, this); + connect(mParseUserJob, SIGNAL(finished(ParseUserScriptJob*)), SLOT(slotGotActiveScripts(ParseUserScriptJob*))); + mParseUserJob->start(); + } +} + +void VacationCreateScriptJob::slotGetScript(KManageSieve::SieveJob *job, bool success, const QString &oldScript, bool active) { - handlePutResult( job, success, true ); + mSieveJob = 0; + QString script = mScript; + if (success || !oldScript.trimmed().isEmpty()) { + script = VacationUtils::mergeRequireLine(oldScript, mScript); + script = VacationUtils::updateVacationBlock(oldScript,mScript); + } + if (mKep14Support) { + mSieveJob = KManageSieve::SieveJob::put( mUrl, mScript, false, false ); + } else { + mSieveJob = KManageSieve::SieveJob::put( mUrl, mScript, mActivate, false ); //Never deactivate + } + connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), + SLOT(slotPutResult(KManageSieve::SieveJob*,bool)) ); } -void VacationCreateScriptJob::slotPutInactiveResult( KManageSieve::SieveJob * job, bool success ) +void VacationCreateScriptJob::slotPutResult( KManageSieve::SieveJob * job, bool success ) { - handlePutResult( job, success, false ); + mSieveJob = 0; + mScriptJobRunning = false; + if (!success) { + mSuccess = false; + } + handleResult(); } -void VacationCreateScriptJob::handlePutResult( KManageSieve::SieveJob *, bool success, bool activated ) +void VacationCreateScriptJob::handleResult() { - if ( success ) - KMessageBox::information( 0, activated + if (mUserJobRunning || mScriptJobRunning) { // Not both jobs are done + return; + } + + if ( mSuccess ) + KMessageBox::information( 0, mActivate ? i18n("Sieve script installed successfully on the server \'%1\'.\n" "Out of Office reply is now active.", mServerName) : i18n("Sieve script installed successfully on the server \'%1\'.\n" "Out of Office reply has been deactivated.", mServerName) ); - kDebug() << "( ???," << success << ", ? )"; - mSieveJob = 0; // job deletes itself after returning from this slot! - Q_EMIT result( success ); - Q_EMIT scriptActive( activated, mServerName ); + kDebug() << "( ???," << mSuccess << ", ? )"; + Q_EMIT result( mSuccess ); + Q_EMIT scriptActive( mActivate, mServerName ); deleteLater(); } + +void VacationCreateScriptJob::slotGotActiveScripts(ParseUserScriptJob *job) +{ + mParseUserJob = 0; + if (!job->error().isEmpty()) { + slotGenerateDone(job->error()); + return; + } + + QStringList list = job->activeScriptList(); + + if (!list.contains(mUrl.fileName())) { + list.prepend(mUrl.fileName()); + mCreateJob = new GenerateGlobalScriptJob(mUrl, this); + mCreateJob->addUserActiveScripts(list); + connect( mCreateJob, SIGNAL(success()), SLOT(slotGenerateDone())); + connect( mCreateJob, SIGNAL(error(QString)), SLOT(slotGenerateDone(QString))); + mCreateJob->start(); + } +} + +void VacationCreateScriptJob::slotGenerateDone(const QString &error) +{ + mCreateJob = 0; + mUserJobRunning = false; + if (!error.isEmpty()) { + qWarning() << error; + mSuccess = false; + } + handleResult(); +} Index: libksieve/ksieveui/vacation/vacationmanager.h =================================================================== --- libksieve/ksieveui/vacation/vacationmanager.h +++ libksieve/ksieveui/vacation/vacationmanager.h @@ -41,17 +41,19 @@ void slotEditVacation(const QString &serverName); Q_SIGNALS: - void updateVacationScriptStatus(bool, const QString&); + void updateVacationScriptStatus(bool active, const QString &serverName); void editVacation(); private slots: void slotDialogCanceled(); void slotDialogOk(); + void slotUpdateVacationScriptStatus(bool active, const QString &serverName); private: QPointer mMultiImapVacationDialog; QPointer mCheckVacation; QWidget *mWidget; + bool mQuestionAsked; }; } Index: libksieve/ksieveui/vacation/vacationmanager.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationmanager.cpp +++ libksieve/ksieveui/vacation/vacationmanager.cpp @@ -30,38 +30,53 @@ VacationManager::VacationManager(QWidget *parent) : QObject(parent), mWidget(parent) + , mMultiImapVacationDialog(0) + , mQuestionAsked(false) { + mCheckVacation = new KSieveUi::MultiImapVacationManager( this ); + connect( mCheckVacation, SIGNAL(scriptActive(bool,QString)), SIGNAL(updateVacationScriptStatus(bool,QString)) ); + connect( mCheckVacation, SIGNAL(scriptActive(bool,QString)), SLOT(slotUpdateVacationScriptStatus(bool,QString)) ); } VacationManager::~VacationManager() { + mCheckVacation = 0; + mMultiImapVacationDialog = 0; } void VacationManager::checkVacation() { - delete mCheckVacation; - - mCheckVacation = new KSieveUi::MultiImapVacationManager( this ); - connect( mCheckVacation, SIGNAL(scriptActive(bool,QString)), SIGNAL(updateVacationScriptStatus(bool,QString)) ); - connect( mCheckVacation, SIGNAL(requestEditVacation()), SIGNAL(editVacation()) ); mCheckVacation->checkVacation(); } +void VacationManager::slotUpdateVacationScriptStatus(bool active, const QString &serverName) +{ + if (active) { + if (!mQuestionAsked) { + mQuestionAsked = true; + if ( KMessageBox::questionYesNo( 0, i18n( "There is still an active out-of-office reply configured.\n" + "Do you want to edit it?"), i18n("Out-of-office reply still active"), + KGuiItem( i18n( "Edit"), QLatin1String("document-properties") ), + KGuiItem( i18n("Ignore"), QLatin1String("dialog-cancel") ) ) + == KMessageBox::Yes ) { + slotEditVacation(serverName); + } + } + } +} + + void VacationManager::slotEditVacation(const QString &serverName) { if ( mMultiImapVacationDialog ) { - mMultiImapVacationDialog->show(); mMultiImapVacationDialog->raise(); mMultiImapVacationDialog->activateWindow(); - if (!serverName.isEmpty()) { - mMultiImapVacationDialog->switchToServerNamePage(serverName); - } - return; + } else { + mMultiImapVacationDialog = new KSieveUi::MultiImapVacationDialog(mCheckVacation, mWidget); + connect( mMultiImapVacationDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) ); + connect( mMultiImapVacationDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCanceled()) ); } - mMultiImapVacationDialog = new KSieveUi::MultiImapVacationDialog(mWidget); - connect( mMultiImapVacationDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) ); - connect( mMultiImapVacationDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCanceled()) ); mMultiImapVacationDialog->show(); if (!serverName.isEmpty()) { mMultiImapVacationDialog->switchToServerNamePage(serverName); @@ -80,6 +95,7 @@ QList listJob = mMultiImapVacationDialog->listCreateJob(); Q_FOREACH (KSieveUi::VacationCreateScriptJob *job, listJob) { connect(job, SIGNAL(scriptActive(bool,QString)), SIGNAL(updateVacationScriptStatus(bool,QString))); + job->setKep14Support(mCheckVacation->kep14Support(job->serverName())); job->start(); } mMultiImapVacationDialog->delayedDestruct(); Index: libksieve/ksieveui/vacation/vacationpagewidget.h =================================================================== --- libksieve/ksieveui/vacation/vacationpagewidget.h +++ libksieve/ksieveui/vacation/vacationpagewidget.h @@ -29,6 +29,8 @@ class VacationEditWidget; class VacationWarningWidget; class VacationCreateScriptJob; +class MultiImapVacationManager; +class ParseUserScriptJob; class VacationPageWidget : public QWidget { Q_OBJECT @@ -40,11 +42,15 @@ void setServerName(const QString &serverName); KSieveUi::VacationCreateScriptJob *writeScript(); void setDefault(); + void setVacationManager(MultiImapVacationManager *vacationManager); private slots: - void slotGetResult(KManageSieve::SieveJob *job, bool success, const QString &script, bool active); + void slotGetResult(const QString &serverName, const QStringList &sieveCapabilities, const QString &scriptName, const QString &script, bool active); private: + + void fillWithDefaults(); + enum PageType { Script = 0, ScriptNotSupported = 1 @@ -56,7 +62,7 @@ QStackedWidget *mStackWidget; VacationEditWidget *mVacationEditWidget; VacationWarningWidget *mVacationWarningWidget; - KManageSieve::SieveJob *mSieveJob; + MultiImapVacationManager *mVacationManager; bool mWasActive; }; } Index: libksieve/ksieveui/vacation/vacationpagewidget.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationpagewidget.cpp +++ libksieve/ksieveui/vacation/vacationpagewidget.cpp @@ -20,6 +20,8 @@ #include "vacationwarningwidget.h" #include "vacationcreatescriptjob.h" #include "vacationutils.h" +#include "multiimapvacationmanager.h" +#include #include "sieve-vacation.h" #include @@ -37,7 +39,6 @@ VacationPageWidget::VacationPageWidget(QWidget *parent) : QWidget(parent), mPageScript(Script), - mSieveJob(0), mWasActive(false) { QVBoxLayout *lay = new QVBoxLayout; @@ -79,18 +80,20 @@ VacationPageWidget::~VacationPageWidget() { - if ( mSieveJob ) - mSieveJob->kill(); - mSieveJob = 0; } void VacationPageWidget::setServerUrl(const KUrl &url) { mUrl = url; mVacationEditWidget->setEnabled(false); - mSieveJob = KManageSieve::SieveJob::get( url ); - connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), - SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool)) ); +} + +void VacationPageWidget::setVacationManager(MultiImapVacationManager *vacationManager) +{ + mVacationManager = vacationManager; + connect(mVacationManager, SIGNAL(scriptAvailable(QString,QStringList,QString,QString,bool)), + SLOT(slotGetResult(QString,QStringList,QString,QString,bool))); + mVacationManager->checkVacation(mServerName, mUrl); } void VacationPageWidget::setServerName(const QString &serverName) @@ -98,24 +101,28 @@ mServerName = serverName; } -void VacationPageWidget::slotGetResult( KManageSieve::SieveJob * job, bool success, const QString & script, bool active ) +void VacationPageWidget::slotGetResult(const QString &serverName, const QStringList &sieveCapabilities, const QString &scriptName, const QString &script, bool active) { - kDebug() << success - << ", ?," << active << ")" << endl + if (serverName != mServerName) { + return; + } + + kDebug() << serverName << sieveCapabilities << endl + << scriptName << "(" << active << ")" << endl << "script:" << endl << script; - mSieveJob = 0; // job deletes itself after returning from this slot! if ( mUrl.protocol() == QLatin1String("sieve") && - !job->sieveCapabilities().contains(QLatin1String("vacation")) ) { + !sieveCapabilities.contains(QLatin1String("vacation")) ) { mStackWidget->setCurrentIndex(ScriptNotSupported); return; } + mUrl.setFileName(scriptName); + // Whether the server supports the "date" extension - const bool supportsSieveDate = mUrl.protocol() == QLatin1String("sieve") && job->sieveCapabilities().contains(QLatin1String("date")); + const bool supportsSieveDate = mUrl.protocol() == QLatin1String("sieve") && sieveCapabilities.contains(QLatin1String("date")); - mVacationEditWidget->setEnabled(true); QString messageText = VacationUtils::defaultMessageText(); QString subject = VacationUtils::defaultSubject(); int notificationInterval = VacationUtils::defaultNotificationInterval(); @@ -124,14 +131,17 @@ QString domainName = VacationUtils::defaultDomainName(); QDate startDate = VacationUtils::defaultStartDate(); QDate endDate = VacationUtils::defaultEndDate(); - if ( !success ) - active = false; // default to inactive + bool scriptActive = true; - if ( ( !success || !KSieveUi::VacationUtils::parseScript( script, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate ) ) ) + const bool bParse = KSieveUi::VacationUtils::parseScript(script, scriptActive, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate); + + if (!bParse) { mVacationWarningWidget->setVisible(true); + } mWasActive = active; - mVacationEditWidget->setActivateVacation( active ); + mVacationEditWidget->setEnabled(true); + mVacationEditWidget->setActivateVacation( active && scriptActive ); mVacationEditWidget->setMessageText( messageText ); mVacationEditWidget->setSubject( subject ); mVacationEditWidget->setNotificationInterval( notificationInterval ); @@ -149,13 +159,16 @@ //emit scriptActive( mWasActive, mServerName ); } + + KSieveUi::VacationCreateScriptJob *VacationPageWidget::writeScript() { if (mPageScript == Script) { KSieveUi::VacationCreateScriptJob *createJob = new KSieveUi::VacationCreateScriptJob; createJob->setServerUrl(mUrl); createJob->setServerName(mServerName); - const QString script = VacationUtils::composeScript( mVacationEditWidget->messageText(), + const bool active = mVacationEditWidget->activateVacation(); + const QString script = VacationUtils::composeScript( mVacationEditWidget->messageText(), active, mVacationEditWidget->subject(), mVacationEditWidget->notificationInterval(), mVacationEditWidget->mailAliases(), @@ -163,7 +176,6 @@ mVacationEditWidget->domainName(), mVacationEditWidget->startDate(), mVacationEditWidget->endDate() ); - const bool active = mVacationEditWidget->activateVacation(); createJob->setStatus(active, mWasActive); //Q_EMIT scriptActive( active, mServerName); createJob->setScript(script); Index: libksieve/ksieveui/vacation/vacationscriptextractor.h =================================================================== --- libksieve/ksieveui/vacation/vacationscriptextractor.h +++ libksieve/ksieveui/vacation/vacationscriptextractor.h @@ -80,14 +80,14 @@ #undef FOREACH #endif #define FOREACH for ( std::vector::const_iterator it = mBuilders.begin(), end = mBuilders.end() ; it != end ; ++it ) (*it)-> - void commandStart( const QString & identifier ) { FOREACH commandStart( identifier ); } - void commandEnd() { FOREACH commandEnd(); } + void commandStart( const QString & identifier, int lineNumber ) { FOREACH commandStart( identifier, lineNumber ); } + void commandEnd(int lineNumber) { FOREACH commandEnd(lineNumber); } void testStart( const QString & identifier ) { FOREACH testStart( identifier ); } void testEnd() { FOREACH testEnd(); } void testListStart() { FOREACH testListStart(); } void testListEnd() { FOREACH testListEnd(); } - void blockStart() { FOREACH blockStart(); } - void blockEnd() { FOREACH blockEnd(); } + void blockStart(int lineNumber) { FOREACH blockStart(lineNumber); } + void blockEnd(int lineNumber) { FOREACH blockEnd(lineNumber); } void hashComment( const QString & comment ) { FOREACH hashComment( comment ); } void bracketComment( const QString & comment ) { FOREACH bracketComment( comment ); } void lineFeed() { FOREACH lineFeed(); } @@ -143,9 +143,11 @@ unsigned int mState; int mNestingDepth; + int mLineNumber; + public: GenericInformationExtractor( const std::vector & nodes ) - : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ) {} + : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ), mLineNumber(0) {} const std::map & results() const { return mResults; } @@ -180,17 +182,17 @@ doProcess( method, string ); } } - void commandStart( const QString & identifier ) { kDebug() ; process( CommandStart, identifier ); } - void commandEnd() { kDebug() ; process( CommandEnd ); } - void testStart( const QString & identifier ) { kDebug() ; process( TestStart, identifier ); } + void commandStart( const QString & identifier, int lineNumber ) { kDebug() << identifier ; process( CommandStart, identifier ); } + void commandEnd(int lineNumber) { kDebug() ; process( CommandEnd ); } + void testStart( const QString & identifier ) { kDebug() << identifier ; process( TestStart, identifier ); } void testEnd() { kDebug() ; process( TestEnd ); } void testListStart() { kDebug() ; process( TestListStart ); } void testListEnd() { kDebug() ; process( TestListEnd ); } - void blockStart() { kDebug() ; process( BlockStart ); ++mNestingDepth; } - void blockEnd() { kDebug() ; --mNestingDepth; process( BlockEnd ); } + void blockStart(int lineNumber) { kDebug() ; process( BlockStart ); ++mNestingDepth; } + void blockEnd(int lineNumber) { kDebug() ; --mNestingDepth; process( BlockEnd ); } void hashComment( const QString & ) { kDebug() ; } void bracketComment( const QString & ) { kDebug() ; } - void lineFeed() { kDebug() ; } + void lineFeed() { kDebug() << ++mLineNumber; } void error( const KSieve::Error & ) { kDebug() ; mState = 0; @@ -208,34 +210,39 @@ typedef GenericInformationExtractor GIE; static const GenericInformationExtractor::StateNode spamNodes[] = { { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 - { 0, GIE::TestStart, "header", 2, 0, 0 }, // 1 - { 0, GIE::TaggedArgument, "contains", 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "allof", 2, 3, 0 }, // 1 + { 0, GIE::TestListStart, 0, 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "not", 4, 3, 0 }, // 3 + { 0, GIE::TestStart, "header", 5, 3, 0 }, // 4 + { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5 // accept both string and string-list: - { 0, GIE::StringArgument, "x-spam-flag", 9, 4, "x-spam-flag" }, // 3 - { 0, GIE::StringListArgumentStart, 0, 5, 0, 0 }, // 4 - { 0, GIE::StringListEntry, "x-spam-flag", 6, 7, "x-spam-flag" }, // 5 - { 0, GIE::StringListEntry, 0, 6, 8, 0 }, // 6 - { 0, GIE::StringListArgumentEnd, 0, 0, 5, 0 }, // 7 - { 0, GIE::StringListArgumentEnd, 0, 9, 0, 0 }, // 8 + { 0, GIE::StringArgument, "x-spam-flag", 12, 7, "x-spam-flag" }, // 6 + { 0, GIE::StringListArgumentStart, 0, 8, 0, 0 }, // 7 + { 0, GIE::StringListEntry, "x-spam-flag", 9, 10, "x-spam-flag" }, // 8 + { 0, GIE::StringListEntry, 0, 9, 11, 0 }, // 9 + { 0, GIE::StringListArgumentEnd, 0, 0, 8, 0 }, // 10 + { 0, GIE::StringListArgumentEnd, 0, 12, 0, 0 }, // 11 // accept both string and string-list: - { 0, GIE::StringArgument, "yes", 15, 10, "spam-flag-yes" }, // 9 - { 0, GIE::StringListArgumentStart, 0, 11, 0, 0 }, // 10 - { 0, GIE::StringListEntry, "yes", 12, 13, "spam-flag-yes" }, // 11 - { 0, GIE::StringListEntry, 0, 12, 14, 0 }, // 12 - { 0, GIE::StringListArgumentEnd, 0, 0, 11, 0 }, // 13 - { 0, GIE::StringListArgumentEnd, 0, 15, 0, 0 }, // 14 + { 0, GIE::StringArgument, "yes", 18, 13, "spam-flag-yes" }, // 12 + { 0, GIE::StringListArgumentStart, 0, 14, 0, 0 }, // 13 + { 0, GIE::StringListEntry, "yes", 15, 16, "spam-flag-yes" }, // 14 + { 0, GIE::StringListEntry, 0, 15, 17, 0 }, // 15 + { 0, GIE::StringListArgumentEnd, 0, 0, 14, 0 }, // 16 + { 0, GIE::StringListArgumentEnd, 0, 18, 0, 0 }, // 17 - { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15 + { 0, GIE::TestEnd, 0, 21, 20, 0 }, // 18 + { 0, GIE::Any, 0, 21, 0, 0 }, // 19 + { 0, GIE::TestListEnd, 0, 21, 19, 0 }, // 20 // block of command, find "stop", take nested if's into account: - { 0, GIE::BlockStart, 0, 17, 0, 0 }, // 16 - { 1, GIE::CommandStart, "stop", 20, 19, "stop" }, // 17 - { -1, GIE::Any, 0, 17, 0, 0 }, // 18 - { 0, GIE::BlockEnd, 0, 0, 18, 0 }, // 19 + { 0, GIE::BlockStart, 0, 22, 18, 0 }, // 21 + { 1, GIE::CommandStart, "vacation", 24, 22, "vacation" }, // 22 + { 1, GIE::Any, 0, 24, 0, 0 }, // 23 + { 0, GIE::BlockEnd, 0, 25, 23, 0 }, // 24 - { -1, GIE::Any, 0, 20, 20, 0 }, // 20 end state + { -1, GIE::Any, 0, 25, 25, 0 }, // 25 end state }; static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ; @@ -250,7 +257,7 @@ bool found() const { return mResults.count( QLatin1String("x-spam-flag") ) && mResults.count( QLatin1String("spam-flag-yes") ) && - mResults.count( QLatin1String("stop") ) ; + mResults.count( QLatin1String("vacation") ) ; } }; @@ -259,39 +266,40 @@ // 'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }' static const GenericInformationExtractor::StateNode domainNodes[] = { { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 - { 0, GIE::TestStart, "not", 2, 0, 0, }, // 1 - { 0, GIE::TestStart, "address", 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "allof", 2, 3, 0 }, // 1 + { 0, GIE::TestListStart, 0, 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "address", 4, 3, 0 }, // 3 // :domain and :contains in arbitrary order: - { 0, GIE::TaggedArgument, "domain", 4, 5, 0 }, // 3 - { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 4 - { 0, GIE::TaggedArgument, "contains", 6, 0, 0 }, // 5 - { 0, GIE::TaggedArgument, "domain", 7, 0, 0 }, // 6 + { 0, GIE::TaggedArgument, "domain", 5, 6, 0 }, // 4 + { 0, GIE::TaggedArgument, "contains", 8, 0, 0 }, // 5 + { 0, GIE::TaggedArgument, "contains", 7, 0, 0 }, // 6 + { 0, GIE::TaggedArgument, "domain", 8, 0, 0 }, // 7 // accept both string and string-list: - { 0, GIE::StringArgument, "from", 13, 8, "from" }, // 7 - { 0, GIE::StringListArgumentStart, 0, 9, 0, 0 }, // 8 - { 0, GIE::StringListEntry, "from", 10, 11, "from" }, // 9 - { 0, GIE::StringListEntry, 0, 10, 12, 0 }, // 10 - { 0, GIE::StringListArgumentEnd, 0, 0, 9, 0 }, // 11 - { 0, GIE::StringListArgumentEnd, 0, 13, 0, 0 }, // 12 + { 0, GIE::StringArgument, "from", 14, 9, "from" }, // 8 + { 0, GIE::StringListArgumentStart, 0, 10, 0, 0 }, // 9 + { 0, GIE::StringListEntry, "from", 11, 12, "from" }, // 10 + { 0, GIE::StringListEntry, 0, 11, 13, 0 }, // 11 + { 0, GIE::StringListArgumentEnd, 0, 0, 10, 0 }, // 12 + { 0, GIE::StringListArgumentEnd, 0, 14, 0, 0 }, // 13 // string: save, string-list: save last - { 0, GIE::StringArgument, 0, 17, 14, "domainName" }, // 13 - { 0, GIE::StringListArgumentStart, 0, 15, 0, 0 }, // 14 - { 0, GIE::StringListEntry, 0, 15, 16, "domainName" }, // 15 - { 0, GIE::StringListArgumentEnd, 0, 17, 0, 0 }, // 16 + { 0, GIE::StringArgument, 0, 18, 15, "domainName" }, // 14 + { 0, GIE::StringListArgumentStart, 0, 16, 0, 0 }, // 15 + { 0, GIE::StringListEntry, 0, 16, 17, "domainName" }, // 16 + { 0, GIE::StringListArgumentEnd, 0, 18, 0, 0 }, // 17 - { 0, GIE::TestEnd, 0, 18, 0, 0 }, // 17 - { 0, GIE::TestEnd, 0, 19, 0, 0 }, // 18 + { 0, GIE::TestEnd, 0, 18, 20, 0 }, // 18 + { 0, GIE::Any, 0, 18, 0, 0 }, // 19 // block of commands, find "stop", take nested if's into account: - { 0, GIE::BlockStart, 0, 20, 0, 0 }, // 19 - { 1, GIE::CommandStart, "stop", 23, 22, "stop" }, // 20 - { -1, GIE::Any, 0, 20, 0, 0 }, // 21 - { 0, GIE::BlockEnd, 0, 0, 21, 0 }, // 22 + { 0, GIE::BlockStart, 0, 21, 19, 0 }, // 20 + { 1, GIE::CommandStart, "vacation", 23, 21, "vacation" }, // 21 + { 1, GIE::Any, 0, 23, 0, 0 }, // 22 + { 0, GIE::BlockEnd, 0, 24, 22, 0 }, // 23 - { -1, GIE::Any, 0, 23, 23, 0 } // 23 end state + { -1, GIE::Any, 0, 24, 24, 0 } // 24 end state }; static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ; @@ -304,7 +312,7 @@ } QString domainName() /*not const, since map::op[] isn't const*/ { - return mResults.count( QLatin1String("stop") ) && mResults.count( QLatin1String("from") ) + return mResults.count( QLatin1String("vacation") ) && mResults.count( QLatin1String("from") ) ? mResults[QLatin1String("domainName")] : QString(); } }; @@ -313,42 +321,44 @@ // currentfate :value "le" date "YYYY-MM-DD) { keep; stop; } static const GenericInformationExtractor::StateNode datesNodes[] = { { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 - { 0, GIE::TestStart, "not", 2, 0, 0 }, // 1 - { 0, GIE::TestStart, "allof", 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "allof", 2, 0, 0 }, // 1 // handle startDate and endDate in arbitrary order - { 0, GIE::TestListStart, 0, 4, 0, 0 }, // 3 - { 0, GIE::TestStart, "currentdate", 5, 0, 0 }, // 4 - { 0, GIE::TaggedArgument, "value", 6, 0, 0 }, // 5 - { 0, GIE::StringArgument, "ge", 7, 9, 0 }, // 6 - { 0, GIE::StringArgument, "date", 8, 0, 0 }, // 7 - { 0, GIE::StringArgument, 0, 12, 0, "startDate" }, // 8 - { 0, GIE::StringArgument, "le", 10, 0, 0 }, // 9 - { 0, GIE::StringArgument, "date", 11, 0, 0 }, // 10 - { 0, GIE::StringArgument, 0, 12, 0, "endDate" }, // 11 - { 0, GIE::TestEnd, 0, 13, 0, 0 }, // 12 - - { 0, GIE::TestStart, "currentdate", 14, 0, 0 }, // 13 - { 0, GIE::TaggedArgument, "value", 15, 0, 0 }, // 14 - { 0, GIE::StringArgument, "le", 16, 18, 0 }, // 15 - { 0, GIE::StringArgument, "date", 17, 0, 0 }, // 16 - { 0, GIE::StringArgument, 0, 21, 0, "endDate" }, // 17 - { 0, GIE::StringArgument, "ge", 19, 0, 0 }, // 18 - { 0, GIE::StringArgument, "date", 20, 0, 0 }, // 19 - { 0, GIE::StringArgument, 0, 21, 0, "startDate" }, // 20 - { 0, GIE::TestEnd, 0, 22, 0, 0 }, // 21 - { 0, GIE::TestListEnd, 0, 23, 0, 0 }, // 22 - - { 0, GIE::TestEnd, 0, 24, 0, 0 }, // 23 - { 0, GIE::TestEnd, 0, 25, 0, 0 }, // 24 + { 0, GIE::TestListStart, 0, 3, 0, 0 }, // 2 + { 0, GIE::TestStart, "currentdate", 4, 3, 0 }, // 3 + { 0, GIE::TaggedArgument, "value", 5, 4, 0 }, // 4 + { 0, GIE::StringArgument, "ge", 6, 8, 0 }, // 5 + { 0, GIE::StringArgument, "date", 7, 0, 0 }, // 6 + { 0, GIE::StringArgument, 0, 11, 0, "startDate" }, // 7 + { 0, GIE::StringArgument, "le", 9, 0, 0 }, // 8 + { 0, GIE::StringArgument, "date", 10, 0, 0 }, // 9 + { 0, GIE::StringArgument, 0, 11, 0, "endDate" }, // 10 + { 0, GIE::TestEnd, 0, 12, 0, 0 }, // 11 + + { 0, GIE::TestStart, "currentdate", 13, 12, 0 }, // 12 + { 0, GIE::TaggedArgument, "value", 14, 13, 0 }, // 13 + { 0, GIE::StringArgument, "le", 15, 17, 0 }, // 14 + { 0, GIE::StringArgument, "date", 16, 0, 0 }, // 15 + { 0, GIE::StringArgument, 0, 20, 0, "endDate" }, // 16 + { 0, GIE::StringArgument, "ge", 18, 0, 0 }, // 17 + { 0, GIE::StringArgument, "date", 19, 0, 0 }, // 18 + { 0, GIE::StringArgument, 0, 20, 0, "startDate" }, // 19 + { 0, GIE::TestEnd, 0, 24, 0, 0 }, // 20 + { 0, GIE::TestStart, 0, 23, 22, 0 }, // 21 + { -1, GIE::Any, 0, 24, 0, 0 }, // 22 + { 0, GIE::TestEnd, 0, 24, 22, 0 }, // 23 + { 0, GIE::TestListEnd, 0, 25, 21, 0 }, // 24 + + { 0, GIE::TestEnd, 0, 26, 0, 0 }, // 25 // block of commands, find "stop", take nested if's into account: - { 0, GIE::BlockStart, 0, 26, 0, 0 }, // 25 - { 1, GIE::CommandStart, "stop", 29, 28, "stop" }, // 26 - { -1, GIE::Any, 0, 26, 0, 0 }, // 27 - { 0, GIE::BlockEnd, 0, 0, 27, 0 }, // 28 + { 0, GIE::BlockStart, 0, 28, 25, 0 }, // 26 + { -1, GIE::Any, 0, 28, 0, 0 }, // 27 + { 1, GIE::CommandStart, "vacation", 30, 27, "vacation" }, // 28 + { -1, GIE::Any, 0, 30, 0, 0 }, // 29 + { 0, GIE::BlockEnd, 0, 31, 29, 0 }, // 30 - { -1, GIE::Any, 0, 27, 27, 0 } // 29 end state + { -1, GIE::Any, 0, 31, 31, 0 } // 31 end state }; static const unsigned int numDatesNodes = sizeof datesNodes / sizeof *datesNodes; @@ -387,34 +397,42 @@ // command itself: VacationCommand, // tagged args: - Days, Addresses, Subject + Days, Addresses, Subject, + VacationEnd, + IfBlock }; public: VacationDataExtractor(); virtual ~VacationDataExtractor(); + bool commandFound() const { return mContext == VacationEnd; } + bool active() const { return mActive; } int notificationInterval() const { return mNotificationInterval; } const QString & messageText() const { return mMessageText; } const QStringList & aliases() const { return mAliases; } + const QString &ifComment() const { return mIfComment; } const QString &subject() const { return mSubject; } + int lineStart() const {return mLineStart;} + int lineEnd() const {return mLineEnd;} + private: - void commandStart( const QString & identifier ); + void commandStart( const QString & identifier, int lineNumber ); - void commandEnd(); + void commandEnd(int lineNumber); - void testStart( const QString & ) {} + void testStart( const QString &); void testEnd() {} void testListStart() {} void testListEnd() {} - void blockStart() {} - void blockEnd() {} - void hashComment( const QString & ) {} - void bracketComment( const QString & ) {} + void blockStart(int lineNumber); + void blockEnd(int lineNumber); + void hashComment( const QString & ); + void bracketComment( const QString &c ) {} void lineFeed() {} void error( const KSieve::Error & e ); void finished(); @@ -435,10 +453,65 @@ QString mMessageText; QString mSubject; QStringList mAliases; + bool mActive; + bool mInIfBlock; + int mBlockLevel; + QString mIfComment; + int mLineStart; + int mLineEnd; void reset(); }; +class RequireExtractor : public KSieve::ScriptBuilder { + enum Context { + None = 0, + // command itself: + RequireCommand, + EndState + }; +public: + RequireExtractor(); + virtual ~RequireExtractor(); + + bool commandFound() const { return mContext == EndState; } + const QStringList &requirements() const { return mRequirements; } + + int lineStart() const {return mLineStart;} + int lineEnd() const {return mLineEnd;} + +private: + void commandStart( const QString & identifier, int lineNumber ); + + void commandEnd(int lineNumber); + + void testStart( const QString &) {} + void testEnd() {} + void testListStart() {} + void testListEnd() {} + void blockStart(int lineNumber){}; + void blockEnd(int lineNumber){}; + void hashComment( const QString & ) {} + void bracketComment( const QString & ) {} + void lineFeed() {} + void error( const KSieve::Error & e ); + void finished(); + + void taggedArgument( const QString & tag ) {} + void numberArgument( unsigned long number, char ) {} + + void stringArgument( const QString & string, bool, const QString & ); + + void stringListArgumentStart(){} + void stringListEntry( const QString & string, bool, const QString & ); + void stringListArgumentEnd(){} + +private: + Context mContext; + QStringList mRequirements; + int mLineStart; + int mLineEnd; +}; } Index: libksieve/ksieveui/vacation/vacationscriptextractor.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationscriptextractor.cpp +++ libksieve/ksieveui/vacation/vacationscriptextractor.cpp @@ -22,6 +22,11 @@ : KSieve::ScriptBuilder(), mContext( None ), mNotificationInterval( 0 ) + , mActive(true) + , mInIfBlock(false) + , mBlockLevel(0) + , mLineStart(0) + , mLineEnd(0) { kDebug(); } @@ -31,17 +36,29 @@ } -void VacationDataExtractor::commandStart( const QString & identifier ) { +void VacationDataExtractor::commandStart( const QString & identifier, int lineNumber ) { kDebug() << "( \"" << identifier <<"\" )"; + if (identifier == QLatin1String("if") && mContext == None) { + mContext = IfBlock; + mLineStart = lineNumber; + mInIfBlock = true; + } if ( identifier != QLatin1String("vacation") ) return; + + if (mContext != IfBlock) { + mLineStart = lineNumber; + } + reset(); mContext = VacationCommand; } -void VacationDataExtractor::commandEnd() { - kDebug(); - mContext = None; +void VacationDataExtractor::commandEnd(int lineNumber) { + if ( mContext != None && mContext != IfBlock && mContext != VacationEnd) { + mContext = VacationEnd; + mLineEnd = lineNumber; + } } void VacationDataExtractor::error( const KSieve::Error & e ) @@ -54,6 +71,42 @@ } +void VacationDataExtractor::testStart(const QString &test) +{ + if (mContext == IfBlock) { + if (test == QLatin1String("true") || test == QLatin1String("false")) { + mActive = (test == QLatin1String("true")); + mIfComment = QString(); + kDebug() << "set active level to" << mActive; + } + } +} + +void VacationDataExtractor::hashComment(const QString &comment) +{ + if (mContext == IfBlock) { + mIfComment += comment; + } +} + + +void VacationDataExtractor::blockStart(int lineNumber) +{ + mBlockLevel++; +} + +void VacationDataExtractor::blockEnd(int lineNumber) +{ + mBlockLevel--; + if(mBlockLevel == 0 && !commandFound()) { //We are in main level again, and didn't found vacation in block + mActive = true; + mIfComment = QString(); + } else if (mInIfBlock && mBlockLevel == 0 && commandFound()) { + mLineEnd = lineNumber; + mInIfBlock = false; + } +} + void VacationDataExtractor::taggedArgument( const QString & tag ) { kDebug() << "( \"" << tag <<"\" )"; @@ -123,3 +176,53 @@ mAliases.clear(); mMessageText.clear(); } + +RequireExtractor::RequireExtractor() + : KSieve::ScriptBuilder() + , mContext( None ) + , mLineStart(0) + , mLineEnd(0) +{ + +} + +RequireExtractor::~RequireExtractor() +{ + +} + +void RequireExtractor::commandStart(const QString &identifier, int lineNumber) +{ + if (identifier == QLatin1String("require") && mContext == None) { + mContext = RequireCommand; + mLineStart = lineNumber; + } +} + +void RequireExtractor::commandEnd(int lineNumber) +{ + if (mContext == RequireCommand) { + mContext = EndState; + mLineEnd = lineNumber; + } +} + +void RequireExtractor::error(const KSieve::Error &e) +{ + kDebug() << e.asString() << "@" << e.line() << "," << e.column(); +} + +void RequireExtractor::finished() +{ + +} + +void RequireExtractor::stringArgument(const QString &string, bool, const QString &) +{ + mRequirements << string; +} + +void RequireExtractor::stringListEntry(const QString &string, bool, const QString &) +{ + mRequirements << string; +} \ No newline at end of file Index: libksieve/ksieveui/vacation/vacationutils.h =================================================================== --- libksieve/ksieveui/vacation/vacationutils.h +++ libksieve/ksieveui/vacation/vacationutils.h @@ -40,17 +40,27 @@ QDate defaultStartDate(); QDate defaultEndDate(); -QString composeScript( const QString & messageText, const QString &subject, +QString composeScript( const QString & messageText, bool active, const QString &subject, int notificationInterval, const KMime::Types::AddrSpecList & aliases, bool sendForSpam, const QString & excludeDomain, const QDate & startDate, const QDate & endDate ); -bool parseScript( const QString & script, QString & messageText, +bool parseScript( const QString & script, bool &active, QString & messageText, QString &subject, int & notificationInterval, QStringList & aliases, bool & sendForSpam, QString & domainName, QDate & startDate, QDate & endDate ); +//returns if a vacation script is found in the sieve script +bool foundVacationScript(const QString &script); + +// returns if the vacation script is active +bool vacationScriptActive(const QString &script); + +QString mergeRequireLine(const QString &script1, const QString script2); + +QString updateVacationBlock(const QString &oldScript, const QString &newScript); + } } Index: libksieve/ksieveui/vacation/vacationutils.cpp =================================================================== --- libksieve/ksieveui/vacation/vacationutils.cpp +++ libksieve/ksieveui/vacation/vacationutils.cpp @@ -98,13 +98,14 @@ } -bool KSieveUi::VacationUtils::parseScript( const QString &script, QString &messageText, +bool KSieveUi::VacationUtils::parseScript( const QString &script, bool &active, QString &messageText, QString &subject, int & notificationInterval, QStringList &aliases, bool & sendForSpam, QString &domainName, QDate & startDate, QDate & endDate ) { if ( script.trimmed().isEmpty() ) { + active = false; messageText = VacationUtils::defaultMessageText(); subject = VacationUtils::defaultSubject(); notificationInterval = VacationUtils::defaultNotificationInterval(); @@ -125,26 +126,72 @@ SpamDataExtractor sdx; DomainRestrictionDataExtractor drdx; DateExtractor dx; - KSieveExt::MultiScriptBuilder tsb( &vdx, &sdx, &drdx, &dx ); + KSieveExt::MultiScriptBuilder tsb( &vdx , &sdx, &drdx, &dx ); parser.setScriptBuilder( &tsb ); - if ( !parser.parse() ) + parser.parse(); + if ( !parser.parse() || !vdx.commandFound() ) { + active = false; return false; + } + active = vdx.active(); messageText = vdx.messageText().trimmed(); if (!vdx.subject().isEmpty()) { subject = vdx.subject().trimmed(); } notificationInterval = vdx.notificationInterval(); aliases = vdx.aliases(); - if ( !VacationSettings::allowOutOfOfficeUploadButNoSettings() ) { - sendForSpam = !sdx.found(); - domainName = drdx.domainName(); + + if (!active && !vdx.ifComment().isEmpty()) { + const QByteArray newScript = QString::fromAscii("if ").toUtf8() + vdx.ifComment().toUtf8() + QString::fromLatin1("{vacation;}").toUtf8(); + tsb = KSieveExt::MultiScriptBuilder( &sdx, &drdx, &dx ); + KSieve::Parser parser( newScript.begin(), + newScript.begin() + newScript.length() ); + parser.setScriptBuilder( &tsb ); + if ( !parser.parse() ) { + return false; + } } + + sendForSpam = !sdx.found(); + domainName = drdx.domainName(); startDate = dx.startDate(); endDate = dx.endDate(); return true; } -QString KSieveUi::VacationUtils::composeScript( const QString & messageText, +bool KSieveUi::VacationUtils::foundVacationScript(const QString &script) +{ + const QByteArray scriptUTF8 = script.trimmed().toUtf8(); + kDebug() << "scriptUtf8 = \"" + scriptUTF8 +"\""; + + if (scriptUTF8.isEmpty()) { + return false; + } + + KSieve::Parser parser( scriptUTF8.begin(), + scriptUTF8.begin() + scriptUTF8.length() ); + VacationDataExtractor vdx; + parser.setScriptBuilder(&vdx); + return parser.parse() && vdx.commandFound(); +} + +bool KSieveUi::VacationUtils::vacationScriptActive(const QString &script) +{ + const QByteArray scriptUTF8 = script.trimmed().toUtf8(); + kDebug() << "scriptUtf8 = \"" + scriptUTF8 +"\""; + + if (scriptUTF8.isEmpty()) { + return false; + } + + KSieve::Parser parser( scriptUTF8.begin(), + scriptUTF8.begin() + scriptUTF8.length() ); + VacationDataExtractor vdx; + parser.setScriptBuilder(&vdx); + return parser.parse() && vdx.commandFound() && vdx.active(); +} + +QString composeOldScript( const QString & messageText, const QString &subject, int notificationInterval, const AddrSpecList & addrSpecs, @@ -194,8 +241,198 @@ } script += QString::fromLatin1("text:\n"); - script += dotstuff( messageText.isEmpty() ? VacationUtils::defaultMessageText() : messageText ); + script += dotstuff( messageText.isEmpty() ? KSieveUi::VacationUtils::defaultMessageText() : messageText ); script += QString::fromLatin1( "\n.\n;\n" ); return script; } +QString KSieveUi::VacationUtils::composeScript( const QString & messageText, bool active, + const QString &subject, + int notificationInterval, + const AddrSpecList & addrSpecs, + bool sendForSpam, const QString & domain, + const QDate & startDate, const QDate & endDate ) +{ + QStringList condition; + + if (startDate.isValid()) { + condition.append(QString::fromLatin1("currentdate :value \"ge\" \"date\" \"%1\"") + .arg(startDate.toString(Qt::ISODate))); + } + + if (endDate.isValid()) { + condition.append(QString::fromLatin1("currentdate :value \"le\" \"date\" \"%1\"") + .arg(endDate.toString(Qt::ISODate))); + } + + if (!sendForSpam) { + condition.append(QString::fromLatin1("not header :contains \"X-Spam-Flag\" \"YES\"")); + } + + if (!domain.isEmpty()) { + condition.append(QString::fromLatin1("address :domain :contains \"from\" \"%1\"").arg( domain )); + } + + QString addressesArgument; + QStringList aliases; + if ( !addrSpecs.empty() ) { + addressesArgument += QLatin1String(":addresses [ "); + QStringList sl; + AddrSpecList::const_iterator end = addrSpecs.constEnd(); + for ( AddrSpecList::const_iterator it = addrSpecs.begin() ; it != end; ++it ) { + sl.push_back( QLatin1Char('"') + (*it).asString().replace( QLatin1Char('\\'), QLatin1String("\\\\") ).replace( QLatin1Char('"'), QLatin1String("\\\"") ) + QLatin1Char('"') ); + aliases.push_back( (*it).asString() ); + } + addressesArgument += sl.join( QLatin1String(", ") ) + QLatin1String(" ] "); + } + + QString vacation(QLatin1String("vacation ")); + vacation += addressesArgument; + if ( notificationInterval > 0 ) + vacation += QString::fromLatin1(":days %1 ").arg(notificationInterval); + + if (!subject.trimmed().isEmpty()) { + vacation += QString::fromLatin1(":subject \"%1\" ").arg(stringReplace(subject).trimmed()); + } + + vacation += QString::fromLatin1("text:\n"); + vacation += dotstuff( messageText.isEmpty() ? VacationUtils::defaultMessageText() : messageText ); + vacation += QString::fromLatin1( "\n.\n;" ); + + QString script; + + if ( startDate.isValid() || endDate.isValid() ) { + script = QString::fromLatin1("require [\"vacation\", \"relational\", \"date\"];\n\n" ); + } else { + script = QString::fromLatin1("require \"vacation\";\n\n" ); + } + + if (condition.count() == 0) { + if (active) { + script += vacation; + } else { + script += QString::fromLatin1("if false\n{\n\t"); + script += vacation; + script += QLatin1String("\n}"); + } + } else { + if (active) { + script += QString::fromLatin1("if allof(%1)\n{\n\t").arg(condition.join(QLatin1String(", "))); + } else { + script += QString::fromLatin1("if false # allof(%1)\n{\n\t").arg(condition.join(QLatin1String(", "))); + } + script += vacation; + script += QLatin1String("\n}"); + } + + script += QLatin1String("\n"); + + return script; +} + + +QString KSieveUi::VacationUtils::mergeRequireLine(const QString &script, const QString scriptUpdate) +{ + const QByteArray scriptUTF8 = script.trimmed().toUtf8(); + const QByteArray scriptUpdateUTF8 = scriptUpdate.trimmed().toUtf8(); + + if (scriptUTF8.isEmpty()) { + return scriptUpdate; + } + + if (scriptUpdateUTF8.isEmpty()) { + return script; + } + + KSieve::Parser parser( scriptUTF8.begin(), + scriptUTF8.begin() + scriptUTF8.length() ); + KSieve::Parser parserUpdate( scriptUpdateUTF8.begin(), + scriptUpdateUTF8.begin() + scriptUpdateUTF8.length() ); + RequireExtractor rx, rxUpdate; + parser.setScriptBuilder(&rx); + parserUpdate.setScriptBuilder(&rxUpdate); + + int insert(0); + QStringList lines = script.split(QLatin1Char('\n')); + QSet requirements; + + if (parser.parse() && rx.commandFound()) { + insert = rx.lineStart(); + const int endOld(rx.lineEnd()); + for (int i=insert; i<=endOld; i++) { + lines.removeAt(insert); + } + requirements = rx.requirements().toSet(); + } + + if (parserUpdate.parse() && rxUpdate.commandFound()) { + requirements += rxUpdate.requirements().toSet(); + } + + if (requirements.count() > 1) { + QStringList req = requirements.toList(); + req.sort(); + lines.insert(insert, QString::fromLatin1("require [\"%1\"];").arg(req.join(QLatin1String("\", \"")))); + } else if (requirements.count() == 1) { + lines.insert(insert, QString::fromLatin1("require \"%1\";").arg(requirements.toList().first())); + } + + return lines.join(QLatin1String("\n")); +} + +QString KSieveUi::VacationUtils::updateVacationBlock(const QString &oldScript, const QString &newScript) +{ + const QByteArray oldScriptUTF8 = oldScript.trimmed().toUtf8(); + const QByteArray newScriptUTF8 = newScript.trimmed().toUtf8(); + + if (oldScriptUTF8.isEmpty()) { + return newScript; + } + + if (newScriptUTF8.isEmpty()) { + return oldScript; + } + + KSieve::Parser parserOld( oldScriptUTF8.begin(), + oldScriptUTF8.begin() + oldScriptUTF8.length() ); + KSieve::Parser parserNew( newScriptUTF8.begin(), + newScriptUTF8.begin() + newScriptUTF8.length() ); + VacationDataExtractor vdxOld, vdxNew; + RequireExtractor rx; + KSieveExt::MultiScriptBuilder tsb( &vdxOld , &rx ); + parserOld.setScriptBuilder(&tsb); + parserNew.setScriptBuilder(&vdxNew); + + int startOld(0); + + int startNew(vdxNew.lineStart()); + int endNew(vdxNew.lineEnd()); + + QStringList lines = oldScript.split(QLatin1Char('\n')); + + QString script; + if (parserOld.parse() && vdxOld.commandFound()) { + startOld = vdxOld.lineStart(); + const int endOld(vdxOld.lineEnd()); + for (int i=startOld; i<=endOld; i++) { + lines.removeAt(startOld); + } + } else { + if (rx.commandFound()) { // after require + startOld = rx.lineEnd() + 1; + } else { + startOld = 0; + } + } + + if (parserNew.parse() && vdxNew.commandFound()) { + const int startNew(vdxNew.lineStart()); + const int endNew(vdxNew.lineEnd()); + QStringList linesNew = newScript.split(QLatin1Char('\n')); + for(int i=endNew;i>=startNew;i--) { + lines.insert(startOld, linesNew.at(i)); + } + } + + return lines.join(QLatin1String("\n")); +} Index: libksieve/ksieveui/widgets/managesievewidget.h =================================================================== --- libksieve/ksieveui/widgets/managesievewidget.h +++ libksieve/ksieveui/widgets/managesievewidget.h @@ -35,6 +35,7 @@ namespace KSieveUi { class ManageSieveTreeView; +class ParseUserScriptJob; class KSIEVEUI_EXPORT ManageSieveWidget : public QWidget { Q_OBJECT @@ -65,6 +66,7 @@ void slotDoubleClicked(QTreeWidgetItem *item); void slotSystemNetworkStatusChanged(Solid::Networking::Status status); void slotCheckNetworkStatus(); + void setActiveScripts(ParseUserScriptJob *job); public Q_SLOTS: void slotGotList(KManageSieve::SieveJob *job, bool success, const QStringList &listScript, const QString &activeScript); @@ -91,8 +93,6 @@ bool isFileNameItem(QTreeWidgetItem *item) const; bool itemIsActived(QTreeWidgetItem *item) const; void changeActiveScript(QTreeWidgetItem *item, bool activate); - bool isProtectedName(const QString &name); - // Maps top-level items to their child which has the radio button selection QMap mSelectedItems; Index: libksieve/ksieveui/widgets/managesievewidget.cpp =================================================================== --- libksieve/ksieveui/widgets/managesievewidget.cpp +++ libksieve/ksieveui/widgets/managesievewidget.cpp @@ -21,6 +21,9 @@ #include +#include +#include +#include #include #include @@ -31,8 +34,11 @@ #include #include #include +#include using namespace KSieveUi; +Q_DECLARE_METATYPE(QTreeWidgetItem*) + ManageSieveWidget::ManageSieveWidget(QWidget *parent) : QWidget(parent), mClearAll( false ), @@ -174,7 +180,7 @@ if ( !ok || name.isEmpty() ) return; - if (isProtectedName(name.toLower())) { + if (Util::isKep14ProtectedName(name)) { KMessageBox::error(this, i18n("You cannot use protected name."), i18n("New Script")); return; } @@ -245,11 +251,27 @@ KUrl u = mUrls[item]; if ( u.isEmpty() ) return; + + if (item->data(0, SIEVE_SERVER_MODE).toInt() == Kep14EditorMode) { + QStringList activeScripts; + for(int i=0; i < item->childCount(); i++) { + QTreeWidgetItem *j = item->child(i); + if (itemIsActived(j)) { + activeScripts << j->text(0); + } + } + GenerateGlobalScriptJob *job = new GenerateGlobalScriptJob(u); + job->addUserActiveScripts(activeScripts); + connect( job, SIGNAL(success()), SLOT(slotRefresh())); + connect( job, SIGNAL(error(QString)), SLOT(slotRefresh())); + job->start(); + return; + } + QTreeWidgetItem* selected = mSelectedItems[item]; if ( !selected ) return; u.setFileName( selected->text(0) ); - KManageSieve::SieveJob * job; if ( activate ) job = KManageSieve::SieveJob::activate( u ); @@ -311,16 +333,6 @@ Q_EMIT scriptDeleted(u); } -bool ManageSieveWidget::isProtectedName(const QString &name) -{ - if (name == QLatin1String("master") || - name == QLatin1String("user") || - name == QLatin1String("management")) { - return true; - } - return false; -} - void ManageSieveWidget::slotRefresh() { mBlockSignal = true; @@ -342,9 +354,7 @@ qDebug()<<"void ManageSieveWidget::slotGotList(KManageSieve::SieveJob *job, bool success, const QStringList &listScript, const QString &activeScript) success: "<(parent))->stopAnimation(); @@ -364,8 +374,7 @@ mBlockSignal = true; // don't trigger slotItemChanged Q_FOREACH (const QString &script, listScript) { //Hide protected name. - const QString lowerScript(script.toLower()); - if (isProtectedName(lowerScript)) + if (Util::isKep14ProtectedName(script)) continue; QTreeWidgetItem* item = new QTreeWidgetItem( parent ); item->setFlags(item->flags() & (Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsSelectable)); @@ -379,20 +388,60 @@ } mBlockSignal = false; - qDebug()<<" LOAD"; - const bool hasIncludeCapability = job->sieveCapabilities().contains(QLatin1String("include")); - const bool hasUserActiveScript = (activeScript.toLower() == QLatin1String("USER")); - QStringList mUserActiveScriptList; - if (hasUserActiveScript && hasIncludeCapability) { - //TODO parse file. + const bool hasKep14EditorMode = Util::hasKep14Support(job->sieveCapabilities(), listScript, activeScript); + if (hasKep14EditorMode) { + KUrl u = mUrls[parent]; + u.setFileName(QLatin1String("USER")); + ParseUserScriptJob *parseJob = new ParseUserScriptJob(u); + parseJob->setProperty(QLatin1String("parentItem").latin1(), QVariant::fromValue(parent)); + connect(parseJob, SIGNAL(finished(ParseUserScriptJob*)), SLOT(setActiveScripts(ParseUserScriptJob*))); + parseJob->start(); + (static_cast(parent))->startAnimation(); } parent->setData( 0, SIEVE_SERVER_CAPABILITIES, job->sieveCapabilities() ); parent->setData( 0, SIEVE_SERVER_ERROR, false ); - parent->setData( 0, SIEVE_SERVER_MODE, hasIncludeCapability ? Kep14EditorMode : NormalEditorMode); + parent->setData( 0, SIEVE_SERVER_MODE, hasKep14EditorMode ? Kep14EditorMode : NormalEditorMode); mTreeView->expandItem( parent ); } +void ManageSieveWidget::setActiveScripts(ParseUserScriptJob *job) +{ + QTreeWidgetItem * parent = job->property(QLatin1String("parentItem").latin1()).value(); + if ( !parent ) { + return; + } + (static_cast(parent))->stopAnimation(); + + if (!job->error().isEmpty()) { + qWarning() << job->error(); + return; + } + + mBlockSignal = true; // don't trigger slotItemChanged + const QStringList activeScriptList = job->activeScriptList(); + QStringList scriptOrder = activeScriptList; + QMap scriptMap; + + const int children = parent->childCount(); + for(int i=0; i < children; i++) { + QTreeWidgetItem *item = parent->takeChild(0); + scriptMap.insert(item->text(0), item); + const bool isActive = activeScriptList.contains(item->text(0)); + item->setCheckState(0, isActive ? Qt::Checked : Qt::Unchecked); + if (!isActive) { + scriptOrder << item->text(0); + } + } + + foreach(const QString &scriptName, scriptOrder) { + parent->addChild(scriptMap[scriptName]); + } + + mBlockSignal = false; +} + + void ManageSieveWidget::slotDoubleClicked( QTreeWidgetItem * item ) { if ( !isFileNameItem( item ) ) Index: libksieve/parser/lexer.cpp =================================================================== --- libksieve/parser/lexer.cpp +++ libksieve/parser/lexer.cpp @@ -161,7 +161,7 @@ #endif static QString removeCRLF( const QString & s ) { const bool CRLF = s.endsWith( QLatin1String("\r\n") ); - const bool LF = !CRLF && s.endsWith( '\n' ); + const bool LF = !CRLF && s.endsWith( QLatin1Char('\n') ); const int e = CRLF ? 2 : LF ? 1 : 0 ; // what to chop off at the end @@ -255,7 +255,7 @@ case ')': case ';': case ',': // Special - result = *mState.cursor++; + result = QLatin1Char(*mState.cursor++); return Special; case '0': case '1': @@ -401,7 +401,7 @@ } if ( reallySave ) { QString tmp = QString::fromUtf8( commentStart, commentLength ); - result += tmp.remove( '\r' ); // get rid of CR in CRLF pairs + result += tmp.remove( QLatin1Char('\r') ); // get rid of CR in CRLF pairs } } @@ -505,7 +505,7 @@ assert( isdigit( *mState.cursor ) ); while ( !atEnd() && isdigit( *mState.cursor ) ) - result += *mState.cursor++; + result += QLatin1Char(*mState.cursor++); if ( atEnd() || isDelim( *mState.cursor ) ) return true; @@ -517,7 +517,7 @@ case 'm': case 'K': case 'k': - result += *mState.cursor++; + result += QLatin1Char(*mState.cursor++); break; default: makeIllegalCharError(); @@ -589,21 +589,21 @@ } const QString line = removeCRLF( QString::fromUtf8( oldBeginOfLine, lineLength ) ); lines.push_back( removeDotStuff( line ) ); - if ( line == "." ) + if ( line == QLatin1String(".") ) break; } else { lines.push_back( QString() ); } } - if ( lines.back() != "." ) { + if ( lines.back() != QLatin1String(".") ) { makeError( Error::PrematureEndOfMultiLine, mlBeginLine, mlBeginCol ); return false; } assert( !lines.empty() ); lines.erase( --lines.end() ); // don't include the lone dot. - result = lines.join("\n"); + result = lines.join(QLatin1String("\n")); return true; } @@ -630,7 +630,7 @@ case '\n': if ( !eatCRLF() ) return false; - result += '\n'; + result += QLatin1Char('\n'); break; case '\\': ++mState.cursor; @@ -639,7 +639,7 @@ // else fall through: default: if ( !is8Bit( *mState.cursor ) ) - result += *mState.cursor++; + result += QLatin1Char(*mState.cursor++); else { // probably UTF-8 const char * const eightBitBegin = mState.cursor; skipTo8BitEnd(); Index: libksieve/parser/parser.cpp =================================================================== --- libksieve/parser/parser.cpp +++ libksieve/parser/parser.cpp @@ -42,6 +42,8 @@ #include // ULONG_MAX #include // isdigit +#include + namespace KSieve { // @@ -130,7 +132,7 @@ return isStringToken() || token() == Lexer::Number || token() == Lexer::Tag || - ( token() == Lexer::Special && mTokenValue == "[" ); + ( token() == Lexer::Special && mTokenValue == QLatin1String("[")) ; } bool Parser::Impl::obtainToken() { @@ -218,8 +220,9 @@ if ( !obtainToken() || token() != Lexer::Identifier ) return false; - if ( scriptBuilder() ) - scriptBuilder()->commandStart( tokenValue() ); + if ( scriptBuilder() ) { + scriptBuilder()->commandStart( tokenValue(), lexer.line() ); + } consumeToken(); // @@ -251,7 +254,7 @@ return false; } - if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list + if ( token() == Lexer::Special && tokenValue() == QLatin1String ("(")) { // test-list if ( !parseTestList() ) { assert( error() ); return false; @@ -280,9 +283,9 @@ return false; } - if ( tokenValue() == ";" ) + if ( tokenValue() == QLatin1String (";")) consumeToken(); - else if ( tokenValue() == "{" ) { // block + else if ( tokenValue() == QLatin1String ("{")) { // block if ( !parseBlock() ) return false; // it's an error since we saw '{' } else { @@ -290,8 +293,9 @@ return false; } - if ( scriptBuilder() ) - scriptBuilder()->commandEnd(); + if ( scriptBuilder() ) { + scriptBuilder()->commandEnd(lexer.line()); + } return true; } @@ -334,7 +338,7 @@ scriptBuilder()->stringArgument( tokenValue(), token() == Lexer::MultiLineString, QString() ); consumeToken(); return true; - } else if ( token() == Lexer::Special && tokenValue() == "[" ) { + } else if ( token() == Lexer::Special && tokenValue() == QLatin1String("[")) { if ( !parseStringList() ) { assert( error() ); return false; @@ -352,7 +356,7 @@ if ( !obtainToken() || atEnd() ) return false; - if ( token() != Lexer::Special || tokenValue() != "(" ) + if ( token() != Lexer::Special || tokenValue() != QLatin1String("(")) return false; if ( scriptBuilder() ) scriptBuilder()->testListStart(); @@ -462,7 +466,7 @@ if ( atEnd() ) // a test w/o nested tests goto TestEnd; - if ( token() == Lexer::Special && tokenValue() == "(" ) { // test-list + if ( token() == Lexer::Special && tokenValue() == QLatin1String("(")) { // test-list if ( !parseTestList() ) { assert( error() ); return false; @@ -488,10 +492,10 @@ if ( !obtainToken() || atEnd() ) return false; - if ( token() != Lexer::Special || tokenValue() != "{" ) + if ( token() != Lexer::Special || tokenValue() != QLatin1String("{")) return false; if ( scriptBuilder() ) - scriptBuilder()->blockStart(); + scriptBuilder()->blockStart(lexer.line()); consumeToken(); if ( !obtainToken() ) @@ -517,12 +521,12 @@ return false; } - if ( token() != Lexer::Special || tokenValue() != "}" ) { + if ( token() != Lexer::Special || tokenValue() != QLatin1String("}")) { makeError( Error::NonCommandInCommandList ); return false; } if ( scriptBuilder() ) - scriptBuilder()->blockEnd(); + scriptBuilder()->blockEnd(lexer.line()); consumeToken(); return true; } @@ -538,7 +542,7 @@ if ( !obtainToken() || atEnd() ) return false; - if ( token() != Lexer::Special || tokenValue() != "[" ) + if ( token() != Lexer::Special || tokenValue() != QLatin1String("[") ) return false; if ( scriptBuilder() ) @@ -619,7 +623,7 @@ int i = 0; const QByteArray s = tokenValue().toLatin1(); for ( const int len = s.length() ; i < len && isdigit( s[i] ) ; ++i ) { - const unsigned long digitValue = s[i] - '0' ; + const unsigned long digitValue = s[i] - QLatin1Char('0').toLatin1() ; if ( willOverflowULong( result, digitValue ) ) { makeError( Error::NumberOutOfRange ); return false; Index: libksieve/tests/parsertest.cpp =================================================================== --- libksieve/tests/parsertest.cpp +++ libksieve/tests/parsertest.cpp @@ -400,12 +400,12 @@ const QString txt = "number" + ( quantifier ? QString(" quantifier=\"%1\"").arg( quantifier ) : QString() ) ; write( txt.toLatin1(), QString::number( number ) ); } - void commandStart( const QString & identifier ) { + void commandStart( const QString & identifier, int lineNumber) { write( "" ); ++indent; write( "identifier", identifier ); } - void commandEnd() { + void commandEnd(int lineNumber) { --indent; write( "" ); } @@ -426,11 +426,11 @@ --indent; write( "" ); } - void blockStart() { + void blockStart(int lineNumber) { write( "" ); ++indent; } - void blockEnd() { + void blockEnd(int lineNumber) { --indent; write( "" ); } @@ -515,12 +515,12 @@ checkEquals( QString::number( number ) + ( quantifier ? quantifier : ' ' ) ); ++mNextResponse; } - void commandStart( const QString & identifier ) { + void commandStart( const QString & identifier, int lineNumber ) { checkIs( CommandStart ); checkEquals( identifier ); ++mNextResponse; } - void commandEnd() { + void commandEnd(int lineNumber) { checkIs( CommandEnd ); ++mNextResponse; } @@ -541,11 +541,11 @@ checkIs( TestListEnd ); ++mNextResponse; } - void blockStart() { + void blockStart(int lineNumber) { checkIs( BlockStart ); ++mNextResponse; } - void blockEnd() { + void blockEnd(int lineNumber) { checkIs( BlockEnd ); ++mNextResponse; }