diff --git a/dev/Sieve/Commands.js b/dev/Sieve/Commands.js new file mode 100644 index 000000000..45c2199c2 --- /dev/null +++ b/dev/Sieve/Commands.js @@ -0,0 +1,181 @@ + +import { capa } from 'Sieve/Utils'; + +import { + ActionCommand, + ControlCommand, + TestCommand +} from 'Sieve/Grammar'; + +import { + DiscardCommand, + FileIntoCommand, + KeepCommand, + RedirectCommand +} from 'Sieve/Commands/Actions'; + +import { + ConditionalCommand, + ElsIfCommand, + ElseCommand, + IfCommand, + RequireCommand, + StopCommand +} from 'Sieve/Commands/Controls'; + +import { + AddressTest, + AllOfTest, + AnyOfTest, + EnvelopeTest, + ExistsTest, + FalseTest, + HeaderTest, + NotTest, + SizeTest, + TrueTest +} from 'Sieve/Commands/Tests'; + +import { BodyTest } from 'Sieve/Extensions/rfc5173'; +import { EnvironmentTest } from 'Sieve/Extensions/rfc5183'; +import { SetCommand, StringTest } from 'Sieve/Extensions/rfc5229'; +import { VacationCommand } from 'Sieve/Extensions/rfc5230'; +import { SetFlagCommand, AddFlagCommand, RemoveFlagCommand, HasFlagTest } from 'Sieve/Extensions/rfc5232'; +import { SpamTestTest, VirusTestTest } from 'Sieve/Extensions/rfc5235'; +import { DateTest, CurrentDateTest } from 'Sieve/Extensions/rfc5260'; +import { AddHeaderCommand, DeleteHeaderCommand } from 'Sieve/Extensions/rfc5293'; +import { ErejectCommand, RejectCommand } from 'Sieve/Extensions/rfc5429'; +import { NotifyCommand, ValidNotifyMethodTest, NotifyMethodCapabilityTest } from 'Sieve/Extensions/rfc5435'; +import { IHaveTest, ErrorCommand } from 'Sieve/Extensions/rfc5463'; +import { MailboxExistsTest, MetadataTest, MetadataExistsTest } from 'Sieve/Extensions/rfc5490'; +import { ForEveryPartCommand, BreakCommand, ReplaceCommand, EncloseCommand, ExtractTextCommand } from 'Sieve/Extensions/rfc5703'; +import { IncludeCommand, ReturnCommand, GlobalCommand } from 'Sieve/Extensions/rfc6609'; + +export const + getIdentifier = (cmd, type) => { + const obj = new cmd, requires = obj.require; + return ( + (!type || obj instanceof type) + && (!requires || (Array.isArray(requires) ? requires : [requires]).every(string => capa.includes(string))) + ) + ? obj.identifier + : null; + }, + + AllCommands = [ + // Control commands + IfCommand, + ElsIfCommand, + ElseCommand, + ConditionalCommand, + RequireCommand, + StopCommand, + // Action commands + DiscardCommand, + FileIntoCommand, + KeepCommand, + RedirectCommand, + // Test commands + AddressTest, + AllOfTest, + AnyOfTest, + EnvelopeTest, + ExistsTest, + FalseTest, + HeaderTest, + NotTest, + SizeTest, + TrueTest, + // rfc5173 + BodyTest, + // rfc5183 + EnvironmentTest, + // rfc5229 + SetCommand, + StringTest, + // rfc5230 + VacationCommand, + // rfc5232 + SetFlagCommand, + AddFlagCommand, + RemoveFlagCommand, + HasFlagTest, + // rfc5235 + SpamTestTest, + VirusTestTest, + // rfc5260 + DateTest, + CurrentDateTest, + // rfc5293 + AddHeaderCommand, + DeleteHeaderCommand, + // rfc5429 + ErejectCommand, + RejectCommand, + // rfc5435 + NotifyCommand, + ValidNotifyMethodTest, + NotifyMethodCapabilityTest, + // rfc5463 + IHaveTest, + ErrorCommand, + // rfc5490 + MailboxExistsTest, + MetadataTest, + MetadataExistsTest, + // rfc5703 + ForEveryPartCommand, + BreakCommand, + ReplaceCommand, + EncloseCommand, + ExtractTextCommand, + // rfc6609 + IncludeCommand, + ReturnCommand, + GlobalCommand + ], + + availableCommands = () => { + let commands = {}, id; + AllCommands.forEach(cmd => { + id = getIdentifier(cmd); + if (id) { + commands[id] = cmd; + } + }); + return commands; + }, + + availableActions = () => { + let actions = {}, id; + AllCommands.forEach(cmd => { + id = getIdentifier(cmd, ActionCommand); + if (id) { + actions[id] = cmd; + } + }); + return actions; + }, + + availableControls = () => { + let controls = {}, id; + AllCommands.forEach(cmd => { + id = getIdentifier(cmd, ControlCommand); + if (id) { + controls[id] = cmd; + } + }); + return controls; + }, + + availableTests = () => { + let tests = {}, id; + AllCommands.forEach(cmd => { + id = getIdentifier(cmd, TestCommand); + if (id) { + tests[id] = cmd; + } + }); + return tests; + }; + diff --git a/dev/Sieve/Commands/Controls.js b/dev/Sieve/Commands/Controls.js index 167f22bad..bb2a17bc6 100644 --- a/dev/Sieve/Commands/Controls.js +++ b/dev/Sieve/Commands/Controls.js @@ -4,7 +4,7 @@ */ import { - GrammarCommand, + ControlCommand, GrammarStringList, GrammarQuotedString } from 'Sieve/Grammar'; @@ -16,7 +16,7 @@ import { * elsif * else */ -export class ConditionalCommand extends GrammarCommand +export class ConditionalCommand extends ControlCommand { constructor() { @@ -61,7 +61,7 @@ export class ElseCommand extends ConditionalCommand /** * https://tools.ietf.org/html/rfc5228#section-3.2 */ -export class RequireCommand extends GrammarCommand +export class RequireCommand extends ControlCommand { constructor() { @@ -87,6 +87,6 @@ export class RequireCommand extends GrammarCommand /** * https://tools.ietf.org/html/rfc5228#section-3.3 */ -export class StopCommand extends GrammarCommand +export class StopCommand extends ControlCommand { } diff --git a/dev/Sieve/Extensions/rfc5229.js b/dev/Sieve/Extensions/rfc5229.js index c979b057e..bb23ab983 100644 --- a/dev/Sieve/Extensions/rfc5229.js +++ b/dev/Sieve/Extensions/rfc5229.js @@ -3,13 +3,13 @@ */ import { - GrammarCommand, + ActionCommand, GrammarQuotedString, GrammarStringList, TestCommand } from 'Sieve/Grammar'; -export class SetCommand extends GrammarCommand +export class SetCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5230.js b/dev/Sieve/Extensions/rfc5230.js index a02670453..8b0b112eb 100644 --- a/dev/Sieve/Extensions/rfc5230.js +++ b/dev/Sieve/Extensions/rfc5230.js @@ -6,13 +6,13 @@ import { capa } from 'Sieve/Utils'; import { - GrammarCommand, + ActionCommand, GrammarNumber, GrammarQuotedString, GrammarStringList } from 'Sieve/Grammar'; -export class VacationCommand extends GrammarCommand +export class VacationCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5232.js b/dev/Sieve/Extensions/rfc5232.js index 5dcbe05ec..0206dba06 100644 --- a/dev/Sieve/Extensions/rfc5232.js +++ b/dev/Sieve/Extensions/rfc5232.js @@ -3,14 +3,14 @@ */ import { - GrammarCommand, + ActionCommand, GrammarQuotedString, GrammarString, GrammarStringList, TestCommand } from 'Sieve/Grammar'; -class FlagCommand extends GrammarCommand +class FlagCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5293.js b/dev/Sieve/Extensions/rfc5293.js index 36411fb2d..25634faf4 100644 --- a/dev/Sieve/Extensions/rfc5293.js +++ b/dev/Sieve/Extensions/rfc5293.js @@ -3,14 +3,14 @@ */ import { - GrammarCommand, + ActionCommand, GrammarNumber, GrammarQuotedString, GrammarString, GrammarStringList } from 'Sieve/Grammar'; -export class AddHeaderCommand extends GrammarCommand +export class AddHeaderCommand extends ActionCommand { constructor() { @@ -38,7 +38,7 @@ export class AddHeaderCommand extends GrammarCommand } } -export class DeleteHeaderCommand extends GrammarCommand +export class DeleteHeaderCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5429.js b/dev/Sieve/Extensions/rfc5429.js index b4bca755a..d422f2eb8 100644 --- a/dev/Sieve/Extensions/rfc5429.js +++ b/dev/Sieve/Extensions/rfc5429.js @@ -3,7 +3,7 @@ */ import { - GrammarCommand, + ActionCommand, GrammarQuotedString, GrammarString } from 'Sieve/Grammar'; @@ -11,7 +11,7 @@ import { /** * https://tools.ietf.org/html/rfc5429#section-2.1 */ -export class ErejectCommand extends GrammarCommand +export class ErejectCommand extends ActionCommand { constructor() { @@ -47,7 +47,7 @@ export class ErejectCommand extends GrammarCommand /** * https://tools.ietf.org/html/rfc5429#section-2.2 */ -export class RejectCommand extends GrammarCommand +export class RejectCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5435.js b/dev/Sieve/Extensions/rfc5435.js index 9c1f0715d..4adcdb72a 100644 --- a/dev/Sieve/Extensions/rfc5435.js +++ b/dev/Sieve/Extensions/rfc5435.js @@ -3,7 +3,7 @@ */ import { - GrammarCommand, + ActionCommand, GrammarNumber, GrammarQuotedString, GrammarStringList, @@ -13,7 +13,7 @@ import { /** * https://datatracker.ietf.org/doc/html/rfc5435#section-3 */ -export class NotifyCommand extends GrammarCommand +export class NotifyCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5463.js b/dev/Sieve/Extensions/rfc5463.js index 8a49232ea..68166f275 100644 --- a/dev/Sieve/Extensions/rfc5463.js +++ b/dev/Sieve/Extensions/rfc5463.js @@ -3,7 +3,7 @@ */ import { - GrammarCommand, + ControlCommand, TestCommand, GrammarQuotedString, GrammarStringList @@ -36,7 +36,7 @@ export class IHaveTest extends TestCommand /** * https://datatracker.ietf.org/doc/html/rfc5463#section-5 */ -export class ErrorCommand extends GrammarCommand +export class ErrorCommand extends ControlCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc5703.js b/dev/Sieve/Extensions/rfc5703.js index 096fd15e8..202d3e902 100644 --- a/dev/Sieve/Extensions/rfc5703.js +++ b/dev/Sieve/Extensions/rfc5703.js @@ -3,7 +3,8 @@ */ import { - GrammarCommand, + ActionCommand, + ControlCommand, GrammarNumber, GrammarQuotedString, GrammarString, @@ -13,7 +14,7 @@ import { /** * https://datatracker.ietf.org/doc/html/rfc5703#section-3 */ -export class ForEveryPartCommand extends GrammarCommand +export class ForEveryPartCommand extends ControlCommand { constructor() { @@ -57,7 +58,7 @@ export class BreakCommand extends ForEveryPartCommand /** * https://datatracker.ietf.org/doc/html/rfc5703#section-5 */ -export class ReplaceCommand extends GrammarCommand +export class ReplaceCommand extends ActionCommand { constructor() { @@ -103,7 +104,7 @@ export class ReplaceCommand extends GrammarCommand /** * https://datatracker.ietf.org/doc/html/rfc5703#section-6 */ -export class EncloseCommand extends GrammarCommand +export class EncloseCommand extends ActionCommand { constructor() { @@ -140,7 +141,7 @@ export class EncloseCommand extends GrammarCommand /** * https://datatracker.ietf.org/doc/html/rfc5703#section-7 */ -export class ExtractTextCommand extends GrammarCommand +export class ExtractTextCommand extends ActionCommand { constructor() { diff --git a/dev/Sieve/Extensions/rfc6609.js b/dev/Sieve/Extensions/rfc6609.js index 35c8c6fc6..1f96ada30 100644 --- a/dev/Sieve/Extensions/rfc6609.js +++ b/dev/Sieve/Extensions/rfc6609.js @@ -3,11 +3,12 @@ */ import { - GrammarCommand, - GrammarQuotedString + ControlCommand, + GrammarQuotedString, + GrammarStringList } from 'Sieve/Grammar'; -export class IncludeCommand extends GrammarCommand +export class IncludeCommand extends ControlCommand { constructor() { @@ -22,7 +23,7 @@ export class IncludeCommand extends GrammarCommand toString() { - return this.identifier + return 'include' + (this.global ? ' :global' : '') + (this.once ? ' :once' : '') + (this.optional ? ' :optional' : '') @@ -41,7 +42,28 @@ export class IncludeCommand extends GrammarCommand } } -export class ReturnCommand extends GrammarCommand +export class ReturnCommand extends ControlCommand { get require() { return 'include'; } } + +export class GlobalCommand extends ControlCommand +{ + constructor() + { + super(); + this.value = new GrammarStringList; + } + + get require() { return ['include', 'variables']; } + + toString() + { + return 'global ' + this.value + ';'; + } + + pushArguments(args) + { + this.value = args.pop(); + } +} diff --git a/dev/Sieve/Parser.js b/dev/Sieve/Parser.js index 65e163ae7..a5ae649b5 100644 --- a/dev/Sieve/Parser.js +++ b/dev/Sieve/Parser.js @@ -2,7 +2,7 @@ * https://tools.ietf.org/html/rfc5228#section-8 */ -import { capa, getMatchTypes } from 'Sieve/Utils'; +import { getMatchTypes } from 'Sieve/Utils'; import { BRACKET_COMMENT, @@ -27,123 +27,11 @@ import { GrammarTestList } from 'Sieve/Grammar'; -import { - DiscardCommand, - FileIntoCommand, - KeepCommand, - RedirectCommand -} from 'Sieve/Commands/Actions'; - -import { - ConditionalCommand, - ElsIfCommand, - ElseCommand, - IfCommand, - RequireCommand, - StopCommand -} from 'Sieve/Commands/Controls'; - -import { - AddressTest, - AllOfTest, - AnyOfTest, - EnvelopeTest, - ExistsTest, - FalseTest, - HeaderTest, - NotTest, - SizeTest, - TrueTest -} from 'Sieve/Commands/Tests'; - -import { BodyTest } from 'Sieve/Extensions/rfc5173'; -import { EnvironmentTest } from 'Sieve/Extensions/rfc5183'; -import { SetCommand, StringTest } from 'Sieve/Extensions/rfc5229'; -import { VacationCommand } from 'Sieve/Extensions/rfc5230'; -import { SetFlagCommand, AddFlagCommand, RemoveFlagCommand, HasFlagTest } from 'Sieve/Extensions/rfc5232'; -import { SpamTestTest, VirusTestTest } from 'Sieve/Extensions/rfc5235'; -import { DateTest, CurrentDateTest } from 'Sieve/Extensions/rfc5260'; -import { AddHeaderCommand, DeleteHeaderCommand } from 'Sieve/Extensions/rfc5293'; -import { ErejectCommand, RejectCommand } from 'Sieve/Extensions/rfc5429'; -import { NotifyCommand, ValidNotifyMethodTest, NotifyMethodCapabilityTest } from 'Sieve/Extensions/rfc5435'; -import { IHaveTest, ErrorCommand } from 'Sieve/Extensions/rfc5463'; -import { MailboxExistsTest, MetadataTest, MetadataExistsTest } from 'Sieve/Extensions/rfc5490'; -import { ForEveryPartCommand, BreakCommand, ReplaceCommand, EncloseCommand, ExtractTextCommand } from 'Sieve/Extensions/rfc5703'; -import { IncludeCommand, ReturnCommand } from 'Sieve/Extensions/rfc6609'; +import { availableCommands } from 'Sieve/Commands'; +import { ConditionalCommand, RequireCommand } from 'Sieve/Commands/Controls'; +import { NotTest } from 'Sieve/Commands/Tests'; const - AllCommands = [ - // Control commands - IfCommand, - ElsIfCommand, - ElseCommand, - ConditionalCommand, - RequireCommand, - StopCommand, - // Action commands - DiscardCommand, - FileIntoCommand, - KeepCommand, - RedirectCommand, - // Test commands - AddressTest, - AllOfTest, - AnyOfTest, - EnvelopeTest, - ExistsTest, - FalseTest, - HeaderTest, - NotTest, - SizeTest, - TrueTest, - // rfc5173 - BodyTest, - // rfc5183 - EnvironmentTest, - // rfc5229 - SetCommand, - StringTest, - // rfc5230 - VacationCommand, - // rfc5232 - SetFlagCommand, - AddFlagCommand, - RemoveFlagCommand, - HasFlagTest, - // rfc5235 - SpamTestTest, - VirusTestTest, - // rfc5260 - DateTest, - CurrentDateTest, - // rfc5293 - AddHeaderCommand, - DeleteHeaderCommand, - // rfc5429 - ErejectCommand, - RejectCommand, - // rfc5435 - NotifyCommand, - ValidNotifyMethodTest, - NotifyMethodCapabilityTest, - // rfc5463 - IHaveTest, - ErrorCommand, - // rfc5490 - MailboxExistsTest, - MetadataTest, - MetadataExistsTest, - // rfc5703 - ForEveryPartCommand, - BreakCommand, - ReplaceCommand, - EncloseCommand, - ExtractTextCommand, - // rfc6609 - IncludeCommand, - ReturnCommand - ], - T_UNKNOWN = 0, T_STRING_LIST = 1, T_QUOTED_STRING = 2, @@ -184,15 +72,7 @@ export const parseScript = (script, name = 'script.sieve') => { script = script.replace(/\r?\n/g, '\r\n'); // Only activate available commands - const Commands = {}; - AllCommands.forEach(cmd => { - const obj = new cmd, requires = obj.require; - if (!requires - || (Array.isArray(requires) ? requires : [requires]).every(string => capa.includes(string)) - ) { - Commands[obj.identifier] = cmd; - } - }); + const Commands = availableCommands(); let match, line = 1, diff --git a/dev/Sieve/View/Script.js b/dev/Sieve/View/Script.js index 71a755fd5..20dd4a325 100644 --- a/dev/Sieve/View/Script.js +++ b/dev/Sieve/View/Script.js @@ -5,6 +5,8 @@ import { FilterPopupView } from 'Sieve/View/Filter'; import { parseScript } from 'Sieve/Parser'; +import { availableActions, availableControls, availableTests } from 'Sieve/Commands'; + import { capa, scripts, @@ -21,10 +23,14 @@ export class SieveScriptPopupView extends rl.pluginPopupView { errorText: '', rawActive: false, allowToggle: false, - script: null + script: null, + + sieveCapabilities: '', + availableActions: '', + availableControls: '', + availableTests: '' }); - this.sieveCapabilities = capa.join(' '); this.saving = false; this.filterForDeletion = ko.observable(null).askDeleteHelper(); @@ -137,6 +143,11 @@ export class SieveScriptPopupView extends rl.pluginPopupView { beforeShow(oScript) { // onShow(oScript) { + this.sieveCapabilities(capa.join(' ')); + this.availableActions([...Object.keys(availableActions())].join(', ')); + this.availableControls([...Object.keys(availableControls())].join(', ')); + this.availableTests([...Object.keys(availableTests())].join(', ')); + oScript = oScript || new SieveScriptModel(); let raw = !oScript.allowFilters(); this.script(oScript); diff --git a/snappymail/v/0.0.0/app/templates/Views/User/PopupsSieveScript.html b/snappymail/v/0.0.0/app/templates/Views/User/PopupsSieveScript.html index 58a4f3ab8..7d26b7f13 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/PopupsSieveScript.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/PopupsSieveScript.html @@ -20,13 +20,23 @@
-
-
-				:
-				
-			
- -
+
+ +

+		
+
+ Actions +

+		
+
+ Controls +

+		
+
+ Tests +

+		
+