Fix Sieve QuotedString handling

This commit is contained in:
the-djmaze 2024-09-23 13:43:24 +02:00
parent 257d9201f6
commit 61c2eefec1
13 changed files with 185 additions and 104 deletions

View file

@ -13,10 +13,13 @@ export class EnvironmentTest extends TestCommand
constructor()
{
super();
this.name = new GrammarQuotedString;
this._name = new GrammarQuotedString;
this.key_list = new GrammarStringList;
}
get name() { return this._name.value; }
set name(v) { this._name.value = v; }
get require() { return 'environment'; }
toString()
@ -24,13 +27,13 @@ export class EnvironmentTest extends TestCommand
return 'environment'
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.name
+ ' ' + this._name
+ ' ' + this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.name = args.pop();
this._name = args.pop();
}
}

View file

@ -21,6 +21,12 @@ export class SetCommand extends ActionCommand
get require() { return 'variables'; }
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; }
toString()
{
return 'set'
@ -29,12 +35,6 @@ export class SetCommand extends ActionCommand
+ ' ' + 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 => {

View file

@ -30,6 +30,20 @@ export class VacationCommand extends ActionCommand
// get require() { return ['vacation','vacation-seconds']; }
get require() { return 'vacation'; }
get days() { return this._days.value; }
get seconds() { return this._seconds.value; }
get subject() { return this._subject.value; }
get from() { return this._from.value; }
get handle() { return this._handle.value; }
get reason() { return this._reason.value; }
set days(int) { this._days.value = int; }
set seconds(int) { this._seconds.value = int; }
set subject(str) { this._subject.value = str; }
set from(str) { this._from.value = str; }
set handle(str) { this._handle.value = str; }
set reason(str) { this._reason.value = str; }
toString()
{
let result = 'vacation';
@ -56,20 +70,6 @@ export class VacationCommand extends ActionCommand
return result + ' ' + this._reason;
}
get days() { return this._days.value; }
get seconds() { return this._seconds.value; }
get subject() { return this._subject.value; }
get from() { return this._from.value; }
get handle() { return this._handle.value; }
get reason() { return this._reason.value; }
set days(int) { this._days.value = int; }
set seconds(int) { this._seconds.value = int; }
set subject(str) { this._subject.value = str; }
set from(str) { this._from.value = str; }
set handle(str) { this._handle.value = str; }
set reason(str) { this._reason.value = str; }
pushArguments(args)
{
this._reason.value = args.pop().value; // GrammarQuotedString

View file

@ -4,7 +4,6 @@
import {
GrammarQuotedString,
GrammarString,
TestCommand
} from 'Sieve/Grammar';
@ -14,19 +13,22 @@ export class SpamTestTest extends TestCommand
{
super();
this.percent = false, // 0 - 100 else 0 - 10
this.value = new GrammarQuotedString;
this._value = new GrammarQuotedString;
}
// get require() { return this.percent ? 'spamtestplus' : 'spamtest'; }
get require() { return /:value|:count/.test(this.match_type) ? ['spamtestplus','relational'] : 'spamtestplus'; }
get value() { return this._value.value; }
set value(v) { this._value.value = v; }
toString()
{
return 'spamtest'
+ (this.percent ? ' :percent' : '')
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.value;
+ ' ' + this._value;
}
pushArguments(args)
@ -34,8 +36,8 @@ export class SpamTestTest extends TestCommand
args.forEach(arg => {
if (':percent' === arg) {
this.percent = true;
} else if (arg instanceof GrammarString) {
this.value = arg;
} else if (arg instanceof GrammarQuotedString) {
this._value = arg;
}
});
}
@ -46,24 +48,27 @@ export class VirusTestTest extends TestCommand
constructor()
{
super();
this.value = new GrammarQuotedString; // 1 - 5
this._value = new GrammarQuotedString; // 1 - 5
}
get require() { return /:value|:count/.test(this.match_type) ? ['virustest','relational'] : 'virustest'; }
get value() { return this._value.value; }
set value(v) { this._value.value = v; }
toString()
{
return 'virustest'
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.value;
+ ' ' + this._value;
}
pushArguments(args)
{
args.forEach(arg => {
if (arg instanceof GrammarString) {
this.value = arg;
if (arg instanceof GrammarQuotedString) {
this._value = arg;
}
});
}

View file

@ -14,10 +14,10 @@ export class DateTest extends TestCommand
constructor()
{
super();
this.zone = new GrammarQuotedString;
this._zone = new GrammarQuotedString;
this.originalzone = false;
this.header_name = new GrammarQuotedString;
this.date_part = new GrammarQuotedString;
this._header_name = new GrammarQuotedString;
this._date_part = new GrammarQuotedString;
this.key_list = new GrammarStringList;
// rfc5260#section-6
this.index = new GrammarNumber;
@ -27,30 +27,39 @@ export class DateTest extends TestCommand
// get require() { return ['date','index']; }
get require() { return 'date'; }
get zone() { return this._zone.value; }
set zone(v) { this._zone.value = v; }
get header_name() { return this._header_name.value; }
set header_name(v) { this._header_name.value = v; }
get date_part() { return this._date_part.value; }
set date_part(v) { this._date_part.value = v; }
toString()
{
return 'date'
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
+ (this.originalzone ? ' :originalzone' : (this.zone.length ? ' :zone ' + this.zone : ''))
+ (this.originalzone ? ' :originalzone' : (this._zone.length ? ' :zone ' + this._zone : ''))
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.header_name
+ ' ' + this.date_part
+ ' ' + this._header_name
+ ' ' + this._date_part
+ ' ' + this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.date_part = args.pop();
this.header_name = args.pop();
this._date_part = args.pop();
this._header_name = args.pop();
args.forEach((arg, i) => {
if (':originalzone' === arg) {
this.originalzone = true;
} else if (':last' === arg) {
this.last = true;
} else if (i && ':zone' === args[i-1]) {
this.zone.value = arg.value;
this._zone.value = arg.value;
} else if (i && ':index' === args[i-1]) {
this.index.value = arg.value;
}
@ -63,30 +72,36 @@ export class CurrentDateTest extends TestCommand
constructor()
{
super();
this.zone = new GrammarQuotedString;
this.date_part = new GrammarQuotedString;
this._zone = new GrammarQuotedString;
this._date_part = new GrammarQuotedString;
this.key_list = new GrammarStringList;
}
get require() { return 'date'; }
get zone() { return this._zone.value; }
set zone(v) { this._zone.value = v; }
get date_part() { return this._date_part.value; }
set date_part(v) { this._date_part.value = v; }
toString()
{
return 'currentdate'
+ (this.zone.length ? ' :zone ' + this.zone : '')
+ (this._zone.length ? ' :zone ' + this._zone : '')
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.date_part
+ ' ' + this._date_part
+ ' ' + this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.date_part = args.pop();
this._date_part = args.pop();
args.forEach((arg, i) => {
if (i && ':zone' === args[i-1]) {
this.zone.value = arg.value;
this._zone.value = arg.value;
}
});
}

View file

@ -16,24 +16,30 @@ export class AddHeaderCommand extends ActionCommand
{
super();
this.last = false;
this.field_name = new GrammarQuotedString;
this.value = new GrammarQuotedString;
this._field_name = new GrammarQuotedString;
this._value = new GrammarQuotedString;
}
get require() { return 'editheader'; }
get field_name() { return this._field_name.value; }
set field_name(v) { this._field_name.value = v; }
get value() { return this._value.value; }
set value(v) { this._value.value = v; }
toString()
{
return this.identifier
+ (this.last ? ' :last' : '')
+ ' ' + this.field_name
+ ' ' + this.value + ';';
+ ' ' + this._field_name
+ ' ' + this._value + ';';
}
pushArguments(args)
{
this.value = args.pop();
this.field_name = args.pop();
this._value = args.pop();
this._field_name = args.pop();
this.last = args.includes(':last');
}
}
@ -47,19 +53,22 @@ export class DeleteHeaderCommand extends ActionCommand
this.last = false;
this.comparator = '',
this.match_type = ':is',
this.field_name = new GrammarQuotedString;
this._field_name = new GrammarQuotedString;
this.value_patterns = new GrammarStringList;
}
get require() { return 'editheader'; }
get field_name() { return this._field_name.value; }
set field_name(v) { this._field_name.value = v; }
toString()
{
return this.identifier
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.match_type
+ ' ' + this.field_name
+ ' ' + this._field_name
+ ' ' + this.value_patterns + ';';
}
@ -76,10 +85,10 @@ export class DeleteHeaderCommand extends ActionCommand
});
if (l && args[l-1] instanceof GrammarString) {
this.field_name = args[l-1];
this._field_name = args[l-1];
this.value_patterns = args[l];
} else {
this.field_name = args[l];
this._field_name = args[l];
}
}
}

View file

@ -26,14 +26,16 @@ export class NotifyCommand extends ActionCommand
}
get method() { return this._method.value; }
get from() { return this._from.value; }
get importance() { return this._importance.value; }
get message() { return this._message.value; }
set method(str) { this._method.value = str; }
set method(str) { this._method.value = str; }
set from(str) { this._from.value = str; }
get from() { return this._from.value; }
set from(str) { this._from.value = str; }
get importance() { return this._importance.value; }
set importance(int) { this._importance.value = int; }
set message(str) { this._message.value = str; }
get message() { return this._message.value; }
set message(str) { this._message.value = str; }
get require() { return 'enotify'; }
@ -99,25 +101,31 @@ export class NotifyMethodCapabilityTest extends TestCommand
constructor()
{
super();
this.notification_uri = new GrammarQuotedString;
this.notification_capability = new GrammarQuotedString;
this._notification_uri = new GrammarQuotedString;
this._notification_capability = new GrammarQuotedString;
this.key_list = new GrammarStringList;
}
get notification_uri() { return this._notification_uri.value; }
set notification_uri(v) { this._notification_uri.value = v; }
get notification_capability() { return this._notification_capability.value; }
set notification_capability(v) { this._notification_capability.value = v; }
toString()
{
return 'valid_notify_method '
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ (this.match_type ? ' ' + this.match_type : '')
+ this.notification_uri
+ this.notification_capability
+ this._notification_uri
+ this._notification_capability
+ this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.notification_capability = args.pop();
this.notification_uri = args.pop();
this._notification_capability = args.pop();
this._notification_uri = args.pop();
}
}

