Prepare some Sieve restructuring for GUI

This commit is contained in:
the-djmaze 2022-03-17 09:03:02 +01:00
parent 37bb9a9a97
commit ff9a89380c
15 changed files with 259 additions and 194 deletions

View file

@ -1,102 +1,20 @@
/**
* https://tools.ietf.org/html/rfc5228#section-2.9
* https://datatracker.ietf.org/doc/html/rfc5228#section-4
* Action commands do not take tests or blocks as arguments.
*/
import { capa } from 'Sieve/Utils';
import {
GrammarCommand,
ActionCommand,
GrammarString,
GrammarStringList,
GrammarQuotedString
} from 'Sieve/Grammar';
/**
* https://tools.ietf.org/html/rfc5228#section-3.1
* Usage:
* if <test1: test> <block1: block>
* elsif <test2: test> <block2: block>
* else <block3: block>
*/
export class ConditionalCommand extends GrammarCommand
{
constructor()
{
super();
this.test = null;
}
toString()
{
return this.identifier + ' ' + this.test + ' ' + this.commands;
}
/*
public function pushArguments(array $args): void
{
args.forEach((arg, i) => {
if (':' === args[i-1][0]) {
this[args[i-1].replace(':','_')].value = arg.value;
}
});
print_r($args);
exit;
}
*/
}
export class IfCommand extends ConditionalCommand
{
}
export class ElsIfCommand extends ConditionalCommand
{
}
export class ElseCommand extends ConditionalCommand
{
toString()
{
return this.identifier + ' ' + this.commands;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.2
*/
export class RequireCommand extends GrammarCommand
{
constructor()
{
super();
this.capabilities = new GrammarStringList();
}
toString()
{
return 'require ' + this.capabilities + ';';
}
pushArguments(args)
{
if (args[0] instanceof GrammarStringList) {
this.capabilities = args[0];
} else if (args[0] instanceof GrammarQuotedString) {
this.capabilities.push(args[0]);
}
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.3
*/
export class StopCommand extends GrammarCommand
{
}
/**
* https://tools.ietf.org/html/rfc5228#section-4.1
*/
export class FileIntoCommand extends GrammarCommand
export class FileIntoCommand extends ActionCommand
{
constructor()
{
@ -139,7 +57,7 @@ export class FileIntoCommand extends GrammarCommand
/**
* https://tools.ietf.org/html/rfc5228#section-4.2
*/
export class RedirectCommand extends GrammarCommand
export class RedirectCommand extends ActionCommand
{
constructor()
{
@ -181,13 +99,13 @@ export class RedirectCommand extends GrammarCommand
/**
* https://tools.ietf.org/html/rfc5228#section-4.3
*/
export class KeepCommand extends GrammarCommand
export class KeepCommand extends ActionCommand
{
}
/**
* https://tools.ietf.org/html/rfc5228#section-4.4
*/
export class DiscardCommand extends GrammarCommand
export class DiscardCommand extends ActionCommand
{
}

View file

@ -0,0 +1,92 @@
/**
* https://tools.ietf.org/html/rfc5228#section-2.9
* A control structure is a control command that ends with a block instead of a semicolon.
*/
import {
GrammarCommand,
GrammarStringList,
GrammarQuotedString
} from 'Sieve/Grammar';
/**
* https://tools.ietf.org/html/rfc5228#section-3.1
* Usage:
* if <test1: test> <block1: block>
* elsif <test2: test> <block2: block>
* else <block3: block>
*/
export class ConditionalCommand extends GrammarCommand
{
constructor()
{
super();
this.test = null;
}
toString()
{
return this.identifier + ' ' + this.test + ' ' + this.commands;
}
/*
public function pushArguments(array $args): void
{
args.forEach((arg, i) => {
if (':' === args[i-1][0]) {
this[args[i-1].replace(':','_')].value = arg.value;
}
});
print_r($args);
exit;
}
*/
}
export class IfCommand extends ConditionalCommand
{
}
export class ElsIfCommand extends ConditionalCommand
{
}
export class ElseCommand extends ConditionalCommand
{
toString()
{
return this.identifier + ' ' + this.commands;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.2
*/
export class RequireCommand extends GrammarCommand
{
constructor()
{
super();
this.capabilities = new GrammarStringList();
}
toString()
{
return 'require ' + this.capabilities + ';';
}
pushArguments(args)
{
if (args[0] instanceof GrammarStringList) {
this.capabilities = args[0];
} else if (args[0] instanceof GrammarQuotedString) {
this.capabilities.push(args[0]);
}
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.3
*/
export class StopCommand extends GrammarCommand
{
}

View file

@ -8,7 +8,7 @@ import {
GrammarNumber,
GrammarString,
GrammarStringList,
GrammarTest,
TestCommand,
GrammarTestList
} from 'Sieve/Grammar';
@ -31,7 +31,7 @@ const
/**
* https://tools.ietf.org/html/rfc5228#section-5.1
*/
export class AddressTest extends GrammarTest
export class AddressTest extends TestCommand
{
constructor()
{
@ -98,7 +98,7 @@ export class AddressTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.2
*/
export class AllOfTest extends GrammarTest
export class AllOfTest extends TestCommand
{
constructor()
{
@ -115,7 +115,7 @@ export class AllOfTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.3
*/
export class AnyOfTest extends GrammarTest
export class AnyOfTest extends TestCommand
{
constructor()
{
@ -132,7 +132,7 @@ export class AnyOfTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.4
*/
export class EnvelopeTest extends GrammarTest
export class EnvelopeTest extends TestCommand
{
constructor()
{
@ -169,7 +169,7 @@ export class EnvelopeTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.5
*/
export class ExistsTest extends GrammarTest
export class ExistsTest extends TestCommand
{
constructor()
{
@ -214,7 +214,7 @@ export class ExistsTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.6
*/
export class FalseTest extends GrammarTest
export class FalseTest extends TestCommand
{
toString()
{
@ -225,7 +225,7 @@ export class FalseTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.7
*/
export class HeaderTest extends GrammarTest
export class HeaderTest extends TestCommand
{
constructor()
{
@ -304,12 +304,12 @@ export class HeaderTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.8
*/
export class NotTest extends GrammarTest
export class NotTest extends TestCommand
{
constructor()
{
super();
this.test = new GrammarTest;
this.test = new TestCommand;
}
toString()
@ -326,7 +326,7 @@ export class NotTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.9
*/
export class SizeTest extends GrammarTest
export class SizeTest extends TestCommand
{
constructor()
{
@ -355,7 +355,7 @@ export class SizeTest extends GrammarTest
/**
* https://tools.ietf.org/html/rfc5228#section-5.10
*/
export class TrueTest extends GrammarTest
export class TrueTest extends TestCommand
{
toString()
{

View file

@ -5,10 +5,10 @@
import {
GrammarString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
export class BodyTest extends GrammarTest
export class BodyTest extends TestCommand
{
constructor()
{

View file

@ -5,10 +5,10 @@
import {
GrammarQuotedString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
export class EnvironmentTest extends GrammarTest
export class EnvironmentTest extends TestCommand
{
constructor()
{

View file

@ -6,7 +6,7 @@ import {
GrammarCommand,
GrammarQuotedString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
export class SetCommand extends GrammarCommand
@ -45,7 +45,7 @@ export class SetCommand extends GrammarCommand
}
}
export class StringTest extends GrammarTest
export class StringTest extends TestCommand
{
constructor()
{

View file

@ -7,7 +7,7 @@ import {
GrammarQuotedString,
GrammarString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
class FlagCommand extends GrammarCommand
@ -63,7 +63,7 @@ export class RemoveFlagCommand extends FlagCommand
{
}
export class HasFlagTest extends GrammarTest
export class HasFlagTest extends TestCommand
{
constructor()
{

View file

@ -5,10 +5,10 @@
import {
GrammarQuotedString,
GrammarString,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
export class SpamTestTest extends GrammarTest
export class SpamTestTest extends TestCommand
{
constructor()
{
@ -41,7 +41,7 @@ export class SpamTestTest extends GrammarTest
}
}
export class VirusTestTest extends GrammarTest
export class VirusTestTest extends TestCommand
{
constructor()
{

View file

@ -6,10 +6,10 @@ import {
GrammarNumber,
GrammarQuotedString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
export class DateTest extends GrammarTest
export class DateTest extends TestCommand
{
constructor()
{
@ -58,7 +58,7 @@ export class DateTest extends GrammarTest
}
}
export class CurrentDateTest extends GrammarTest
export class CurrentDateTest extends TestCommand
{
constructor()
{

View file

@ -7,7 +7,7 @@ import {
GrammarNumber,
GrammarQuotedString,
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
/**
@ -72,7 +72,7 @@ export class NotifyCommand extends GrammarCommand
/**
* https://datatracker.ietf.org/doc/html/rfc5435#section-4
*/
export class ValidNotifyMethodTest extends GrammarTest
export class ValidNotifyMethodTest extends TestCommand
{
constructor()
{
@ -94,7 +94,7 @@ export class ValidNotifyMethodTest extends GrammarTest
/**
* https://datatracker.ietf.org/doc/html/rfc5435#section-5
*/
export class NotifyMethodCapabilityTest extends GrammarTest
export class NotifyMethodCapabilityTest extends TestCommand
{
constructor()
{

View file

@ -4,7 +4,7 @@
import {
GrammarCommand,
GrammarTest,
TestCommand,
GrammarQuotedString,
GrammarStringList
} from 'Sieve/Grammar';
@ -12,7 +12,7 @@ import {
/**
* https://datatracker.ietf.org/doc/html/rfc5463#section-4
*/
export class IHaveTest extends GrammarTest
export class IHaveTest extends TestCommand
{
constructor()
{

View file

@ -3,7 +3,7 @@
*/
import {
GrammarTest,
TestCommand,
GrammarQuotedString,
GrammarStringList
} from 'Sieve/Grammar';
@ -11,7 +11,7 @@ import {
/**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.1
*/
export class MailboxExistsTest extends GrammarTest
export class MailboxExistsTest extends TestCommand
{
constructor()
{
@ -37,7 +37,7 @@ export class MailboxExistsTest extends GrammarTest
/**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.3
*/
export class MetadataTest extends GrammarTest
export class MetadataTest extends TestCommand
{
constructor()
{
@ -70,7 +70,7 @@ export class MetadataTest extends GrammarTest
/**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.4
*/
export class MetadataExistsTest extends GrammarTest
export class MetadataExistsTest extends TestCommand
{
constructor()
{
@ -98,7 +98,7 @@ export class MetadataExistsTest extends GrammarTest
/**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.3
*/
export class ServerMetadataTest extends GrammarTest
export class ServerMetadataTest extends TestCommand
{
constructor()
{
@ -128,7 +128,7 @@ export class ServerMetadataTest extends GrammarTest
/**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.4
*/
export class ServerMetadataExistsTest extends GrammarTest
export class ServerMetadataExistsTest extends TestCommand
{
constructor()
{

View file

@ -4,13 +4,13 @@
import {
GrammarStringList,
GrammarTest
TestCommand
} from 'Sieve/Grammar';
/**
* https://datatracker.ietf.org/doc/html/rfc6134#section-2.7
*/
export class ValidExtListTest extends GrammarTest
export class ValidExtListTest extends TestCommand
{
constructor()
{

View file

@ -56,7 +56,7 @@ export class GrammarCommand
{
constructor(identifier)
{
this.identifier = identifier || this.constructor.name.toLowerCase().replace('command', '');
this.identifier = identifier || this.constructor.name.toLowerCase().replace(/(test|command|action)$/, '');
this.arguments = [];
this.commands = new GrammarCommands;
}
@ -105,6 +105,114 @@ export class GrammarCommands extends Array
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3
*/
export class ControlCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
this.commands = new GrammarCommands;
}
toString()
{
let result = this.identifier;
if (this.arguments.length) {
result += ' ' + arrayToString(this.arguments, ' ');
}
return result + (
this.commands.length ? ' ' + this.commands : ';'
);
}
getComparators()
{
return ['i;ascii-casemap'];
}
getMatchTypes()
{
return [':is', ':contains', ':matches'];
}
pushArguments(args)
{
this.arguments = args;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-4
*/
export class ActionCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
}
toString()
{
let result = this.identifier;
if (this.arguments.length) {
result += ' ' + arrayToString(this.arguments, ' ');
}
return result + ';'
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5
*/
export class TestCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
// Almost every test has a comparator and match_type, so define them here
this.comparator = '';
this.match_type = ':is';
}
toString()
{
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
if (!getMatchTypes().includes(this.match_type)) {
throw 'Unsupported match-type ' + this.match_type;
}
return (this.identifier
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ (this.match_type ? ' ' + this.match_type : '')
+ ' ' + arrayToString(this.arguments, ' ')).trim();
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5.2
* https://tools.ietf.org/html/rfc5228#section-5.3
*/
export class GrammarTestList extends Array
{
toString()
{
if (1 < this.length) {
// return '(\r\n\t' + arrayToString(this, ',\r\n\t') + '\r\n)';
return '(' + this.join(', ') + ')';
}
return this.length ? this[0] : '';
}
push(value)
{
if (!(value instanceof TestCommand)) {
throw 'Not an instanceof Test';
}
super.push(value);
}
}
export class GrammarBracketComment extends GrammarComment
{
toString()
@ -221,59 +329,3 @@ GrammarMultiLine.fromString = string => {
}
return new GrammarMultiLine();
}
/**
* https://tools.ietf.org/html/rfc5228#section-5
*/
export class GrammarTest
{
constructor(identifier)
{
this.identifier = identifier || this.constructor.name.toLowerCase().replace(/test$/, '');
// Almost every test has a comparator and match_type, so define them here
this.comparator = '',
this.match_type = ':is',
this.arguments = [];
}
toString()
{
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
if (!getMatchTypes().includes(this.match_type)) {
throw 'Unsupported match-type ' + this.match_type;
}
return (this.identifier
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ (this.match_type ? ' ' + this.match_type : '')
+ ' ' + arrayToString(this.arguments, ' ')).trim();
}
pushArguments(args)
{
this.arguments = args;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5.2
* https://tools.ietf.org/html/rfc5228#section-5.3
*/
export class GrammarTestList extends Array
{
toString()
{
if (1 < this.length) {
// return '(\r\n\t' + arrayToString(this, ',\r\n\t') + '\r\n)';
return '(' + this.join(', ') + ')';
}
return this.length ? this[0] : '';
}
push(value)
{
if (!(value instanceof GrammarTest)) {
throw 'Not an instanceof Test';
}
super.push(value);
}
}

View file

@ -23,22 +23,25 @@ import {
GrammarNumber,
GrammarQuotedString,
GrammarStringList,
GrammarTest,
TestCommand,
GrammarTestList
} from 'Sieve/Grammar';
import {
ConditionalCommand,
DiscardCommand,
FileIntoCommand,
KeepCommand,
RedirectCommand
} from 'Sieve/Commands/Actions';
import {
ConditionalCommand,
ElsIfCommand,
ElseCommand,
FileIntoCommand,
IfCommand,
KeepCommand,
RedirectCommand,
RequireCommand,
StopCommand
} from 'Sieve/Commands';
} from 'Sieve/Commands/Controls';
import {
AddressTest,
@ -51,7 +54,7 @@ import {
NotTest,
SizeTest,
TrueTest
} from 'Sieve/Tests';
} from 'Sieve/Commands/Tests';
import { BodyTest } from 'Sieve/Extensions/rfc5173';
import { EnvironmentTest } from 'Sieve/Extensions/rfc5183';
@ -265,14 +268,14 @@ export const parseScript = (script, name = 'script.sieve') => {
|| command instanceof NotTest
|| command.tests instanceof GrammarTestList)) {
console.error('Unknown test: ' + value);
new_command = new GrammarTest(value);
new_command = new TestCommand(value);
} else {
console.error('Unknown command: ' + value);
new_command = new GrammarCommand(value);
}
}
if (new_command instanceof GrammarTest) {
if (new_command instanceof TestCommand) {
if (command instanceof ConditionalCommand || command instanceof NotTest) {
// if/elsif/else new_command
// not new_command