Skip to content

Commit

Permalink
Implement RFC 8580: Sieve Extension: File Carbon Copy (FCC)
Browse files Browse the repository at this point in the history
Fixes #60.
  • Loading branch information
dburkart committed Apr 3, 2024
1 parent 65be91b commit 610be98
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/AST/ASTVerificationVisitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,15 @@ void ASTVerificationVisitor::_enable_capability(std::string_view capability) {
_test_map["valid_ext_list"] = true;
}

// Proposed Standards

// "fcc"
// RFC 8580
// https://www.rfc-editor.org/rfc/rfc8580.html
if (capability == "fcc") {
_tag_map[":fcc"] = true;
}

// DRAFT RFCs

// "regex"
Expand Down
12 changes: 10 additions & 2 deletions src/AST/Validation/Command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Command::Command() {
_usage_map["global"] = "global <value: string-list>";
_usage_map["include"] = "include [:global / :personal] [:once] [:optional] <value: string>";
_usage_map["keep"] = "keep [:flags <list-of-flags: string-list>]";
_usage_map["notify"] = "notify [:from string] [:importance <1 / 2 / 3>] [:options string-list] [:message string] <method: string>";
_usage_map["notify"] = "notify [:from string] [:importance <1 / 2 / 3>]\n\t[:options string-list] [:message string] [:fcc string] <method: string>";
_usage_map["redirect"] = "redirect [:copy / :list] <address: string>";
_usage_map["reject"] = "reject <reason: string>";
_usage_map["removeflag"] = "removeflag [<variablename: string>] <list-of-flags: string-list>";
Expand All @@ -42,7 +42,7 @@ Command::Command() {
_usage_map["setflag"] = "setflag [<variablename: string>] <list-of-flags: string-list>";
_usage_map["stop"] = "stop";
_usage_map["unexpire"] = "unexpire";
_usage_map["vacation"] = "vacation [:days number] [:subject string] [:from string]\n\t[:addresses string-list] [:mime] [:handle string] <reason: string>";
_usage_map["vacation"] = "vacation [:days number] [:subject string] [:from string]\n\t[:addresses string-list] [:mime] [:handle string]\n\t[:fcc string] <reason: string>";

_validation_fn_map["addflag"] = &Command::_validateIMAP4FlagsAction;
_validation_fn_map["addheader"] = &Command::_validateAddHeadersCommand;
Expand Down Expand Up @@ -411,6 +411,10 @@ bool Command::_validateVacationCommand(const ASTNode *node) {
if (command->find(ASTTag(":handle")) != command->children().end()) {
numArguments += 2;
}

if (command->find(ASTTag(":fcc")) != command->children().end()) {
numArguments += 2;
}

if (size != numArguments) {
return false;
Expand Down Expand Up @@ -527,6 +531,10 @@ bool Command::_validateNotifyCommand(const ASTNode *node) {
if (command->find(ASTTag(":message")) != command->children().end()) {
numArguments += 2;
}

if (command->find(ASTTag(":fcc")) != command->children().end()) {
numArguments += 2;
}

if (size != numArguments)
return false;
Expand Down
2 changes: 2 additions & 0 deletions src/AST/Validation/Tag.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ Tag::Tag() {
_usage_map[":subject"] = ":subject string";
_usage_map[":eval"] = ":eval string";
_usage_map[":list"] = ":list string";
_usage_map[":fcc"] = ":fcc <mailbox: string>";

_validation_fn_map[":comparator"] = &Tag::_validateSingleString; // TODO: Validate comparator string
_validation_fn_map[":days"] = &Tag::_validateSingleNumeric;
_validation_fn_map[":subject"] = &Tag::_validateSingleString;
_validation_fn_map[":eval"] = &Tag::_validateSingleString;
_validation_fn_map[":list"] = &Tag::_validateList;
_validation_fn_map[":fcc"] = &Tag::_validateSingleString;
}

bool Tag::validate(const ASTNode *node) {
Expand Down
Empty file added test/8580/__init__.py
Empty file.
57 changes: 57 additions & 0 deletions test/8580/examples_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import unittest
import checksieve

class TestExamples(unittest.TestCase):

def test_example_1(self):
sieve = '''
require ["vacation", "fcc", "mailbox", "imap4flags"];
vacation :days 7
:from "[email protected]" "Gone Fishin'"
:fcc "INBOX.Sent";
'''
self.assertFalse(checksieve.parse_string(sieve, False))

def test_example_2(self):
sieve = '''
require ["enotify", "fcc"];
notify :fcc "INBOX.Sent"
:message "You got mail!"
"mailto:[email protected]";
'''
self.assertFalse(checksieve.parse_string(sieve, False))

def test_example_3(self):
sieve = '''
require ["enotify", "fcc"];
if notify_method_capability "xmpp:" "fcc" "yes" {
notify :fcc "INBOX.Sent"
:message "You got mail"
"xmpp:[email protected]?message;subject=SIEVE";
} else {
notify :fcc "INBOX.Sent"
:message "You got mail!"
"mailto:[email protected]";
}
'''
self.assertFalse(checksieve.parse_string(sieve, False))

def test_no_reject(self):
sieve = '''
require ["reject", "fcc"];
if size :over 100K {
reject :fcc "foo" text:
Your message is too big. If you want to send me a big attachment,
put it on a public web site and send me a URL.
.
;
}
'''
self.assertTrue(checksieve.parse_string(sieve, True))

0 comments on commit 610be98

Please sign in to comment.