mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-03 14:37:02 +03:00
Added Sieve parser code in master
This commit is contained in:
parent
e90e8a55ce
commit
f4cd25f8ad
21 changed files with 2126 additions and 8 deletions
277
dev/Sieve/Grammar.js
Normal file
277
dev/Sieve/Grammar.js
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/**
|
||||
* https://tools.ietf.org/html/rfc5228#section-8.2
|
||||
*/
|
||||
|
||||
import {
|
||||
QUOTED_TEXT,
|
||||
HASH_COMMENT,
|
||||
MULTILINE_LITERAL,
|
||||
MULTILINE_DOTSTART
|
||||
} from 'Sieve/RegEx';
|
||||
|
||||
import {
|
||||
arrayToString
|
||||
} from 'Sieve/Utils';
|
||||
|
||||
/**
|
||||
* abstract
|
||||
*/
|
||||
export class GrammarString /*extends String*/
|
||||
{
|
||||
constructor(value = '')
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
toString()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
get value()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
set value(value)
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
get length()
|
||||
{
|
||||
return this._value.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* abstract
|
||||
*/
|
||||
export class GrammarComment extends GrammarString
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* https://tools.ietf.org/html/rfc5228#section-2.9
|
||||
*/
|
||||
export class GrammarCommand
|
||||
{
|
||||
constructor(identifier)
|
||||
{
|
||||
this.identifier = identifier || this.constructor.name.toLowerCase().replace('command', '');
|
||||
this.arguments = [];
|
||||
this.commands = new GrammarCommands;
|
||||
}
|
||||
|
||||
toString()
|
||||
{
|
||||
let result = this.identifier;
|
||||
if (this.arguments.length) {
|
||||
result += ' ' + arrayToString(this.arguments, ' ');
|
||||
}
|
||||
return result + (
|
||||
this.commands.length ? ' ' + this.commands.toString() : ';'
|
||||
);
|
||||
}
|
||||
|
||||
getComparators()
|
||||
{
|
||||
return ['i;ascii-casemap'];
|
||||
}
|
||||
|
||||
getMatchTypes()
|
||||
{
|
||||
return [':is', ':contains', ':matches'];
|
||||
}
|
||||
|
||||
pushArguments(args)
|
||||
{
|
||||
this.arguments = args;
|
||||
}
|
||||
}
|
||||
|
||||
export class GrammarCommands extends Array
|
||||
{
|
||||
toString()
|
||||
{
|
||||
return this.length
|
||||
? '{\r\n\t' + arrayToString(this, '\r\n\t') + '\r\n}'
|
||||
: '{}';
|
||||
}
|
||||
|
||||
push(value)
|
||||
{
|
||||
if (value instanceof GrammarCommand || value instanceof GrammarComment) {
|
||||
super.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class GrammarBracketComment extends GrammarComment
|
||||
{
|
||||
toString()
|
||||
{
|
||||
return '/* ' + super.toString() + ' */';
|
||||
}
|
||||
}
|
||||
|
||||
export class GrammarHashComment extends GrammarComment
|
||||
{
|
||||
toString()
|
||||
{
|
||||
return '# ' + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export class GrammarNumber /*extends Number*/
|
||||
{
|
||||
constructor(value = '0')
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
toString()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
get value()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
set value(value)
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class GrammarStringList extends Array
|
||||
{
|
||||
toString()
|
||||
{
|
||||
if (1 < this.length) {
|
||||
return '[' + this.join(',') + ']';
|
||||
}
|
||||
return this.length ? this[0] : '';
|
||||
}
|
||||
|
||||
push(value)
|
||||
{
|
||||
if (!(value instanceof GrammarString)) {
|
||||
value = new GrammarQuotedString(value);
|
||||
}
|
||||
super.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
const StringListRegEx = RegExp('(?:^\\s*|\\s*,\\s*)(?:"(' + QUOTED_TEXT + ')"|text:[ \\t]*('
|
||||
+ HASH_COMMENT + ')?\\r\\n'
|
||||
+ '((?:' + MULTILINE_LITERAL + '|' + MULTILINE_DOTSTART + ')*)'
|
||||
+ '\\.\\r\\n)', 'gm');
|
||||
GrammarStringList.fromString = list => {
|
||||
let string,
|
||||
obj = new GrammarStringList;
|
||||
list = list.replace(/^[\r\n\t[]+/, '');
|
||||
while ((string = StringListRegEx.exec(list))) {
|
||||
if (string[3]) {
|
||||
obj.push(new GrammarMultiLine(string[3], string[2]));
|
||||
} else {
|
||||
obj.push(new GrammarQuotedString(string[1]));
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
export class GrammarQuotedString extends GrammarString
|
||||
{
|
||||
toString()
|
||||
{
|
||||
return '"' + this._value.replace(/[\\"]/g, '\\$&') + '"';
|
||||
// return '"' + super.toString().replace(/[\\"]/g, '\\$&') + '"';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://tools.ietf.org/html/rfc5228#section-8.1
|
||||
*/
|
||||
export class GrammarMultiLine extends GrammarString
|
||||
{
|
||||
constructor(value, comment = '')
|
||||
{
|
||||
super();
|
||||
this.value = value;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
toString()
|
||||
{
|
||||
return 'text:'
|
||||
+ (this.comment ? '# ' + this.comment : '') + "\r\n"
|
||||
+ this.value
|
||||
+ "\r\n.\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
const MultiLineRegEx = RegExp('text:[ \\t]*(' + HASH_COMMENT + ')?\\r\\n'
|
||||
+ '((?:' + MULTILINE_LITERAL + '|' + MULTILINE_DOTSTART + ')*)'
|
||||
+ '\\.\\r\\n', 'm');
|
||||
GrammarMultiLine.fromString = string => {
|
||||
string = string.match(MultiLineRegEx);
|
||||
if (string[2]) {
|
||||
return new GrammarMultiLine(string[2].replace(/\r\n$/, ''), string[1]);
|
||||
}
|
||||
return new GrammarMultiLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* https://tools.ietf.org/html/rfc5228#section-5
|
||||
*/
|
||||
export class GrammarTest
|
||||
{
|
||||
constructor(identifier)
|
||||
{
|
||||
this.identifier = identifier || this.constructor.name.toLowerCase().replace('command', '');
|
||||
// Almost every test has a comparator and match_type, so define them here
|
||||
this.comparator = '',
|
||||
this.match_type = ':is',
|
||||
this.arguments = [];
|
||||
}
|
||||
|
||||
toString()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue