diff --git a/dev/Sieve/Extensions/rfc5173.js b/dev/Sieve/Extensions/rfc5173.js index 4cd41ec2e..d1ae95a9c 100644 --- a/dev/Sieve/Extensions/rfc5173.js +++ b/dev/Sieve/Extensions/rfc5173.js @@ -11,8 +11,6 @@ class Body extends Grammar.Test constructor() { super('body'); - this.comparator = '', - this.match_type = ':is', this.body_transform = ''; // :raw, :content , :text this.key_list = new Grammar.StringList; } diff --git a/dev/Sieve/Extensions/rfc5183.js b/dev/Sieve/Extensions/rfc5183.js new file mode 100644 index 000000000..e2dfe6649 --- /dev/null +++ b/dev/Sieve/Extensions/rfc5183.js @@ -0,0 +1,38 @@ +/** + * https://tools.ietf.org/html/rfc5183 + */ + +(Sieve => { + +const Grammar = Sieve.Grammar; + +class Environment extends Grammar.Test +{ + constructor() + { + super('environment'); + this.name = new Grammar.QuotedString; + this.key_list = new Grammar.StringList; + } + + get require() { return 'environment'; } + + toString() + { + return 'body' +// + ' ' + this.comparator + + ' ' + this.match_type + + ' ' + this.name + + ' ' + this.key_list; + } + + pushArguments(args) + { + this.name = args[args.length-2]; + this.key_list = args[args.length-1]; + } +} + +Sieve.Commands.environment = Environment; + +})(this.Sieve); diff --git a/dev/Sieve/Extensions/rfc5229.js b/dev/Sieve/Extensions/rfc5229.js new file mode 100644 index 000000000..5d8e1f6de --- /dev/null +++ b/dev/Sieve/Extensions/rfc5229.js @@ -0,0 +1,73 @@ +/** + * https://tools.ietf.org/html/rfc5229 + */ + +(Sieve => { + +const Grammar = Sieve.Grammar; + +class Set extends Grammar.Command +{ + constructor() + { + super('set'); + this.modifiers = []; + this._name = new Grammar.QuotedString; + this._value = new Grammar.QuotedString; + } + + get require() { return 'variables'; } + + toString() + { + return 'set' + + ' ' + this.modifiers.join(' ') + + ' ' + this._name + + ' ' + this._value; + } + + get name() { return this._name.value; } + set name(str) { this._name.value = str; } + + get value() { return this._value.value; } + set value(str) { this._value.value = str; } + + pushArguments(args) + { + [':lower', ':upper', ':lowerfirst', ':upperfirst', ':quotewildcard', ':length'].forEach(modifier => { + args.includes(modifier) && this.modifiers.push(modifier); + }); + this._name = args[args.length-2]; + this._value = args[args.length-1]; + } +} + +class String extends Grammar.Test +{ + constructor() + { + super('string'); + this.source = new Grammar.StringList; + this.key_list = new Grammar.StringList; + } + + toString() + { + return 'string' + + ' ' + this.match_type +// + ' ' + this.comparator + + ' ' + this.source + + ' ' + this.key_list; + } + + pushArguments(args) + { + this.source = args[args.length-2]; + this.key_list = args[args.length-1]; + } +} + +Sieve.Commands.set = Set; +Sieve.Commands.string = String; + +})(this.Sieve); diff --git a/dev/Sieve/Extensions/rfc5232.js b/dev/Sieve/Extensions/rfc5232.js index e862d9d87..ad789ec13 100644 --- a/dev/Sieve/Extensions/rfc5232.js +++ b/dev/Sieve/Extensions/rfc5232.js @@ -76,8 +76,6 @@ class HasFlag extends Grammar.Test constructor() { super('hasflag'); - this.comparator = '', - this.match_type = ':is', this.variable_list = new Grammar.StringList; this.list_of_flags = new Grammar.StringList; } diff --git a/dev/Sieve/Extensions/rfc5235.js b/dev/Sieve/Extensions/rfc5235.js index 9b5199ce1..21378d83c 100644 --- a/dev/Sieve/Extensions/rfc5235.js +++ b/dev/Sieve/Extensions/rfc5235.js @@ -12,8 +12,6 @@ class SpamTest extends Grammar.Test { super('spamtest'); this.percent = false, // 0 - 100 else 0 - 10 - this.comparator = '', - this.match_type = ':is', this.value = new Grammar.QuotedString; } @@ -47,8 +45,6 @@ class VirusTest extends Grammar.Test constructor() { super('virustest'); - this.comparator = '', - this.match_type = ':is', this.value = new Grammar.QuotedString; // 1 - 5 } diff --git a/dev/Sieve/Extensions/rfc5260.js b/dev/Sieve/Extensions/rfc5260.js new file mode 100644 index 000000000..806421d44 --- /dev/null +++ b/dev/Sieve/Extensions/rfc5260.js @@ -0,0 +1,103 @@ +/** + * https://tools.ietf.org/html/rfc5260 + */ + +(Sieve => { + +const Grammar = Sieve.Grammar; + +class DateTest extends Grammar.Test +{ + constructor() + { + super('date'); + this.zone = new Grammar.QuotedString; + this.originalzone = false; + this.header_name = new Grammar.QuotedString; + this.date_part = new Grammar.QuotedString; + this.key_list = new Grammar.StringList; + // rfc5260#section-6 + this.index = new Grammar.Number; + this.last = false; + } + +// get require() { return ['date','index']; } + get require() { return 'date'; } + + toString() + { + return 'date' + + (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : '')) + + (this.originalzone ? ' :originalzone' : (this.zone.length ? ' :zone ' + this.zone : '')) +// + ' ' + this.comparator + + ' ' + this.match_type + + ' ' + this.header_name + + ' ' + this.date_part + + ' ' + this.key_list; + } + + pushArguments(args) + { + let l = args.length - 1; + args.forEach((arg, i) => { + if (':originalzone' === arg) { + this.originalzone = true; + } else if (':last' === arg) { + this.last = true; + } else if (':zone' === args[i-1]) { + this.zone.value = arg.value; + } else if (':index' === args[i-1]) { + this.index.value = arg.value; + } else if (l-2 === i) { + this.header_name = arg; + } else if (l-1 === i) { + this.date_part = arg; + } else if (l === i) { + this.key_list = arg; + } + }); + } +} + +class CurrentDate extends Grammar.Test +{ + constructor() + { + super('date'); + this.zone = new Grammar.QuotedString; + this.date_part = new Grammar.QuotedString; + this.key_list = new Grammar.StringList; + } + + get require() { return 'date'; } + + toString() + { + return 'date' + + (this.zone.length ? ' :zone ' + this.zone : '') +// + ' ' + this.comparator + + ' ' + this.match_type + + ' ' + this.date_part + + ' ' + this.key_list; + } + + pushArguments(args) + { + let l = args.length - 1; + args.forEach((arg, i) => { + if (':zone' === args[i-1]) { + this.zone.value = arg.value; + } else if (l-1 === i) { + this.date_part = arg; + } else if (l === i) { + this.key_list = arg; + } + }); + } +} + +Sieve.Commands.date = DateTest; +Sieve.Commands.currentdate = CurrentDate; + +})(this.Sieve); + diff --git a/dev/Sieve/Extensions/rfc5293.js b/dev/Sieve/Extensions/rfc5293.js new file mode 100644 index 000000000..ddc201178 --- /dev/null +++ b/dev/Sieve/Extensions/rfc5293.js @@ -0,0 +1,88 @@ +/** + * https://tools.ietf.org/html/rfc5293 + */ + +(Sieve => { + +const Grammar = Sieve.Grammar; + +class AddHeader extends Grammar.Command +{ + constructor() + { + super('addheader'); + this.last = false; + this.field_name = new Grammar.QuotedString; + this.value = new Grammar.QuotedString; + } + + get require() { return 'editheader'; } + + toString() + { + return this.identifier + + (this.last ? ' :last' : '') + + ' ' + this.field_name + + ' ' + this.value + ';'; + } + + pushArguments(args) + { + this.last = args.includes(':last'); + this.field_name = args[args.length - 2]; + this.value = args[args.length - 1]; + } +} + +class DeleteHeader extends Grammar.Command +{ + constructor() + { + super('deleteheader'); + this.index = new Grammar.Number; + this.last = false; + this.comparator = '', + this.match_type = ':is', + this.field_name = new Grammar.QuotedString; + this.value_patterns = new Grammar.StringList; + } + + get require() { return 'editheader'; } + + toString() + { + return this.identifier + + (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : '')) +// + ' ' + this.comparator + + ' ' + this.match_type + + ' ' + this.field_name + + ' ' + this.value_patterns + ';'; + } + + pushArguments(args) + { + let l = args.length - 1; + args.forEach((arg, i) => { + if (':last' === arg) { + this.last = true; + } else if (':index' === args[i-1]) { + this.index.value = arg.value; + args[i] = null; + } + }); + + if (args[l-1] instanceof Grammar.StringType) { + this.field_name = args[l-1]; + this.value_patterns = args[l]; + } else { + this.field_name = args[l]; + } + } +} + +Object.assign(Sieve.Commands, { + addheader: AddHeader, + deleteheader: DeleteHeader +}); + +})(this.Sieve); diff --git a/dev/Sieve/Grammar.js b/dev/Sieve/Grammar.js index cdac6a3d0..70646e4f9 100644 --- a/dev/Sieve/Grammar.js +++ b/dev/Sieve/Grammar.js @@ -218,6 +218,9 @@ class Test constructor(identifier) { this.identifier = identifier; + // Almost every test has a comparator and match_type, so define them here + this.comparator = '', + this.match_type = ':is', this.arguments = []; } diff --git a/dev/Sieve/Tests.js b/dev/Sieve/Tests.js index 65119767a..1318a3807 100644 --- a/dev/Sieve/Tests.js +++ b/dev/Sieve/Tests.js @@ -16,16 +16,20 @@ class Address extends Test constructor() { super('address'); - this.comparator = ''; this.address_part = ':all'; // :localpart | :domain | :all - this.match_type = ':is'; this.header_list = new StringList; this.key_list = new StringList; + // rfc5260#section-6 +// this.index = new Grammar.Number; +// this.last = false; } + get require() { return this.last ? 'index' : ''; } + toString() { return 'address' +// + (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : '')) // + ' ' + this.comparator + ' ' + this.address_part + ' ' + this.match_type @@ -38,6 +42,10 @@ class Address extends Test args.forEach((arg, i) => { if (':localpart' === arg || ':domain' === arg || ':all' === arg) { this.address_part = arg; + } else if (':last' === arg) { + this.last = true; + } else if (':index' === args[i-1]) { + this.index.value = arg.value; } else if (arg instanceof StringList || arg instanceof Grammar.StringType) { this[args[i+1] ? 'header_list' : 'key_list'] = arg; // (args[i+1] ? this.header_list : this.key_list) = arg; @@ -88,9 +96,7 @@ class Envelope extends Test constructor() { super('envelope'); - this.comparator = ''; this.address_part = ':all'; // :localpart | :domain | :all - this.match_type = ':is'; this.envelope_part = new StringList; this.key_list = new StringList; } @@ -165,16 +171,20 @@ class Header extends Test constructor() { super('header'); - this.comparator = ''; this.address_part = ':all'; // :localpart | :domain | :all - this.match_type = ':is'; this.header_names = new StringList; this.key_list = new StringList; + // rfc5260#section-6 +// this.index = new Grammar.Number; +// this.last = false; } + get require() { return this.last ? 'index' : ''; } + toString() { return 'header' +// + (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : '')) // + ' ' + this.comparator + ' ' + this.match_type + ' ' + this.header_names @@ -186,6 +196,10 @@ class Header extends Test args.forEach((arg, i) => { if (':localpart' === arg || ':domain' === arg || ':all' === arg) { this.address_part = arg; + } else if (':last' === arg) { + this.last = true; + } else if (':index' === args[i-1]) { + this.index.value = arg.value; } else if (arg instanceof StringList || arg instanceof Grammar.StringType) { this[args[i+1] ? 'header_names' : 'key_list'] = arg; // (args[i+1] ? this.header_names : this.key_list) = arg;