diff --git a/libksieve/src/ksieveui/CMakeLists.txt b/libksieve/src/ksieveui/CMakeLists.txt --- a/libksieve/src/ksieveui/CMakeLists.txt +++ b/libksieve/src/ksieveui/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(editor/autotests) add_subdirectory(autocreatescripts/tests) add_subdirectory(scriptsparsing/tests) + add_subdirectory(vacation/autotests) add_subdirectory(vacation/tests) add_subdirectory(sievescriptdebugger/autotests) add_subdirectory(sievescriptdebugger/tests) diff --git a/libksieve/src/ksieveui/vacation/autotests/CMakeLists.txt b/libksieve/src/ksieveui/vacation/autotests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/CMakeLists.txt @@ -0,0 +1,26 @@ +include_directories(${CMAKE_SOURCE_DIR}/libksieve/src + ) + +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/src/ksieveui/sieve-vacation.cpp + ) + get_filename_component(_name ${_source} NAME_WE) + ecm_qt_declare_logging_category(_test HEADER libksieve_debug.h IDENTIFIER LIBKSIEVE_LOG CATEGORY_NAME log_libksieve) + add_executable(${_name} ${_test}) + add_test(vacation-${_name} ${_name}) + ecm_mark_as_test(vacation-${_name}) + add_definitions(-DVACATIONTESTDATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data/") + target_link_libraries(${_name} + KF5::KSieveUi + Qt5::Test + KF5::IdentityManagement + KF5::Mime + ) +endmacro() + +add_vacation_test(vacationutils) diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-active-discard.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-active-discard.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/data/vacation-active-discard.siv @@ -0,0 +1,9 @@ +require ["date","relational","vacation"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if allof (not header :contains "X-Spam-Flag" "YES") +{ + vacation :days 7 :addresses "test@test.de" :subject "XXX" "dsfgsdfgsdfg"; + discard; +} \ No newline at end of file diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-complex-time.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-complex-time.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/data/vacation-complex-time.siv @@ -0,0 +1,8 @@ +require ["date","relational","vacation"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if allof (currentdate :value "ge" "iso8601" "2015-01-02T02:00:00+00:00", currentdate :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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-complex.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-complex.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate-complex.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate-complex.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate-multiple.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate-multiple.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactivate.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-copy.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-copy.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-copy.siv @@ -0,0 +1,10 @@ +require ["vacation", "copy"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if false +{ + vacation :days 7 :addresses "test@test.de" :subject "XXX" "dsfgsdfgsdfg"; + redirect :copy "copy@example.org"; +} +discard; \ No newline at end of file diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-send.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-send.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/data/vacation-deactive-send.siv @@ -0,0 +1,11 @@ +require ["vacation", "copy"]; +# EDITOR Roundcube (Managesieve) +# EDITOR_VERSION 8.2 +# rule:[Urlaub] +if false +{ + vacation :days 7 :addresses "test@test.de" :subject "XXX" "dsfgsdfgsdfg"; + redirect "redirect@example.org"; +} + +redirect :copy "argh@example.org"; \ No newline at end of file diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-multiple.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-multiple.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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; +} diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-notfound.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-notfound.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/data/vacation-simple.siv b/libksieve/src/ksieveui/vacation/autotests/data/vacation-simple.siv new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/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 diff --git a/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.h b/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.h new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 Sandro Knauß + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef VACATIONUTILSTEST_H +#define VACATIONUTILSTEST_H + +#include + +namespace KSieveUi +{ +class VacationUtilsTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testParseEmptyScript(); + void testParseOnlyComment(); + void testParseActivate_data(); + void testParseActivate(); + void testParseScript_data(); + void testParseScript(); + void testParseScriptComplex(); + void testParseScriptComplexTime(); + void testMailAction_data(); + void testMailAction(); + void testWriteScript(); + void testWriteSimpleScript(); + void testUpdateVacationBlock(); + void testMergeRequireLine(); +}; +} +#endif // VACATIONUTILSTEST_H diff --git a/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.cpp b/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.cpp new file mode 100644 --- /dev/null +++ b/libksieve/src/ksieveui/vacation/autotests/vacationutilstest.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2015 Sandro Knauß + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "vacationutilstest.h" +#include "ksieveui/vacation/vacationutils.h" + +#include + +#include +#include + +using namespace KSieveUi; + +QTEST_MAIN(VacationUtilsTest) + +void testAliases(const KMime::Types::AddrSpecList &l1, const KMime::Types::AddrSpecList &l2) +{ + const int l1count = l1.count(); + QCOMPARE(l1count, l2.count()); + for (int i = 0; i < l1count; ++i) { + QCOMPARE(l1.at(i).asString(), l2.at(i).asString()); + } +} + +void testAliases(const KMime::Types::AddrSpecList &l1, const QStringList &l2) +{ + const int l1count = l1.count(); + QCOMPARE(l1count, l2.count()); + for (int i = 0; i < l1count; ++i) { + QCOMPARE(l1.at(i).asString(), l2.at(i)); + } +} + +void VacationUtilsTest::testParseEmptyScript() +{ + const QString script; + QCOMPARE(VacationUtils::parseScript(script).isValid(), false); +} + +void VacationUtilsTest::testParseOnlyComment() +{ + QString script(QStringLiteral("#comment")); + QCOMPARE(VacationUtils::parseScript(script).isValid(), false); + script = QStringLiteral("#comment\n\n#comment\n"); + QCOMPARE(VacationUtils::parseScript(script).isValid(), false); +} + +void VacationUtilsTest::testParseActivate_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("found"); + QTest::addColumn("active"); + + QTest::newRow("notfound") << QStringLiteral("vacation-notfound.siv") << false << false; + QTest::newRow("simple") << QStringLiteral("vacation-simple.siv") << true << true; + QTest::newRow("multile if") << QStringLiteral("vacation-multiple.siv") << true << true; + QTest::newRow("deactivate") << QStringLiteral("vacation-deactivate.siv") << true << false; + QTest::newRow("deactivate-multiple if") << QStringLiteral("vacation-deactivate-multiple.siv") << true << false; + QTest::newRow("deactivate-complex") << QStringLiteral("vacation-deactivate-complex.siv") << true << false; +} + +void VacationUtilsTest::testParseActivate() +{ + QFETCH(QString, filename); + QFETCH(bool, found); + QFETCH(bool, active); + + QFile file(QStringLiteral(VACATIONTESTDATADIR) + filename); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + + VacationUtils::Vacation vacation = VacationUtils::parseScript(script); + QCOMPARE(vacation.isValid(), found); + QCOMPARE(vacation.active, active); +} + +void VacationUtilsTest::testParseScript_data() +{ + QTest::addColumn("activate"); + QTest::addColumn("deactivate"); + + QTest::newRow("simple") << QStringLiteral("vacation-simple.siv") << QStringLiteral("vacation-deactivate.siv"); + QTest::newRow("complex") << QStringLiteral("vacation-complex.siv") << QStringLiteral("vacation-deactivate-complex.siv"); +} + +void VacationUtilsTest::testParseScript() +{ + QFETCH(QString, activate); + QFETCH(QString, deactivate); + QFile fileA(QStringLiteral(VACATIONTESTDATADIR) + activate); + QVERIFY(fileA.open(QIODevice::ReadOnly)); + QString scriptA = QString::fromUtf8(fileA.readAll()); + QFile fileD(QStringLiteral(VACATIONTESTDATADIR) + deactivate); + QVERIFY(fileD.open(QIODevice::ReadOnly)); + QString scriptD = QString::fromUtf8(fileD.readAll()); + + VacationUtils::Vacation vacationA = VacationUtils::parseScript(scriptA); + VacationUtils::Vacation vacationD = VacationUtils::parseScript(scriptD); + QCOMPARE(vacationA.active, true); + QCOMPARE(vacationD.active, false); + QCOMPARE(vacationD.messageText, vacationA.messageText); + QCOMPARE(vacationD.subject, vacationA.subject); + QCOMPARE(vacationD.notificationInterval, vacationA.notificationInterval); + testAliases(vacationD.aliases, vacationA.aliases); + QCOMPARE(vacationD.sendForSpam, vacationA.sendForSpam); + QCOMPARE(vacationD.excludeDomain, vacationA.excludeDomain); + QCOMPARE(vacationD.startDate, vacationA.startDate); + QCOMPARE(vacationD.endDate, vacationA.endDate); + QCOMPARE(vacationD.startTime, QTime()); + QCOMPARE(vacationD.endTime, QTime()); +} + +void VacationUtilsTest::testMailAction_data() +{ + QTest::addColumn("filename"); + QTest::addColumn("action"); + QTest::addColumn("recipient"); + + QTest::newRow("keep") << QStringLiteral("vacation-complex.siv") << (int)VacationUtils::Keep << QString(); + QTest::newRow("discard") << QStringLiteral("vacation-active-discard.siv") << (int)VacationUtils::Discard << QString(); + QTest::newRow("send") << QStringLiteral("vacation-deactive-send.siv") << (int)VacationUtils::Sendto << QStringLiteral("redirect@example.org"); + QTest::newRow("copy") << QStringLiteral("vacation-deactive-copy.siv") << (int)VacationUtils::CopyTo << QStringLiteral("copy@example.org"); +} + +void VacationUtilsTest::testMailAction() +{ + QFETCH(QString, filename); + QFETCH(int, action); + QFETCH(QString, recipient); + + QFile file(QStringLiteral(VACATIONTESTDATADIR) + filename); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + + VacationUtils::Vacation vacation = VacationUtils::parseScript(script); + QCOMPARE((int)vacation.mailAction, action); + QCOMPARE(vacation.mailActionRecipient, recipient); + + const QString composedScript = VacationUtils::composeScript(vacation); + vacation = VacationUtils::parseScript(composedScript); + QCOMPARE((int)vacation.mailAction, action); + QCOMPARE(vacation.mailActionRecipient, recipient); +} + +void VacationUtilsTest::testParseScriptComplex() +{ + QFile file(QStringLiteral(VACATIONTESTDATADIR "vacation-complex.siv")); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + + VacationUtils::Vacation vacation = VacationUtils::parseScript(script); + QCOMPARE(vacation.active, true); + QCOMPARE(vacation.messageText, QStringLiteral("dsfgsdfgsdfg")); + QCOMPARE(vacation.subject, QStringLiteral("XXX")); + QCOMPARE(vacation.notificationInterval, 7); + testAliases(vacation.aliases, QStringList() << QStringLiteral("test@test.de")); + QCOMPARE(vacation.sendForSpam, false); + QCOMPARE(vacation.excludeDomain, QString()); + QCOMPARE(vacation.startDate, QDate(2015, 01, 02)); + QCOMPARE(vacation.endDate, QDate(2015, 03, 04)); + QCOMPARE(vacation.startTime, QTime()); + QCOMPARE(vacation.endTime, QTime()); +} + +void VacationUtilsTest::testParseScriptComplexTime() +{ + QFile file(QStringLiteral(VACATIONTESTDATADIR "vacation-complex-time.siv")); + QVERIFY(file.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(file.readAll()); + + VacationUtils::Vacation vacation = VacationUtils::parseScript(script); + QCOMPARE(vacation.active, true); + QCOMPARE(vacation.messageText, QStringLiteral("dsfgsdfgsdfg")); + QCOMPARE(vacation.subject, QStringLiteral("XXX")); + QCOMPARE(vacation.notificationInterval, 7); + testAliases(vacation.aliases, QStringList() << QStringLiteral("test@test.de")); + QCOMPARE(vacation.sendForSpam, false); + QCOMPARE(vacation.excludeDomain, QString()); + QCOMPARE(vacation.startDate, QDate(2015, 01, 02)); + QCOMPARE(vacation.endDate, QDate(2015, 03, 04)); + QCOMPARE(vacation.startTime, QTime(2, 0)); + QCOMPARE(vacation.endTime, QTime()); + + QString composedScript = VacationUtils::composeScript(vacation); + vacation = VacationUtils::parseScript(composedScript); + QCOMPARE(vacation.startTime, QTime(2, 0)); + QCOMPARE(vacation.endTime, QTime()); +} + +void VacationUtilsTest::testWriteScript() +{ + VacationUtils::Vacation vacation, vacationA; + QStringList aliases = QStringList() << QStringLiteral("test@test.de"); + vacation.valid = true; + + vacation.messageText = QStringLiteral("dsfgsdfgsdfg"); + vacation.subject = QStringLiteral("XXX"); + vacation.notificationInterval = 7; + vacation.sendForSpam = false; + vacation.excludeDomain = QStringLiteral("example.org"); + vacation.startDate = QDate(2015, 01, 02); + vacation.endDate = QDate(2015, 03, 04); + vacation.active = true; + + foreach(const QString &alias, aliases) { + KMime::Types::Mailbox a; + a.fromUnicodeString(alias); + vacation.aliases.append(a.addrSpec()); + } + + QString script = VacationUtils::composeScript(vacation); + vacationA = VacationUtils::parseScript(script); + QCOMPARE(vacationA.isValid(), true); + QCOMPARE(vacationA.active, vacation.active); + QCOMPARE(vacationA.messageText, vacation.messageText); + QCOMPARE(vacationA.subject, vacation.subject); + QCOMPARE(vacationA.notificationInterval, vacation.notificationInterval); + testAliases(vacationA.aliases, vacation.aliases); + QCOMPARE(vacationA.sendForSpam, vacation.sendForSpam); + QCOMPARE(vacationA.excludeDomain, vacation.excludeDomain); + QCOMPARE(vacationA.startDate, vacation.startDate); + QCOMPARE(vacationA.endDate, vacation.endDate); + QCOMPARE(vacationA.startTime, QTime()); + QCOMPARE(vacationA.endTime, QTime()); + + vacation.active = false; + script = VacationUtils::composeScript(vacation); + vacationA = VacationUtils::parseScript(script); + QCOMPARE(vacationA.isValid(), true); + QCOMPARE(vacationA.active, vacation.active); + QCOMPARE(vacationA.messageText, vacation.messageText); + QCOMPARE(vacationA.subject, vacation.subject); + QCOMPARE(vacationA.notificationInterval, vacation.notificationInterval); + testAliases(vacationA.aliases, vacation.aliases); + QCOMPARE(vacationA.sendForSpam, vacation.sendForSpam); + QCOMPARE(vacationA.excludeDomain, vacation.excludeDomain); + QCOMPARE(vacationA.startDate, vacation.startDate); + QCOMPARE(vacationA.endDate, vacation.endDate); + QCOMPARE(vacationA.startTime, QTime()); + QCOMPARE(vacationA.endTime, QTime()); +} + +void VacationUtilsTest::testWriteSimpleScript() +{ + VacationUtils::Vacation vacation; + vacation.valid = true; + vacation.messageText = QStringLiteral("dsfgsdfgsdfg"); + vacation.subject = QStringLiteral("XXX"); + vacation.notificationInterval = 7; + vacation.active = true; + vacation.sendForSpam = true; + + QString script = VacationUtils::composeScript(vacation); + VacationUtils::Vacation vacationA = VacationUtils::parseScript(script); + QCOMPARE(vacation.isValid(), true); + QCOMPARE(vacationA.active, vacation.active); + QCOMPARE(vacationA.messageText, vacation.messageText); + QCOMPARE(vacationA.subject, vacation.subject); + QCOMPARE(vacationA.notificationInterval, vacation.notificationInterval); + + vacation.active = false; + script = VacationUtils::composeScript(vacation); + vacationA = VacationUtils::parseScript(script); + QCOMPARE(vacation.isValid(), true); + QCOMPARE(vacationA.active, vacation.active); + QCOMPARE(vacationA.messageText, vacation.messageText); + QCOMPARE(vacationA.subject, vacation.subject); + QCOMPARE(vacationA.notificationInterval, vacation.notificationInterval); + +} + +void VacationUtilsTest::testUpdateVacationBlock() +{ + QFile fileA(QStringLiteral(VACATIONTESTDATADIR "vacation-simple.siv")); + QVERIFY(fileA.open(QIODevice::ReadOnly)); + QString scriptA = QString::fromUtf8(fileA.readAll()); + + QFile fileB(QStringLiteral(VACATIONTESTDATADIR "vacation-deactivate.siv")); + QVERIFY(fileB.open(QIODevice::ReadOnly)); + QString scriptB = QString::fromUtf8(fileB.readAll()); + + const QString attend = QStringLiteral("if true\n{\ntestcmd;\n}\n"); + const QString require = QStringLiteral("require [\"date\", \"test\"];"); + const QString scriptAattend = scriptA + QStringLiteral("\n") + attend; + const QString scriptBattend = scriptB + QStringLiteral("\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; i < linesA.count(); ++i) { + vacation.append(linesA.at(i)); + } + + QCOMPARE(VacationUtils::updateVacationBlock(scriptA, QString()), scriptA); + QCOMPARE(VacationUtils::updateVacationBlock(QString(), scriptB), scriptB); + QCOMPARE(VacationUtils::updateVacationBlock(scriptA, scriptB), scriptB); + QCOMPARE(VacationUtils::updateVacationBlock(scriptB, scriptA), scriptA); + QCOMPARE(VacationUtils::updateVacationBlock(scriptAattend, scriptB), scriptBattend); + QCOMPARE(VacationUtils::updateVacationBlock(scriptBattend, scriptA), scriptAattend); + QCOMPARE(VacationUtils::updateVacationBlock(scriptA, attend), header.join(QStringLiteral("\n"))); + QStringList output = vacation; + output << attend; + QCOMPARE(VacationUtils::updateVacationBlock(attend, scriptA), output.join(QStringLiteral("\n"))); + output.insert(0, require); + QCOMPARE(VacationUtils::updateVacationBlock(require + QStringLiteral("\n") + attend, scriptA), output.join(QStringLiteral("\n"))); +} + +void VacationUtilsTest::testMergeRequireLine() +{ + QString sEmpty = QStringLiteral("require;"); + QString sOne = QStringLiteral("require \"test\";"); + QString sList1 = QStringLiteral("require [\"test\"];"); + QString sList2 = QStringLiteral("require [\"test\", \"test2\"];"); + QString sList3 = QStringLiteral("require [\"test3\",\n \"test4\"];\ntestcmd;"); + + QCOMPARE(VacationUtils::mergeRequireLine(sEmpty, sOne), sOne); + QCOMPARE(VacationUtils::mergeRequireLine(sOne, sEmpty), sOne); + QCOMPARE(VacationUtils::mergeRequireLine(sOne, sList1), sOne); + QCOMPARE(VacationUtils::mergeRequireLine(sOne, sList2), sList2); + QCOMPARE(VacationUtils::mergeRequireLine(sOne, sList3), QStringLiteral("require [\"test\", \"test3\", \"test4\"];")); + QCOMPARE(VacationUtils::mergeRequireLine(sList3, sOne), QStringLiteral("require [\"test\", \"test3\", \"test4\"];\ntestcmd;")); +} diff --git a/libksieve/src/ksieveui/vacation/vacation.cpp b/libksieve/src/ksieveui/vacation/vacation.cpp --- a/libksieve/src/ksieveui/vacation/vacation.cpp +++ b/libksieve/src/ksieveui/vacation/vacation.cpp @@ -78,7 +78,7 @@ QUrl Vacation::findURL(QString &serverName) const { const Akonadi::AgentInstance::List instances = Util::imapAgentInstances(); - foreach (const Akonadi::AgentInstance &instance, instances) { + foreach(const Akonadi::AgentInstance &instance, instances) { if (instance.status() == Akonadi::AgentInstance::Broken) { continue; } @@ -113,42 +113,41 @@ return; } + const bool supportsDate = job->sieveCapabilities().contains(QStringLiteral("date")); + if (!mDialog && !mCheckOnly) { mDialog = new VacationDialog(i18n("Configure \"Out of Office\" Replies"), Q_NULLPTR, false); } - QString messageText = VacationUtils::defaultMessageText(); - QString subject = VacationUtils::defaultSubject(); - int notificationInterval = VacationUtils::defaultNotificationInterval(); - QStringList aliases = VacationUtils::defaultMailAliases(); - bool sendForSpam = VacationUtils::defaultSendForSpam(); - QString domainName = VacationUtils::defaultDomainName(); - QDate startDate = VacationUtils::defaultStartDate(); - QDate endDate = VacationUtils::defaultEndDate(); if (!success) { active = false; // default to inactive } - if (!mCheckOnly && (!success || !KSieveUi::VacationUtils::parseScript(script, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate))) + KSieveUi::VacationUtils::Vacation vacation = KSieveUi::VacationUtils::parseScript(script); + + if (!mCheckOnly && (!success || (!vacation.isValid() && !script.trimmed().isEmpty()))) { KMessageBox::information(Q_NULLPTR, i18n("Someone (probably you) changed the " "vacation script on the server.\n" "KMail is no longer able to determine " "the parameters for the autoreplies.\n" "Default values will be used.")); - + } mWasActive = active; if (mDialog) { - mDialog->setActivateVacation(active); - mDialog->setSubject(subject); - mDialog->setMessageText(messageText); - mDialog->setNotificationInterval(notificationInterval); - mDialog->setMailAliases(aliases.join(QStringLiteral(", "))); - mDialog->setSendForSpam(sendForSpam); - mDialog->setDomainName(domainName); + mDialog->setActivateVacation(active && vacation.active); + mDialog->setSubject(vacation.subject); + mDialog->setMessageText(vacation.messageText); + mDialog->setNotificationInterval(vacation.notificationInterval); + mDialog->setMailAliases(vacation.aliases); + mDialog->setSendForSpam(vacation.sendForSpam); + mDialog->setDomainName(vacation.excludeDomain); mDialog->enableDomainAndSendForSpam(!VacationSettings::allowOutOfOfficeUploadButNoSettings()); - mDialog->enableDates(job->sieveCapabilities().contains(QStringLiteral("date"))); - mDialog->setStartDate(startDate); - mDialog->setEndDate(endDate); + mDialog->enableDates(supportsDate); + + if (supportsDate) { + mDialog->setStartDate(vacation.startDate); + mDialog->setEndDate(vacation.endDate); + } connect(mDialog, &VacationDialog::okClicked, this, &Vacation::slotDialogOk); connect(mDialog, &VacationDialog::cancelClicked, this, &Vacation::slotDialogCancel); @@ -171,16 +170,20 @@ { qCDebug(LIBKSIEVE_LOG); // compose a new script: - const QString script = VacationUtils::composeScript(mDialog->messageText(), - mDialog->subject(), - mDialog->notificationInterval(), - mDialog->mailAliases(), - mDialog->sendForSpam(), - mDialog->domainName(), - mDialog->startDate(), - mDialog->endDate()); const bool active = mDialog->activateVacation(); - Q_EMIT scriptActive(active, mServerName); + VacationUtils::Vacation vacation; + vacation.valid = true; + vacation.active = active; + vacation.messageText = mDialog->messageText(); + vacation.subject = mDialog->subject(); + vacation.notificationInterval = mDialog->notificationInterval(); + vacation.aliases = mDialog->mailAliases(); + vacation.sendForSpam = mDialog->sendForSpam(); + vacation.excludeDomain = mDialog->domainName(); + vacation.startDate = mDialog->startDate(); + vacation.endDate = mDialog->endDate(); + const QString script = VacationUtils::composeScript(vacation); + emit scriptActive(active, mServerName); qCDebug(LIBKSIEVE_LOG) << "script:" << endl << script; diff --git a/libksieve/src/ksieveui/vacation/vacationcheckjob.cpp b/libksieve/src/ksieveui/vacation/vacationcheckjob.cpp --- a/libksieve/src/ksieveui/vacation/vacationcheckjob.cpp +++ b/libksieve/src/ksieveui/vacation/vacationcheckjob.cpp @@ -48,20 +48,13 @@ active = false; // default to inactive } - QDate startDate, endDate; - - QString dummyStr; - QStringList dummyStrList; - int dummyInt; - bool dummyBool; - // If the script is active then parse it, and verify whether it has date range set if (active) { - bool valid = VacationUtils::parseScript(script, dummyStr, dummyStr, dummyInt, dummyStrList, dummyBool, dummyStr, startDate, endDate); + const VacationUtils::Vacation vacation = VacationUtils::parseScript(script); // If the date range is set, mark the script as active only if the date range // includes now/today - if (valid && startDate.isValid() && endDate.isValid()) { - active = (startDate <= QDate::currentDate() && endDate >= QDate::currentDate()); + if (vacation.isValid() && vacation.startDate.isValid() && vacation.endDate.isValid()) { + active = (vacation.startDate <= QDate::currentDate() && vacation.endDate >= QDate::currentDate()); } } diff --git a/libksieve/src/ksieveui/vacation/vacationeditwidget.cpp b/libksieve/src/ksieveui/vacation/vacationeditwidget.cpp --- a/libksieve/src/ksieveui/vacation/vacationeditwidget.cpp +++ b/libksieve/src/ksieveui/vacation/vacationeditwidget.cpp @@ -320,7 +320,7 @@ setMessageText(VacationUtils::defaultMessageText()); setSubject(VacationUtils::defaultSubject()); setNotificationInterval(VacationUtils::defaultNotificationInterval()); - setMailAliases(VacationUtils::defaultMailAliases().join(QStringLiteral(", "))); + setMailAliases(VacationUtils::defaultMailAliases()); setSendForSpam(VacationUtils::defaultSendForSpam()); setDomainName(VacationUtils::defaultDomainName()); setDomainCheck(false); diff --git a/libksieve/src/ksieveui/vacation/vacationpagewidget.cpp b/libksieve/src/ksieveui/vacation/vacationpagewidget.cpp --- a/libksieve/src/ksieveui/vacation/vacationpagewidget.cpp +++ b/libksieve/src/ksieveui/vacation/vacationpagewidget.cpp @@ -113,57 +113,50 @@ return; } - mVacationEditWidget->setEnabled(true); - QString messageText = VacationUtils::defaultMessageText(); - QString subject = VacationUtils::defaultSubject(); - int notificationInterval = VacationUtils::defaultNotificationInterval(); - QStringList aliases = VacationUtils::defaultMailAliases(); - bool sendForSpam = VacationUtils::defaultSendForSpam(); - QString domainName = VacationUtils::defaultDomainName(); - QDate startDate = VacationUtils::defaultStartDate(); - QDate endDate = VacationUtils::defaultEndDate(); - if (!success) { - active = false; // default to inactive - } + KSieveUi::VacationUtils::Vacation vacation = KSieveUi::VacationUtils::parseScript(script); - if ((!success || !KSieveUi::VacationUtils::parseScript(script, messageText, subject, notificationInterval, aliases, sendForSpam, domainName, startDate, endDate))) { + if (!vacation.isValid() && !script.trimmed().isEmpty()) { mVacationWarningWidget->setVisible(true); } mWasActive = active; - mVacationEditWidget->setActivateVacation(active); - mVacationEditWidget->setMessageText(messageText); - mVacationEditWidget->setSubject(subject); - mVacationEditWidget->setNotificationInterval(notificationInterval); - mVacationEditWidget->setMailAliases(aliases.join(QStringLiteral(", "))); - mVacationEditWidget->setSendForSpam(sendForSpam); - mVacationEditWidget->setDomainName(domainName); + mVacationEditWidget->setEnabled(true); + mVacationEditWidget->setActivateVacation(active && vacation.active); + mVacationEditWidget->setMessageText(vacation.messageText); + mVacationEditWidget->setSubject(vacation.subject); + mVacationEditWidget->setNotificationInterval(vacation.notificationInterval); + mVacationEditWidget->setMailAliases(vacation.aliases); + mVacationEditWidget->setSendForSpam(vacation.sendForSpam); + mVacationEditWidget->setDomainName(vacation.excludeDomain); mVacationEditWidget->enableDomainAndSendForSpam(!VacationSettings::allowOutOfOfficeUploadButNoSettings()); - mHasDateSupport = job->sieveCapabilities().contains(QStringLiteral("date")); - mVacationEditWidget->enableDates(mHasDateSupport); - mVacationEditWidget->setStartDate(mHasDateSupport ? startDate : QDate()); - mVacationEditWidget->setEndDate(mHasDateSupport ? endDate : QDate()); - //Q_EMIT scriptActive( mWasActive, mServerName ); + mVacationEditWidget->enableDates(mHasDateSupport); + if (mHasDateSupport) { + mVacationEditWidget->setStartDate(vacation.startDate); + mVacationEditWidget->setEndDate(vacation.endDate); + } } 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(), - mVacationEditWidget->subject(), - mVacationEditWidget->notificationInterval(), - mVacationEditWidget->mailAliases(), - mVacationEditWidget->sendForSpam(), - mVacationEditWidget->domainName(), - mHasDateSupport ? mVacationEditWidget->startDate() : QDate(), - mHasDateSupport ? mVacationEditWidget->endDate() : QDate()); const bool active = mVacationEditWidget->activateVacation(); + VacationUtils::Vacation vacation; + vacation.valid = true; + vacation.active = active; + vacation.messageText = mVacationEditWidget->messageText(); + vacation.subject = mVacationEditWidget->subject(); + vacation.notificationInterval = mVacationEditWidget->notificationInterval(); + vacation.aliases = mVacationEditWidget->mailAliases(); + vacation.sendForSpam = mVacationEditWidget->sendForSpam(); + vacation.excludeDomain = mVacationEditWidget->domainName(); + vacation.startDate = mVacationEditWidget->startDate(); + vacation.endDate = mVacationEditWidget->endDate(); + const QString script = VacationUtils::composeScript(vacation); createJob->setStatus(active, mWasActive); - //Q_EMIT scriptActive( active, mServerName); createJob->setScript(script); return createJob; } diff --git a/libksieve/src/ksieveui/vacation/vacationutils.h b/libksieve/src/ksieveui/vacation/vacationutils.h --- a/libksieve/src/ksieveui/vacation/vacationutils.h +++ b/libksieve/src/ksieveui/vacation/vacationutils.h @@ -19,18 +19,10 @@ #define VACATIONUTILS_H #include #include +#include class QDate; -namespace KMime -{ -namespace Types -{ -struct AddrSpec; -typedef QVector AddrSpecList; -} -} - namespace KSieveUi { namespace VacationUtils @@ -45,24 +37,54 @@ QString defaultMessageText(); QString defaultSubject(); +MailAction defaultMailAction(); int defaultNotificationInterval(); -QStringList defaultMailAliases(); +KMime::Types::AddrSpecList defaultMailAliases(); bool defaultSendForSpam(); QString defaultDomainName(); QDate defaultStartDate(); QDate defaultEndDate(); -QString composeScript(const QString &messageText, - 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, - QString &subject, - int ¬ificationInterval, QStringList &aliases, - bool &sendForSpam, QString &domainName, - QDate &startDate, QDate &endDate); +struct Vacation { + Vacation() + : notificationInterval(1) + , mailAction(Keep) + , valid(false) + , active(false) + , sendForSpam(true) + { + } + + bool isValid() const + { + return valid; + } + + QString mailActionRecipient; + QString messageText; + QString subject; + KMime::Types::AddrSpecList aliases; + QString excludeDomain; + QDate startDate; + QTime startTime; + QDate endDate; + QTime endTime; + int notificationInterval; + MailAction mailAction; + bool valid; + bool active; + bool sendForSpam; +}; + +QString composeScript(const Vacation &vacation); + +KSieveUi::VacationUtils::Vacation parseScript(const QString &script); + +QString mergeRequireLine(const QString &script, const QString &scriptUpdate); + +QString updateVacationBlock(const QString &oldScript, const QString &newScript); + +QString mailAction(MailAction action); } } diff --git a/libksieve/src/ksieveui/vacation/vacationutils.cpp b/libksieve/src/ksieveui/vacation/vacationutils.cpp --- a/libksieve/src/ksieveui/vacation/vacationutils.cpp +++ b/libksieve/src/ksieveui/vacation/vacationutils.cpp @@ -48,7 +48,29 @@ return i18n("Out of office till %1", QLocale().toString(QDate::currentDate().addDays(1))); } -QString VacationUtils::defaultMessageText() +QString KSieveUi::VacationUtils::mailAction(KSieveUi::VacationUtils::MailAction action) +{ + switch (action) { + case Keep: + return i18n("Keep"); + case Discard: + return i18n("Discard"); + case Sendto: + return i18n("Redirect to"); + case CopyTo: + return i18n("Copy to"); + default: + qCWarning(LIBKSIEVE_LOG) << "Unknown mail action" << action; + return i18n("Unkown action"); + } +} + +KSieveUi::VacationUtils::MailAction KSieveUi::VacationUtils::defaultMailAction() +{ + return KSieveUi::VacationUtils::Keep; +} + +QString KSieveUi::VacationUtils::defaultMessageText() { return i18n("I am out of office till %1.\n" "\n" @@ -68,17 +90,24 @@ return 7; // days } -QStringList VacationUtils::defaultMailAliases() +KMime::Types::AddrSpecList VacationUtils::defaultMailAliases() { - QStringList sl; + KMime::Types::AddrSpecList sl; KIdentityManagement::IdentityManager manager(true); KIdentityManagement::IdentityManager::ConstIterator end(manager.end()); for (KIdentityManagement::IdentityManager::ConstIterator it = manager.begin(); it != end; ++it) { if (!(*it).primaryEmailAddress().isEmpty()) { - sl.push_back((*it).primaryEmailAddress()); + KMime::Types::Mailbox a; + a.fromUnicodeString((*it).primaryEmailAddress()); + sl.push_back(a.addrSpec()); + } + foreach(const QString &email, (*it).emailAliases()) { + KMime::Types::Mailbox a; + a.fromUnicodeString(email); + sl.push_back(a.addrSpec()); } - sl += (*it).emailAliases(); } + return sl; } @@ -102,20 +131,20 @@ return defaultStartDate().addDays(7); } -bool VacationUtils::parseScript(const QString &script, QString &messageText, - QString &subject, - int ¬ificationInterval, QStringList &aliases, - bool &sendForSpam, QString &domainName, - QDate &startDate, QDate &endDate) +VacationUtils::Vacation VacationUtils::parseScript(const QString &script) { + KSieveUi::VacationUtils::Vacation vacation; if (script.trimmed().isEmpty()) { - messageText = VacationUtils::defaultMessageText(); - subject = VacationUtils::defaultSubject(); - notificationInterval = VacationUtils::defaultNotificationInterval(); - aliases = VacationUtils::defaultMailAliases(); - sendForSpam = VacationUtils::defaultSendForSpam(); - domainName = VacationUtils::defaultDomainName(); - return true; + vacation.valid = false; + vacation.active = false; + vacation.mailAction = VacationUtils::defaultMailAction(); + vacation.messageText = VacationUtils::defaultMessageText(); + vacation.subject = VacationUtils::defaultSubject(); + vacation.notificationInterval = VacationUtils::defaultNotificationInterval(); + vacation.aliases = VacationUtils::defaultMailAliases(); + vacation.sendForSpam = VacationUtils::defaultSendForSpam(); + vacation.excludeDomain = VacationUtils::defaultDomainName(); + return vacation; } // The trimmed() call below prevents parsing errors. The @@ -128,83 +157,258 @@ VacationDataExtractor vdx; SpamDataExtractor sdx; DomainRestrictionDataExtractor drdx; - DateExtractor dtx; - KSieveExt::MultiScriptBuilder tsb(&vdx, &sdx, &drdx, &dtx); + DateExtractor dx; + KSieveExt::MultiScriptBuilder tsb(&vdx , &sdx, &drdx, &dx); parser.setScriptBuilder(&tsb); - if (!parser.parse()) { - return false; + if (!parser.parse() || !vdx.commandFound()) { + vacation.active = false; + vacation.valid = false; + return vacation; } - messageText = vdx.messageText().trimmed(); + vacation.valid = true; + vacation.active = vdx.active(); + vacation.mailAction = vdx.mailAction(); + vacation.mailActionRecipient = vdx.mailActionRecipient(); + vacation.messageText = vdx.messageText().trimmed(); if (!vdx.subject().isEmpty()) { - subject = vdx.subject().trimmed(); + vacation.subject = vdx.subject().trimmed(); } - notificationInterval = vdx.notificationInterval(); - aliases = vdx.aliases(); - if (!VacationSettings::allowOutOfOfficeUploadButNoSettings()) { - sendForSpam = !sdx.found(); - domainName = drdx.domainName(); + vacation.notificationInterval = vdx.notificationInterval(); + vacation.aliases = KMime::Types::AddrSpecList(); + foreach(const QString &alias, vdx.aliases()) { + KMime::Types::Mailbox a; + a.fromUnicodeString(alias); + vacation.aliases.append(a.addrSpec()); } - startDate = dtx.startDate(); - endDate = dtx.endDate(); - return true; + + if (!vacation.active && !vdx.ifComment().isEmpty()) { + const QByteArray newScript = QByteArrayLiteral("if ") + vdx.ifComment().toUtf8() + QByteArrayLiteral("{vacation;}"); + tsb = KSieveExt::MultiScriptBuilder(&sdx, &drdx, &dx); + KSieve::Parser parser(newScript.begin(), + newScript.begin() + newScript.length()); + parser.setScriptBuilder(&tsb); + if (!parser.parse()) { + vacation.valid = false; + return vacation; + } + } + + vacation.sendForSpam = !sdx.found(); + vacation.excludeDomain = drdx.domainName(); + vacation.startDate = dx.startDate(); + vacation.startTime = dx.startTime(); + vacation.endDate = dx.endDate(); + vacation.endTime = dx.endTime(); + return vacation; } -QString VacationUtils::composeScript(const QString &messageText, - const QString &subject, - int notificationInterval, - const AddrSpecList &addrSpecs, - bool sendForSpam, const QString &domain, - const QDate &startDate, const QDate &endDate) +QString KSieveUi::VacationUtils::composeScript(const Vacation &vacation) { + QStringList condition; + QStringList require; + + require << QStringLiteral("vacation"); + + if (vacation.startDate.isValid() || vacation.endDate.isValid()) { + require << QStringLiteral("date"); + require << QStringLiteral("relational"); + } + + if (vacation.startDate.isValid()) { + if (vacation.startTime.isValid()) { + const QDateTime start(vacation.startDate, vacation.startTime); + condition.append(QStringLiteral("currentdate :value \"ge\" \"iso8601\" \"%1\"") + .arg(start.toString(Qt::ISODate))); + } else { + condition.append(QStringLiteral("currentdate :value \"ge\" \"date\" \"%1\"") + .arg(vacation.startDate.toString(Qt::ISODate))); + } + } + + if (vacation.endDate.isValid()) { + if (vacation.endTime.isValid()) { + const QDateTime end(vacation.endDate, vacation.endTime); + condition.append(QStringLiteral("currentdate :value \"le\" \"iso8601\" \"%1\"") + .arg(end.toString(Qt::ISODate))); + } else { + condition.append(QStringLiteral("currentdate :value \"le\" \"date\" \"%1\"") + .arg(vacation.endDate.toString(Qt::ISODate))); + } + } + + if (!vacation.sendForSpam) { + condition.append(QStringLiteral("not header :contains \"X-Spam-Flag\" \"YES\"")); + } + + if (!vacation.excludeDomain.isEmpty()) { + condition.append(QStringLiteral("address :domain :contains \"from\" \"%1\"").arg(vacation.excludeDomain)); + } + QString addressesArgument; QStringList aliases; - if (!addrSpecs.empty()) { - addressesArgument += QLatin1String(":addresses [ "); + if (!vacation.aliases.empty()) { + addressesArgument += QStringLiteral(":addresses [ "); QStringList sl; - AddrSpecList::const_iterator end = addrSpecs.constEnd(); - for (AddrSpecList::const_iterator it = addrSpecs.begin(); it != end; ++it) { + AddrSpecList::const_iterator end = vacation.aliases.constEnd(); + for (AddrSpecList::const_iterator it = vacation.aliases.begin(); it != end; ++it) { sl.push_back(QLatin1Char('"') + (*it).asString().replace(QLatin1Char('\\'), QStringLiteral("\\\\")).replace(QLatin1Char('"'), QStringLiteral("\\\"")) + QLatin1Char('"')); aliases.push_back((*it).asString()); } - addressesArgument += sl.join(QStringLiteral(", ")) + QLatin1String(" ] "); + addressesArgument += sl.join(QStringLiteral(", ")) + QStringLiteral(" ] "); + } + + QString sVacation(QStringLiteral("vacation ")); + sVacation += addressesArgument; + if (vacation.notificationInterval > 0) { + sVacation += QStringLiteral(":days %1 ").arg(vacation.notificationInterval); + } + + if (!vacation.subject.trimmed().isEmpty()) { + sVacation += QStringLiteral(":subject \"%1\" ").arg(stringReplace(vacation.subject).trimmed()); + } + + sVacation += QStringLiteral("text:\n"); + sVacation += dotstuff(vacation.messageText.isEmpty() ? VacationUtils::defaultMessageText() : vacation.messageText); + sVacation += QStringLiteral("\n.\n;"); + + switch (vacation.mailAction) { + case VacationUtils::Keep: + break; + case VacationUtils::Discard: + sVacation += QStringLiteral("\ndiscard;"); + break; + case VacationUtils::Sendto: + sVacation += QStringLiteral("\nredirect \"") + vacation.mailActionRecipient + QStringLiteral("\";"); + break; + case VacationUtils::CopyTo: + require << QStringLiteral("copy"); + sVacation += QStringLiteral("\nredirect :copy \"") + vacation.mailActionRecipient + QStringLiteral("\";"); + break; } - QString script = QStringLiteral("require \"vacation\";\n"); - if (startDate.isValid() && endDate.isValid()) { - script += QStringLiteral("require \"relational\";\n" - "require \"date\";\n\n"); + QString script = QStringLiteral("require [\"%1\"];\n\n").arg(require.join(QStringLiteral("\", \""))); + + if (condition.isEmpty()) { + if (vacation.active) { + script += sVacation; + } else { + script += QStringLiteral("if false\n{\n\t"); + script += sVacation; + script += QStringLiteral("\n}"); + } } else { - script += QStringLiteral("\n"); + if (vacation.active) { + script += QStringLiteral("if allof(%1)\n{\n\t").arg(condition.join(QStringLiteral(", "))); + } else { + script += QStringLiteral("if false # allof(%1)\n{\n\t").arg(condition.join(QStringLiteral(", "))); + } + script += sVacation; + script += QStringLiteral("\n}"); } - if (!sendForSpam) - script += QStringLiteral("if header :contains \"X-Spam-Flag\" \"YES\"" - " { keep; stop; }\n"); // FIXME? + script += QStringLiteral("\n"); - if (!domain.isEmpty()) { // FIXME - script += QStringLiteral("if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n").arg(domain); + return script; +} + +QString KSieveUi::VacationUtils::mergeRequireLine(const QString &script, const QString &scriptUpdate) +{ + const QByteArray scriptUTF8 = script.trimmed().toUtf8(); + if (scriptUTF8.isEmpty()) { + return scriptUpdate; } - if (startDate.isValid() && endDate.isValid()) { - script += QStringLiteral("if not allof(currentdate :value \"ge\" \"date\" \"%1\"," - " currentdate :value \"le\" \"date\" \"%2\")" - " { keep; stop; }\n").arg(startDate.toString(Qt::ISODate), - endDate.toString(Qt::ISODate)); + const QByteArray scriptUpdateUTF8 = scriptUpdate.trimmed().toUtf8(); + if (scriptUpdateUTF8.isEmpty()) { + return script; } - script += QLatin1String("vacation "); - script += addressesArgument; - if (notificationInterval > 0) { - script += QStringLiteral(":days %1 ").arg(notificationInterval); + 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 (!subject.trimmed().isEmpty()) { - script += QStringLiteral(":subject \"%1\" ").arg(stringReplace(subject).trimmed()); + if (parserUpdate.parse() && rxUpdate.commandFound()) { + requirements += rxUpdate.requirements().toSet(); } - script += QStringLiteral("text:\n"); - script += dotstuff(messageText.isEmpty() ? VacationUtils::defaultMessageText() : messageText); - script += QStringLiteral("\n.\n;\n"); - return script; + const int requirementscount = requirements.count(); + if (requirementscount > 1) { + QStringList req = requirements.toList(); + req.sort(); + lines.insert(insert, QStringLiteral("require [\"%1\"];").arg(req.join(QStringLiteral("\", \"")))); + } else if (requirementscount == 1) { + lines.insert(insert, QStringLiteral("require \"%1\";").arg(requirements.toList().first())); + } + + return lines.join(QStringLiteral("\n")); } +QString KSieveUi::VacationUtils::updateVacationBlock(const QString &oldScript, const QString &newScript) +{ + const QByteArray oldScriptUTF8 = oldScript.trimmed().toUtf8(); + if (oldScriptUTF8.isEmpty()) { + return newScript; + } + + const QByteArray newScriptUTF8 = newScript.trimmed().toUtf8(); + 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); + + 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(QStringLiteral("\n")); +}