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