diff --git a/libksieve/ksieveui/vacation/tests/data/vacation-complex-time.siv b/libksieve/ksieveui/vacation/tests/data/vacation-complex-time.siv new file mode 100644 index 0000000000..0b1c2def35 --- /dev/null +++ b/libksieve/ksieveui/vacation/tests/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/ksieveui/vacation/tests/vacationutilstest.cpp b/libksieve/ksieveui/vacation/tests/vacationutilstest.cpp index 800bb66f28..f694c345dd 100644 --- a/libksieve/ksieveui/vacation/tests/vacationutilstest.cpp +++ b/libksieve/ksieveui/vacation/tests/vacationutilstest.cpp @@ -1,278 +1,311 @@ /* 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 testAliases(KMime::Types::AddrSpecList l1, KMime::Types::AddrSpecList l2) { QCOMPARE(l1.count(),l2.count()); for (int i=0; i < l1.count(); i++) { QCOMPARE(l1.at(i).asString(),l2.at(i).asString()); } } void testAliases(KMime::Types::AddrSpecList l1, QStringList l2) { QCOMPARE(l1.count(),l2.count()); for (int i=0;i < l1.count(); 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(QLatin1String("#comment")); QCOMPARE(VacationUtils::parseScript(script).isValid(), false); script = QLatin1String("#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") << 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()); 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") << 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()); 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::testParseScriptComplex() { QFile file(QLatin1String(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, QLatin1String("dsfgsdfgsdfg")); QCOMPARE(vacation.subject, QLatin1String("XXX")); QCOMPARE(vacation.notificationInterval, 7); testAliases(vacation.aliases, QStringList() << QLatin1String("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(QLatin1String(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, QLatin1String("dsfgsdfgsdfg")); + QCOMPARE(vacation.subject, QLatin1String("XXX")); + QCOMPARE(vacation.notificationInterval, 7); + testAliases(vacation.aliases, QStringList() << QLatin1String("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() << QLatin1String("test@test.de"); vacation.valid = true; vacation.messageText = QLatin1String("dsfgsdfgsdfg"); vacation.subject = QLatin1String("XXX"); vacation.notificationInterval = 7; vacation.sendForSpam = false; vacation.excludeDomain = QLatin1String("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); kDebug() << "huih"; 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 = QLatin1String("dsfgsdfgsdfg"); vacation.subject = QLatin1String("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(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; i 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 */ #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 testWriteScript(); void testWriteSimpleScript(); void testUpdateVacationBlock(); void testMergeRequireLine(); }; } #endif // VACATIONUTILSTEST_H diff --git a/libksieve/ksieveui/vacation/vacation.cpp b/libksieve/ksieveui/vacation/vacation.cpp index f3fc7b10c7..c24050b3eb 100644 --- a/libksieve/ksieveui/vacation/vacation.cpp +++ b/libksieve/ksieveui/vacation/vacation.cpp @@ -1,228 +1,232 @@ /* -*- c++ -*- vacation.cpp KMail, the KDE mail client. Copyright (c) 2002 Marc Mutz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. 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, US */ #include "vacation.h" #include "vacationutils.h" #include "vacationscriptextractor.h" #include "sieve-vacation.h" #include "util/util.h" #include "vacationdialog.h" #include #include #include #include #include #include #include #include using namespace KSieveUi; Vacation::Vacation(QObject * parent, bool checkOnly, const KUrl &url) : QObject( parent ), mSieveJob( 0 ), mDialog( 0 ), mWasActive( false ), mCheckOnly( checkOnly ) { if (url.isEmpty()) { mUrl = findURL(mServerName); } else { mUrl = url; } kDebug() << "Vacation: found url \"" << mUrl.prettyUrl() <<"\""; if ( mUrl.isEmpty() ) // nothing to do... return; mSieveJob = KManageSieve::SieveJob::get( mUrl ); if (checkOnly) { mSieveJob->setInteractive( false ); } connect( mSieveJob, SIGNAL(gotScript(KManageSieve::SieveJob*,bool,QString,bool)), SLOT(slotGetResult(KManageSieve::SieveJob*,bool,QString,bool)) ); } Vacation::~Vacation() { if ( mSieveJob ) mSieveJob->kill(); mSieveJob = 0; delete mDialog; mDialog = 0; kDebug() << "~Vacation()"; } KUrl Vacation::findURL(QString &serverName) const { const Akonadi::AgentInstance::List instances = Util::imapAgentInstances(); foreach ( const Akonadi::AgentInstance &instance, instances ) { if ( instance.status() == Akonadi::AgentInstance::Broken ) continue; const KUrl url = Util::findSieveUrlForAccount( instance.identifier() ); if ( !url.isEmpty() ) { serverName = instance.name(); return url; } } return KUrl(); } void Vacation::slotGetResult( KManageSieve::SieveJob * job, bool success, const QString & script, bool active ) { kDebug() << success << ", ?," << active << ")" << endl << "script:" << endl << script; mSieveJob = 0; // job deletes itself after returning from this slot! if ( !mCheckOnly && mUrl.protocol() == QLatin1String("sieve") && !job->sieveCapabilities().contains(QLatin1String("vacation")) ) { KMessageBox::sorry( 0, i18n( "Your server did not list \"vacation\" in " "its list of supported Sieve extensions;\n" "without it, KMail cannot install out-of-" "office replies for you.\n" "Please contact your system administrator." ) ); emit result( false ); return; } const bool supportsDate = job->sieveCapabilities().contains(QLatin1String("date")); if ( !mDialog && !mCheckOnly ) mDialog = new VacationDialog( i18n("Configure \"Out of Office\" Replies"), 0, false ); if ( !success ) { active = false; // default to inactive } KSieveUi::VacationUtils::Vacation vacation = KSieveUi::VacationUtils::parseScript(script); if ( !mCheckOnly && ( !success || (!vacation.isValid() && !script.trimmed().isEmpty())) ) { KMessageBox::information( 0, 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 && 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() ); if (supportsDate) { mDialog->enableDates( supportsDate ); mDialog->setStartDate( vacation.startDate ); + mDialog->setEndTime(vacation.endTime); mDialog->setEndDate( vacation.endDate ); + mDialog->setEndTime(vacation.endTime); } connect( mDialog, SIGNAL(okClicked()), SLOT(slotDialogOk()) ); connect( mDialog, SIGNAL(cancelClicked()), SLOT(slotDialogCancel()) ); mDialog->show(); } emit scriptActive( mWasActive, mServerName ); if ( mCheckOnly && mWasActive ) { 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 ) { emit requestEditVacation(); } } } void Vacation::slotDialogOk() { kDebug(); // compose a new script: const bool active = mDialog->activateVacation(); 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.startTime = mDialog->startTime(); vacation.endDate = mDialog->endDate(); + vacation.endTime = mDialog->endTime(); const QString script = VacationUtils::composeScript(vacation); emit scriptActive( active, mServerName); kDebug() << "script:" << endl << script; // and commit the dialog's settings to the server: mSieveJob = KManageSieve::SieveJob::put( mUrl, script, active, mWasActive ); if ( active ) 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)) ); // destroy the dialog: mDialog->delayedDestruct(); mDialog = 0; } void Vacation::slotDialogCancel() { kDebug(); mDialog->delayedDestruct(); mDialog = 0; emit result( false ); } void Vacation::slotPutActiveResult( KManageSieve::SieveJob * job, bool success ) { handlePutResult( job, success, true ); } void Vacation::slotPutInactiveResult( KManageSieve::SieveJob * job, bool success ) { handlePutResult( job, success, false ); } void Vacation::handlePutResult( KManageSieve::SieveJob *, bool success, bool activated ) { if ( success ) KMessageBox::information( 0, activated ? i18n("Sieve script installed successfully on the server.\n" "Out of Office reply is now active.") : i18n("Sieve script installed successfully on the server.\n" "Out of Office reply has been deactivated.") ); kDebug() << "( ???," << success << ", ? )"; mSieveJob = 0; // job deletes itself after returning from this slot! emit result( success ); emit scriptActive( activated, mServerName ); } void Vacation::showVacationDialog() { if (mDialog) { mDialog->show(); mDialog->raise(); mDialog->activateWindow(); } } diff --git a/libksieve/ksieveui/vacation/vacationdialog.cpp b/libksieve/ksieveui/vacation/vacationdialog.cpp index 951f663ee4..14b805b06c 100644 --- a/libksieve/ksieveui/vacation/vacationdialog.cpp +++ b/libksieve/ksieveui/vacation/vacationdialog.cpp @@ -1,200 +1,220 @@ /* vacationdialog.cpp Copyright (c) 2013, 2014 Montel Laurent Copyright (c) 2002 Marc Mutz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. 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, US */ #include "vacationdialog.h" #include "vacationeditwidget.h" #include #include #include #include #include #include #include #include #include using KMime::Types::AddrSpecList; using namespace KSieveUi; VacationDialog::VacationDialog( const QString &caption, QWidget * parent, bool modal ) : KDialog( parent ) { setCaption( caption ); setButtons( Ok|Cancel|Default ); setDefaultButton( Ok ); setModal( modal ); QWidget *w = new QWidget; QVBoxLayout *vbox = new QVBoxLayout; vbox->setMargin(0); w->setLayout(vbox); vbox->addWidget(mVacationEditWidget); mVacationEditWidget = new VacationEditWidget; KSeparator *separator = new KSeparator; vbox->addWidget(separator); setMainWidget( w ); KWindowSystem::setIcons( winId(), qApp->windowIcon().pixmap(IconSize(KIconLoader::Desktop),IconSize(KIconLoader::Desktop)), qApp->windowIcon().pixmap(IconSize(KIconLoader::Small),IconSize(KIconLoader::Small)) ); readConfig(); connect( this, SIGNAL(defaultClicked()), this, SLOT(slotDialogDefaults()) ); } VacationDialog::~VacationDialog() { kDebug() << "~VacationDialog()"; writeConfig(); } void VacationDialog::writeConfig() { KConfigGroup group( KGlobal::config(), "VacationDialog" ); group.writeEntry( "Size", size() ); } void VacationDialog::readConfig() { KConfigGroup group( KGlobal::config(), "VacationDialog" ); const QSize size = group.readEntry( "Size", QSize() ); if ( size.isValid() ) { resize( size ); } else { resize( sizeHint().width(), sizeHint().height() ); } } bool VacationDialog::activateVacation() const { return mVacationEditWidget->activateVacation(); } void VacationDialog::setActivateVacation( bool activate ) { mVacationEditWidget->setActivateVacation(activate); } QString VacationDialog::messageText() const { return mVacationEditWidget->messageText(); } void VacationDialog::setMessageText( const QString &text ) { mVacationEditWidget->setMessageText(text); } QString VacationDialog::subject() const { return mVacationEditWidget->subject(); } void VacationDialog::setSubject(const QString &subject) { return mVacationEditWidget->setSubject(subject); } int VacationDialog::notificationInterval() const { return mVacationEditWidget->notificationInterval(); } void VacationDialog::setNotificationInterval( int days ) { mVacationEditWidget->setNotificationInterval(days); } AddrSpecList VacationDialog::mailAliases() const { return mVacationEditWidget->mailAliases(); } void VacationDialog::setMailAliases( const AddrSpecList &aliases ) { mVacationEditWidget->setMailAliases(aliases); } void VacationDialog::setMailAliases( const QString &aliases ) { mVacationEditWidget->setMailAliases(aliases); } QString VacationDialog::domainName() const { return mVacationEditWidget->domainName(); } void VacationDialog::setDomainName( const QString &domain ) { mVacationEditWidget->setDomainName(domain); } bool VacationDialog::domainCheck() const { return mVacationEditWidget->domainCheck(); } void VacationDialog::setDomainCheck( bool check ) { mVacationEditWidget->setDomainCheck(check); } bool VacationDialog::sendForSpam() const { return mVacationEditWidget->sendForSpam(); } void VacationDialog::setSendForSpam( bool enable ) { mVacationEditWidget->setSendForSpam(enable); } void VacationDialog::enableDomainAndSendForSpam( bool enable ) { mVacationEditWidget->enableDomainAndSendForSpam(enable); } void VacationDialog::slotDialogDefaults() { mVacationEditWidget->setDefault(); } void VacationDialog::enableDates(bool enable) { mVacationEditWidget->enableDates(enable); } QDate VacationDialog::endDate() const { return mVacationEditWidget->endDate(); } void VacationDialog::setEndDate( const QDate &endDate ) { mVacationEditWidget->setEndDate( endDate ); } +QTime VacationDialog::endTime() const +{ + return mVacationEditWidget->endTime(); +} + +void VacationDialog::setEndTime(const QTime &endTime) +{ + mVacationEditWidget->setEndTime(endTime); +} + QDate VacationDialog::startDate() const { return mVacationEditWidget->startDate(); } void VacationDialog::setStartDate( const QDate &startDate ) { mVacationEditWidget->setStartDate( startDate ); } + +QTime VacationDialog::startTime() const +{ + return mVacationEditWidget->startTime(); +} + +void VacationDialog::setStartTime(const QTime &startTime) +{ + mVacationEditWidget->setStartTime(startTime); +} diff --git a/libksieve/ksieveui/vacation/vacationdialog.h b/libksieve/ksieveui/vacation/vacationdialog.h index 02fb0faa17..dceb516b65 100644 --- a/libksieve/ksieveui/vacation/vacationdialog.h +++ b/libksieve/ksieveui/vacation/vacationdialog.h @@ -1,89 +1,94 @@ /* -*- c++ -*- vacationdialog.h Copyright (c) 2002 Marc Mutz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. 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, US */ #ifndef KSIEVE_KSIEVEUI_VACATIONDIALOG_H #define KSIEVE_KSIEVEUI_VACATIONDIALOG_H #include template class QList; class KDateTime; namespace KMime { namespace Types { struct AddrSpec; typedef QList AddrSpecList; } } namespace KSieveUi { class VacationEditWidget; class VacationDialog : public KDialog { Q_OBJECT public: explicit VacationDialog( const QString &caption, QWidget * parent=0, bool modal=true ); ~VacationDialog(); void enableDomainAndSendForSpam( bool enable = true ); bool activateVacation() const; void setActivateVacation( bool activate ); bool domainCheck() const; void setDomainCheck( bool check ); QString messageText() const; void setMessageText( const QString &text ); QString subject() const; void setSubject( const QString &subject ); int notificationInterval() const; void setNotificationInterval( int days ); KMime::Types::AddrSpecList mailAliases() const; void setMailAliases( const KMime::Types::AddrSpecList & aliases ); void setMailAliases( const QString &aliases ); QString domainName() const; void setDomainName( const QString &domain ); bool sendForSpam() const; void setSendForSpam( bool enable ); void enableDates( bool enable = true ); QDate startDate() const; void setStartDate( const QDate &startDate ); + QTime startTime() const; + void setStartTime( const QTime &startTime ); + QDate endDate() const; void setEndDate( const QDate &endDate ); + QTime endTime() const; + void setEndTime( const QTime &endTime ); private slots: void slotDialogDefaults(); private: void writeConfig(); void readConfig(); VacationEditWidget *mVacationEditWidget; }; } #endif diff --git a/libksieve/ksieveui/vacation/vacationeditwidget.cpp b/libksieve/ksieveui/vacation/vacationeditwidget.cpp index dadbd0d44c..a6b9c16b6c 100644 --- a/libksieve/ksieveui/vacation/vacationeditwidget.cpp +++ b/libksieve/ksieveui/vacation/vacationeditwidget.cpp @@ -1,323 +1,388 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 "vacationeditwidget.h" #include "vacationutils.h" #include #include #include #include #include #include #include #include #include #include +#include #include +#include #include using KMime::Types::AddrSpecList; using KMime::Types::AddressList; using KMime::Types::MailboxList; using KMime::HeaderParsing::parseAddressList; using namespace KSieveUi; VacationEditWidget::VacationEditWidget(QWidget *parent) : QWidget(parent) { int row = -1; QGridLayout * glay = new QGridLayout( this ); glay->setSpacing( KDialog::spacingHint() ); glay->setMargin( 0 ); glay->setColumnStretch( 1, 1 ); // explanation label: ++row; glay->addWidget( new QLabel( i18n("Configure vacation " "notifications to be sent:"), this ), row, 0, 1, 2 ); // Activate checkbox: ++row; mActiveCheck = new QCheckBox( i18n("&Activate vacation notifications"), this ); glay->addWidget( mActiveCheck, row, 0, 1, 2 ); // Message text edit: ++row; glay->setRowStretch( row, 1 ); mTextEdit = new PimCommon::RichTextEditorWidget( this ); mTextEdit->setObjectName( QLatin1String("mTextEdit") ); mTextEdit->setAcceptRichText( false ); glay->addWidget( mTextEdit, row, 0, 1, 2 ); // Subject ++row; mSubject = new KLineEdit(this); mSubject->setObjectName(QLatin1String("mSubject")); mSubject->setClearButtonShown(true); QLabel *tmpLabel = new QLabel(i18n("&Subject of the vacation mail:"), this); tmpLabel->setBuddy(mSubject); glay->addWidget(tmpLabel, row, 0); glay->addWidget(mSubject, row, 1); // From date - ++row; + + QHBoxLayout *timeLayout = new QHBoxLayout(this); + mStartDate = new KDateComboBox( this ); mStartDate->setObjectName( QLatin1String( "mStartDate" ) ); mStartDate->setOptions( KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::DateKeywords | KDateComboBox::WarnOnInvalid ); mStartDate->setEnabled( false ); // Disable by default - we need an extension to support this + + mStartTime = new KTimeComboBox( this ); + mStartTime->setObjectName( QLatin1String( "mStartTime" ) ); + mStartTime->setOptions( KTimeComboBox::EditTime | KTimeComboBox::SelectTime | KTimeComboBox::EditTime | KTimeComboBox::WarnOnInvalid ); + mStartTime->setEnabled( false ); // Disable by default - we need an extension to support this + + mStartTimeActive = new QCheckBox(this); + connect(mStartTimeActive,SIGNAL(toggled(bool)), mStartTime, SLOT(setEnabled(bool))); + + timeLayout->addWidget(mStartDate); + timeLayout->addWidget(mStartTimeActive); + timeLayout->addWidget(mStartTime); + + ++row; QLabel *label = new QLabel( i18n("&Start:"), this ); label->setBuddy( mStartDate ); glay->addWidget( label, row, 0 ); - glay->addWidget( mStartDate, row, 1 ); + glay->addLayout(timeLayout, row, 1); // End date - ++row; + timeLayout = new QHBoxLayout(this); + mEndDate = new KDateComboBox( this ); mEndDate->setObjectName( QLatin1String( "mEndDate" ) ); mEndDate->setOptions( KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::DateKeywords | KDateComboBox::WarnOnInvalid ); mEndDate->setEnabled( false ); // Disable by default - we need an extension to support this + + mEndTime = new KTimeComboBox( this ); + mEndTime->setObjectName( QLatin1String( "mEndTime" ) ); + mEndTime->setOptions( KTimeComboBox::EditTime | KTimeComboBox::SelectTime | KTimeComboBox::EditTime | KTimeComboBox::WarnOnInvalid ); + mEndTime->setEnabled( false ); // Disable by default - we need an extension to support this + + mEndTimeActive = new QCheckBox(this); + connect(mEndTimeActive,SIGNAL(toggled(bool)), mEndTime, SLOT(setEnabled(bool))); + + timeLayout->addWidget(mEndDate); + timeLayout->addWidget(mEndTimeActive); + timeLayout->addWidget(mEndTime); + + ++row; label = new QLabel( i18n("&End:"), this ); label->setBuddy( mEndDate ); glay->addWidget( label, row, 0 ); - glay->addWidget( mEndDate, row, 1 ); + glay->addLayout(timeLayout, row, 1); // "Resent only after" spinbox and label: ++row; int defDayInterval = 7; //default day interval mIntervalSpin = new KIntSpinBox( 0, 356, 1, defDayInterval, this ); mIntervalSpin->setObjectName( QLatin1String("mIntervalSpin") ); mIntervalSpin->setSuffix( i18np(" day", " days", defDayInterval) ); connect(mIntervalSpin, SIGNAL(valueChanged(int)), SLOT(slotIntervalSpinChanged(int)) ); label = new QLabel( i18n("&Resend notification only after:"), this ); label->setBuddy( mIntervalSpin ); glay->addWidget( label, row, 0 ); glay->addWidget( mIntervalSpin, row, 1 ); // "Send responses for these addresses" lineedit and label: ++row; mMailAliasesEdit = new KLineEdit( this ); mMailAliasesEdit->setObjectName( QLatin1String("mMailAliasesEdit") ); mMailAliasesEdit->setClearButtonShown( true ); tmpLabel = new QLabel( i18n("&Send responses for these addresses:"), this ); tmpLabel->setBuddy( mMailAliasesEdit ); glay->addWidget( tmpLabel, row, 0 ); glay->addWidget( mMailAliasesEdit, row, 1 ); // "Send responses also to SPAM mail" checkbox: ++row; mSpamCheck = new QCheckBox( i18n("Do not send vacation replies to spam messages"), this ); mSpamCheck->setObjectName( QLatin1String("mSpamCheck") ); mSpamCheck->setChecked( true ); glay->addWidget( mSpamCheck, row, 0, 1, 2 ); // domain checkbox and linedit: ++row; mDomainCheck = new QCheckBox( i18n("Only react to mail coming from domain"), this ); mDomainCheck->setObjectName( QLatin1String("mDomainCheck") ); mDomainCheck->setChecked( false ); mDomainEdit = new KLineEdit( this ); mDomainEdit->setObjectName( QLatin1String("mDomainEdit") ); mDomainEdit->setClearButtonShown( true ); mDomainEdit->setEnabled( false ); mDomainEdit->setValidator( new QRegExpValidator( QRegExp( QLatin1String("[a-zA-Z0-9+-]+(?:\\.[a-zA-Z0-9+-]+)*") ), mDomainEdit ) ); glay->addWidget( mDomainCheck, row, 0 ); glay->addWidget( mDomainEdit, row, 1 ); connect( mDomainCheck, SIGNAL(toggled(bool)), mDomainEdit, SLOT(setEnabled(bool)) ); } VacationEditWidget::~VacationEditWidget() { } bool VacationEditWidget::activateVacation() const { return mActiveCheck->isChecked(); } void VacationEditWidget::setActivateVacation( bool activate ) { mActiveCheck->setChecked( activate ); } QString VacationEditWidget::messageText() const { return mTextEdit->toPlainText().trimmed(); } void VacationEditWidget::setMessageText( const QString &text ) { mTextEdit->setPlainText( text ); const int height = ( mTextEdit->fontMetrics().lineSpacing() + 1 ) * 11; mTextEdit->setMinimumHeight( height ); } int VacationEditWidget::notificationInterval() const { return mIntervalSpin->value(); } void VacationEditWidget::setNotificationInterval( int days ) { mIntervalSpin->setValue( days ); } AddrSpecList VacationEditWidget::mailAliases() const { QByteArray text = mMailAliasesEdit->text().toLatin1(); // ### IMAA: !ok AddressList al; const char * s = text.begin(); parseAddressList( s, text.end(), al ); AddrSpecList asl; AddressList::const_iterator end(al.constEnd()); for ( AddressList::const_iterator it = al.constBegin() ; it != end; ++it ) { const MailboxList & mbl = (*it).mailboxList; for ( MailboxList::const_iterator jt = mbl.constBegin() ; jt != mbl.constEnd() ; ++jt ) asl.push_back( (*jt).addrSpec() ); } return asl; } void VacationEditWidget::setMailAliases( const AddrSpecList &aliases ) { QStringList sl; AddrSpecList::const_iterator end(aliases.constEnd()); for ( AddrSpecList::const_iterator it = aliases.constBegin() ; it != end; ++it ) sl.push_back( (*it).asString() ); mMailAliasesEdit->setText( sl.join(QLatin1String(", ")) ); } void VacationEditWidget::setMailAliases( const QString &aliases ) { mMailAliasesEdit->setText( aliases ); } void VacationEditWidget::slotIntervalSpinChanged ( int value ) { mIntervalSpin->setSuffix( i18np(" day", " days", value) ); } QString VacationEditWidget::domainName() const { return mDomainCheck->isChecked() ? mDomainEdit->text() : QString() ; } void VacationEditWidget::setDomainName( const QString &domain ) { if ( !domain.isEmpty() ) { mDomainEdit->setText( domain ); mDomainCheck->setChecked( true ); } } bool VacationEditWidget::domainCheck() const { return mDomainCheck->isChecked(); } void VacationEditWidget::setDomainCheck( bool check ) { mDomainCheck->setChecked( check ); } bool VacationEditWidget::sendForSpam() const { return !mSpamCheck->isChecked(); } void VacationEditWidget::setSendForSpam( bool enable ) { mSpamCheck->setChecked( !enable ); } -QDate VacationEditWidget::endDate() +QDate VacationEditWidget::endDate() const { if ( mEndDate->isEnabled() ) { return mEndDate->date(); } else { return QDate(); } } void VacationEditWidget::setEndDate( const QDate &endDate ) { mEndDate->setDate( endDate ); } +QTime VacationEditWidget::endTime() const +{ + if ( mEndTime->isEnabled() ) { + return mEndTime->time(); + } else { + return QTime(); + } +} + +void VacationEditWidget::setEndTime( const QTime &endTime ) +{ + mEndTimeActive->setChecked(endTime.isValid()); + mEndTime->setEnabled(endTime.isValid()); + mEndTime->setTime( endTime ); +} + QDate VacationEditWidget::startDate() const { if ( mStartDate->isEnabled() ) { return mStartDate->date(); } else { return QDate(); } } void VacationEditWidget::setStartDate( const QDate &startDate ) { mStartDate->setDate( startDate ); } +QTime VacationEditWidget::startTime() const +{ + if ( mStartTime->isEnabled() ) { + return mStartTime->time(); + } else { + return QTime(); + } +} + +void VacationEditWidget::setStartTime( const QTime &startTime ) +{ + mStartTimeActive->setChecked(startTime.isValid()); + mStartTime->setEnabled(startTime.isValid()); + mStartTime->setTime( startTime ); +} + void VacationEditWidget::setSubject(const QString &subject) { mSubject->setText(subject); } QString VacationEditWidget::subject() const { if (mSubject->isEnabled()) { return mSubject->text(); } else { return QString(); } } void VacationEditWidget::enableDates( bool enable ) { mStartDate->setEnabled( enable ); mEndDate->setEnabled( enable ); } void VacationEditWidget::enableDomainAndSendForSpam( bool enable ) { mDomainCheck->setEnabled( enable ); mDomainEdit->setEnabled( enable && mDomainCheck->isChecked() ); mSpamCheck->setEnabled( enable ); } void VacationEditWidget::setDefault() { setActivateVacation( true ); setMessageText( VacationUtils::defaultMessageText() ); setSubject(VacationUtils::defaultSubject()); setNotificationInterval( VacationUtils::defaultNotificationInterval() ); setMailAliases( VacationUtils::defaultMailAliases() ); setSendForSpam( VacationUtils::defaultSendForSpam() ); setDomainName( VacationUtils::defaultDomainName() ); setDomainCheck( false ); } diff --git a/libksieve/ksieveui/vacation/vacationeditwidget.h b/libksieve/ksieveui/vacation/vacationeditwidget.h index df70d73f18..35ebb13c54 100644 --- a/libksieve/ksieveui/vacation/vacationeditwidget.h +++ b/libksieve/ksieveui/vacation/vacationeditwidget.h @@ -1,104 +1,116 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 */ #ifndef VACATIONEDITWIDGET_H #define VACATIONEDITWIDGET_H #include class KIntSpinBox; class KLineEdit; class KDateComboBox; +class KTimeComboBox; class QDate; +class QTime; namespace PimCommon { class RichTextEditorWidget; } class QCheckBox; template class QList; namespace KMime { namespace Types { struct AddrSpec; typedef QList AddrSpecList; } } namespace KSieveUi { class VacationEditWidget : public QWidget { Q_OBJECT public: explicit VacationEditWidget(QWidget *parent=0); ~VacationEditWidget(); void enableDates( bool enable = true ); void enableDomainAndSendForSpam( bool enable = true ); bool activateVacation() const; void setActivateVacation( bool activate ); bool domainCheck() const; void setDomainCheck( bool check ); QString messageText() const; void setMessageText( const QString &text ); int notificationInterval() const; void setNotificationInterval( int days ); KMime::Types::AddrSpecList mailAliases() const; void setMailAliases( const KMime::Types::AddrSpecList & aliases ); void setMailAliases( const QString &aliases ); QString domainName() const; void setDomainName( const QString &domain ); QString subject() const; void setSubject(const QString &subject); bool sendForSpam() const; void setSendForSpam( bool enable ); QDate startDate() const; void setStartDate( const QDate &startDate ); - QDate endDate(); + QTime startTime() const; + void setStartTime( const QTime &startTime ); + + QDate endDate() const; void setEndDate( const QDate &endDate ); + QTime endTime() const; + void setEndTime( const QTime &endTime ); + void setDefault(); private Q_SLOTS: void slotIntervalSpinChanged( int value ); protected: QCheckBox *mActiveCheck; KIntSpinBox *mIntervalSpin; KLineEdit *mMailAliasesEdit; PimCommon::RichTextEditorWidget *mTextEdit; QCheckBox *mSpamCheck; QCheckBox *mDomainCheck; KLineEdit *mDomainEdit; KLineEdit *mSubject; KDateComboBox *mStartDate; + KTimeComboBox *mStartTime; + QCheckBox *mStartTimeActive; KDateComboBox *mEndDate; + KTimeComboBox *mEndTime; + QCheckBox *mEndTimeActive; }; } #endif // VACATIONEDITWIDGET_H diff --git a/libksieve/ksieveui/vacation/vacationpagewidget.cpp b/libksieve/ksieveui/vacation/vacationpagewidget.cpp index 8530620caa..31e9d49233 100644 --- a/libksieve/ksieveui/vacation/vacationpagewidget.cpp +++ b/libksieve/ksieveui/vacation/vacationpagewidget.cpp @@ -1,185 +1,189 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 "vacationpagewidget.h" #include "vacationeditwidget.h" #include "vacationwarningwidget.h" #include "vacationcreatescriptjob.h" #include "vacationutils.h" #include "multiimapvacationmanager.h" #include #include "sieve-vacation.h" #include #include #include #include #include #include #include using namespace KSieveUi; VacationPageWidget::VacationPageWidget(QWidget *parent) : QWidget(parent), mPageScript(Script), mWasActive(false) { QVBoxLayout *lay = new QVBoxLayout; lay->setMargin(0); mStackWidget = new QStackedWidget; lay->addWidget(mStackWidget); //Main Page QWidget *mainPage = new QWidget; QVBoxLayout *vbox = new QVBoxLayout; mainPage->setLayout(vbox); mVacationWarningWidget = new VacationWarningWidget; vbox->addWidget(mVacationWarningWidget); mVacationEditWidget = new VacationEditWidget; vbox->addWidget(mVacationEditWidget); mStackWidget->addWidget(mainPage); QWidget *w = new QWidget; vbox = new QVBoxLayout; QLabel *lab = new QLabel(i18n( "Your server did not list \"vacation\" in " "its list of supported Sieve extensions;" "without it, KMail cannot install out-of-" "office replies for you." "Please contact your system administrator." ) ); vbox->addWidget(lab); vbox->setAlignment(lab, Qt::AlignVCenter); lab->setWordWrap(true); w->setLayout(vbox); mStackWidget->addWidget(w); mStackWidget->setCurrentIndex(Script); setLayout(lay); } VacationPageWidget::~VacationPageWidget() { } void VacationPageWidget::setServerUrl(const KUrl &url) { mUrl = url; mVacationEditWidget->setEnabled(false); } 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) { mServerName = serverName; } void VacationPageWidget::slotGetResult(const QString &serverName, const QStringList &sieveCapabilities, const QString &scriptName, const QString &script, bool active) { if (serverName != mServerName) { return; } kDebug() << serverName << sieveCapabilities << endl << scriptName << "(" << active << ")" << endl << "script:" << endl << script; if ( mUrl.protocol() == QLatin1String("sieve") && !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") && sieveCapabilities.contains(QLatin1String("date")); KSieveUi::VacationUtils::Vacation vacation = KSieveUi::VacationUtils::parseScript(script); if (!vacation.isValid() && !script.trimmed().isEmpty() ) { mVacationWarningWidget->setVisible(true); } mWasActive = active; 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() ); mVacationEditWidget->enableDates( supportsSieveDate ); if ( supportsSieveDate ) { mVacationEditWidget->setStartDate( vacation.startDate ); + mVacationEditWidget->setStartTime(vacation.startTime); mVacationEditWidget->setEndDate( vacation.endDate ); + mVacationEditWidget->setEndTime(vacation.endTime); } //emit scriptActive( mWasActive, mServerName ); } KSieveUi::VacationCreateScriptJob *VacationPageWidget::writeScript() { if (mPageScript == Script) { KSieveUi::VacationCreateScriptJob *createJob = new KSieveUi::VacationCreateScriptJob; createJob->setServerUrl(mUrl); createJob->setServerName(mServerName); 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.startTime = mVacationEditWidget->startTime(); vacation.endDate = mVacationEditWidget->endDate(); + vacation.endTime = mVacationEditWidget->endTime(); const QString script = VacationUtils::composeScript(vacation); createJob->setStatus(active, mWasActive); //Q_EMIT scriptActive( active, mServerName); createJob->setScript(script); return createJob; } return 0; } void VacationPageWidget::setDefault() { if (mVacationEditWidget->isEnabled()) mVacationEditWidget->setDefault(); } diff --git a/libksieve/ksieveui/vacation/vacationscriptextractor.h b/libksieve/ksieveui/vacation/vacationscriptextractor.h index 1812ada37d..28475ee2a5 100644 --- a/libksieve/ksieveui/vacation/vacationscriptextractor.h +++ b/libksieve/ksieveui/vacation/vacationscriptextractor.h @@ -1,518 +1,552 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 */ #ifndef VACATIONSCRIPTEXTRACTOR_H #define VACATIONSCRIPTEXTRACTOR_H #include "sieve-vacation.h" #include "util/util.h" #include #include #include #include #include #include #include #include #include namespace KSieveExt { class MultiScriptBuilder : public KSieve::ScriptBuilder { std::vector mBuilders; public: MultiScriptBuilder() : KSieve::ScriptBuilder() {} MultiScriptBuilder( KSieve::ScriptBuilder * sb1 ) : KSieve::ScriptBuilder(), mBuilders( 1 ) { mBuilders[0] = sb1; assert( sb1 ); } MultiScriptBuilder( KSieve::ScriptBuilder * sb1, KSieve::ScriptBuilder * sb2 ) : KSieve::ScriptBuilder(), mBuilders( 2 ) { mBuilders[0] = sb1; mBuilders[1] = sb2; assert( sb1 ); assert( sb2 ); } MultiScriptBuilder( KSieve::ScriptBuilder * sb1, KSieve::ScriptBuilder * sb2, KSieve::ScriptBuilder * sb3 ) : KSieve::ScriptBuilder(), mBuilders( 3 ) { mBuilders[0] = sb1; mBuilders[1] = sb2; mBuilders[2] = sb3; assert( sb1 ); assert( sb2 ); assert( sb3 ); } MultiScriptBuilder( KSieve::ScriptBuilder * sb1, KSieve::ScriptBuilder * sb2, KSieve::ScriptBuilder * sb3, KSieve::ScriptBuilder * sb4 ) : KSieve::ScriptBuilder(), mBuilders( 4 ) { mBuilders[0] = sb1; mBuilders[1] = sb2; mBuilders[2] = sb3; mBuilders[3] = sb4; assert( sb1 ); assert( sb2 ); assert( sb3 ); assert( sb4 ); } ~MultiScriptBuilder() {} private: #ifdef FOREACH #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, 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(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(); } void error( const KSieve::Error & e ) { FOREACH error( e ); } void finished() { FOREACH finished(); } void taggedArgument( const QString & tag ) { FOREACH taggedArgument( tag ); } void stringArgument( const QString & string, bool multiline, const QString & fixme ) { FOREACH stringArgument( string, multiline, fixme ); } void numberArgument( unsigned long number, char quantifier ) { FOREACH numberArgument( number, quantifier ); } void stringListArgumentStart() { FOREACH stringListArgumentStart(); } void stringListEntry( const QString & string, bool multiline, const QString & fixme) { FOREACH stringListEntry( string, multiline, fixme ); } void stringListArgumentEnd() { FOREACH stringListArgumentEnd(); } #undef FOREACH }; } namespace KSieveUi { class GenericInformationExtractor : public KSieve::ScriptBuilder { public: enum BuilderMethod { Any, TaggedArgument, StringArgument, NumberArgument, CommandStart, CommandEnd, TestStart, TestEnd, TestListStart, TestListEnd, BlockStart, BlockEnd, StringListArgumentStart, StringListEntry, StringListArgumentEnd }; struct StateNode { // expectation: int depth; BuilderMethod method; const char * string; // actions: int if_found; int if_not_found; const char * save_tag; }; const std::vector mNodes; std::map mResults; std::set mRecursionGuard; unsigned int mState; int mNestingDepth; int mLineNumber; public: GenericInformationExtractor( const std::vector & nodes ) : KSieve::ScriptBuilder(), mNodes( nodes ), mState( 0 ), mNestingDepth( 0 ), mLineNumber(0) {} const std::map & results() const { return mResults; } private: virtual void process( BuilderMethod method, const QString & string=QString() ) { doProcess( method, string ); mRecursionGuard.clear(); } void doProcess( BuilderMethod method, const QString & string ) { mRecursionGuard.insert( mState ); bool found = true; const StateNode & expected = mNodes[mState]; if ( expected.depth != -1 && mNestingDepth != expected.depth ) found = false; if ( expected.method != Any && method != expected.method ) found = false; if ( const char * str = expected.string ) if ( string.toLower() != QString::fromUtf8( str ).toLower() ) found = false; kDebug() << ( found ?"found:" :"not found:" ) << mState << "->" << ( found ? expected.if_found : expected.if_not_found ); mState = found ? expected.if_found : expected.if_not_found ; assert( mState < mNodes.size() ); if ( found ) if ( const char * save_tag = expected.save_tag ) { kDebug() << "stored tag" << save_tag << ":" << string; mResults[QString::fromLatin1(save_tag)] = string; } if ( !found && !mRecursionGuard.count( mState ) ) { doProcess( method, string ); } } 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(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() << ++mLineNumber; } void error( const KSieve::Error & ) { kDebug() ; mState = 0; } void finished() { kDebug() ; } void taggedArgument( const QString & tag ) { kDebug() ; process( TaggedArgument, tag ); } void stringArgument( const QString & string, bool, const QString & ) { kDebug() ; process( StringArgument, string ); } void numberArgument( unsigned long number, char ) { kDebug(); process( NumberArgument, QString::number( number ) ); } void stringListArgumentStart() { kDebug() ; process( StringListArgumentStart ); } void stringListEntry( const QString & string, bool, const QString & ) { kDebug() ; process( StringListEntry, string ); } void stringListArgumentEnd() { kDebug() ; process( StringListArgumentEnd ); } }; typedef GenericInformationExtractor GIE; static const GenericInformationExtractor::StateNode spamNodes[] = { { 0, GIE::CommandStart, "if", 1, 0, 0 }, // 0 { 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", 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", 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, 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, 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, 25, 25, 0 }, // 25 end state }; static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes ; class SpamDataExtractor : public GenericInformationExtractor { public: SpamDataExtractor() : GenericInformationExtractor( std::vector( spamNodes, spamNodes + numSpamNodes ) ) { } bool found() const { return mResults.count( QLatin1String("x-spam-flag") ) && mResults.count( QLatin1String("spam-flag-yes") ) && mResults.count( QLatin1String("vacation") ) ; } }; // to understand this table, study the output of // libksieve/tests/parsertest // '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, "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", 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", 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, 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, 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, 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, 24, 24, 0 } // 24 end state }; static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes ; class DomainRestrictionDataExtractor : public GenericInformationExtractor { public: DomainRestrictionDataExtractor() : GenericInformationExtractor( std::vector( domainNodes, domainNodes+numDomainNodes ) ) { } QString domainName() /*not const, since map::op[] isn't const*/ { return mResults.count( QLatin1String("vacation") ) && mResults.count( QLatin1String("from") ) ? mResults[QLatin1String("domainName")] : QString(); } }; // if not allof (currentdate :value "ge" date "YYYY-MM-DD", // 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, "allof", 2, 0, 0 }, // 1 // handle startDate and endDate in arbitrary order { 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 + { 0, GIE::TestStart, "currentdate", 4, 3, 0 }, // 3 + { 0, GIE::TaggedArgument, "value", 5, 4, 0 }, // 4 + { 0, GIE::StringArgument, "ge", 6, 10, 0 }, // 5 + { 0, GIE::StringArgument, "date", 7, 8, 0 }, // 6 + { 0, GIE::StringArgument, 0, 15, 0, "startDate" }, // 7 + { 0, GIE::StringArgument, "iso8601", 9, 0, 0 }, // 8 + { 0, GIE::StringArgument, 0, 15, 0, "startDateTime" },// 9 + { 0, GIE::StringArgument, "le", 11, 0, 0 }, // 10 + { 0, GIE::StringArgument, "date", 12, 13, 0 }, // 11 + { 0, GIE::StringArgument, 0, 15, 0, "endDate" }, // 12 + { 0, GIE::StringArgument, "iso8601", 14, 0, 0 }, // 13 + { 0, GIE::StringArgument, 0, 15, 0, "endDateTime" }, // 14 + { 0, GIE::TestEnd, 0, 16, 0, 0 }, // 15 + + { 0, GIE::TestStart, "currentdate", 17, 16, 0 }, // 16 + { 0, GIE::TaggedArgument, "value", 18, 17, 0 }, // 17 + { 0, GIE::StringArgument, "le", 19, 23, 0 }, // 18 + { 0, GIE::StringArgument, "date", 20, 21, 0 }, // 19 + { 0, GIE::StringArgument, 0, 28, 0, "endDate" }, // 20 + { 0, GIE::StringArgument, "iso8601", 22, 0, 0 }, // 21 + { 0, GIE::StringArgument, 0, 28, 0, "endDateTime" }, // 22 + { 0, GIE::StringArgument, "ge", 24, 0, 0 }, // 23 + { 0, GIE::StringArgument, "date", 25, 26, 0 }, // 24 + { 0, GIE::StringArgument, 0, 28, 0, "startDate" }, // 25 + { 0, GIE::StringArgument, "iso8601", 27, 0, 0 }, // 26 + { 0, GIE::StringArgument, 0, 28, 0, "startDateTime" }, // 27 + { 0, GIE::TestEnd, 0, 32, 0, 0 }, // 28 + { 0, GIE::TestStart, 0, 31, 30, 0 }, // 29 + { -1, GIE::Any, 0, 32, 0, 0 }, // 30 + { 0, GIE::TestEnd, 0, 32, 30, 0 }, // 31 + { 0, GIE::TestListEnd, 0, 33, 29, 0 }, // 32 + + { 0, GIE::TestEnd, 0, 34, 0, 0 }, // 33 // block of commands, find "stop", take nested if's into account: - { 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 + { 0, GIE::BlockStart, 0, 36, 33, 0 }, // 34 + { -1, GIE::Any, 0, 36, 0, 0 }, // 35 + { 1, GIE::CommandStart, "vacation", 38, 35, "vacation" }, // 36 + { -1, GIE::Any, 0, 38, 0, 0 }, // 37 + { 0, GIE::BlockEnd, 0, 39, 37, 0 }, // 38 - { -1, GIE::Any, 0, 31, 31, 0 } // 31 end state + { -1, GIE::Any, 0, 39, 39, 0 } // 39 end state }; static const unsigned int numDatesNodes = sizeof datesNodes / sizeof *datesNodes; class DateExtractor : public GenericInformationExtractor { public: DateExtractor() : GenericInformationExtractor( std::vector( datesNodes, datesNodes+numDatesNodes ) ) { } QDate endDate() { - return date( QLatin1String( "endDate" ) ); + if (mResults.count(QLatin1String("endDateTime")) == 1) { + return datetime(QLatin1String("endDateTime")).date(); + } else { + return date(QLatin1String("endDate")); + } } QDate startDate() { - return date( QLatin1String( "startDate" ) ); + if (mResults.count(QLatin1String("startDateTime")) == 1) { + return datetime(QLatin1String("startDateTime")).date(); + } else { + return date(QLatin1String("startDate")); + } + } + + QTime endTime() + { + return datetime(QLatin1String("endDateTime")).time(); + } + + QTime startTime() + { + return datetime(QLatin1String("startDateTime")).time(); } private: QDate date(const QString &name ) { if (mResults.count( name ) == 0) { return QDate(); } else { return QDate::fromString( mResults[name], Qt::ISODate ); } } + + QDateTime datetime(const QString &name ) { + if (mResults.count(name) == 0) { + return QDateTime(); + } else { + return QDateTime::fromString( mResults[name], Qt::ISODate ); + } + } }; class VacationDataExtractor : public KSieve::ScriptBuilder { enum Context { None = 0, // command itself: VacationCommand, // tagged args: 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, 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 &c ) {} void lineFeed() {} void error( const KSieve::Error & e ); void finished(); void taggedArgument( const QString & tag ); void stringArgument( const QString & string, bool, const QString & ); void numberArgument( unsigned long number, char ); void stringListArgumentStart(); void stringListEntry( const QString & string, bool, const QString & ); void stringListArgumentEnd(); private: Context mContext; int mNotificationInterval; 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; }; } #endif // VACATIONSCRIPTEXTRACTOR_H diff --git a/libksieve/ksieveui/vacation/vacationutils.cpp b/libksieve/ksieveui/vacation/vacationutils.cpp index 8c5633c074..1508c2ca5d 100644 --- a/libksieve/ksieveui/vacation/vacationutils.cpp +++ b/libksieve/ksieveui/vacation/vacationutils.cpp @@ -1,411 +1,425 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 "vacationutils.h" #include "vacationscriptextractor.h" #include "sieve-vacation.h" #include #include #include #include #include -#include +#include using KMime::Types::AddrSpecList; static inline QString dotstuff( QString s ) { // krazy:exclude=passbyvalue if ( s.startsWith( QLatin1Char('.') ) ) return QLatin1Char('.') + s.replace( QLatin1String("\n."), QLatin1String("\n..") ); else return s.replace( QLatin1String("\n."), QLatin1String("\n..") ); } static inline QString stringReplace(QString s) { s = s.replace(QRegExp(QLatin1String("[\n\t]+")),QLatin1String(" ")); return s.replace(QLatin1Char('\"'),QLatin1String("\\\"")); } QString KSieveUi::VacationUtils::defaultSubject() { return i18n("Out of office till %1", QLocale().toString(QDate::currentDate().addDays(1))); } QString KSieveUi::VacationUtils::defaultMessageText() { return i18n( "I am out of office till %1.\n" "\n" "In urgent cases, please contact Mrs. \"vacation replacement\"\n" "\n" "email: \"email address of vacation replacement\"\n" "phone: +49 711 1111 11\n" "fax.: +49 711 1111 12\n" "\n" "Yours sincerely,\n" "-- \"enter your name and email address here\"\n", KGlobal::locale()->formatDate( QDate::currentDate().addDays( 1 ) ) ); } int KSieveUi::VacationUtils::defaultNotificationInterval() { return 7; // days } KMime::Types::AddrSpecList KSieveUi::VacationUtils::defaultMailAliases() { KMime::Types::AddrSpecList sl; KPIMIdentities::IdentityManager manager( true ); KPIMIdentities::IdentityManager::ConstIterator end(manager.end()); for ( KPIMIdentities::IdentityManager::ConstIterator it = manager.begin(); it != end ; ++it ) { if ( !(*it).primaryEmailAddress().isEmpty() ) { 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()); } } return sl; } bool KSieveUi::VacationUtils::defaultSendForSpam() { return VacationSettings::outOfOfficeReactToSpam(); } QString KSieveUi::VacationUtils::defaultDomainName() { return VacationSettings::outOfOfficeDomain(); } QDate KSieveUi::VacationUtils::defaultStartDate() { return QDate::currentDate(); } QDate KSieveUi::VacationUtils::defaultEndDate() { return defaultStartDate().addDays(7); } KSieveUi::VacationUtils::Vacation KSieveUi::VacationUtils::parseScript(const QString &script) { KSieveUi::VacationUtils::Vacation vacation; if ( script.trimmed().isEmpty() ) { vacation.valid = false; vacation.active = false; 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 // slave somehow omits the last \n, which results in a lone \r at // the end, leading to a parse error. const QByteArray scriptUTF8 = script.trimmed().toUtf8(); kDebug() << "scriptUtf8 = \"" + scriptUTF8 +"\""; KSieve::Parser parser( scriptUTF8.begin(), scriptUTF8.begin() + scriptUTF8.length() ); VacationDataExtractor vdx; SpamDataExtractor sdx; DomainRestrictionDataExtractor drdx; DateExtractor dx; KSieveExt::MultiScriptBuilder tsb( &vdx , &sdx, &drdx, &dx ); parser.setScriptBuilder( &tsb ); parser.parse(); if ( !parser.parse() || !vdx.commandFound() ) { vacation.active = false; vacation.valid = false; return vacation; } vacation.valid = true; vacation.active = vdx.active(); vacation.messageText = vdx.messageText().trimmed(); if (!vdx.subject().isEmpty()) { vacation.subject = vdx.subject().trimmed(); } 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()); } if (!vacation.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() ) { 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 composeOldScript( const QString & messageText, const QString &subject, int notificationInterval, const AddrSpecList & addrSpecs, bool sendForSpam, const QString & domain, const QDate & startDate, const QDate & endDate ) { 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 script; if ( startDate.isValid() && endDate.isValid() ) { script = QString::fromLatin1("require [\"vacation\", \"relational\", \"date\"];\n\n" ); } else { script = QString::fromLatin1("require \"vacation\";\n\n" ); } if ( !sendForSpam ) script += QString::fromLatin1( "if header :contains \"X-Spam-Flag\" \"YES\"" " { keep; stop; }\n" ); // FIXME? if ( !domain.isEmpty() ) // FIXME script += QString::fromLatin1( "if not address :domain :contains \"from\" \"%1\" { keep; stop; }\n" ).arg( domain ); if ( startDate.isValid() && endDate.isValid() ) { script += QString::fromLatin1( "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) ); } script += QLatin1String("vacation "); script += addressesArgument; if ( notificationInterval > 0 ) script += QString::fromLatin1(":days %1 ").arg( notificationInterval ); if (!subject.trimmed().isEmpty()) { script += QString::fromLatin1(":subject \"%1\" ").arg(stringReplace(subject).trimmed()); } script += QString::fromLatin1("text:\n"); script += dotstuff( messageText.isEmpty() ? KSieveUi::VacationUtils::defaultMessageText() : messageText ); script += QString::fromLatin1( "\n.\n;\n" ); return script; } QString KSieveUi::VacationUtils::composeScript(const Vacation &vacation) { QStringList condition; if (vacation.startDate.isValid()) { - condition.append(QString::fromLatin1("currentdate :value \"ge\" \"date\" \"%1\"") - .arg(vacation.startDate.toString(Qt::ISODate))); + if (vacation.startTime.isValid()) { + KDateTime start(vacation.startDate, vacation.startTime); + condition.append(QString::fromLatin1("currentdate :value \"ge\" \"iso8601\" \"%1\"") + .arg(start.toString(KDateTime::ISODate))); + } else { + condition.append(QString::fromLatin1("currentdate :value \"ge\" \"date\" \"%1\"") + .arg(vacation.startDate.toString(Qt::ISODate))); + } } if (vacation.endDate.isValid()) { - condition.append(QString::fromLatin1("currentdate :value \"le\" \"date\" \"%1\"") - .arg(vacation.endDate.toString(Qt::ISODate))); + if (vacation.endTime.isValid()) { + KDateTime end(vacation.endDate, vacation.endTime); + condition.append(QString::fromLatin1("currentdate :value \"le\" \"iso8601\" \"%1\"") + .arg(end.toString(KDateTime::ISODate))); + } else { + condition.append(QString::fromLatin1("currentdate :value \"le\" \"date\" \"%1\"") + .arg(vacation.endDate.toString(Qt::ISODate))); + } } if (!vacation.sendForSpam) { condition.append(QString::fromLatin1("not header :contains \"X-Spam-Flag\" \"YES\"")); } if (!vacation.excludeDomain.isEmpty()) { condition.append(QString::fromLatin1("address :domain :contains \"from\" \"%1\"").arg( vacation.excludeDomain )); } QString addressesArgument; QStringList aliases; if ( !vacation.aliases.empty() ) { addressesArgument += QLatin1String(":addresses [ "); QStringList sl; 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('\\'), QLatin1String("\\\\") ).replace( QLatin1Char('"'), QLatin1String("\\\"") ) + QLatin1Char('"') ); aliases.push_back( (*it).asString() ); } addressesArgument += sl.join( QLatin1String(", ") ) + QLatin1String(" ] "); } QString sVacation(QLatin1String("vacation ")); sVacation += addressesArgument; if ( vacation.notificationInterval > 0 ) sVacation += QString::fromLatin1(":days %1 ").arg(vacation.notificationInterval); if (!vacation.subject.trimmed().isEmpty()) { sVacation += QString::fromLatin1(":subject \"%1\" ").arg(stringReplace(vacation.subject).trimmed()); } sVacation += QString::fromLatin1("text:\n"); sVacation += dotstuff( vacation.messageText.isEmpty() ? VacationUtils::defaultMessageText() : vacation.messageText ); sVacation += QString::fromLatin1( "\n.\n;" ); QString script; if ( vacation.startDate.isValid() || vacation.endDate.isValid() ) { script = QString::fromLatin1("require [\"vacation\", \"relational\", \"date\"];\n\n" ); } else { script = QString::fromLatin1("require \"vacation\";\n\n" ); } if (condition.count() == 0) { if (vacation.active) { script += sVacation; } else { script += QString::fromLatin1("if false\n{\n\t"); script += sVacation; script += QLatin1String("\n}"); } } else { if (vacation.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 += sVacation; 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); 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")); } diff --git a/libksieve/ksieveui/vacation/vacationutils.h b/libksieve/ksieveui/vacation/vacationutils.h index d326989b8d..066bcc6358 100644 --- a/libksieve/ksieveui/vacation/vacationutils.h +++ b/libksieve/ksieveui/vacation/vacationutils.h @@ -1,63 +1,65 @@ /* Copyright (c) 2013, 2014 Montel Laurent 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 */ #ifndef VACATIONUTILS_H #define VACATIONUTILS_H #include #include #include #include namespace KSieveUi { namespace VacationUtils { QString defaultMessageText(); QString defaultSubject(); int defaultNotificationInterval(); KMime::Types::AddrSpecList defaultMailAliases(); bool defaultSendForSpam(); QString defaultDomainName(); QDate defaultStartDate(); QDate defaultEndDate(); struct Vacation { Vacation():valid(false), active(false), notificationInterval(1), sendForSpam(true) {} bool isValid() const {return valid;} bool valid; QString messageText; QString subject; bool active; int notificationInterval; KMime::Types::AddrSpecList aliases; bool sendForSpam; QString excludeDomain; QDate startDate; + QTime startTime; QDate endDate; + QTime endTime; }; QString composeScript(const Vacation &vacation); KSieveUi::VacationUtils::Vacation parseScript(const QString &script); QString mergeRequireLine(const QString &script1, const QString script2); QString updateVacationBlock(const QString &oldScript, const QString &newScript); } } #endif // VACATIONUTILS_H