Skip to content

Commit 0bc5373

Browse files
added reject command and multiline strings
1 parent a01d0d1 commit 0bc5373

File tree

10 files changed

+68
-10
lines changed

10 files changed

+68
-10
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ FEATURES
1818

1919
- Supports all of the base Sieve spec from RFC 5228, except for
2020
features still listed under TODO below
21+
- multiline strings (since version 0.2.2)
2122
- Extensions supported:
2223
- regex (draft-ietf-sieve-regex-01)
2324
- body (RFC 5173)

docs/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ FEATURES
99

1010
- Supports all of the base Sieve spec from RFC 5228, except for
1111
features still listed under TODO below
12+
13+
- multiline strings (since version 0.2.2)
14+
1215
- Extensions supported:
1316

1417
- regex (draft-ietf-sieve-regex-01)
@@ -73,7 +76,6 @@ TODO
7376
- Base spec features not yet implemented:
7477

7578
- encoded characters (section 2.4.2.4)
76-
- multi-line strings (section 2.4.2)
7779
- bracketed comments (section 2.3)
7880
- message uniqueness (section 2.10.3)
7981
- envelope test (section 5.4)

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name="sifter3",
13-
version="0.2.1",
13+
version="0.2.2",
1414
author="Manfred Kaiser, Gary Peck",
1515
1616
url="https://sifter3.readthedocs.io/en/latest/",
@@ -60,6 +60,7 @@
6060
'keep = sifter.commands.keep:CommandKeep',
6161
'notify = sifter.commands.notify:CommandNotify',
6262
'redirect = sifter.commands.redirect:CommandRedirect',
63+
'reject = sifter.commands.reject:CommandReject',
6364
'require = sifter.commands.require:CommandRequire',
6465
'set = sifter.commands.variables:CommandSet',
6566
'stop = sifter.commands.stop:CommandStop',

sifter/commands/reject.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from email.message import Message
2+
from typing import (
3+
Text,
4+
Optional
5+
)
6+
7+
from sifter.grammar.command import Command
8+
from sifter.validators.stringlist import StringList
9+
from sifter.grammar.state import EvaluationState
10+
from sifter.grammar.actions import Actions
11+
12+
13+
# section 3.2
14+
class CommandReject(Command):
15+
16+
RULE_IDENTIFIER: Text = 'REJECT'
17+
POSITIONAL_ARGS = [StringList()]
18+
19+
def evaluate(self, message: Message, state: EvaluationState) -> Optional[Actions]:
20+
print(self.positional_args[0][0])
21+
state.actions.append('reject', self.positional_args[0][0])
22+
state.actions.cancel_implicit_keep()
23+
return None

sifter/extensions/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ class ExtensionRegistry():
3434
]
3535
] = {}
3636
DEFAULT_EXTENSION: List[Text] = [
37-
'regex',
37+
'body',
3838
'comparator-i;ascii-casemap',
3939
'comparator-i;octet',
40+
'enotify',
4041
'fileinto',
41-
'body'
42+
'imap4flags',
43+
'regex',
44+
'reject',
4245
'variables',
43-
'enotify',
44-
'imap4flags'
4546
]
4647

4748
def __init__(self) -> None:

sifter/grammar/grammar.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(self, debug: bool = False) -> None:
3232
def make_parser(mod: Any, debug: bool = False) -> 'LRParser':
3333
return yacc(
3434
module=mod,
35-
debug=debug,
35+
debug=True,
3636
write_tables=False,
3737
errorlog=NullLogger() if not debug else None
3838
)
@@ -167,6 +167,10 @@ def p_argument_tag(self, p: 'YaccProduction') -> None:
167167
"""argument : TAG"""
168168
p[0] = Tag(p[1])
169169

170+
def p_argument_multiline_string(self, p: 'YaccProduction') -> None:
171+
"""argument : MULTILINE_STRING"""
172+
p[0] = [p[1]]
173+
170174
def p_stringlist_error(self, p: 'YaccProduction') -> None:
171175
"""argument : '[' error ']'"""
172176
print("Syntax error in string list that starts on line %d" % p.lineno(1))
@@ -186,4 +190,9 @@ def p_string(self, p: 'YaccProduction') -> None:
186190
p[0] = String(p[1])
187191

188192
def p_error(self, p: 'YaccProduction') -> None:
189-
pass
193+
if p is None:
194+
token = "end of file"
195+
else:
196+
token = f"{p.type}({p.value}) on line {p.lineno}"
197+
198+
print(f"Syntax error: Unexpected {token}")

sifter/grammar/lexer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def t_BRACKET_COMMENT(self, t: 'LexToken') -> Optional['LexToken']:
5454

5555
# section 2.4.2
5656
def t_MULTILINE_STRING(self, t: 'LexToken') -> Optional['LexToken']:
57-
r'"@@@@@@@@@@@@@@@"'
57+
r'text:\s?(?:\#.*)\r?\n(?P<multilinetext>[\r\n\S\s.]*?\r?\n)\.\r?\n'
5858
# TODO: For entering larger amounts of text, such as an email message,
5959
# a multi-line form is allowed. It starts with the keyword "text:",
6060
# followed by a CRLF, and ends with the sequence of a CRLF, a single
@@ -68,7 +68,8 @@ def t_MULTILINE_STRING(self, t: 'LexToken') -> Optional['LexToken']:
6868
# that is, ".foo" is interpreted as ".foo". However, because this is
6969
# potentially ambiguous, scripts SHOULD be properly dot-stuffed so such
7070
# lines do not appear.
71-
return None
71+
t.value = t.lexer.lexmatch.group('multilinetext')
72+
return t
7273

7374
# section 2.4.2
7475
def t_QUOTED_STRING(self, t: 'LexToken') -> Optional['LexToken']:

tests/evaluation_4.rules

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
require "reject";
2+
3+
if header "from" "[email protected]"
4+
{
5+
reject "I do not accept messages from this address."
6+
;
7+
}

tests/evaluation_5.rules

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require "reject";
2+
3+
if header "from" "[email protected]"
4+
{
5+
reject text: # testcomment
6+
I do not accept messages from
7+
this address.
8+
..
9+
.
10+
;
11+
}

tests/test_evaluation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def test_evaulation():
2424
("evaluation_3.msg", "evaluation_1.rules", [('redirect', '[email protected]')]),
2525
("evaluation_3.msg", "evaluation_2.rules", [('fileinto', ['INBOX'])]),
2626
("evaluation_3.msg", "evaluation_3.rules", [('keep', None)]),
27+
("evaluation_1.msg", "evaluation_4.rules", [('reject', 'I do not accept messages from this address.')]),
28+
("evaluation_1.msg", "evaluation_5.rules", [('reject', 'I do not accept messages from\nthis address.\n..\n')]),
2729
)
2830

2931
for messagefile, rulefile, evaluated_rules in EVAL_RESULTS:

0 commit comments

Comments
 (0)