From 345703f39d34fe5e33ea28c0072c672edb873e2d Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Tue, 18 Dec 2007 15:11:24 +0100 Subject: [PATCH] Started skeleton for the body extension. --- README | 3 +- configure.in | 1 + src/lib-sieve/Makefile.am | 3 +- src/lib-sieve/plugins/Makefile.am | 2 +- src/lib-sieve/plugins/body/Makefile.am | 12 + .../plugins/body/draft-ietf-sieve-body-07.txt | 679 ++++++++++++++++++ src/lib-sieve/plugins/body/ext-body.c | 266 +++++++ 7 files changed, 963 insertions(+), 3 deletions(-) create mode 100644 src/lib-sieve/plugins/body/Makefile.am create mode 100644 src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt create mode 100644 src/lib-sieve/plugins/body/ext-body.c diff --git a/README b/README index efd4d7b5f..9d181feb5 100644 --- a/README +++ b/README @@ -130,7 +130,7 @@ Extensions and their implementation status: vacation: almost complete, but no support for required References header imapflags: flag management works, but flags are not stored include: full, but needs much more work - body: planned + body: skeleton variables: planned (* also amend previously implemented extensions) notify: planned, mailto only (- very low priority) @@ -194,6 +194,7 @@ Current: * Implement body extension Next (in order of descending priority/precedence): +* Implement encoded-character extension * Implement variables extension. * Finish implementing all extensions supported by cmusieve, except notify. * Limit the maximum number of errors. diff --git a/configure.in b/configure.in index 8893991bf..a07703a09 100644 --- a/configure.in +++ b/configure.in @@ -67,6 +67,7 @@ src/lib-sieve/plugins/regex/Makefile src/lib-sieve/plugins/imapflags/Makefile src/lib-sieve/plugins/copy/Makefile src/lib-sieve/plugins/include/Makefile +src/lib-sieve/plugins/body/Makefile src/plugins/Makefile src/plugins/lda-sieve/Makefile src/sieve-bin/Makefile diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index 3bab6db66..fed8d7557 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -38,7 +38,8 @@ plugins = \ ./plugins/regex/libsieve_ext_regex.la \ ./plugins/copy/libsieve_ext_copy.la \ ./plugins/imapflags/libsieve_ext_imapflags.la \ - ./plugins/include/libsieve_ext_include.la + ./plugins/include/libsieve_ext_include.la \ + ./plugins/body/libsieve_ext_body.la libsieve_la_DEPENDENCIES = $(plugins) libsieve_la_LIBADD = $(plugins) diff --git a/src/lib-sieve/plugins/Makefile.am b/src/lib-sieve/plugins/Makefile.am index 5c11f0316..da2823df3 100644 --- a/src/lib-sieve/plugins/Makefile.am +++ b/src/lib-sieve/plugins/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = vacation subaddress comparator-i-ascii-numeric relational regex imapflags copy include +SUBDIRS = vacation subaddress comparator-i-ascii-numeric relational regex imapflags copy include body diff --git a/src/lib-sieve/plugins/body/Makefile.am b/src/lib-sieve/plugins/body/Makefile.am new file mode 100644 index 000000000..8077860de --- /dev/null +++ b/src/lib-sieve/plugins/body/Makefile.am @@ -0,0 +1,12 @@ +noinst_LTLIBRARIES = libsieve_ext_body.la + +AM_CPPFLAGS = \ + -I../../ \ + -I$(dovecot_incdir) \ + -I$(dovecot_incdir)/src/lib \ + -I$(dovecot_incdir)/src/lib-mail \ + -I$(dovecot_incdir)/src/lib-storage + +libsieve_ext_body_la_SOURCES = \ + ext-body.c + diff --git a/src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt b/src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt new file mode 100644 index 000000000..7a038ca29 --- /dev/null +++ b/src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt @@ -0,0 +1,679 @@ + +Network Working Group Jutta Degener +Internet Draft Philip Guenther +Intended status: Standards Track Sendmail, Inc. +Expires: December 2007 June 2008 +Updates: RFC-ietf-sieve-variables-08 + + + Sieve Email Filtering: Body Extension + draft-ietf-sieve-body-07.txt + + +Status of this memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as + Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six + months and may be updated, replaced, or obsoleted by other + documents at any time. It is inappropriate to use Internet- + Drafts as reference material or to cite them other than as + "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/1id-abstracts.html + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + +Abstract + + This document defines a new command for the "Sieve" email + filtering language that tests for the occurrence of one or more + strings in the body of an email message. + + + + + + + + + + + + +Degener & Guenther Standards Track [Page 1] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +1. Introduction + + The "body" test checks for the occurrence of one + or more strings in the body of an email message. + Such a test was initially discussed for the [SIEVE] base + document, but was subsequently removed because it was + thought to be too costly to implement. + + Nevertheless, several server vendors have implemented + some form of the "body" test. + + This document reintroduces the "body" test as an extension, + and specifies its syntax and semantics. + + +2. Conventions used. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + + Conventions for notations are as in [SIEVE] section 1.1, including + use of the "Usage:" label for the definition of text and tagged + arguments syntax. + + The capability string associated with the extension defined in + this document is "body". + + +3. Test body + + Usage: "body" [COMPARATOR] [MATCH-TYPE] [BODY-TRANSFORM] + <key-list: string-list> + + The body test matches content in the body of an email message, + that is, anything following the first empty line after the header. + (The empty line itself, if present, is not considered to be part + of the body.) + + The COMPARATOR and MATCH-TYPE keyword parameters are defined + in [SIEVE]. The BODY-TRANSFORM is a keyword parameter + discussed in section 4, below. + + If a message consists of a header only, not followed by an empty + line, all "body" tests return false, including that for an empty + string. + + + + + +Degener & Guenther Standards Track [Page 2] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + + If a message consists of a header followed only by an empty + line with no body lines following it, the message is considered + to have an empty string as a body. + + +4. Body Transform + + Prior to matching content in a message body, "transformations" + can be applied that filter and decode certain parts of the body. + These transformations are selected by a "BODY-TRANSFORM" + keyword parameter. + + Usage: ":raw" + / ":content" <content-types: string-list> + / ":text" + + The default transformation is :text. + + +4.1 Body Transform ":raw" + + The ":raw" transform is intended to match against the undecoded + body of a message. + + If the specified body-transform is ":raw", the [MIME] structure + of the body is irrelevant. The implementation MUST NOT remove + any transfer encoding from the message, MUST NOT refuse to filter + messages with syntactic errors (unless the environment it is + part of rejects them outright), and MUST treat multipart boundaries + or the MIME headers of enclosed body parts as part of the content + being matched against instead of MIME structures to interpret. + + Example: + + require "body"; + + # This will match a message containing the literal text + # "MAKE MONEY FAST" in body parts (ignoring any + # content-transfer-encodings) or MIME headers other than + # the outermost RFC 2822 header. + + if body :raw :contains "MAKE MONEY FAST" { + discard; + } + + + + + + + +Degener & Guenther Standards Track [Page 3] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +4.2 Body Transform ":content" + + If the body transform is ":content", only MIME parts that have + the specified content-types are selected for matching. + + If an individual content type begins or ends with a '/' (slash) + or contains multiple slashes, it matches no content types. + Otherwise, if it contains a slash, then it specifies a full + <type>/<subtype> pair, and matches only that specific content + type. If it is the empty string, all MIME content types are + matched. Otherwise, it specifies a <type> only, and any subtype + of that type matches it. + + The search for MIME parts matching the :content specification + is recursive and automatically descends into multipart and + message/rfc822 MIME parts. All MIME parts with matching types + are searched for the key strings. The test returns true if any + combination of searched MIME part and key-list argument match. + + If the :content specification matches a multipart MIME part, + only the prologue and epilogue sections of the part will be + searched for the key strings; the contents of nested parts are + only searched if their respective types match the :content + specification. + + If the :content specification matches a message/rfc822 MIME part, + only the header of the nested message will be searched for the + key strings; the contents of the nested message body parts are + only searched if its content-type matches the :content specification. + + (Matches against container types with an empty match string can + be useful as tests for the existence of such parts.) + + + + + + + + + + + + + + + + + + + +Degener & Guenther Standards Track [Page 4] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + + Example: + From: Whomever + To: Someone + Date: Whenever + Subject: whatever + Content-Type: multipart/mixed; boundary=outer + + & This is a multi-part message in MIME format. + & + --outer + Content-Type: multipart/alternative; boundary=inner + + & This is a nested multi-part message in MIME format. + & + --inner + Content-Type: text/plain; charset="us-ascii" + + $ Hello + $ + --inner + Content-Type: text/html; charset="us-ascii" + + % <html><body>Hello</body></html> + % + --inner-- + & + & This is the end of the inner MIME multipart. + & + --outer + Content-Type: message/rfc822 + + ! From: Someone Else + ! Subject: hello request + + $ Please say Hello + $ + --outer-- + & + & This is the end of the outer MIME multipart. + + + In the above example, the '&', '$', '%', and '!' characters at + the start of a line are used to illustrate what portions of the + example message are used in tests: + + - the lines starting with '&' are the ones that are tested when + a 'body :content "multipart" :contains "MIME"' + test is executed. + + + +Degener & Guenther Standards Track [Page 5] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + + - the lines starting with '$' are the ones that are tested when + a 'body :content "text/plain" :contains "Hello"' test is + executed. + + - the lines starting with '%' are the ones that are tested when + a 'body :content "text/html" :contains "Hello"' test is executed. + + - the lines starting with '$' or '%' are the ones that are tested + when a 'body :content "text" :contains "Hello"' test is executed. + + - the lines starting with '!' are the ones that are tested when + a 'body :content "message/rfc822" :contains "Hello"' test is + executed. + + Comparisons are performed on octets. Implementations decode + the content-transfer-encoding and convert text to [UTF-8] as + input to the comparator. MIME parts that cannot be decoded and + converted MAY be treated as plain US-ASCII, omitted, or processed + according to local conventions. A NUL octet (character zero) + SHOULD NOT cause early termination of the content being compared + against. Implementations MUST support the "quoted-printable", + "base64", "7bit", "8bit", and "binary" content transfer encodings. + Implementations MUST be capable of converting to UTF-8 the + US-ASCII, ISO-8859-1, and the US-ASCII subset of + ISO-8859-* character sets. + + Search expressions MUST NOT match across MIME part boundaries. + MIME headers of the containing part MUST NOT be included in the + data. + + Example: + require ["body", "fileinto"]; + + # Save any message with any text MIME part that contains the + # words "missile" or "coordinates" in the "secrets" folder. + + if body :content "text" :contains ["missile", "coordinates"] { + fileinto "secrets"; + } + + # Save any message with an audio/mp3 MIME part in + # the "jukebox" folder. + + if body :content "audio/mp3" :contains "" { + fileinto "jukebox"; + } + + + + + +Degener & Guenther Standards Track [Page 6] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +4.3 Body Transform ":text" + + The ":text" body transform matches against the results of + an implementation's best effort at extracting UTF-8 encoded + text from a message. + + In simple implementations, :text MAY be treated the same + as :content "text". + + Sophisticated implementations MAY strip mark-up from the text + prior to matching, and MAY convert media types other than text + to text prior to matching. + + (For example, they may be able to convert proprietary text + editor formats to text or apply optical character recognition + algorithms to image data.) + + Example: + require ["body", "fileinto"]; + + # Save messages mentioning the project schedule in the + # project/schedule folder. + if body :text :contains "project schedule" { + fileinto "project/schedule"; + } + + +5. Interaction with Other Sieve Extensions + + Any extension that extends the grammar for the COMPARATOR or + MATCH-TYPE nonterminals will also affect the implementation of + "body". + + Wildcard expressions used with "body" are exempt from the side + effects described in [VARIABLES]. That is, they MUST NOT set + match variables (${1}, ${2}...) to the input values corresponding + to wild card sequences in the matched pattern. However, if the + extension is present, variable references in the key strings or + content type strings are evaluated as described in the draft. + + + + + + + + + + + + +Degener & Guenther Standards Track [Page 7] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +6. IANA Considerations + + The following template specifies the IANA registration of the Sieve + extension specified in this document: + + To: iana@iana.org + Subject: Registration of new Sieve extension + + Capability name: body + Description: adds the 'body' test for matching against the + the body of the message being processed + RFC number: this RFC + Contact Address: Jutta Degener <jutta@pobox.com> + + This information should be added to the list of sieve extensions + given on http://www.iana.org/assignments/sieve-extensions. + + +7. Security Considerations + + The system MUST be sized and restricted in such a manner that + even malicious use of body matching does not deny service to + other users of the host system. + + Filters relying on string matches in the raw body of an email + message may be more general than intended. Text matches are no + replacement for a spam, virus, or other security related + filtering system. + + +8. Acknowledgments + + This document has been revised in part based on comments and + discussions that took place on and off the SIEVE mailing list. + Thanks to Cyrus Daboo, Ned Freed, Bob Johannessen, Simon Josefsson, + Mark E. Mallett, Chris Markle, Alexey Melnikov, Ken Murchison, + Greg Shapiro, Tim Showalter, Nigel Swinson, and Dowson Tong for + reviews and suggestions. + + + + + + + + + + + + + +Degener & Guenther Standards Track [Page 8] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +9. Authors' Addresses + + Jutta Degener + 5245 College Ave, Suite #127 + Oakland, CA 94618 + + Email: jutta@pobox.com + + Philip Guenther + Sendmail, Inc. + 6425 Christie Ave, 4th Floor + Emeryville, CA 94608 + + Email: guenther@sendmail.com + + +10. Discussion + + This section will be removed when this document leaves the + Internet-Draft stage. + + This draft is intended as an extension to the Sieve mail filtering + language. Sieve extensions are discussed on the MTA Filters mailing + list at <ietf-mta-filters@imc.org>. Subscription requests can + be sent to <ietf-mta-filters-request@imc.org> (send an email + message with the word "subscribe" in the body). + + More information on the mailing list along with a WWW archive of + back messages is available at <http://www.imc.org/ietf-mta-filters/>. + + +10.1 Changes from draft-ietf-sieve-body-06.txt + + Changed "matched text" to "matched content". Drop the word + "proposed". + + +10.2 Changes from draft-ietf-sieve-body-05.txt + + Updated boilerplate to match RFC 4748. + + Added "Intended-Status: Standards Track" and + "Updates: draft-ietf-sieve-variables-08" + + Change the references from appendices to sections. + Update [SIEVE] reference. + + + + + +Degener & Guenther Standards Track [Page 9] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +10.3 Changes from draft-ietf-sieve-body-04.txt + + Changed 'reject' to 'discard' in the example. + + Removed reference to regex draft. + + Update copyright boilerplate. + + +10.4 Changes from draft-ietf-sieve-body-03.txt + + Update IANA registration to match 3028bis. + + Added direct boilerplate for [KEYWORDS]. + + +10.5 Changes from draft-ietf-sieve-body-02.txt + + Updated charset conversion to match draft-ietf-sieve-3028bis-06.txt. + + Change "Syntax:" to "Usage:". + + Updated references. + + +10.6 Changes from draft-ietf-sieve-body-01.txt + + Updated charset conversion requirements to match those in + draft-ietf-sieve-3028bis-03.txt for headers. + + +10.7 Changes from draft-ietf-sieve-body-00.txt + + Updated IPR boilerplate to RFC 3978/3979. + + Many prose corrections in response to WGLC comments. Of particular + note: + - made clear that :raw treats MIME boundaries and headers as + text to be matched against + - corrected description in comment of :raw example + - clarified the interpretation of invalid content-types in + :content + - gave precise description of what gets matched when :content + is used with message/rfc822 or any multipart type, as well + as a comprehensive example + - include an example of :text + - tightened wording of interaction with [VARIABLES] + - added informative reference to [REGEX] + + + +Degener & Guenther Standards Track [Page 10] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +10.8 Changes from draft-degener-sieve-body-04.txt + + Renamed to draft-ietf-sieve-body-00.txt; tweaked the title and + abstract. + + Added Philip Guenther as co-author. + + Split references into normative and informative. Updated [UTF-8] + and [VARIABLES] references. + + Updated IPR boilerplate. + + +10.9 Changes from draft-degener-sieve-body-03.txt + + Made "body" exempt from variable-setting side effects in the + presence of the "variables" extension and wild cards. It's too + hard to implement. + + Removed :binary. It's uglier and less useful than it needs to be + to bother. + + Added IANA section. + + +11. Normative References + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 15, RFC 2119, March 1997. + + [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [SIEVE] Guenther, P. and T. Showalter, "Sieve: A Mail Filtering + Language", draft-ietf-sieve-3028bis-13, October 2007. + + [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 3629, November 2003. + + +12. Informative References + + [VARIABLES] Homme, K. T., "Sieve Extension: Variables", + draft-ietf-sieve-variables-08.txt, December 2005. + + + + + + +Degener & Guenther Standards Track [Page 11] + +Internet-Draft Sieve Email Filtering: Body Extension December 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the IETF + Administrative Support Activity (IASA). + + + + + + + +Degener & Guenther Standards Track [Page 12] + + +------- End of Forwarded Message + + diff --git a/src/lib-sieve/plugins/body/ext-body.c b/src/lib-sieve/plugins/body/ext-body.c new file mode 100644 index 000000000..d99b2daa3 --- /dev/null +++ b/src/lib-sieve/plugins/body/ext-body.c @@ -0,0 +1,266 @@ +/* Extension body + * ------------------ + * + * Authors: Stephan Bosch + * Specification: draft-ietf-sieve-body-07 + * Implementation: skeleton + * Status: under development + * + */ + +#include <stdio.h> + +#include "lib.h" +#include "array.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-address-parts.h" + +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-code-dumper.h" + +/* Forward declarations */ + +static bool ext_body_load(int ext_id); +static bool ext_body_validator_load(struct sieve_validator *validator); + +static bool ext_body_opcode_dump + (const struct sieve_opcode *opcode, + const struct sieve_dumptime_env *denv, sieve_size_t *address); +static bool ext_body_opcode_execute + (const struct sieve_opcode *opcode, + const struct sieve_runtime_env *renv, sieve_size_t *address); + +static bool tst_body_registered + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); +static bool tst_body_validate + (struct sieve_validator *validator, struct sieve_command_context *tst); +static bool tst_body_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx); + +/* Extension definitions */ + +static int ext_my_id; + +const struct sieve_opcode body_opcode; + +const struct sieve_extension body_extension = { + "body", + ext_body_load, + ext_body_validator_load, + NULL, NULL, NULL, + SIEVE_EXT_DEFINE_OPCODE(body_opcode), + NULL +}; + +static bool ext_body_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} + +/* body test + * + * Syntax + * body [COMPARATOR] [MATCH-TYPE] [BODY-TRANSFORM] + * <key-list: string-list> + */ +static const struct sieve_command body_test = { + "body", + SCT_TEST, + 2, 0, FALSE, FALSE, + tst_body_registered, + NULL, + tst_body_validate, + tst_body_generate, + NULL +}; + +/* body opcode */ + +const struct sieve_opcode body_opcode = { + "body", + SIEVE_OPCODE_CUSTOM, + &body_extension, + 0, + ext_body_opcode_dump, + ext_body_opcode_execute +}; + +/* Command Registration */ +static bool tst_body_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) +{ + /* The order of these is not significant */ + sieve_comparators_link_tag(validator, cmd_reg, SIEVE_AM_OPT_COMPARATOR); + sieve_match_types_link_tags(validator, cmd_reg, SIEVE_AM_OPT_MATCH_TYPE); + + return TRUE; +} + +/* + * Validation + */ + +static bool tst_body_validate(struct sieve_validator *validator, struct sieve_command_context *tst) +{ + struct sieve_ast_argument *arg = tst->first_positional; + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "body part", 1, SAAT_STRING_LIST) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, arg); + + arg = sieve_ast_argument_next(arg); + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, arg); + + /* Validate the key argument to a specified match type */ + sieve_match_type_validate(validator, tst, arg); + + return TRUE; +} + +/* Load extension into validator */ +static bool ext_body_validator_load(struct sieve_validator *validator) +{ + /* Register new test */ + sieve_validator_register_command(validator, &body_test); + + return TRUE; +} + +/* + * Generation + */ + +static bool tst_body_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx) +{ + (void)sieve_generator_emit_opcode_ext + (generator, &body_opcode, ext_my_id); + + /* Generate arguments */ + if ( !sieve_generate_arguments(generator, ctx, NULL) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool ext_body_opcode_dump +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_code_dumpf(denv, "body"); + sieve_code_descend(denv); + + /* Handle any optional arguments */ + if ( !sieve_addrmatch_default_dump_optionals(denv, address) ) + return FALSE; + + return + sieve_opr_stringlist_dump(denv, address) && + sieve_opr_stringlist_dump(denv, address); +} + +static int ext_body_get_fields +(const struct sieve_message_data *msgdata, const char *field, + const char *const **value_r) +{ + const char *value; + ARRAY_DEFINE(body_values, const char *); + + p_array_init(&body_values, pool_datastack_create(), 2); + + if ( strncmp(field, "from", 4) == 0 ) + value = msgdata->return_path; + else if ( strncmp(field, "to", 2) == 0 ) + value = msgdata->to_address; + else if ( strncmp(field, "auth", 2) == 0 ) /* Non-standard */ + value = msgdata->auth_user; + + if ( value != NULL ) + array_append(&body_values, &value, 1); + + (void)array_append_space(&body_values); + *value_r = array_idx(&body_values, 0); + + return 0; +} + +static bool ext_body_opcode_execute +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + bool result = TRUE; + const struct sieve_comparator *cmp = &i_octet_comparator; + const struct sieve_match_type *mtch = &is_match_type; + const struct sieve_address_part *addrp = &all_address_part; + struct sieve_match_context *mctx; + struct sieve_coded_stringlist *hdr_list; + struct sieve_coded_stringlist *key_list; + string_t *hdr_item; + bool matched; + + printf("?? BODY\n"); + + if ( !sieve_addrmatch_default_get_optionals + (renv->sbin, address, &addrp, &mtch, &cmp) ) + return FALSE; + + t_push(); + + /* Read header-list */ + if ( (hdr_list=sieve_opr_stringlist_read(renv->sbin, address)) == NULL ) { + t_pop(); + return FALSE; + } + + /* Read key-list */ + if ( (key_list=sieve_opr_stringlist_read(renv->sbin, address)) == NULL ) { + t_pop(); + return FALSE; + } + + /* Initialize match context */ + mctx = sieve_match_begin(mtch, cmp, key_list); + + /* Iterate through all requested headers to match */ + hdr_item = NULL; + matched = FALSE; + while ( !matched && (result=sieve_coded_stringlist_next_item(hdr_list, &hdr_item)) + && hdr_item != NULL ) { + const char *const *fields; + + if ( ext_body_get_fields(renv->msgdata, str_c(hdr_item), &fields) >= 0 ) { + + int i; + for ( i = 0; !matched && fields[i] != NULL; i++ ) { + if ( sieve_address_match(addrp, mctx, fields[i]) ) + matched = TRUE; + } + } + } + + matched = sieve_match_end(mctx) || matched; + + t_pop(); + + if ( result ) + sieve_interpreter_set_test_result(renv->interp, matched); + + return result; +} -- GitLab