View file

@ -41,18 +41,21 @@ export class ErrorCommand extends ControlCommand
constructor()
{
super();
this.message = new GrammarQuotedString;
this._message = new GrammarQuotedString;
}
get require() { return 'ihave'; }
get message() { return this._message.value; }
set message(v) { this._message.value = v; }
toString()
{
return 'error ' + this.message + ';';
return 'error ' + this._message + ';';
}
pushArguments(args)
{
this.message = args.pop();
this._message = args.pop();
}
}

View file

@ -42,28 +42,34 @@ export class MetadataTest extends TestCommand
constructor()
{
super();
this.mailbox = new GrammarQuotedString;
this.annotation_name = new GrammarQuotedString;
this._mailbox = new GrammarQuotedString;
this._annotation_name = new GrammarQuotedString;
this.key_list = new GrammarStringList;
}
get require() { return 'mboxmetadata'; }
get mailbox() { return this._mailbox.value; }
set mailbox(v) { this._mailbox.value = v; }
get annotation_name() { return this._annotation_name.value; }
set annotation_name(v) { this._annotation_name.value = v; }
toString()
{
return 'metadata '
+ ' ' + this.match_type
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.mailbox
+ ' ' + this.annotation_name
+ ' ' + this._mailbox
+ ' ' + this._annotation_name
+ ' ' + this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.annotation_name = args.pop();
this.mailbox = args.pop();
this._annotation_name = args.pop();
this._mailbox = args.pop();
}
}
@ -75,23 +81,26 @@ export class MetadataExistsTest extends TestCommand
constructor()
{
super();
this.mailbox = new GrammarQuotedString;
this._mailbox = new GrammarQuotedString;
this.annotation_names = new GrammarStringList;
}
get require() { return 'mboxmetadata'; }
get mailbox() { return this._mailbox.value; }
set mailbox(v) { this._mailbox.value = v; }
toString()
{
return 'metadataexists '
+ ' ' + this.mailbox
+ ' ' + this._mailbox
+ ' ' + this.annotation_names;
}
pushArguments(args)
{
this.annotation_names = args.pop();
this.mailbox = args.pop();
this._mailbox = args.pop();
}
}
@ -103,25 +112,28 @@ export class ServerMetadataTest extends TestCommand
constructor()
{
super();
this.annotation_name = new GrammarQuotedString;
this._annotation_name = new GrammarQuotedString;
this.key_list = new GrammarStringList;
}
get require() { return 'servermetadata'; }
get annotation_name() { return this._annotation_name.value; }
set annotation_name(v) { this._annotation_name.value = v; }
toString()
{
return 'servermetadata '
+ ' ' + this.match_type
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ ' ' + this.annotation_name
+ ' ' + this._annotation_name
+ ' ' + this.key_list;
}
pushArguments(args)
{
this.key_list = args.pop();
this.annotation_name = args.pop();
this._annotation_name = args.pop();
}
}

