File indexing completed on 2025-02-16 04:55:54

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "sieve-vacation.h"
0010 #include "vacationutils.h"
0011 
0012 #include "error.h"
0013 #include "parser.h"
0014 #include "scriptbuilder.h"
0015 
0016 #include "libksievecore_debug.h"
0017 #include <cassert>
0018 #include <climits>
0019 #include <map>
0020 #include <set>
0021 #include <vector>
0022 
0023 namespace KSieveExt
0024 {
0025 class MultiScriptBuilder : public KSieve::ScriptBuilder
0026 {
0027     std::vector<KSieve::ScriptBuilder *> mBuilders;
0028 
0029 public:
0030     MultiScriptBuilder()
0031         : KSieve::ScriptBuilder()
0032     {
0033     }
0034 
0035     MultiScriptBuilder(KSieve::ScriptBuilder *sb1)
0036         : KSieve::ScriptBuilder()
0037         , mBuilders(1)
0038     {
0039         mBuilders[0] = sb1;
0040         assert(sb1);
0041     }
0042 
0043     MultiScriptBuilder(KSieve::ScriptBuilder *sb1, KSieve::ScriptBuilder *sb2)
0044         : KSieve::ScriptBuilder()
0045         , mBuilders(2)
0046     {
0047         mBuilders[0] = sb1;
0048         mBuilders[1] = sb2;
0049         assert(sb1);
0050         assert(sb2);
0051     }
0052 
0053     MultiScriptBuilder(KSieve::ScriptBuilder *sb1, KSieve::ScriptBuilder *sb2, KSieve::ScriptBuilder *sb3)
0054         : KSieve::ScriptBuilder()
0055         , mBuilders(3)
0056     {
0057         mBuilders[0] = sb1;
0058         mBuilders[1] = sb2;
0059         mBuilders[2] = sb3;
0060         assert(sb1);
0061         assert(sb2);
0062         assert(sb3);
0063     }
0064 
0065     MultiScriptBuilder(KSieve::ScriptBuilder *sb1, KSieve::ScriptBuilder *sb2, KSieve::ScriptBuilder *sb3, KSieve::ScriptBuilder *sb4)
0066         : KSieve::ScriptBuilder()
0067         , mBuilders(4)
0068     {
0069         mBuilders[0] = sb1;
0070         mBuilders[1] = sb2;
0071         mBuilders[2] = sb3;
0072         mBuilders[3] = sb4;
0073         assert(sb1);
0074         assert(sb2);
0075         assert(sb3);
0076         assert(sb4);
0077     }
0078 
0079     ~MultiScriptBuilder() override = default;
0080 
0081 private:
0082 #ifdef FOREACH
0083 #undef FOREACH
0084 #endif
0085 #define FOREACH                                                                                                                                                \
0086     for (std::vector<KSieve::ScriptBuilder *>::const_iterator it = mBuilders.begin(), end = mBuilders.end(); it != end; ++it)                                  \
0087     (*it)->
0088     void commandStart(const QString &identifier, int lineNumber) override
0089     {
0090         FOREACH commandStart(identifier, lineNumber);
0091     }
0092 
0093     void commandEnd(int lineNumber) override
0094     {
0095         FOREACH commandEnd(lineNumber);
0096     }
0097 
0098     void testStart(const QString &identifier) override
0099     {
0100         FOREACH testStart(identifier);
0101     }
0102 
0103     void testEnd() override
0104     {
0105         FOREACH testEnd();
0106     }
0107 
0108     void testListStart() override
0109     {
0110         FOREACH testListStart();
0111     }
0112 
0113     void testListEnd() override
0114     {
0115         FOREACH testListEnd();
0116     }
0117 
0118     void blockStart(int lineNumber) override
0119     {
0120         FOREACH blockStart(lineNumber);
0121     }
0122 
0123     void blockEnd(int lineNumber) override
0124     {
0125         FOREACH blockEnd(lineNumber);
0126     }
0127 
0128     void hashComment(const QString &comment) override
0129     {
0130         FOREACH hashComment(comment);
0131     }
0132 
0133     void bracketComment(const QString &comment) override
0134     {
0135         FOREACH bracketComment(comment);
0136     }
0137 
0138     void lineFeed() override
0139     {
0140         FOREACH lineFeed();
0141     }
0142 
0143     void error(const KSieve::Error &e) override
0144     {
0145         FOREACH error(e);
0146     }
0147 
0148     void finished() override
0149     {
0150         FOREACH finished();
0151     }
0152 
0153     void taggedArgument(const QString &tag) override
0154     {
0155         FOREACH taggedArgument(tag);
0156     }
0157 
0158     void stringArgument(const QString &string, bool multiline, const QString &fixme) override
0159     {
0160         FOREACH stringArgument(string, multiline, fixme);
0161     }
0162 
0163     void numberArgument(unsigned long number, char quantifier) override
0164     {
0165         FOREACH numberArgument(number, quantifier);
0166     }
0167 
0168     void stringListArgumentStart() override
0169     {
0170         FOREACH stringListArgumentStart();
0171     }
0172 
0173     void stringListEntry(const QString &string, bool multiline, const QString &fixme) override
0174     {
0175         FOREACH stringListEntry(string, multiline, fixme);
0176     }
0177 
0178     void stringListArgumentEnd() override
0179     {
0180         FOREACH stringListArgumentEnd();
0181     }
0182 
0183 #undef FOREACH
0184 };
0185 }
0186 
0187 namespace KSieveCore
0188 {
0189 class GenericInformationExtractor : public KSieve::ScriptBuilder
0190 {
0191 public:
0192     enum BuilderMethod {
0193         Any,
0194         TaggedArgument,
0195         StringArgument,
0196         NumberArgument,
0197         CommandStart,
0198         CommandEnd,
0199         TestStart,
0200         TestEnd,
0201         TestListStart,
0202         TestListEnd,
0203         BlockStart,
0204         BlockEnd,
0205         StringListArgumentStart,
0206         StringListEntry,
0207         StringListArgumentEnd
0208     };
0209 
0210     struct StateNode {
0211         // expectation:
0212         int depth;
0213         BuilderMethod method;
0214         const char *string;
0215         // actions:
0216         int if_found;
0217         int if_not_found;
0218         const char *save_tag;
0219     };
0220 
0221     const std::vector<StateNode> mNodes;
0222     std::map<QString, QString> mResults;
0223     std::set<unsigned int> mRecursionGuard;
0224     unsigned int mState;
0225     int mNestingDepth;
0226 
0227     int mLineNumber;
0228 
0229 public:
0230     GenericInformationExtractor(const std::vector<StateNode> &nodes)
0231         : KSieve::ScriptBuilder()
0232         , mNodes(nodes)
0233         , mState(0)
0234         , mNestingDepth(0)
0235         , mLineNumber(0)
0236     {
0237     }
0238 
0239     const std::map<QString, QString> &results() const
0240     {
0241         return mResults;
0242     }
0243 
0244 private:
0245     void process(BuilderMethod method, const QString &string = QString())
0246     {
0247         doProcess(method, string);
0248         mRecursionGuard.clear();
0249     }
0250 
0251     void doProcess(BuilderMethod method, const QString &string)
0252     {
0253         mRecursionGuard.insert(mState);
0254         bool found = true;
0255         const StateNode &expected = mNodes[mState];
0256         if (expected.depth != -1 && mNestingDepth != expected.depth) {
0257             found = false;
0258         }
0259         if (expected.method != Any && method != expected.method) {
0260             found = false;
0261         }
0262         if (const char *str = expected.string) {
0263             if (string.toLower() != QString::fromUtf8(str).toLower()) {
0264                 found = false;
0265             }
0266         }
0267         qCDebug(LIBKSIEVECORE_LOG) << (found ? "found:" : "not found:") << mState << "->" << (found ? expected.if_found : expected.if_not_found);
0268         mState = found ? expected.if_found : expected.if_not_found;
0269         assert(mState < mNodes.size());
0270         if (found) {
0271             if (const char *save_tag = expected.save_tag) {
0272                 mResults[QString::fromLatin1(save_tag)] = string;
0273             }
0274         }
0275         if (!found && !mRecursionGuard.count(mState)) {
0276             doProcess(method, string);
0277         }
0278     }
0279 
0280     void commandStart(const QString &identifier, int lineNumber) override
0281     {
0282         Q_UNUSED(lineNumber)
0283         qCDebug(LIBKSIEVECORE_LOG);
0284         process(CommandStart, identifier);
0285     }
0286 
0287     void commandEnd(int lineNumber) override
0288     {
0289         Q_UNUSED(lineNumber)
0290         qCDebug(LIBKSIEVECORE_LOG);
0291         process(CommandEnd);
0292     }
0293 
0294     void testStart(const QString &identifier) override
0295     {
0296         qCDebug(LIBKSIEVECORE_LOG);
0297         process(TestStart, identifier);
0298     }
0299 
0300     void testEnd() override
0301     {
0302         qCDebug(LIBKSIEVECORE_LOG);
0303         process(TestEnd);
0304     }
0305 
0306     void testListStart() override
0307     {
0308         qCDebug(LIBKSIEVECORE_LOG);
0309         process(TestListStart);
0310     }
0311 
0312     void testListEnd() override
0313     {
0314         qCDebug(LIBKSIEVECORE_LOG);
0315         process(TestListEnd);
0316     }
0317 
0318     void blockStart(int lineNumber) override
0319     {
0320         Q_UNUSED(lineNumber)
0321         qCDebug(LIBKSIEVECORE_LOG);
0322         process(BlockStart);
0323         ++mNestingDepth;
0324     }
0325 
0326     void blockEnd(int lineNumber) override
0327     {
0328         Q_UNUSED(lineNumber)
0329         qCDebug(LIBKSIEVECORE_LOG);
0330         --mNestingDepth;
0331         process(BlockEnd);
0332     }
0333 
0334     void hashComment(const QString &) override
0335     {
0336         qCDebug(LIBKSIEVECORE_LOG);
0337     }
0338 
0339     void bracketComment(const QString &) override
0340     {
0341         qCDebug(LIBKSIEVECORE_LOG);
0342     }
0343 
0344     void lineFeed() override
0345     {
0346         qCDebug(LIBKSIEVECORE_LOG);
0347     }
0348 
0349     void error(const KSieve::Error &) override
0350     {
0351         qCDebug(LIBKSIEVECORE_LOG);
0352         mState = 0;
0353     }
0354 
0355     void finished() override
0356     {
0357         qCDebug(LIBKSIEVECORE_LOG);
0358     }
0359 
0360     void taggedArgument(const QString &tag) override
0361     {
0362         qCDebug(LIBKSIEVECORE_LOG);
0363         process(TaggedArgument, tag);
0364     }
0365 
0366     void stringArgument(const QString &string, bool, const QString &) override
0367     {
0368         qCDebug(LIBKSIEVECORE_LOG);
0369         process(StringArgument, string);
0370     }
0371 
0372     void numberArgument(unsigned long number, char) override
0373     {
0374         qCDebug(LIBKSIEVECORE_LOG);
0375         process(NumberArgument, QString::number(number));
0376     }
0377 
0378     void stringListArgumentStart() override
0379     {
0380         qCDebug(LIBKSIEVECORE_LOG);
0381         process(StringListArgumentStart);
0382     }
0383 
0384     void stringListEntry(const QString &string, bool, const QString &) override
0385     {
0386         qCDebug(LIBKSIEVECORE_LOG);
0387         process(StringListEntry, string);
0388     }
0389 
0390     void stringListArgumentEnd() override
0391     {
0392         qCDebug(LIBKSIEVECORE_LOG);
0393         process(StringListArgumentEnd);
0394     }
0395 };
0396 
0397 using GIE = GenericInformationExtractor;
0398 static const GenericInformationExtractor::StateNode spamNodes[] = {
0399     {0, GIE::CommandStart, "if", 1, 0, nullptr}, // 0
0400     {0, GIE::TestStart, "allof", 2, 3, nullptr}, // 1
0401     {0, GIE::TestListStart, nullptr, 3, 0, nullptr}, // 2
0402     {0, GIE::TestStart, "not", 4, 3, nullptr}, // 3
0403     {0, GIE::TestStart, "header", 5, 3, nullptr}, // 4
0404     {0, GIE::TaggedArgument, "contains", 6, 0, nullptr}, // 5
0405 
0406     // accept both string and string-list:
0407     {0, GIE::StringArgument, "x-spam-flag", 12, 7, "x-spam-flag"}, // 6
0408     {0, GIE::StringListArgumentStart, nullptr, 8, 0, nullptr}, // 7
0409     {0, GIE::StringListEntry, "x-spam-flag", 9, 10, "x-spam-flag"}, // 8
0410     {0, GIE::StringListEntry, nullptr, 9, 11, nullptr}, // 9
0411     {0, GIE::StringListArgumentEnd, nullptr, 0, 8, nullptr}, // 10
0412     {0, GIE::StringListArgumentEnd, nullptr, 12, 0, nullptr}, // 11
0413 
0414     // accept both string and string-list:
0415     {0, GIE::StringArgument, "yes", 18, 13, "spam-flag-yes"}, // 12
0416     {0, GIE::StringListArgumentStart, nullptr, 14, 0, nullptr}, // 13
0417     {0, GIE::StringListEntry, "yes", 15, 16, "spam-flag-yes"}, // 14
0418     {0, GIE::StringListEntry, nullptr, 15, 17, nullptr}, // 15
0419     {0, GIE::StringListArgumentEnd, nullptr, 0, 14, nullptr}, // 16
0420     {0, GIE::StringListArgumentEnd, nullptr, 18, 0, nullptr}, // 17
0421 
0422     {0, GIE::TestEnd, nullptr, 21, 20, nullptr}, // 18
0423     {0, GIE::Any, nullptr, 21, 0, nullptr}, // 19
0424     {0, GIE::TestListEnd, nullptr, 21, 19, nullptr}, // 20
0425 
0426     // block of command, find "stop", take nested if's into account:
0427     {0, GIE::BlockStart, nullptr, 22, 18, nullptr}, // 21
0428     {1, GIE::CommandStart, "vacation", 24, 22, "vacation"}, // 22
0429     {1, GIE::Any, nullptr, 24, 0, nullptr}, // 23
0430     {0, GIE::BlockEnd, nullptr, 25, 23, nullptr}, // 24
0431 
0432     {-1, GIE::Any, nullptr, 25, 25, nullptr}, // 25 end state
0433 };
0434 static const unsigned int numSpamNodes = sizeof spamNodes / sizeof *spamNodes;
0435 
0436 class SpamDataExtractor : public GenericInformationExtractor
0437 {
0438 public:
0439     SpamDataExtractor()
0440         : GenericInformationExtractor(std::vector<StateNode>(spamNodes, spamNodes + numSpamNodes))
0441     {
0442     }
0443 
0444     bool found() const
0445     {
0446         return mResults.count(QStringLiteral("x-spam-flag")) && mResults.count(QStringLiteral("spam-flag-yes")) && mResults.count(QStringLiteral("vacation"));
0447     }
0448 };
0449 
0450 // to understand this table, study the output of
0451 // libksieve/tests/parsertest
0452 //   'if not address :domain :contains ["from"] ["mydomain.org"] { keep; stop; }'
0453 static const GenericInformationExtractor::StateNode domainNodes[] = {
0454     {0, GIE::CommandStart, "if", 1, 0, nullptr}, // 0
0455     {0, GIE::TestStart, "allof", 2, 3, nullptr}, // 1
0456     {0, GIE::TestListStart, nullptr, 3, 0, nullptr}, // 2
0457     {0, GIE::TestStart, "address", 4, 3, nullptr}, // 3
0458 
0459     // :domain and :contains in arbitrary order:
0460     {0, GIE::TaggedArgument, "domain", 5, 6, nullptr}, // 4
0461     {0, GIE::TaggedArgument, "contains", 8, 0, nullptr}, // 5
0462     {0, GIE::TaggedArgument, "contains", 7, 0, nullptr}, // 6
0463     {0, GIE::TaggedArgument, "domain", 8, 0, nullptr}, // 7
0464 
0465     // accept both string and string-list:
0466     {0, GIE::StringArgument, "from", 14, 9, "from"}, // 8
0467     {0, GIE::StringListArgumentStart, nullptr, 10, 0, nullptr}, // 9
0468     {0, GIE::StringListEntry, "from", 11, 12, "from"}, // 10
0469     {0, GIE::StringListEntry, nullptr, 11, 13, nullptr}, // 11
0470     {0, GIE::StringListArgumentEnd, nullptr, 0, 10, nullptr}, // 12
0471     {0, GIE::StringListArgumentEnd, nullptr, 14, 0, nullptr}, // 13
0472 
0473     // string: save, string-list: save last
0474     {0, GIE::StringArgument, nullptr, 18, 15, "domainName"}, // 14
0475     {0, GIE::StringListArgumentStart, nullptr, 16, 0, nullptr}, // 15
0476     {0, GIE::StringListEntry, nullptr, 16, 17, "domainName"}, // 16
0477     {0, GIE::StringListArgumentEnd, nullptr, 18, 0, nullptr}, // 17
0478 
0479     {0, GIE::TestEnd, nullptr, 18, 20, nullptr}, // 18
0480     {0, GIE::Any, nullptr, 18, 0, nullptr}, // 19
0481 
0482     // block of commands, find "stop", take nested if's into account:
0483     {0, GIE::BlockStart, nullptr, 21, 19, nullptr}, // 20
0484     {1, GIE::CommandStart, "vacation", 23, 21, "vacation"}, // 21
0485     {1, GIE::Any, nullptr, 23, 0, nullptr}, // 22
0486     {0, GIE::BlockEnd, nullptr, 24, 22, nullptr}, // 23
0487 
0488     {-1, GIE::Any, nullptr, 24, 24, nullptr} // 24 end state
0489 };
0490 static const unsigned int numDomainNodes = sizeof domainNodes / sizeof *domainNodes;
0491 
0492 class DomainRestrictionDataExtractor : public GenericInformationExtractor
0493 {
0494 public:
0495     DomainRestrictionDataExtractor()
0496         : GenericInformationExtractor(std::vector<StateNode>(domainNodes, domainNodes + numDomainNodes))
0497     {
0498     }
0499 
0500     QString domainName() /*not const, since map::op[] isn't const*/
0501     {
0502         return mResults.count(QStringLiteral("vacation")) && mResults.count(QStringLiteral("from")) ? mResults[QStringLiteral("domainName")] : QString();
0503     }
0504 };
0505 
0506 // if not allof (currentdate :value "ge" date "YYYY-MM-DD",
0507 //               currentfate :value "le" date "YYYY-MM-DD) { keep; stop; }
0508 static const GenericInformationExtractor::StateNode datesNodes[] = {
0509     {0, GIE::CommandStart, "if", 1, 0, nullptr}, // 0
0510     {0, GIE::TestStart, "allof", 2, 0, nullptr}, // 1
0511 
0512     // handle startDate and endDate in arbitrary order
0513     {0, GIE::TestListStart, nullptr, 3, 0, nullptr}, // 2
0514     {0, GIE::TestStart, "currentdate", 4, 3, nullptr}, // 3
0515     {0, GIE::TaggedArgument, "value", 5, 4, nullptr}, // 4
0516     {0, GIE::StringArgument, "ge", 6, 10, nullptr}, // 5
0517     {0, GIE::StringArgument, "date", 7, 8, nullptr}, // 6
0518     {0, GIE::StringArgument, nullptr, 15, 0, "startDate"}, // 7
0519     {0, GIE::StringArgument, "iso8601", 9, 0, nullptr}, // 8
0520     {0, GIE::StringArgument, nullptr, 15, 0, "startDateTime"}, // 9
0521     {0, GIE::StringArgument, "le", 11, 0, nullptr}, // 10
0522     {0, GIE::StringArgument, "date", 12, 13, nullptr}, // 11
0523     {0, GIE::StringArgument, nullptr, 15, 0, "endDate"}, // 12
0524     {0, GIE::StringArgument, "iso8601", 14, 0, nullptr}, // 13
0525     {0, GIE::StringArgument, nullptr, 15, 0, "endDateTime"}, // 14
0526     {0, GIE::TestEnd, nullptr, 16, 0, nullptr}, // 15
0527 
0528     {0, GIE::TestStart, "currentdate", 17, 16, nullptr}, // 16
0529     {0, GIE::TaggedArgument, "value", 18, 17, nullptr}, // 17
0530     {0, GIE::StringArgument, "le", 19, 23, nullptr}, // 18
0531     {0, GIE::StringArgument, "date", 20, 21, nullptr}, // 19
0532     {0, GIE::StringArgument, nullptr, 28, 0, "endDate"}, // 20
0533     {0, GIE::StringArgument, "iso8601", 22, 0, nullptr}, // 21
0534     {0, GIE::StringArgument, nullptr, 28, 0, "endDateTime"}, // 22
0535     {0, GIE::StringArgument, "ge", 24, 0, nullptr}, // 23
0536     {0, GIE::StringArgument, "date", 25, 26, nullptr}, // 24
0537     {0, GIE::StringArgument, nullptr, 28, 0, "startDate"}, // 25
0538     {0, GIE::StringArgument, "iso8601", 27, 0, nullptr}, // 26
0539     {0, GIE::StringArgument, nullptr, 28, 0, "startDateTime"}, // 27
0540     {0, GIE::TestEnd, nullptr, 32, 0, nullptr}, // 28
0541     {0, GIE::TestStart, nullptr, 31, 30, nullptr}, // 29
0542     {-1, GIE::Any, nullptr, 32, 0, nullptr}, // 30
0543     {0, GIE::TestEnd, nullptr, 32, 30, nullptr}, // 31
0544     {0, GIE::TestListEnd, nullptr, 33, 29, nullptr}, // 32
0545 
0546     {0, GIE::TestEnd, nullptr, 34, 0, nullptr}, // 33
0547 
0548     // block of commands, find "stop", take nested if's into account:
0549     {0, GIE::BlockStart, nullptr, 36, 33, nullptr}, // 34
0550     {-1, GIE::Any, nullptr, 36, 0, nullptr}, // 35
0551     {1, GIE::CommandStart, "vacation", 38, 35, "vacation"}, // 36
0552     {-1, GIE::Any, nullptr, 38, 0, nullptr}, // 37
0553     {0, GIE::BlockEnd, nullptr, 39, 37, nullptr}, // 38
0554 
0555     {-1, GIE::Any, nullptr, 39, 39, nullptr} // 39 end state
0556 };
0557 
0558 static const unsigned int numDatesNodes = sizeof datesNodes / sizeof *datesNodes;
0559 
0560 class DateExtractor : public GenericInformationExtractor
0561 {
0562 public:
0563     DateExtractor()
0564         : GenericInformationExtractor(std::vector<StateNode>(datesNodes, datesNodes + numDatesNodes))
0565     {
0566     }
0567 
0568     QDate endDate() const
0569     {
0570         if (results().count(QStringLiteral("endDateTime")) == 1) {
0571             return datetime(QStringLiteral("endDateTime")).date();
0572         } else {
0573             return date(QStringLiteral("endDate"));
0574         }
0575     }
0576 
0577     QDate startDate() const
0578     {
0579         if (results().count(QStringLiteral("startDateTime")) == 1) {
0580             return datetime(QStringLiteral("startDateTime")).date();
0581         } else {
0582             return date(QStringLiteral("startDate"));
0583         }
0584     }
0585 
0586     QTime endTime() const
0587     {
0588         return datetime(QStringLiteral("endDateTime")).time();
0589     }
0590 
0591     QTime startTime() const
0592     {
0593         return datetime(QStringLiteral("startDateTime")).time();
0594     }
0595 
0596 private:
0597     QDate date(const QString &name) const
0598     {
0599         if (results().count(name) == 0) {
0600             return {};
0601         } else {
0602             return QDate::fromString(results().at(name), Qt::ISODate);
0603         }
0604     }
0605 
0606     QDateTime datetime(const QString &name) const
0607     {
0608         if (results().count(name) == 0) {
0609             return {};
0610         } else {
0611             return QDateTime::fromString(results().at(name), Qt::ISODate);
0612         }
0613     }
0614 };
0615 
0616 class VacationDataExtractor : public KSieve::ScriptBuilder
0617 {
0618     enum Context {
0619         None = 0,
0620         // command itself:
0621         VacationCommand,
0622         // tagged args:
0623         Days,
0624         Addresses,
0625         Subject,
0626         VacationEnd,
0627         IfBlock,
0628         RedirectCommand
0629     };
0630 
0631 public:
0632     VacationDataExtractor();
0633     ~VacationDataExtractor() override;
0634 
0635     bool commandFound() const
0636     {
0637         return mContext == VacationEnd;
0638     }
0639 
0640     bool active() const
0641     {
0642         return mActive;
0643     }
0644 
0645     int notificationInterval() const
0646     {
0647         return mNotificationInterval;
0648     }
0649 
0650     const QString &messageText() const
0651     {
0652         return mMessageText;
0653     }
0654 
0655     const QStringList &aliases() const
0656     {
0657         return mAliases;
0658     }
0659 
0660     const QString &ifComment() const
0661     {
0662         return mIfComment;
0663     }
0664 
0665     VacationUtils::MailAction mailAction() const
0666     {
0667         return mMailAction;
0668     }
0669 
0670     const QString &mailActionRecipient() const
0671     {
0672         return mMailActionRecipient;
0673     }
0674 
0675     const QString &subject() const
0676     {
0677         return mSubject;
0678     }
0679 
0680     int lineStart() const
0681     {
0682         return mLineStart;
0683     }
0684 
0685     int lineEnd() const
0686     {
0687         return mLineEnd;
0688     }
0689 
0690 private:
0691     void commandStart(const QString &identifier, int lineNumber) override;
0692 
0693     void commandEnd(int lineNumber) override;
0694 
0695     void testStart(const QString &) override;
0696     void testEnd() override
0697     {
0698     }
0699 
0700     void testListStart() override
0701     {
0702     }
0703 
0704     void testListEnd() override
0705     {
0706     }
0707 
0708     void blockStart(int lineNumber) override;
0709     void blockEnd(int lineNumber) override;
0710     void hashComment(const QString &) override;
0711     void bracketComment(const QString &) override
0712     {
0713     }
0714 
0715     void lineFeed() override
0716     {
0717     }
0718 
0719     void error(const KSieve::Error &e) override;
0720     void finished() override;
0721 
0722     void taggedArgument(const QString &tag) override;
0723 
0724     void stringArgument(const QString &string, bool, const QString &) override;
0725 
0726     void numberArgument(unsigned long number, char) override;
0727 
0728     void stringListArgumentStart() override;
0729     void stringListEntry(const QString &string, bool, const QString &) override;
0730     void stringListArgumentEnd() override;
0731 
0732 private:
0733     Context mContext = None;
0734     int mNotificationInterval = 0;
0735     QString mMessageText;
0736     QString mSubject;
0737     QStringList mAliases;
0738     bool mActive = true;
0739     bool mInIfBlock = false;
0740     bool mFoundInBlock = false;
0741     int mBlockLevel = 0;
0742     QString mIfComment;
0743     int mLineStart = 0;
0744     int mLineEnd = 0;
0745 
0746     VacationUtils::MailAction mMailAction = VacationUtils::Keep;
0747     Context mMailActionContext = None;
0748     QString mMailActionRecipient;
0749 
0750     void reset();
0751 };
0752 
0753 class RequireExtractor : public KSieve::ScriptBuilder
0754 {
0755     enum Context {
0756         None = 0,
0757         // command itself:
0758         RequireCommand,
0759         EndState
0760     };
0761 
0762 public:
0763     RequireExtractor();
0764     ~RequireExtractor() override;
0765 
0766     bool commandFound() const
0767     {
0768         return mContext == EndState;
0769     }
0770 
0771     const QStringList &requirements() const
0772     {
0773         return mRequirements;
0774     }
0775 
0776     int lineStart() const
0777     {
0778         return mLineStart;
0779     }
0780 
0781     int lineEnd() const
0782     {
0783         return mLineEnd;
0784     }
0785 
0786 private:
0787     void commandStart(const QString &identifier, int lineNumber) override;
0788 
0789     void commandEnd(int lineNumber) override;
0790 
0791     void testStart(const QString &) override
0792     {
0793     }
0794 
0795     void testEnd() override
0796     {
0797     }
0798 
0799     void testListStart() override
0800     {
0801     }
0802 
0803     void testListEnd() override
0804     {
0805     }
0806 
0807     void blockStart(int lineNumber) override
0808     {
0809         Q_UNUSED(lineNumber)
0810     }
0811 
0812     void blockEnd(int lineNumber) override
0813     {
0814         Q_UNUSED(lineNumber)
0815     }
0816 
0817     void hashComment(const QString &) override
0818     {
0819     }
0820 
0821     void bracketComment(const QString &) override
0822     {
0823     }
0824 
0825     void lineFeed() override
0826     {
0827     }
0828 
0829     void error(const KSieve::Error &e) override;
0830     void finished() override;
0831 
0832     void taggedArgument(const QString &tag) override
0833     {
0834         Q_UNUSED(tag)
0835     }
0836 
0837     void numberArgument(unsigned long number, char) override
0838     {
0839         Q_UNUSED(number)
0840     }
0841 
0842     void stringArgument(const QString &string, bool, const QString &) override;
0843 
0844     void stringListArgumentStart() override
0845     {
0846     }
0847 
0848     void stringListEntry(const QString &string, bool, const QString &) override;
0849     void stringListArgumentEnd() override
0850     {
0851     }
0852 
0853 private:
0854     Context mContext;
0855     QStringList mRequirements;
0856     int mLineStart;
0857     int mLineEnd;
0858 };
0859 }