diff options
-rw-r--r-- | NEWS | 32 | ||||
-rw-r--r-- | doc/texinfo/libmu_sieve.texi | 459 | ||||
-rw-r--r-- | doc/texinfo/sieve.texi | 404 | ||||
-rw-r--r-- | libmu_sieve/comparator.c | 14 | ||||
-rw-r--r-- | sieve/sieve.c | 2 | ||||
-rw-r--r-- | sieve/tests/pipetest.at | 2 |
6 files changed, 654 insertions, 259 deletions
@@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2016-12-07 +GNU mailutils NEWS -- history of user-visible changes. 2016-12-13 Copyright (C) 2002-2016 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -7,8 +7,34 @@ Please send mailutils bug reports to <bug-mailutils@gnu.org>. Version 3.0.90 (Git) -Sieve library essentially rewritten. It now inludes support for -the "variables" extension (RFC 5229). +* Sieve + +The Sieve library essentially rewritten. The following new extensions +are implemented: + + encoded-character - RFC 5228, 2.4.2.4 + variables - RFC 5229 + environment - RFC 5183 + +The tools define the Sieve environment "location", and +"phase" as follows: + + Utility | "location" | "phase" + --------+-------------+-------- + maidag | "MDA" | "during" + inc | "MUA" | "post" + sieve | "MS" | "post" + +The "sieve" utility provides new option: --environment, for +manipulating the environment. + +* Bugfixes +** Fix program name duplicate in the output of "mailutils help COMMAND" +** Fix several bugs in mhn +** Fix expansion of #, &, %, etc. in mail "copy" and "file" commands. +** Fix improper permissions after delivery to MH and Maildir mailboxes. +** Fix stream flushing code +** Fix the implementation of -nowhatnowproc option in mh Version 3.0 - 2016-11-06 diff --git a/doc/texinfo/libmu_sieve.texi b/doc/texinfo/libmu_sieve.texi index 987dfad00..2706b8cf6 100644 --- a/doc/texinfo/libmu_sieve.texi +++ b/doc/texinfo/libmu_sieve.texi @@ -44,6 +44,8 @@ Sieve Library. * Sieve Data Types:: * Manipulating the Sieve Machine:: * Logging and Diagnostic Functions:: +* String Accessors:: +* Argument Accessors:: * Symbol Space Functions:: * Memory Allocation:: * Compiling and Executing the Script:: @@ -53,13 +55,13 @@ Sieve Library. @node Sieve Data Types @subsection Sieve Data Types -@deftp {Data Type} sieve_machine_t +@deftp {Data Type} mu_sieve_machine_t This is an opaque data type representing a pointer to an instance of -sieve machine. The @code{sieve_machine_t} keeps all information necessary +sieve machine. The @code{mu_sieve_machine_t} keeps all information necessary for compiling and executing the script. -It is created by @code{sieve_machine_create()} and destroyed by -@code{sieve_machine_destroy()}. The functions for manipulating this data +It is created by @code{mu_sieve_machine_create()} and destroyed by +@code{mu_sieve_machine_destroy()}. The functions for manipulating this data type are described in @ref{Manipulating the Sieve Machine}. @end deftp @@ -77,16 +79,13 @@ Numeric type. Character string. @item SVT_STRING_LIST -A @code{mu_list_t}. Each item in this list represents a character string. +A list of strings. @item SVT_TAG -A sieve tag. See @code{mu_sieve_runtime_tag_t} below. - -@item SVT_IDENT -A character string representing an identifier. - -@item SVT_POINTER -An opaque pointer. +A sieve tag. This data type is available only during the +compilation. On runtime, all tags are converted to one of the above +types, depending on their arguments. Tags without arguments are +converted to SVT_VOID. @end table @end deftp @@ -96,18 +95,23 @@ as follows: @smallexample @group -typedef struct -@{ - mu_sieve_data_type type; /* Type of the data */ - union @{ - char *string; /* String value or identifier */ - size_t number; /* Numeric value */ - mu_list_t list; /* List value */ - mu_sieve_runtime_tag_t *tag; /* Tag value */ - void *ptr; /* Pointer value */ - @} v; -@} -mu_sieve_value_t; + typedef struct + @{ + union mu_sieve_value_storage + @{ + char *string; + size_t number; + struct mu_sieve_slice list; + @}; + + typedef struct + @{ + mu_sieve_data_type type; + char *tag; + union mu_sieve_value_storage v; + @} mu_sieve_value_t; + @} + mu_sieve_value_t; @end group @end smallexample @@ -116,25 +120,48 @@ union @code{v} keep the actual value: @table @code @item SVT_VOID -Never appears. +No associated value. @item SVT_NUMBER -The numeric value is kept in @code{number} member. - -@item SVT_STRING -The string is kept in @code{string} member. +The numeric value is kept in the @code{number} member. @item SVT_STRING_LIST -The list itself is pointed to by @code{list} member +@itemx SVT_STRING +The list is identified by the @code{list} member of the union +@code{mu_sieve_value_storage}. This member is defined as follows: -@item SVT_TAG -The tag value is pointed to by @code{tag} member. +@example +struct mu_sieve_slice +@{ + size_t first; /* Index of the first string */ + size_t count; /* Number of strings */ +@}; +@end example + +The @code{first} member identifies the first string in the list. +The @code{count} member gives the number of strings in the list. If +the data type is @code{SVT_STRING}, @code{count} is guaranteed to be +1. -@item SVT_IDENT -The @code{string} member points to the identifier name. +The string itself can be accessed using the @code{mu_sieve_string} +function (@pxref{String Accessors}). For example, the following code +fragment iterates over all strings in the list: -@item SVT_POINTER -The data are pointed to by @code{ptr} member. +@example +size_t i; +mu_sieve_value_t *val; + +for (i = 0; i < val->v.list.count; i++) + @{ + char *string; + + string = mu_sieve_string (mach, &val->v.list, i); + ... + @} +@end example + +@item SVT_TAG +Never appears. @end table @end deftp @@ -159,131 +186,39 @@ colon}. The @code{argtype} is set to @code{SVT_VOID} if the tag does not take argument, or to the type of the argument otherwise. @end deftp -@deftp {Data Type} mu_sieve_runtime_tag_t -This structure represents the tagged (optional) argument at a runtime. -It is defined as: - -@smallexample -@group -struct mu_sieve_runtime_tag -@{ - char *tag; /* Tag name */ - mu_sieve_value_t *arg; /* Tag argument (if any) */ -@}; -@end group -@end smallexample - -The @code{arg} member is @code{NULL} if the tag does not take an argument. -@end deftp - -@deftp {Data Type} mu_sieve_locus_t -Objects of this type represent a location in the Sieve source file: - -@smallexample -@group -typedef struct -@{ - const char *source_file; - size_t source_line; -@} -mu_sieve_locus_t; -@end group -@end smallexample -@end deftp - @deftp {Data Type} mu_sieve_handler_t This is a pointer to function handler for a sieve action or test. It is defined as follows: @smallexample -typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t @var{mach}, - mu_list_t @var{args}, - mu_list_t @var{tags}); -@end smallexample - -The arguments to the handler have the following meaning: - -@table @var -@item mach -Sieve machine being processed. -@item args -A list of required arguments to the handler -@item tags -A list of optional arguments (tags). -@end table -@end deftp - -@deftp {Data Type} mu_sieve_printf_t -A pointer to a diagnostic output function. It is defined as follows: -@smallexample -typedef int (*mu_sieve_printf_t) (void *@var{data}, - const char *@var{fmt}, va_list @var{ap}); +typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t @var{mach}); @end smallexample -@table @var -@item data -A pointer to application specific data. It is set using -the @code{mu_sieve_set_data} call. -@item fmt -Printf-like format string. -@item ap -Other arguments. -@end table -@end deftp - -@deftp {Data Type} mu_sieve_parse_error_t -This data type is declared as follows: -@smallexample -typedef int (*mu_sieve_parse_error_t) (void *@var{data}, - const char *@var{filename}, - int @var{lineno}, - const char *@var{fmt}, - va_list @var{ap}); -@end smallexample - -It is used to declare error handlers for parsing errors. The -application-specific data are passed in the @var{data} -argument. Arguments @var{filename} and @var{line} indicate the location -of the error in the source text, while @var{fmt} and @var{ap} give -verbose description of the error. -@end deftp +The @var{mach} argument is the machine being worked upon. The rest of +data can be obtained from it. @deftp {Data Type} mu_sieve_action_log_t A pointer to the application-specific logging function: @smallexample -typedef void (*mu_sieve_action_log_t) (void *@var{data}, - const mu_sieve_locus_t *@var{locus}, - size_t @var{msgno}, - mu_message_t @var{msg}, - const char *@var{action}, - const char *@var{fmt}, +typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t @var{mach}, + const char *@var{action}, + const char *@var{fmt}, va_list @var{ap}); @end smallexample @table @var -@item data -Application-specific data. - -@item locus -Location in the Sieve source file. - -@item script -Name of the sieve script being executed. - -@item msgno -Ordinal number of the message in mailbox, if appropriate. When execution -is started using @code{sieve_message()}, this argument is zero. - -@item msg -The message this action is executed upon. +@item nach +The sieve machine. @item action The name of the action. @item fmt -@itemx var -These two arguments give the detailed description of the action. +A @code{printf}-style format string. + +@item ap +Arguments for the format. @end table @end deftp @@ -329,25 +264,11 @@ associated with @code{data}. See the description of @deftp {Data Type} mu_sieve_tag_checker_t @smallexample -typedef int (*mu_sieve_tag_checker_t) (const char *@var{name}, - mu_list_t @var{tags}, - mu_list_t @var{args}) +typedef int (*mu_sieve_tag_checker_t) (const char *@var{name}) @end smallexample A pointer to tag checker function. The purpose of the function is to -perform compilation-time consistency test on tags. Its arguments are: - -@table @var -@item name -Name of the test or action whose tags are being checked. - -@item tags -A list of @code{mu_sieve_runtime_tag_t} representing tags. - -@item args -A list of @code{mu_sieve_value_t} representing required arguments to -@var{name}. -@end table +perform compilation-time consistency test on tags. The function is allowed to make any changes in @var{tags} and @var{args}. It should return 0 if the syntax is correct and non-zero @@ -386,33 +307,7 @@ of the destructor is to free any resources associated with the item @var{ptr}. The destructor function takes a single argument --- a pointer to the data being destroyed. All registered destructors are called in reverse order upon execution of -@code{mu_sieve_machine_destroy()}. Here's a short example of the use -of this function: - -@smallexample -@group -static void -free_regex (void *data) -@{ - regfree ((regex_t*)data); -@} - -int -match_part_checker (const char *name, list_t tags, list_t args) -@{ - regex_t *regex; - - /* Initialise the regex: */ - regex = mu_sieve_malloc (mach, sizeof (*regex)); - /* Make sure it will be freed when necessary */ - mu_sieve_machine_add_destructor (sieve_machine, free_regex, regex); - . - . - . -@} -@end group -@end smallexample -@end deftypefun +@code{mu_sieve_machine_destroy()}. @deftypefun {void *} mu_sieve_get_data (mu_sieve_machine_t @var{mach}) This function returns the application-specific data associated with @@ -433,15 +328,12 @@ with @code{mu_sieve_message}, this function returns 1. Returns the debug level set for this instance of sieve machine. @end deftypefun -@deftypefun mu_ticket_t mu_sieve_get_ticket (mu_sieve_machine_t @var{mach}) -Returns the authentication ticket for this machine. -@end deftypefun - @deftypefun mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t @var{mach}) Returns the mailer. @end deftypefun -@deftypefun int mu_sieve_get_locus (mu_sieve_machine_t @var{mach}, mu_sieve_locus_t *@var{locus}) +@deftypefun int mu_sieve_get_locus (mu_sieve_machine_t @var{mach}, @ + struct mu_locus *@var{locus}) Returns the locus in the Sieve source file corresponding to the code pointer where the Sieve machine currently is. @end deftypefun @@ -453,70 +345,30 @@ envelope from addresses of automatic reply messages. By default its local part is @samp{<MAILER-DAEMON>} and the domain part is the machine name. @end deftypefun - -@deftypefun void mu_sieve_set_error (mu_sieve_machine_t @var{mach}, mu_sieve_printf_t @var{error_printer}) -This function sets the error printer function for the machine. If it is -not set, the default error printer will be used. It is defined as -follows: - -@smallexample -int -_sieve_default_error_printer (void *unused, const char *fmt, - va_list ap) -@{ - return mu_verror (fmt, ap); -@} -@end smallexample +@deftypefun void mu_sieve_get_diag_stream (mu_sieve_machine_t @var{mach}, @ + mu_stream_t *@var{pstr}) +Get a reference to the machine's diagnostic stream. The obtained +stream must be dereferenced by using @code{mu_stream_unref} or +@code{mu_stream_destroy}, when no longer needed. @end deftypefun -@deftypefun void mu_sieve_set_parse_error (mu_sieve_machine_t @var{mach}, mu_sieve_parse_error_t @var{p}) -This function sets the parse error printer function for the machine. If it is -not set, the default parse error printer will be used. It is defined as -follows: - -@smallexample -@group -int -_sieve_default_parse_error (void *unused, - const char *filename, int lineno, - const char *fmt, va_list ap) -@{ - if (filename) - fprintf (stderr, "%s:%d: ", filename, lineno); - vfprintf (stderr, fmt, ap); - fprintf (stderr, "\n"); - return 0; -@} -@end group -@end smallexample +@deftypefun void mu_sieve_set_diag_stream (mu_sieve_machine_t @var{mach}, + mu_stream_t @var{stream} +Register @var{stream} as the diagnostic stream for this machine. The +reference count of @var{stream} is increased. @end deftypefun -@deftypefun void mu_sieve_set_debug (mu_sieve_machine_t @var{mach}, mu_sieve_printf_t @var{debug}); -This function sets the debug printer function for the machine. If it is -not set, the default debug printer is @code{NULL} which means no -debugging information will be displayed. +@deftypefun void mu_sieve_get_dbg_stream (mu_sieve_machine_t @var{mach}, @ + mu_stream_t *@var{pstr}) +Get a reference to the machine's debug output stream. The obtained +stream must be dereferenced by using @code{mu_stream_unref} or +@code{mu_stream_destroy}, when no longer needed. @end deftypefun - -@deftypefun void mu_sieve_set_debug_level (mu_sieve_machine_t @var{mach}, mu_debug_t @var{dbg}, int @var{level}) -This function sets the debug level for the given instance of sieve -machine. The @var{dbg} argument is the @code{mu_debug_t} object to be -used with mailutils library, the @var{level} argument specifies the -debugging level for the sieve library itself. It is a bitwise or of -the following values: - -@table @code -@item MU_SIEVE_DEBUG_TRACE -Trace the execution of the sieve script. - -@item MU_SIEVE_DEBUG_INSTR -Print the sieve machine instructions as they are executed. - -@item MU_SIEVE_DEBUG_DISAS -Dump the disassembled code of the sieve machine. Do not run it. - -@item MU_SIEVE_DRY_RUN -Do not executed the actions, only show what would have been done. -@end table + +@deftypefun void mu_sieve_set_dbg_stream (mu_sieve_machine_t @var{mach}, + mu_stream_t @var{stream}) +Register @var{stream} as the debug output stream for this machine. The +reference count of @var{stream} is increased. @end deftypefun @deftypefun void mu_sieve_set_logger (mu_sieve_machine_t @var{mach}, mu_sieve_action_log_t @var{logger}) @@ -524,10 +376,6 @@ This function sets the logger function. By default the logger function is @code{NULL}, which means that the executed actions are not logged. @end deftypefun -@deftypefun void mu_sieve_set_ticket (mu_sieve_machine_t @var{mach}, mu_ticket_t @var{ticket}) -This function sets the authentication ticket to be used with this machine. -@end deftypefun - @deftypefun void mu_sieve_set_mailer (mu_sieve_machine_t @var{mach}, mu_mailer_t @var{mailer}) This function sets the mailer. The default mailer is @code{"sendmail:"}. @end deftypefun @@ -569,6 +417,115 @@ Log a sieve action using logger function associated with the machine @var{mach}. Immediately abort the execution of the script. @end deftypefun +@node String Accessors +@subsection String Accessors +Strings are stored in a special memory area within the Sieve machine, +which is called @dfn{string space}. A string is identified by its +index in the string space. Array of strings is represented internally +as a contiguous area within the string space that holds one or more +strings. An array is identified by the index of its first element and +number of elements in it: + +@example +struct mu_sieve_slice +@{ + size_t first; /* Index of the first object */ + size_t count; /* Number of objects */ +@}; +@end example + +A single sieve string is represented by an array of strings with +zero @code{count}. + +To obtain actual value of a string, use the @code{mu_sieve_string} +function: + +@deftypefun {char *} mu_sieve_string (mu_sieve_machine_t @var{mach}, @ + mu_sieve_slice_t @var{slice}, @ + size_t @var{n}) +Return actual textual value of the @var{n}th string in the array +@var{slice} of the Sieve machine @var{mach}. + +If the @code{variables} extension is required, the returned value will +have variables expanded. +@end deftypefun + +Two functions are provided for manipulating raw string values. Each +string in the string space is kept in the following structure: + +@example +typedef struct mu_sieve_string +@{ + unsigned constant:1; /* String is constant */ + unsigned changed:1; /* String value has changed */ + char *orig; /* String original value */ + char *exp; /* Actual string value after expansion */ + void *rx; /* Pointer to the corresponding regular expr */ +@} mu_sieve_string_t; +@end example + +All fields in this structure shall be deemed constant. Sieve code +(such as new actions or tests) should never try to change any of them. + +The meaning of its fields is: + +@deftypecv Field {struct mu_sieve_string} unsigned constant +Zero if the string is subject to variable expansion and 1 otherwise. + +This field is defined when compiling the Sieve script. +@end deftypecv + +@deftypecv Field {struct mu_sieve_string} unsigned changed +This field is @samp{1} if the expanded value of the string has changed +since it was retrieved for the last time. This is used by the Sieve +machine to determine whether the associated regular expression (if +any) needs to be recompiled. + +This field is modified by the string accessor functions. Obviously, +if @code{constant == 1}, then @code{changed == 0}. +@end deftypecv + +@deftypecv Field {struct mu_sieve_string} {char *} orig +A pointer to the original string value, as it appeared in the Sieve +script source file. +@end deftypecv + +@deftypecv Field {struct mu_sieve_string} {char *} exp +A pointer to the string value after expansion. Valid only if +@code{constant == 0}. +@end deftypecv + +@deftypecv Field {struct mu_sieve_string} {void *} rx +Points to the memory area containig the compiled regular expression +corresponding to that string. This member is valid, e.g. if the +string represents the second argument of a test used with +@code{:match} or @code{:regex} tag. +@end deftypecv + +The raw string values are accessed via the following two functions: + +@deftypefun {mu_sieve_string_t *} mu_sieve_string_raw (mu_sieve_machine_t @var{mach}, @ + mu_sieve_slice_t @var{slice}, @ + size_t @var{n}) +Returns pointer to the structure representing @var{n}th string in +slice @var{slice}. A runtime exception is raised if @var{n} is out of +range represented by @var{slice}. + +Extension writers should treat this as a constant object. +@end deftypefun + +@deftypefun {char *} mu_sieve_string_get (mu_sieve_machine_t @var{mach}, @ + mu_sieve_string_t *@var{string}) +Evaluate @var{string} and return its textual representation. If the +@code{variables} extension is required, this function performs +variable substitution. +@end deftypefun + +@node Argument Accessors +@subsection Argument Accessors + + + @node Symbol Space Functions @subsection Symbol Space Functions diff --git a/doc/texinfo/sieve.texi b/doc/texinfo/sieve.texi index 6722970bb..cc8e3d1fc 100644 --- a/doc/texinfo/sieve.texi +++ b/doc/texinfo/sieve.texi @@ -15,6 +15,7 @@ is a superset of the Sieve language as described in RFC 3028. * Comparators:: * Tests:: * Actions:: +* Extensions:: * GNU Extensions:: @end menu @@ -1562,6 +1563,409 @@ message regardless of whether the user email is listed as a recipient for the message. @end deftypefn +@node Extensions +@section Extensions + +The following extensions are implemented + +@menu +* encoded-character:: +* relational:: +* variables:: +* environment:: +* numaddr:: +* editheader:: +* list:: +* moderator:: +* pipe:: +* spamd:: +* timestamp:: +* vacation:: +@end menu + +@node encoded-character +@subsection The encoded-character extension + +The @samp{encoded-character} extension complies with @cite{RFC 5228}, +part 2.4.2.4. It provides a way of incorporating multibyte sequences +in a Sieve script using only ASCII characters. This is a built-in +extension. It is enabled using the following statement: + +@example +require "encoded-character"; +@end example + +When this extension is enabled, the sequences @samp{$@{hex: ...@}}, +and @samp{$@{unicode: ...@}} can appear inside of quoted strings. + +The sequence + +@example +$@{hex: @var{XX}@} +@end example + +@noindent +where @var{XX} is a sequence of one or two-digit hex numbers separated +by any amount of whitespace, is replaced with the octets with the +hexadecimal values given by each hex number. For example, + +@example +"$@{hex: 24 24@}" @result{} "$$" +@end example + +Thus, the following script will discard any message containing three +contiguous dollar signs in its @samp{Subject} header: + +@example +require "encoded-character"; + +if header :contains "Subject" "$$@{hex:24 24@}" @{ + discard; +@} +@end example + +The @samp{hex:} keyword is case-insensitive. If @var{XX} contains +invalid hex numbers, the entire sequence is left verbatim. This is +illustrated by the following example: + +@example +"$$@{hex:40@}" @result{} "$@@" +"$@{hex: 40 @}" @result{} "@@" +"$@{HEX: 40@}" @result{} "@@" +"$@{hex:40" @result{} "$@{hex:40" +"$@{hex:400@}" @result{} "$@{hex:400@}" +"$@{hex:4$@{hex:30@}@}" @result{} "$@{hex:40@}" +@end example + +The sequence + +@example +$@{unicode: @var{HEXNUM}@} +@end example + +@noindent +where @var{HEXNUM} is a list of hexadecimal numbers separated with +whitespace, will be replaced by the UTF-8 encoding of the specified +Unicode characters, which are identified by the hexadecimal value of +@var{HEXNUM}. For example, the following string represents a single +@samp{@@} sign: + +@example +"$@{UNICODE:40@}" +@end example + +Similarly to @samp{hex:}, the @samp{unicode:} indicator is case +insensitive. The following examples demonstrate the handling of +several valid and invalid encodings: + +@example +"$@{unicode:40@}" @result{} "@@" +"$@{ unicode:40@}" @result{} "$@{ unicode:40@}" +"$@{UNICODE:40@}" @result{} "@@" +"$@{UnICoDE:0000040@}" @result{} "@@" +"$@{Unicode:40@}" @result{} "@@" +"$@{Unicode:Cool@}" @result{} "$@{Unicode:Cool@}" +"$@{unicode:200000@}" @result{} error +"$@{Unicode:DF01@} @result{} error +@end example + +@node relational +@subsection The relational extension + +The @samp{relational} extension complies with @cite{RFC 3431}. It is +a built-in extension. When enabled, the two new match types become +available: @code{:count} and @code{:value}. Both keywords take a +single argument defining the relational operator to use: + +@multitable @columnfractions 0.2 0.8 +@item @samp{"gt"} @tab greater than (@samp{>}) +@item @samp{"ge"} @tab greater than or equal (@samp{>=}) +@item @samp{"lt"} @tab less than (@samp{<}) +@item @samp{"le"} @tab less than or equal (@samp{<=}) +@item @samp{"eq"} @tab equal to (@samp{==}) +@item @samp{"ne"} @tab not equal to (@samp{!=}) +@end multitable + +The @code{:value} keyword requires a relational comparison between +strings. The left side of the relation is formed by the value from +the message. The right side of the relation is the value from the +test expression. If there are multiple values on either side or both +sides, the test is considered true if any pair is true. For example, + +@example +require ["relational", "fileinto"]; + +if header :value "gt" :comparator "i;ascii-numeric" + ["x-spam-level] ["5"] +@{ + fileinto "spam"; +@} +@end example + +The @code{:count} keyword counts the specified entities in the message +and compares their number with the value given in the test +expression. The latter must be a list of one element. This match +type can only be used with numeric comparators. For example, the +following script will discard any message with 10 or more recipient +addresses in the @samp{To} and @samp{Cc} headers: + +@example +require "relational"; + +if address :count "ge" :comparator "i;ascii-numeric" + ["to", "cc"] ["10"] +@{ + discard; +@} +@end example + +@node variables +@subsection The variables extension + +The @samp{variables} extension is defined in @cite{RFC 5229}. It is +a built-in extension. It introduces support for variables in Sieve +scripts. + +There are two kind of variables: user-defined and match variables. + +A @dfn{user-defined} variable is initialized using the @code{set} +action: + +@deftypefn Action {} set [@var{modifiers}] @var{name}(string) @var{value}(string) +Stores the specified @var{value} in the variable identified by +@var{name}. Optional @var{modifiers} are applied on @var{value} before it +is stored in the variable. + +The following modifiers are available: + +@table @code +@item :lower +Convert value to lower case letters. +@item :upper +Convert value to upper case letters. + +@item :lowerfirst +Convert the first character in value to lower case. + +@item :upperfirst +Convert the first character in value to upper case. + +@item :quotewildcard +Quote wildcard characters (@samp{*}, @samp{?}, @samp{\}) by prefixing +each occurrence with a backslash (@samp{\}). This can be used to +ensure that the variable will only match a literal occurrence if used +as a parameter to @code{:matches}. + +@item :length +The value is the decimal number of characters in the expansion, +converted to a string. +@end table + +When several modifiers are present, they are applied in the following +order of precedence (largest value first): + +@multitable @columnfractions 0.2 0.8 +@headitem precedence @tab modifiers +@item 40 @tab @code{:lower} or @code{:upper} +@item 30 @tab @code{:lowerfirst} or @code{:upperfirst} +@item 20 @tab @code{:quotewildcard} +@item 10 @tab @code{:length} +@end multitable + +Modifiers having the same precedence (i.e. listed on the same row in +the above table) cannot be used together. +@end deftypefn + +Variables are referenced within text strings using the construct +@samp{$@{@var{name}@}}, where @var{name} is the name of the variable +as it appeared in the first parameter to the @code{set} statement. +For example: + +@example +require "variables"; + +set "sender" "root@*": + +if envelope :matches "$@{sender@}" +@{ + ... +@} +@end example + +@dfn{Match variables} refer to parts of the most recently evaluated +successful match of type @code{:matches} or @code{:regex}. They have +names consisting entirely of decimal digits. The variable +@samp{$@{0@}} refers to the entire matched expression. The variable +@samp{$@{1@}} refers to the substring matching the first occurrence of +the wildcard (@samp{?} and @samp{*}), @samp{$@{2@}} refers to the +second occurrence and so on. The wildcards match as little as possible +(non-greedy matching). For example: + +@example +require ["variables", "fileinto"]; + +if header :matches "List-ID" "*<*@*" @{ + fileinto "INBOX.lists.$@{2@}"; + stop; +@} +@end example + +If @code{:regex} match is used, the match variables starting from +@samp{$@{1@}} refer to the substrings of the argument value matching +subsequent parenthesized groups of the regular expression. + +@deftypefn Test {} string [@var{comparator}] @ + [@var{match-type}] @ + @var{source}(string-list) @var{keys}(string-list) +The @code{string} test compares two strings according to the selected +comparator and match type. The test evaluates to @samp{true} if any +two strings from @var{source} and @var{keys} match. + +The @samp{:count} match used in @samp{string} counts each empty string +as 0, and each non-empty one as 1. The count of a string list is the +sum of the counts of the member strings. +@end deftypefn + +@node environment +@subsection environment + +The @samp{environment} extension complies with @cite{RFC 5183}. It is +a built-in extension. It introduces the following test: + +@deftypefn Test {} environment [@var{comparator}] @ + [@var{match-type}] @ + @var{name}(string) @var{keys}(string-list) +The @code{environment} test evaluates to @samp{true} if the value of +the environment items @var{name} matches any string from @var{keys}. +@end deftypefn + +The following environment items are defined: + +@table @asis +@item domain +The primary DNS domain of the machine where the Sieve script is +executing. + +@item host +The fully-qualified domain name of the host where the Sieve script is +executing. + +@item location +Type of service that is evaluating the script. Depending on the +utility that is evaluating the script it is: + +@multitable @columnfractions 0.6 0.4 +@headitem Utility @tab Location +@item sieve @tab @samp{"MUA"}, or set with the @option{--environment} option. +@item maidag @tab @samp{"MDA"} +@item inc @tab @samp{"MUA"} +@end multitable + +@item name +The string @samp{GNU Mailutils} + +@item phase +The point relative to final delivery where the Sieve script is being +evaluated. Depending on the utility that is evaluating the script it is: + +@multitable @columnfractions 0.6 0.4 +@headitem Utility @tab Location +@item sieve @tab @samp{post} unless set with the @option{--environment} option. +@item maidag @tab @samp{"during"} +@item inc @tab @samp{"post"} +@end multitable + +@item version +Mailutils version string (e.g. @samp{@value{VERSION}}). +@end table + +@node numaddr +@subsection The numaddr extension + +This is an example loadable extension. @ref{External Tests, numaddr}. + +@node editheader +@subsection The editheader extension + +The @code{editheader} extension complies with @cite{RFC 5293}. It +provides the following actions: + +@deftypefn Action {} addheader [:last] @var{field-name}(string) @var{value}(string +Adds a header field to the existing message header. By default the +header is inserted at the beginning of the header list. If the tag +@code{:last} is specified, it is appended at the end. +@end deftypefn + +@deftypefn Action {} deleteheader" [:index @var{fieldno}(number) :last] @ + [@var{comparator}] @ + [@var{match-type}] @ + @var{field-name}(string) @ + [@var{value-patterns}(string-list)] + +Deletes occurrences of the header field matching the criteria. + +The @var{value-patterns}, if specified, determines which occurrences +of the header fielde to delete. If not supplied, @var{comparator} and +@var{match-type} are silently ignored. + +If @samp{:index @var{fieldno}} is specified, only the numbered +occurrence of the named header field will be matched (header numbering +begins at 1), If @code{:last} is specified, the count is backwards; 1 +denotes the last named header field, 2 the second to last, and so on. +The counting happens before the @var{value-patterns} match, if any. +Thus, e.g. the action + +@example +deleteheader :index 1 :contains "Delivered-To" "bob@@example.com"; +@end example + +@noindent +would delete the first @samp{Delivered-To} header field if it contains +the string @samp{bob@@example.com}. +@end deftypefn + +@node list +@subsection The list extension + +@ref{External Tests, list}. + +@node moderator +@subsection The moderator extension + +A loadable extension implementing a moderator robot for Mailman-driven +mail archives. @ref{External Actions, moderator}. + +@node pipe +@subsection The pipe extension + +A loadable extension for external command execution. It provides the +@code{pipe} action (@pxref{External Actions, pipe}) and test +(@pxref{External Tests, pipe}). + +@node spamd +@subsection The spamd extension + +Implements a test which interfaces to SpamAssassin filter. This is a +loadable extension. @pxref{External Tests, spamd}. + +@node timestamp |