View file

@ -20,7 +20,7 @@ export class ForEveryPartCommand extends ControlCommand
constructor()
{
super();
this._name = new GrammarString;
this.name = new GrammarString;
this.commands = new GrammarCommands;
}
@ -29,8 +29,8 @@ export class ForEveryPartCommand extends ControlCommand
toString()
{
let result = 'foreverypart';
if (this._name.length) {
result += ' :name ' + this._name;
if (this.name.length) {
result += ' :name ' + this.name;
}
return result + ' ' + this.commands;
}
@ -39,7 +39,7 @@ export class ForEveryPartCommand extends ControlCommand
{
args.forEach((arg, i) => {
if (':name' === arg) {
this._name.value = args[i+1].value;
this.name.value = args[i+1].value;
}
});
}
@ -53,8 +53,8 @@ export class BreakCommand extends ForEveryPartCommand
toString()
{
let result = 'break';
if (this._name.length) {
result += ' :name ' + this._name;
if (this.name.length) {
result += ' :name ' + this.name;
}
return result + ';';
}
@ -68,14 +68,23 @@ export class ReplaceCommand extends ActionCommand
constructor()
{
super();
this.mime = false;
this._subject = new GrammarQuotedString;
this._from = new GrammarQuotedString;
this.replacement = new GrammarQuotedString;
this.mime = false;
this._subject = new GrammarQuotedString;
this._from = new GrammarQuotedString;
this._replacement = new GrammarQuotedString;
}
get require() { return 'replace'; }
get subject() { return this._subject.value; }
set subject(str) { this._subject.value = str; }
get from() { return this._from.value; }
set from(str) { this._from.value = str; }
get replacement() { return this._replacement.value; }
set replacement(str) { this._replacement.value = str; }
toString()
{
let result = 'replace';
@ -88,12 +97,12 @@ export class ReplaceCommand extends ActionCommand
if (this._from.length) {
result += ' :from ' + this._from;
}
return result + this.replacement + ';';
return result + this._replacement + ';';
}
pushArguments(args)
{
this.replacement = args.pop();
this._replacement = args.pop();
args.forEach((arg, i) => {
if (':mime' === arg) {
this.mime = true;
@ -119,6 +128,9 @@ export class EncloseCommand extends ActionCommand
get require() { return 'enclose'; }
get subject() { return this._subject.value; }
set subject(v) { this._subject.value = v; }
toString()
{
let result = 'enclose';
@ -153,9 +165,12 @@ export class ExtractTextCommand extends ActionCommand
super();
this.modifiers = [];
this._first = new GrammarNumber;
this.varname = new GrammarQuotedString;
this._varname = new GrammarQuotedString;
}
get varname() { return this._varname.value; }
set varname(v) { this._varname.value = v; }
get require() { return 'extracttext'; }
toString()
@ -165,12 +180,12 @@ export class ExtractTextCommand extends ActionCommand
if (0 < this._first.value) {
result += ' :first ' + this._first;
}
return result + ' ' + this.varname + ';';
return result + ' ' + this._varname + ';';
}
pushArguments(args)
{
this.varname = args.pop();
this._varname = args.pop();
[':lower', ':upper', ':lowerfirst', ':upperfirst', ':quotewildcard', ':length'].forEach(modifier => {
args.includes(modifier) && this.modifiers.push(modifier);
});

View file

@ -16,18 +16,21 @@ export class IncludeCommand extends ControlCommand
this.global = false; // ':personal' / ':global';
this.once = false;
this.optional = false;
this.value = new GrammarQuotedString;
this._value = new GrammarQuotedString;
}
get require() { return 'include'; }
get value() { return this._value.value; }
set value(v) { this._value.value = v; }
toString()
{
return 'include'
+ (this.global ? ' :global' : '')
+ (this.once ? ' :once' : '')
+ (this.optional ? ' :optional' : '')
+ ' ' + this.value + ';';
+ ' ' + this._value + ';';
}
pushArguments(args)
@ -36,7 +39,7 @@ export class IncludeCommand extends ControlCommand
if (':global' === arg || ':once' === arg || ':optional' === arg) {
this[arg.slice(1)] = true;
} else if (arg instanceof GrammarQuotedString) {
this.value = arg;
this._value = arg;
}
});
}

View file

@ -271,10 +271,14 @@ GrammarStringList.fromString = list => {
export class GrammarQuotedString extends GrammarString
{
constructor(value = '')
{
super(value instanceof GrammarQuotedString ? value.value : value);
}
toString()
{
return '"' + this._value.replace(/[\\"]/g, '\\$&') + '"';
// return '"' + super.toString().replace(/[\\"]/g, '\\$&') + '"';
}
}

View file

@ -169,6 +169,9 @@ export const parseScript = (script, name = 'script.sieve') => {
}
valid || error('Not after IF/ELSIF condition');
}
if ('allof' === value || 'anyof' === value) {
// (command instanceof ConditionalCommand || command instanceof NotTest) || error('Test-list not in conditional');
}
new_command = new Commands[value]();
} else {
if (command && (
@ -225,7 +228,8 @@ export const parseScript = (script, name = 'script.sieve') => {
pushArg(GrammarMultiLine.fromString(value));
break;
case T_QUOTED_STRING:
pushArg(new GrammarQuotedString(value.slice(1,-1)));
try { value = JSON.parse(value); } catch(e) { console.error(e, value); }
pushArg(new GrammarQuotedString(value));
break;
case T_NUMBER:
pushArg(new GrammarNumber(value));