mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-06 07:57:02 +03:00
Fix Sieve math-type and comparator handling
This commit is contained in:
parent
92a6027aa0
commit
3893849d21
12 changed files with 128 additions and 48 deletions
|
|
@ -68,9 +68,10 @@ export class AddressTest extends TestCommand
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
|
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.address_part
|
+ ' ' + this.address_part
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this.header_list
|
+ ' ' + this.header_list
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +148,10 @@ export class EnvelopeTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'envelope'
|
return 'envelope'
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.address_part
|
+ ' ' + this.address_part
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this.envelope_part
|
+ ' ' + this.envelope_part
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +232,6 @@ export class HeaderTest extends TestCommand
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
this.match_type = ':is';
|
|
||||||
this.address_part = ':all';
|
this.address_part = ':all';
|
||||||
this.header_names = new GrammarStringList;
|
this.header_names = new GrammarStringList;
|
||||||
this.key_list = new GrammarStringList;
|
this.key_list = new GrammarStringList;
|
||||||
|
|
@ -280,8 +281,9 @@ export class HeaderTest extends TestCommand
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
|
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this.header_names
|
+ ' ' + this.header_names
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ export class BodyTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'body'
|
return 'body'
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this.body_transform
|
+ ' ' + this.body_transform
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,9 @@ export class EnvironmentTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'environment'
|
return 'environment'
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this._name
|
+ ' ' + this._name
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,9 @@ export class StringTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'string'
|
return 'string'
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.source
|
+ ' ' + this.source
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,9 @@ export class HasFlagTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'hasflag'
|
return 'hasflag'
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.variable_list
|
+ ' ' + this.variable_list
|
||||||
+ ' ' + this.list_of_flags;
|
+ ' ' + this.list_of_flags;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class SpamTestTest extends TestCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// get require() { return this.percent ? 'spamtestplus' : 'spamtest'; }
|
// get require() { return this.percent ? 'spamtestplus' : 'spamtest'; }
|
||||||
get require() { return /:value|:count/.test(this.match_type) ? ['spamtestplus','relational'] : 'spamtestplus'; }
|
get require() { return /:value|:count/.test(this._match_type) ? ['spamtestplus','relational'] : 'spamtestplus'; }
|
||||||
|
|
||||||
get value() { return this._value.value; }
|
get value() { return this._value.value; }
|
||||||
set value(v) { this._value.value = v; }
|
set value(v) { this._value.value = v; }
|
||||||
|
|
@ -26,8 +26,9 @@ export class SpamTestTest extends TestCommand
|
||||||
{
|
{
|
||||||
return 'spamtest'
|
return 'spamtest'
|
||||||
+ (this.percent ? ' :percent' : '')
|
+ (this.percent ? ' :percent' : '')
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this._value;
|
+ ' ' + this._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +52,7 @@ export class VirusTestTest extends TestCommand
|
||||||
this._value = new GrammarQuotedString; // 1 - 5
|
this._value = new GrammarQuotedString; // 1 - 5
|
||||||
}
|
}
|
||||||
|
|
||||||
get require() { return /:value/.test(this.match_type) ? ['virustest','relational'] : 'virustest'; }
|
get require() { return ':value' == this._match_type ? ['virustest','relational'] : 'virustest'; }
|
||||||
|
|
||||||
get value() { return this._value.value; }
|
get value() { return this._value.value; }
|
||||||
set value(v) { this._value.value = v; }
|
set value(v) { this._value.value = v; }
|
||||||
|
|
@ -59,8 +60,9 @@ export class VirusTestTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'virustest'
|
return 'virustest'
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this._value;
|
+ ' ' + this._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,9 @@ export class DateTest extends TestCommand
|
||||||
return 'date'
|
return 'date'
|
||||||
+ (this.last ? ' :last' : (this.index.value ? ' :index ' + this.index : ''))
|
+ (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._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this._header_name
|
+ ' ' + this._header_name
|
||||||
+ ' ' + this._date_part
|
+ ' ' + this._date_part
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
|
|
@ -89,8 +90,9 @@ export class CurrentDateTest extends TestCommand
|
||||||
{
|
{
|
||||||
return 'currentdate'
|
return 'currentdate'
|
||||||
+ (this._zone.length ? ' :zone ' + this._zone : '')
|
+ (this._zone.length ? ' :zone ' + this._zone : '')
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this.match_type
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + this._date_part
|
+ ' ' + this._date_part
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,9 @@ export class NotifyMethodCapabilityTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'valid_notify_method '
|
return 'valid_notify_method '
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ (this.match_type ? ' ' + this.match_type : '')
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ this._notification_uri
|
+ this._notification_uri
|
||||||
+ this._notification_capability
|
+ this._notification_capability
|
||||||
+ this.key_list;
|
+ this.key_list;
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,9 @@ export class MetadataTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'metadata '
|
return 'metadata '
|
||||||
+ ' ' + this.match_type
|
+ ' ' + this._match_type
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this._mailbox
|
+ ' ' + this._mailbox
|
||||||
+ ' ' + this._annotation_name
|
+ ' ' + this._annotation_name
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
|
|
@ -124,8 +125,9 @@ export class ServerMetadataTest extends TestCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'servermetadata '
|
return 'servermetadata '
|
||||||
+ ' ' + this.match_type
|
+ ' ' + this._match_type
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ ' ' + this._annotation_name
|
+ ' ' + this._annotation_name
|
||||||
+ ' ' + this.key_list;
|
+ ' ' + this.key_list;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
MULTILINE_DOTSTART
|
MULTILINE_DOTSTART
|
||||||
} from 'Sieve/RegEx';
|
} from 'Sieve/RegEx';
|
||||||
|
|
||||||
import { arrayToString, getMatchTypes } from 'Sieve/Utils';
|
import { arrayToString, getMatchTypes, getComparators } from 'Sieve/Utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* abstract
|
* abstract
|
||||||
|
|
@ -151,19 +151,64 @@ export /*abstract*/ class TestCommand extends GrammarCommand
|
||||||
*/
|
*/
|
||||||
super(identifier);
|
super(identifier);
|
||||||
// Almost every test has a comparator and match_type, so define them here
|
// Almost every test has a comparator and match_type, so define them here
|
||||||
this.comparator = '';
|
this._comparator = '';
|
||||||
this.match_type = ':is';
|
this._match_type = '';
|
||||||
|
this.relational_match = ''; // GrammarQuotedString DQUOTE ( "gt" / "ge" / "lt" / "le" / "eq" / "ne" ) DQUOTE
|
||||||
|
}
|
||||||
|
|
||||||
|
get require() { return /:value|:count/.test(this._match_type) ? 'relational' : ''; }
|
||||||
|
|
||||||
|
get match_type()
|
||||||
|
{
|
||||||
|
return this._match_type;
|
||||||
|
}
|
||||||
|
set match_type(value)
|
||||||
|
{
|
||||||
|
// default?
|
||||||
|
if (':is' == value) {
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
if (value.length && !getMatchTypes(0).includes(value)) {
|
||||||
|
throw 'Unsupported match-type ' + value;
|
||||||
|
}
|
||||||
|
if (':list' == value) {
|
||||||
|
this._comparator = '';
|
||||||
|
}
|
||||||
|
if (':count' != value && ':value' != value) {
|
||||||
|
this.relational_match = '';
|
||||||
|
}
|
||||||
|
this._match_type = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get comparator()
|
||||||
|
{
|
||||||
|
return this._comparator;
|
||||||
|
}
|
||||||
|
set comparator(value)
|
||||||
|
{
|
||||||
|
if (!(value instanceof GrammarQuotedString)) {
|
||||||
|
value = new GrammarQuotedString(value);
|
||||||
|
}
|
||||||
|
// default?
|
||||||
|
if (value.length && 'i;ascii-casemap' != value.value) {
|
||||||
|
if (':list' == this._match_type) {
|
||||||
|
throw 'Comparator not allowed when using :list';
|
||||||
|
}
|
||||||
|
if (!getComparators().includes(value.value)) {
|
||||||
|
throw 'Unsupported comparator ' + value;
|
||||||
|
}
|
||||||
|
this._comparator = value;
|
||||||
|
} else {
|
||||||
|
this._comparator = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toString()
|
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
|
return (this.identifier
|
||||||
+ (this.comparator ? ' :comparator ' + this.comparator : '')
|
+ (this._comparator ? ' :comparator ' + this._comparator : '')
|
||||||
+ (this.match_type ? ' ' + this.match_type : '')
|
+ (this._match_type ? ' ' + this._match_type : '')
|
||||||
|
+ (this.relational_match ? ' ' + this.relational_match : '')
|
||||||
+ ' ' + arrayToString(this.arguments, ' ')).trim();
|
+ ' ' + arrayToString(this.arguments, ' ')).trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,18 +119,20 @@ export const parseScript = (script, name = 'script.sieve') => {
|
||||||
let prev_arg = args[args.length-1];
|
let prev_arg = args[args.length-1];
|
||||||
if (getMatchTypes(0).includes(arg)) {
|
if (getMatchTypes(0).includes(arg)) {
|
||||||
command.match_type = arg;
|
command.match_type = arg;
|
||||||
} else if (':value' === prev_arg || ':count' === prev_arg) {
|
} else if (getMatchTypes(0).includes(prev_arg)) {
|
||||||
// Sieve relational [RFC5231] match types
|
|
||||||
/^(gt|ge|lt|le|eq|ne)$/.test(arg.value) || error('Invalid relational match-type ' + arg);
|
|
||||||
command.match_type = prev_arg + ' ' + arg;
|
|
||||||
--args.length;
|
--args.length;
|
||||||
// requires.push('relational');
|
if (':value' === prev_arg || ':count' === prev_arg) {
|
||||||
|
// Sieve relational [RFC5231] match types
|
||||||
|
/^"(gt|ge|lt|le|eq|ne)"$/.test(arg) || error('Invalid relational match-type ' + arg);
|
||||||
|
command.relational_match = arg;
|
||||||
|
// requires.push('relational');
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if (':comparator' === prev_arg) {
|
} else if (':comparator' === prev_arg) {
|
||||||
command.comparator = arg;
|
command.comparator = arg;
|
||||||
--args.length;
|
--args.length;
|
||||||
} else {
|
|
||||||
args.push(arg);
|
|
||||||
}
|
}
|
||||||
|
args.push(arg);
|
||||||
},
|
},
|
||||||
pushArgs = () => {
|
pushArgs = () => {
|
||||||
if (args.length) {
|
if (args.length) {
|
||||||
|
|
|
||||||
|
|
@ -58,13 +58,33 @@ export const
|
||||||
serverErrorDesc(text);
|
serverErrorDesc(text);
|
||||||
},
|
},
|
||||||
|
|
||||||
getComparators = () => ['i;ascii-casemap'],
|
getComparators = (validOnly = 0) => {
|
||||||
|
let result = [
|
||||||
|
// Default
|
||||||
|
'i;ascii-casemap',
|
||||||
|
];
|
||||||
|
if (capa.includes('relational') || !validOnly) {
|
||||||
|
result.push('i;octet');
|
||||||
|
}
|
||||||
|
if (capa.includes('comparator-i;ascii-numeric') || !validOnly) {
|
||||||
|
result.push('i;ascii-numeric');
|
||||||
|
}
|
||||||
|
if (capa.includes('comparator-i;unicode-casemap') || !validOnly) {
|
||||||
|
result.push('i;unicode-casemap');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
getMatchTypes = (validOnly = 1) => {
|
getMatchTypes = (validOnly = 1) => {
|
||||||
let result = [':is',':contains',':matches'];
|
let result = [':is',':contains',':matches'];
|
||||||
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
||||||
|
// Only available for tests with a key_list property
|
||||||
if (capa.includes('extlists') || !validOnly) {
|
if (capa.includes('extlists') || !validOnly) {
|
||||||
result.push(':list');
|
result.push(':list');
|
||||||
}
|
}
|
||||||
|
if (capa.includes('relational') || !validOnly) {
|
||||||
|
result.push(':value');
|
||||||
|
result.push(':count');
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue