Added some draft templates for Sieve GUI

This commit is contained in:
the-djmaze 2024-09-22 16:36:12 +02:00
parent 04f3133f27
commit 74a67aabaf
42 changed files with 542 additions and 101 deletions

View file

@ -15,7 +15,6 @@ import {
} from 'Sieve/Commands/Actions'; } from 'Sieve/Commands/Actions';
import { import {
ConditionalCommand,
ElsIfCommand, ElsIfCommand,
ElseCommand, ElseCommand,
IfCommand, IfCommand,
@ -67,7 +66,6 @@ export const
IfCommand, IfCommand,
ElsIfCommand, ElsIfCommand,
ElseCommand, ElseCommand,
ConditionalCommand,
RequireCommand, RequireCommand,
StopCommand, StopCommand,
// Action commands // Action commands

View file

@ -21,6 +21,10 @@ export class FileIntoCommand extends ActionCommand
super(); super();
// QuotedString / MultiLine // QuotedString / MultiLine
this._mailbox = new GrammarQuotedString(); this._mailbox = new GrammarQuotedString();
// https://datatracker.ietf.org/doc/html/rfc3894
// this.copy = false;
// https://datatracker.ietf.org/doc/html/rfc5490#section-3.2
// this.create = false;
} }
get require() { return 'fileinto'; } get require() { return 'fileinto'; }
@ -28,9 +32,7 @@ export class FileIntoCommand extends ActionCommand
toString() toString()
{ {
return 'fileinto' return 'fileinto'
// https://datatracker.ietf.org/doc/html/rfc3894
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '') + ((this.copy && capa.includes('copy')) ? ' :copy' : '')
// https://datatracker.ietf.org/doc/html/rfc5490#section-3.2
+ ((this.create && capa.includes('mailbox')) ? ' :create' : '') + ((this.create && capa.includes('mailbox')) ? ' :create' : '')
+ ' ' + this._mailbox + ' ' + this._mailbox
+ ';'; + ';';
@ -64,15 +66,17 @@ export class RedirectCommand extends ActionCommand
super(); super();
// QuotedString / MultiLine // QuotedString / MultiLine
this._address = new GrammarQuotedString(); this._address = new GrammarQuotedString();
// https://datatracker.ietf.org/doc/html/rfc3894
// this.copy = false;
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
// this.list = null;
} }
toString() toString()
{ {
return 'redirect' return 'redirect'
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
// + ((this.list && capa.includes('extlists')) ? ' :list ' + this.list : '') // + ((this.list && capa.includes('extlists')) ? ' :list ' + this.list : '')
// https://datatracker.ietf.org/doc/html/rfc3894
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '') + ((this.copy && capa.includes('copy')) ? ' :copy' : '')
+ ' ' + this._address + ' ' + this._address
+ ';'; + ';';

View file

@ -5,6 +5,7 @@
import { import {
ControlCommand, ControlCommand,
GrammarCommands,
GrammarStringList, GrammarStringList,
GrammarQuotedString GrammarQuotedString
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
@ -16,37 +17,55 @@ import {
* elsif <test2: test> <block2: block> * elsif <test2: test> <block2: block>
* else <block3: block> * else <block3: block>
*/ */
export class ConditionalCommand extends ControlCommand export /*abstract*/ class ConditionalCommand extends ControlCommand
{ {
constructor(identifier) constructor()
{ {
super(identifier);
this.test = null;
}
toString()
{
return this.identifier + ' ' + this.test + ' ' + this.commands;
}
/* /*
public function pushArguments(array $args): void if (this.constructor == ConditionalCommand) {
{ throw Error("Abstract class can't be instantiated.");
args.forEach((arg, i) => {
if (i && ':' === args[i-1][0]) {
this[args[i-1].replace(':','_')].value = arg.value;
}
});
print_r($args);
exit;
} }
*/ */
super();
this.commands = new GrammarCommands;
}
} }
export class IfCommand extends ConditionalCommand export class IfCommand extends ConditionalCommand
{ {
constructor()
{
super();
this._test = null; // must be descendent instanceof TestCommand
}
get test()
{
return this._test;
}
set test(value)
{
/*
if (!value instanceof TestCommand) {
throw Error("test must be descendent instanceof TestCommand.");
}
*/
this._test = value;
}
toString()
{
/*
if (!this._test instanceof TestCommand) {
throw Error("test must be descendent instanceof TestCommand.");
}
*/
return this.identifier + ' ' + this._test + ' ' + this.commands;
}
} }
export class ElsIfCommand extends ConditionalCommand export class ElsIfCommand extends IfCommand
{ {
} }

View file

@ -316,11 +316,6 @@ export class NotTest extends TestCommand
{ {
return 'not ' + this.test; return 'not ' + this.test;
} }
pushArguments()
{
throw 'No arguments';
}
} }
/** /**

View file

@ -43,7 +43,6 @@ export class VacationCommand extends ActionCommand
} }
if (this._from.length) { if (this._from.length) {
result += ' :from ' + this._from; result += ' :from ' + this._from;
// result += ' :from ' + this.arguments[':from'];
} }
if (this.addresses.length) { if (this.addresses.length) {
result += ' :addresses ' + this.addresses; result += ' :addresses ' + this.addresses;

View file

@ -8,11 +8,11 @@ import {
GrammarString GrammarString
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
class rfc5429Command extends ActionCommand class /*abstract*/ rfc5429Command extends ActionCommand
{ {
constructor(identifier) constructor()
{ {
super(identifier); super();
this._reason = new GrammarQuotedString; this._reason = new GrammarQuotedString;
} }
@ -44,7 +44,6 @@ class rfc5429Command extends ActionCommand
*/ */
export class ErejectCommand extends rfc5429Command export class ErejectCommand extends rfc5429Command
{ {
constructor() { super('ereject'); }
get require() { return 'ereject'; } get require() { return 'ereject'; }
} }
@ -53,6 +52,5 @@ export class ErejectCommand extends rfc5429Command
*/ */
export class RejectCommand extends rfc5429Command export class RejectCommand extends rfc5429Command
{ {
constructor() { super('reject'); }
get require() { return 'reject'; } get require() { return 'reject'; }
} }

View file

@ -5,6 +5,7 @@
import { import {
ActionCommand, ActionCommand,
ControlCommand, ControlCommand,
GrammarCommands,
GrammarNumber, GrammarNumber,
GrammarQuotedString, GrammarQuotedString,
GrammarString, GrammarString,
@ -20,6 +21,7 @@ export class ForEveryPartCommand extends ControlCommand
{ {
super(); super();
this._name = new GrammarString; this._name = new GrammarString;
this.commands = new GrammarCommands;
} }
get require() { return 'foreverypart'; } get require() { return 'foreverypart'; }
@ -27,7 +29,7 @@ export class ForEveryPartCommand extends ControlCommand
toString() toString()
{ {
let result = 'foreverypart'; let result = 'foreverypart';
if (this._subject.length) { if (this._name.length) {
result += ' :name ' + this._name; result += ' :name ' + this._name;
} }
return result + ' ' + this.commands; return result + ' ' + this.commands;
@ -43,12 +45,15 @@ export class ForEveryPartCommand extends ControlCommand
} }
} }
/**
* Must be inside foreverypart
*/
export class BreakCommand extends ForEveryPartCommand export class BreakCommand extends ForEveryPartCommand
{ {
toString() toString()
{ {
let result = 'break'; let result = 'break';
if (this._subject.length) { if (this._name.length) {
result += ' :name ' + this._name; result += ' :name ' + this._name;
} }
return result + ';'; return result + ';';
@ -82,7 +87,6 @@ export class ReplaceCommand extends ActionCommand
} }
if (this._from.length) { if (this._from.length) {
result += ' :from ' + this._from; result += ' :from ' + this._from;
// result += ' :from ' + this.arguments[':from'];
} }
return result + this.replacement + ';'; return result + this.replacement + ';';
} }
@ -140,6 +144,7 @@ export class EncloseCommand extends ActionCommand
/** /**
* https://datatracker.ietf.org/doc/html/rfc5703#section-7 * https://datatracker.ietf.org/doc/html/rfc5703#section-7
* Should be inside foreverypart, else empty and flagged as a compilation error
*/ */
export class ExtractTextCommand extends ActionCommand export class ExtractTextCommand extends ActionCommand
{ {

View file

@ -52,34 +52,26 @@ export class GrammarComment extends GrammarString
/** /**
* https://tools.ietf.org/html/rfc5228#section-2.9 * https://tools.ietf.org/html/rfc5228#section-2.9
*/ */
export class GrammarCommand const cmdNameSuffix = /(test|command|action)$/;
export /*abstract*/ class GrammarCommand
{ {
constructor(identifier) constructor(identifier)
{ {
this.identifier = identifier || this.constructor.name.toLowerCase().replace(/(test|command|action)$/, ''); /*
this.arguments = []; if (this.constructor == GrammarCommand) {
this.commands = new GrammarCommands; throw Error("Abstract class can't be instantiated.");
}
*/
this.identifier = identifier || this.constructor.name.toLowerCase().replace(cmdNameSuffix, '');
} }
toString() toString()
{ {
let result = this.identifier; let result = this.identifier;
if (this.arguments.length) { if (this.arguments?.length) {
result += ' ' + arrayToString(this.arguments, ' '); result += ' ' + arrayToString(this.arguments, ' ');
} }
return result + ( return result + ';';
this.commands.length ? ' ' + this.commands : ';'
);
}
getComparators()
{
return ['i;ascii-casemap'];
}
getMatchTypes()
{
return [':is', ':contains', ':matches'];
} }
pushArguments(args) pushArguments(args)
@ -108,63 +100,47 @@ export class GrammarCommands extends Array
/** /**
* https://tools.ietf.org/html/rfc5228#section-3 * https://tools.ietf.org/html/rfc5228#section-3
*/ */
export class ControlCommand extends GrammarCommand export /*abstract*/ class ControlCommand extends GrammarCommand
{ {
/*
constructor(identifier) constructor(identifier)
{ {
if (this.constructor == ControlCommand) {
throw Error("Abstract class can't be instantiated.");
}
super(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'];
} }
*/
} }
/** /**
* https://tools.ietf.org/html/rfc5228#section-4 * https://tools.ietf.org/html/rfc5228#section-4
*/ */
export class ActionCommand extends GrammarCommand export /*abstract*/ class ActionCommand extends GrammarCommand
{ {
/*
constructor(identifier) constructor(identifier)
{ {
if (this.constructor == ActionCommand) {
throw Error("Abstract class can't be instantiated.");
}
super(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 * https://tools.ietf.org/html/rfc5228#section-5
*/ */
export class TestCommand extends GrammarCommand export /*abstract*/ class TestCommand extends GrammarCommand
{ {
constructor(identifier) constructor(identifier)
{ {
/*
if (this.constructor == TestCommand) {
throw Error("Abstract class can't be instantiated.");
}
*/
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 = '';
@ -324,3 +300,23 @@ GrammarMultiLine.fromString = string => {
} }
return new GrammarMultiLine(); return new GrammarMultiLine();
} }
export class UnknownCommand 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 : ';'
);
}
}

View file

@ -154,12 +154,10 @@ export const parseScript = (script, name = 'script.sieve') => {
pushArgs(); pushArgs();
value = value.toLowerCase(); value = value.toLowerCase();
let new_command; let new_command;
if ('if' === value) { if (Commands[value]) {
new_command = new ConditionalCommand(value); if ('elsif' === value || 'else' === value) {
} else if ('elsif' === value || 'else' === value) {
// (prev_command instanceof ConditionalCommand) || error('Not after IF condition'); // (prev_command instanceof ConditionalCommand) || error('Not after IF condition');
new_command = new ConditionalCommand(value); }
} else if (Commands[value]) {
if ('allof' === value || 'anyof' === value) { if ('allof' === value || 'anyof' === value) {
// (command instanceof ConditionalCommand || command instanceof NotTest) || error('Test-list not in conditional'); // (command instanceof ConditionalCommand || command instanceof NotTest) || error('Test-list not in conditional');
} }

View file

@ -31,3 +31,259 @@ https://www.iana.org/assignments/sieve-extensions/sieve-extensions.xhtml
- [ ] RFC regex https://tools.ietf.org/html/draft-ietf-sieve-regex-01 - [ ] RFC regex https://tools.ietf.org/html/draft-ietf-sieve-regex-01
- [ ] vnd.cyrus.* - [ ] vnd.cyrus.*
- [ ] vnd.dovecot.* - [ ] vnd.dovecot.*
# Classes
## abstract GrammarCommand
identifier = identifier || constructor.name.toLowerCase().replace(/(test|command|action)$/, '');
arguments = []; only initialized at pushArguments()
### abstract ControlCommand extends GrammarCommand
#### IncludeCommand extends ControlCommand
global = false; // ':personal' / ':global';
once = false;
optional = false;
value = new GrammarQuotedString;
#### ReturnCommand extends ControlCommand
no properties
#### GlobalCommand extends ControlCommand
value = new GrammarStringList;
#### ForEveryPartCommand extends ControlCommand
_name = new GrammarString;
commands = new GrammarCommands;
#### ErrorCommand extends ControlCommand
message = new GrammarQuotedString;
#### RequireCommand extends ControlCommand
capabilities = new GrammarStringList();
#### StopCommand extends ControlCommand
no properties
#### abstract ConditionalCommand extends ControlCommand
no properties
#### IfCommand extends ConditionalCommand
test = null; // must be descendent instanceof TestCommand
commands = new GrammarCommands;
#### ElsIfCommand extends IfCommand
test = null; // must be descendent instanceof TestCommand
commands = new GrammarCommands;
#### ElseCommand extends ConditionalCommand
no properties
commands = new GrammarCommands;
### abstract ActionCommand extends GrammarCommand
#### FileIntoCommand extends ActionCommand
_mailbox = new GrammarQuotedString();
copy = false;
create = false;
#### RedirectCommand extends ActionCommand
_address = new GrammarQuotedString();
copy = false;
list = null;
#### KeepCommand extends ActionCommand
no properties
#### DiscardCommand extends ActionCommand
no properties
#### SetCommand extends ActionCommand
modifiers = [];
_name = new GrammarQuotedString;
_value = new GrammarQuotedString;
#### VacationCommand extends ActionCommand
_days = new GrammarNumber;
_seconds = new GrammarNumber;
_subject = new GrammarQuotedString;
_from = new GrammarQuotedString;
addresses = new GrammarStringList;
mime = false;
_handle = new GrammarQuotedString;
_reason = new GrammarQuotedString; // QuotedString / MultiLine
#### SetFlagCommand extends ActionCommand
_variablename = new GrammarQuotedString;
list_of_flags = new GrammarStringList;
#### AddFlagCommand extends ActionCommand
_variablename = new GrammarQuotedString;
list_of_flags = new GrammarStringList;
#### RemoveFlagCommand extends ActionCommand
_variablename = new GrammarQuotedString;
list_of_flags = new GrammarStringList;
#### AddHeaderCommand extends ActionCommand
last = false;
field_name = new GrammarQuotedString;
value = new GrammarQuotedString;
#### DeleteHeaderCommand extends ActionCommand
index = new GrammarNumber;
last = false;
comparator = '',
match_type = ':is',
field_name = new GrammarQuotedString;
value_patterns = new GrammarStringList;
#### ErejectCommand extends ActionCommand
_reason = new GrammarQuotedString;
#### RejectCommand extends ActionCommand
_reason = new GrammarQuotedString;
#### NotifyCommand extends ActionCommand
_method = new GrammarQuotedString;
_from = new GrammarQuotedString;
_importance = new GrammarNumber;
options = new GrammarStringList;
_message = new GrammarQuotedString;
#### ReplaceCommand extends ActionCommand
mime = false;
_subject = new GrammarQuotedString;
_from = new GrammarQuotedString;
replacement = new GrammarQuotedString;
#### EncloseCommand extends ActionCommand
_subject = new GrammarQuotedString;
headers = new GrammarStringList;
#### ExtractTextCommand extends ActionCommand
modifiers = [];
_first = new GrammarNumber;
varname = new GrammarQuotedString;
### abstract TestCommand extends GrammarCommand
#### AddressTest extends TestCommand
address_part = ':all';
header_list = new GrammarStringList;
key_list = new GrammarStringList;
index = new GrammarNumber;
last = false;
// mime
// anychild
#### AllOfTest extends TestCommand
tests = new GrammarTestList;
#### AnyOfTest extends TestCommand
tests = new GrammarTestList;
#### EnvelopeTest extends TestCommand
address_part = ':all';
envelope_part = new GrammarStringList;
key_list = new GrammarStringList;
#### ExistsTest extends TestCommand
header_names = new GrammarStringList;
// mime
// anychild
#### FalseTest extends TestCommand
#### HeaderTest extends TestCommand
address_part = ':all';
header_names = new GrammarStringList;
key_list = new GrammarStringList;
index = new GrammarNumber;
last = false;
mime = false;
anychild = false;
// when ":mime" is used:
type = false;
subtype = false;
contenttype = false;
param = new GrammarStringList;
#### NotTest extends TestCommand
test = new TestCommand;
#### SizeTest extends TestCommand
mode = ':over'; // :under
limit = 0;
#### TrueTest extends TestCommand
#### BodyTest extends TestCommand
body_transform = ''; // :raw, :content <string-list>, :text
key_list = new GrammarStringList;
#### EnvironmentTest extends TestCommand
name = new GrammarQuotedString;
key_list = new GrammarStringList;
#### StringTest extends TestCommand
source = new GrammarStringList;
key_list = new GrammarStringList;
#### HasFlagTest extends TestCommand
variable_list = new GrammarStringList;
list_of_flags = new GrammarStringList;
#### SpamTestTest extends TestCommand
percent = false, // 0 - 100 else 0 - 10
value = new GrammarQuotedString;
#### VirusTestTest extends TestCommand
value = new GrammarQuotedString; // 1 - 5
#### DateTest extends TestCommand
zone = new GrammarQuotedString;
originalzone = false;
header_name = new GrammarQuotedString;
date_part = new GrammarQuotedString;
key_list = new GrammarStringList;
index = new GrammarNumber;
last = false;
#### CurrentDateTest extends TestCommand
zone = new GrammarQuotedString;
date_part = new GrammarQuotedString;
key_list = new GrammarStringList;
#### ValidNotifyMethodTest extends TestCommand
notification_uris = new GrammarStringList;
#### NotifyMethodCapabilityTest extends TestCommand
notification_uri = new GrammarQuotedString;
notification_capability = new GrammarQuotedString;
key_list = new GrammarStringList;
#### IHaveTest extends TestCommand
capabilities = new GrammarStringList;
#### MailboxExistsTest extends TestCommand
mailbox_names = new GrammarStringList;
#### MetadataTest extends TestCommand
mailbox = new GrammarQuotedString;
annotation_name = new GrammarQuotedString;
key_list = new GrammarStringList;
#### MetadataExistsTest extends TestCommand
mailbox = new GrammarQuotedString;
annotation_names = new GrammarStringList;
#### ServerMetadataTest extends TestCommand
annotation_name = new GrammarQuotedString;
key_list = new GrammarStringList;
#### ServerMetadataExistsTest extends TestCommand
annotation_names = new GrammarStringList;
#### ValidExtListTest extends TestCommand
ext_list_names = new GrammarStringList;

View file

@ -22,7 +22,7 @@ export const
koComputable = fn => ko.computed(fn, {'pure':true}), koComputable = fn => ko.computed(fn, {'pure':true}),
arrayToString = (arr, separator) => arrayToString = (arr, separator) =>
arr.map(item => item.toString?.() || item).join(separator), (arr || []).map(item => item.toString?.() || item).join(separator),
/* /*
getNotificationMessage = code => { getNotificationMessage = code => {
let key = getKeyByValue(Notifications, code); let key = getKeyByValue(Notifications, code);
@ -58,6 +58,8 @@ export const
serverErrorDesc(text); serverErrorDesc(text);
}, },
getComparators = () => ['i;ascii-casemap'],
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

View file

@ -645,7 +645,15 @@ class ServiceActions
$aTemplates[$sTemplateName] = $file; $aTemplates[$sTemplateName] = $file;
} }
} }
/*
// if (!$this->GetCapa(Capa::SIEVE, $oAccount)) {
if (!$bAdmin) {
foreach (\glob(APP_VERSION_ROOT_PATH."app/templates/Views/Sieve/*.html") as $file) {
$sTemplateName = 'Sieve' . \basename($file, '.html');
$aTemplates[$sTemplateName] = $file;
}
}
*/
$this->oActions->Plugins()->CompileTemplate($aTemplates, $bAdmin); $this->oActions->Plugins()->CompileTemplate($aTemplates, $bAdmin);
$sHtml = ''; $sHtml = '';

View file

@ -0,0 +1,13 @@
<!-- rfc5228 -->
address
<select name="address_part">
<option>:localpart</option>
<option>:domain</option>
<option>:all</option>
</select>
<textarea name="header_list">GrammarStringList</textarea>
<textarea name="key_list">GrammarStringList</textarea>
<input type="number" name="index">
<input type="checkbox" name="last">
// mime
// anychild

View file

@ -0,0 +1,3 @@
<!-- rfc5228 -->
allof
<div data-bind="template: { name: 'SieveTest', foreach: tests, as: 'test' }"></div>

View file

@ -0,0 +1,3 @@
<!-- rfc5228 -->
anyof
<div data-bind="template: { name: 'SieveTest', foreach: tests, as: 'test' }"></div>

View file

@ -0,0 +1,4 @@
<!-- rfc5173 -->
body
body_transform = ''; // :raw, :content <string-list>, :text
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,5 @@
<!-- rfc5260 -->
currentdate
<input type="text" name="zone">
<input type="text" name="date_part">
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,9 @@
<!-- rfc5260 -->
date
<input type="text" name="zone">
<label><input type="checkbox" name="originalzone"> originalzone</label>
<input type="text" name="header_name">
<input type="text" name="date_part">
<textarea name="key_list">GrammarStringList</textarea>
<input type="number" name="index">
<label><input type="checkbox" name="last"> last</label>

View file

@ -0,0 +1,9 @@
<!-- rfc5228 -->
elsif
<div>
this.test
</div>
{
<div data-bind="template: { name: 'SieveCommand', foreach: commands, as: 'command' }"></div>
}

View file

@ -0,0 +1,5 @@
<!-- rfc5228 -->
else
{
<div data-bind="template: { name: 'SieveCommand', foreach: commands, as: 'command' }"></div>
}

View file

@ -0,0 +1,9 @@
<!-- rfc5228 -->
envelope
<select name="address_part">
<option>:localpart</option>
<option>:domain</option>
<option>:all</option>
</select>
<textarea name="envelope_part">GrammarStringList</textarea>
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,4 @@
<!-- rfc5183 -->
environment
<input type="text" name="name">
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,5 @@
<!-- rfc5228 -->
exists
<textarea name="header_names">GrammarStringList</textarea>
// mime
// anychild

View file

@ -0,0 +1,5 @@
<!-- rfc5228 -->
fileinto
<label data-bind="root.capa.copy"><input type="checkbox"> copy</label><!-- rfc3894 -->
<label data-bind="root.capa.mailbox"><input type="checkbox"> create</label><!-- rfc5490 -->
<input data-bind="mailbox">

View file

@ -0,0 +1,4 @@
<!-- rfc5232 -->
hasflag
<textarea name="variable_list">GrammarStringList</textarea>
<textarea name="list_of_flags">GrammarStringList</textarea>

View file

@ -0,0 +1,18 @@
<!-- rfc5228 -->
header
<select name="address_part">
<option>:localpart</option>
<option>:domain</option>
<option>:all</option>
</select>
<textarea name="header_names">GrammarStringList</textarea>
<textarea name="key_list">GrammarStringList</textarea>
<input type="number" name="index">
<input type="checkbox" name="last">
<input type="checkbox" name="mime">
<input type="checkbox" name="anychild">
<!-- when ":mime" is used: -->
<input type="checkbox" name="type">
<input type="checkbox" name="subtype">
<input type="checkbox" name="contenttype">
<textarea name="param">GrammarStringList</textarea>

View file

@ -0,0 +1,3 @@
<!-- rfc5463 -->
ihave
<textarea name="capabilities">GrammarStringList</textarea>

View file

@ -0,0 +1,8 @@
<!-- rfc5228 -->
if
<div>
this.test
</div>
{
<div data-bind="template: { name: 'SieveCommand', foreach: commands, as: 'command' }"></div>
}

View file

@ -0,0 +1,3 @@
<!-- rfc5490 -->
mailboxexists
<textarea name="mailbox_names">GrammarStringList</textarea>

View file

@ -0,0 +1,4 @@
<!-- rfc5490 -->
metadataexists
<input type="text" name="mailbox">
<textarea name="annotation_names">GrammarStringList</textarea>

View file

@ -0,0 +1,5 @@
<!-- rfc5490 -->
metadata
<input type="text" name="mailbox">
<input type="text" name="annotation_name">
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,3 @@
<!-- rfc5228 -->
not
<div data-bind="template: { name: 'SieveTest', as: 'test' }"></div>

View file

@ -0,0 +1,5 @@
<!-- rfc5435 -->
notifymethodcapability
<input type="text" name="notification_uri">
<input type="text" name="notification_capability">
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,5 @@
<!-- rfc5228 -->
redirect
<label data-bind="root.capa.copy"><input type="checkbox"> copy</label><!-- rfc3894 -->
<label data-bind="root.capa.extlists">list<!-- rfc6134 -->
<input data-bind="address">

View file

@ -0,0 +1,3 @@
<!-- rfc5490 -->
servermetadataexists
<textarea name="annotation_names">GrammarStringList</textarea>

View file

@ -0,0 +1,4 @@
<!-- rfc5490 -->
servermetadata
<input type="text" name="annotation_name">
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,7 @@
<!-- rfc5228 -->
size
<select name="mode">
<option>:over</option>
<option>:under</option>
</select>
<input type="number" name="limit">

View file

@ -0,0 +1,4 @@
<!-- rfc5235 -->
spamtest
<input type="number" name="percent">
<input type="text" name="value">

View file

@ -0,0 +1,4 @@
<!-- rfc5229 -->
string
<textarea name="source">GrammarStringList</textarea>
<textarea name="key_list">GrammarStringList</textarea>

View file

@ -0,0 +1,3 @@
<!-- rfc6134 -->
validextlist
<textarea name="ext_list_names">GrammarStringList</textarea>

View file

@ -0,0 +1,3 @@
<!-- rfc5435 -->
validnotifymethod
<textarea name="notification_uris">GrammarStringList</textarea>

View file

@ -0,0 +1,3 @@
<!-- rfc5235 -->
virustest
<input type="text" name="value"> // 1 - 5