commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-3.0-49-geef0d16


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-3.0-49-geef0d16
Date: Tue, 13 Dec 2016 16:13:15 +0000 (UTC)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=eef0d16dc96ab8570c8da92283c81408c63edcee

The branch, master has been updated
       via  eef0d16dc96ab8570c8da92283c81408c63edcee (commit)
       via  53e14817a7de9262d61981a86eb65fb2675f0e92 (commit)
       via  5d4b76c56c558bfbd968e95ec57ff7055417d158 (commit)
       via  a1612b96fc4592af50cb65caff5b54e74f437b09 (commit)
       via  98011160928d6891abb5af1d67ebf2a6124e558b (commit)
       via  151eb4b9e00a56a1e4c85e8120403385012eb95a (commit)
      from  a923b221dc3a620dd5507ad935774cc70c9c28ec (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit eef0d16dc96ab8570c8da92283c81408c63edcee
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Dec 13 17:41:47 2016 +0200

    Pacify a paranoid compiler warning
    
    * libmailutils/string/wordsplit.c (mu_wordsplit_perror): Use %s format
    specifier

commit 53e14817a7de9262d61981a86eb65fb2675f0e92
Author: Jordi Mallach <address@hidden>
Date:   Tue Dec 13 17:40:20 2016 +0200

    Fix spelling errors

commit 5d4b76c56c558bfbd968e95ec57ff7055417d158
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Dec 13 17:34:57 2016 +0200

    Bugfixes
    
    * libmu_sieve/sieve.y: Fix compilation of chained elsif conditions.
    * sieve/sieve.c: Define the location environment item.

commit a1612b96fc4592af50cb65caff5b54e74f437b09
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Dec 13 16:29:58 2016 +0200

    Document changes to Sieve
    
    * NEWS: Update.
    * doc/texinfo/libmu_sieve.texi: Update.
    * doc/texinfo/sieve.texi: Document extensions
    
    * libmu_sieve/comparator.c (mu_sieve_match_part_checker): Check
    the type of the 2nd argument.
    * sieve/sieve.c: Define "location" and "phase" environment items.
    * sieve/tests/pipetest.at: Use "pipe" as the capability string.

commit 98011160928d6891abb5af1d67ebf2a6124e558b
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Dec 13 12:07:48 2016 +0200

    New sieve machine accessor functions
    
    * include/mailutils/sieve.h (mu_sieve_get_mailbox)
    (mu_sieve_get_argc): New protos.
    * libmu_sieve/runtime.c: New functions.

commit 151eb4b9e00a56a1e4c85e8120403385012eb95a
Author: Sergey Poznyakoff <address@hidden>
Date:   Tue Dec 13 12:04:56 2016 +0200

    Fix command expansion in wordsplit
    
    * libmailutils/string/wordsplit.c: Change ordering of expansions so
    that command expansion occurs first.  This fixes nested expansions
    and command expansions occurring after variable expansions.
    * libmailutils/tests/wordsplit.at: Add more tests.

-----------------------------------------------------------------------

Summary of changes:
 NEWS                            |   32 ++-
 doc/texinfo/libmu_sieve.texi    |  459 ++++++++++++++++++---------------------
 doc/texinfo/sieve.texi          |  404 ++++++++++++++++++++++++++++++++++
 examples/nntpclient.c           |    2 +-
 imap4d/uid.c                    |    2 +-
 include/mailutils/sieve.h       |    4 +
 libmailutils/string/wordsplit.c |   37 ++--
 libmailutils/tests/wordsplit.at |  205 ++++++++++++++++-
 libmu_sieve/comparator.c        |   14 +-
 libmu_sieve/runtime.c           |   15 ++
 libmu_sieve/sieve.y             |   29 +--
 mail/mailvar.c                  |    2 +-
 mu/shell.c                      |    2 +-
 sieve/sieve.c                   |    3 +
 sieve/tests/pipetest.at         |    2 +-
 15 files changed, 913 insertions(+), 299 deletions(-)

diff --git a/NEWS b/NEWS
index 38feada..e141bd2 100644
--- a/NEWS
+++ b/NEWS
@@ -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 <address@hidden>.
 
 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 987dfad..2706b8c 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
 
address@hidden {Data Type} sieve_machine_t
address@hidden {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
address@hidden()}. The functions for manipulating this data
+It is created by @code{mu_sieve_machine_create()} and destroyed by
address@hidden()}. 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.
-
address@hidden SVT_IDENT
-A character string representing an identifier. 
-
address@hidden 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 
address@hidden
-  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;
address@hidden 
-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.
-
address@hidden 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
address@hidden SVT_STRING
+The list is identified by the @code{list} member of the union 
address@hidden  This member is defined as follows:
 
address@hidden SVT_TAG
-The tag value is pointed to by @code{tag} member.
address@hidden
+struct mu_sieve_slice
address@hidden
+  size_t first;            /* Index of the first string */
+  size_t count;            /* Number of strings */
address@hidden;
address@hidden 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.
 
address@hidden 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:
 
address@hidden SVT_POINTER
-The data are pointed to by @code{ptr} member.
address@hidden
+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);
+    ...
+  @}
address@hidden example
+
address@hidden 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
 
address@hidden {Data Type} mu_sieve_runtime_tag_t
-This structure represents the tagged (optional) argument at a runtime.
-It is defined as:
-
address@hidden
address@hidden
-struct mu_sieve_runtime_tag 
address@hidden
-  char *tag;                   /* Tag name */
-  mu_sieve_value_t *arg;       /* Tag argument (if any) */
address@hidden;
address@hidden group
address@hidden smallexample
-
-The @code{arg} member is @code{NULL} if the tag does not take an argument.
address@hidden deftp
-
address@hidden {Data Type} mu_sieve_locus_t
-Objects of this type represent a location in the Sieve source file:
-
address@hidden
address@hidden
-typedef struct
address@hidden
-  const char *source_file;
-  size_t source_line;
address@hidden
-mu_sieve_locus_t;
address@hidden group
address@hidden smallexample
address@hidden 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});
address@hidden smallexample
-
-The arguments to the handler have the following meaning:
-
address@hidden @var
address@hidden mach
-Sieve machine being processed.
address@hidden args
-A list of required arguments to the handler
address@hidden tags
-A list of optional arguments (tags).
address@hidden table
address@hidden deftp
-
address@hidden {Data Type} mu_sieve_printf_t
-A pointer to a diagnostic output function. It is defined as follows:
address@hidden
-typedef int (*mu_sieve_printf_t) (void address@hidden, 
-                                  const char address@hidden, va_list @var{ap});
+typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t @var{mach});
 @end smallexample
 
address@hidden @var
address@hidden data
-A pointer to application specific data.  It is set using
-the @code{mu_sieve_set_data} call.
address@hidden fmt
-Printf-like format string.
address@hidden ap
-Other arguments.
address@hidden table
address@hidden deftp
-
address@hidden {Data Type} mu_sieve_parse_error_t
-This data type is declared as follows:
address@hidden
-typedef int (*mu_sieve_parse_error_t) (void address@hidden,
-                                       const char address@hidden, 
-                                       int @var{lineno},
-                                       const char address@hidden, 
-                                       va_list @var{ap});
address@hidden 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.
address@hidden 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 address@hidden,
-                                       const mu_sieve_locus_t address@hidden,
-                                       size_t @var{msgno}, 
-                                       mu_message_t @var{msg},
-                                       const char address@hidden,
-                                       const char address@hidden, 
+typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t @var{mach},
+                                      const char address@hidden,
+                                      const char address@hidden,
                                        va_list @var{ap});
 @end smallexample
 
 @table @var
address@hidden data
-Application-specific data.
-
address@hidden locus
-Location in the Sieve source file.
-
address@hidden script
-Name of the sieve script being executed.
-
address@hidden msgno
-Ordinal number of the message in mailbox, if appropriate. When execution
-is started using @code{sieve_message()}, this argument is zero.
-
address@hidden msg
-The message this action is executed upon.
address@hidden nach
+The sieve machine.
 
 @item action
 The name of the action.
 
 @item fmt
address@hidden var
-These two arguments give the detailed description of the action.
+A @code{printf}-style format string.
+
address@hidden 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 address@hidden, 
-                                       mu_list_t @var{tags}, 
-                                       mu_list_t @var{args})
+typedef int (*mu_sieve_tag_checker_t) (const char address@hidden)
 @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:
-
address@hidden @var
address@hidden name
-Name of the test or action whose tags are being checked.
-
address@hidden tags
-A list of @code{mu_sieve_runtime_tag_t} representing tags.
-
address@hidden args
-A list of @code{mu_sieve_value_t} representing required arguments to
address@hidden
address@hidden 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
address@hidden()}. Here's a short example of the use
-of this function:
-
address@hidden
address@hidden
-static void
-free_regex (void *data)
address@hidden
-  regfree ((regex_t*)data);        
address@hidden
-
-int
-match_part_checker (const char *name, list_t tags, list_t args)
address@hidden
-  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);
-  .
-  .
-  .
address@hidden
address@hidden group
address@hidden smallexample
address@hidden deftypefun
address@hidden()}.
 
 @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
 
address@hidden mu_ticket_t mu_sieve_get_ticket (mu_sieve_machine_t @var{mach})
-Returns the authentication ticket for this machine.
address@hidden deftypefun
-
 @deftypefun mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t @var{mach})
 Returns the mailer.
 @end deftypefun
 
address@hidden int mu_sieve_get_locus (mu_sieve_machine_t @var{mach}, 
mu_sieve_locus_t address@hidden)
address@hidden int mu_sieve_get_locus (mu_sieve_machine_t @var{mach}, @
+                                    struct mu_locus address@hidden)
 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
 
-
address@hidden 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:
-
address@hidden
-int
-_sieve_default_error_printer (void *unused, const char *fmt, 
-                              va_list ap)
address@hidden
-  return mu_verror (fmt, ap);
address@hidden
address@hidden smallexample
address@hidden void mu_sieve_get_diag_stream (mu_sieve_machine_t @var{mach}, @
+    mu_stream_t address@hidden)
+Get a reference to the machine's diagnostic stream.  The obtained
+stream must be dereferenced by using @code{mu_stream_unref} or
address@hidden, when no longer needed.
 @end deftypefun
 
address@hidden 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:
-
address@hidden
address@hidden
-int
-_sieve_default_parse_error (void *unused,
-                            const char *filename, int lineno,
-                            const char *fmt, va_list ap)
address@hidden
-  if (filename)
-    fprintf (stderr, "%s:%d: ", filename, lineno);
-  vfprintf (stderr, fmt, ap);
-  fprintf (stderr, "\n");
-  return 0;
address@hidden
address@hidden group
address@hidden smallexample
address@hidden 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
 
address@hidden 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.
address@hidden void mu_sieve_get_dbg_stream (mu_sieve_machine_t @var{mach}, @
+    mu_stream_t address@hidden)
+Get a reference to the machine's debug output stream.  The obtained
+stream must be dereferenced by using @code{mu_stream_unref} or
address@hidden, when no longer needed.
 @end deftypefun
-
address@hidden 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:
-
address@hidden @code
address@hidden MU_SIEVE_DEBUG_TRACE
-Trace the execution of the sieve script.
-
address@hidden MU_SIEVE_DEBUG_INSTR 
-Print the sieve machine instructions as they are executed.
-
address@hidden MU_SIEVE_DEBUG_DISAS
-Dump the disassembled code of the sieve machine. Do not run it.
-
address@hidden MU_SIEVE_DRY_RUN
-Do not executed the actions, only show what would have been done.
address@hidden table
+    
address@hidden 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
 
address@hidden 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.
address@hidden 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
 
address@hidden String Accessors
address@hidden 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:
+
address@hidden
+struct mu_sieve_slice
address@hidden
+  size_t first;            /* Index of the first object */
+  size_t count;            /* Number of objects */
address@hidden;
address@hidden 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:
+
address@hidden {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
address@hidden of the Sieve machine @var{mach}.
+
+If the @code{variables} extension is required, the returned value will
+have variables expanded.
address@hidden deftypefun
+
+Two functions are provided for manipulating raw string values.  Each
+string in the string space is kept in the following structure:
+
address@hidden
+typedef struct mu_sieve_string
address@hidden
+  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 */
address@hidden mu_sieve_string_t;
address@hidden 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:
+
address@hidden 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.
address@hidden deftypecv
+
address@hidden 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}.
address@hidden deftypecv
+
address@hidden Field {struct mu_sieve_string} {char *} orig
+A pointer to the original string value, as it appeared in the Sieve
+script source file.
address@hidden deftypecv
+
address@hidden Field {struct mu_sieve_string} {char *} exp
+A pointer to the string value after expansion.  Valid only if
address@hidden == 0}.
address@hidden deftypecv
+
address@hidden 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
address@hidden:match} or @code{:regex} tag.
address@hidden deftypecv
+
+The raw string values are accessed via the following two functions:
+
address@hidden {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.
address@hidden deftypefun
+
address@hidden {char *} mu_sieve_string_get (mu_sieve_machine_t @var{mach}, @
+                 mu_sieve_string_t address@hidden)
+Evaluate @var{string} and return its textual representation.  If the
address@hidden extension is required, this function performs
+variable substitution.
address@hidden deftypefun
+
address@hidden Argument Accessors
address@hidden Argument Accessors
+
+
+
 @node Symbol Space Functions
 @subsection Symbol Space Functions
 
diff --git a/doc/texinfo/sieve.texi b/doc/texinfo/sieve.texi
index 6722970..cc8e3d1 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
 
address@hidden Extensions
address@hidden Extensions
+
+The following extensions are implemented
+
address@hidden
+* encoded-character::
+* relational::
+* variables::
+* environment::
+* numaddr::
+* editheader::
+* list::
+* moderator::
+* pipe::
+* spamd::
+* timestamp::
+* vacation::
address@hidden menu
+
address@hidden encoded-character
address@hidden 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:
+
address@hidden
+require "encoded-character";
address@hidden example
+
+When this extension is enabled, the sequences @address@hidden: address@hidden,
+and @address@hidden: address@hidden can appear inside of quoted strings.
+
+The sequence
+
address@hidden
address@hidden: @address@hidden
address@hidden example
+
address@hidden
+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,
+
address@hidden
+"address@hidden: 24 address@hidden" @result{} "$$"
address@hidden example
+
+Thus, the following script will discard any message containing three
+contiguous dollar signs in its @samp{Subject} header:
+
address@hidden
+require "encoded-character";
+
+if header :contains "Subject" "address@hidden:24 address@hidden" @{
+     discard;
address@hidden
address@hidden 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: 
+
address@hidden
+"address@hidden:address@hidden"         @result{} "$@@"
+"address@hidden: 40 @}"        @result{} "@@"
+"address@hidden: address@hidden"         @result{} "@@"
+"address@hidden:40"             @result{} "address@hidden:40"
+"address@hidden:address@hidden"         @result{} 
"address@hidden:address@hidden"
+"address@hidden:address@hidden:address@hidden@}"  @result{} 
"address@hidden:address@hidden"
address@hidden example
+
+The sequence
+
address@hidden
address@hidden: @address@hidden
address@hidden example
+
address@hidden
+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
address@hidden  For example, the following string represents a single
address@hidden@@} sign:
+
address@hidden
+"address@hidden:address@hidden"
address@hidden example
+
+Similarly to @samp{hex:}, the @samp{unicode:} indicator is case
+insensitive.  The following examples demonstrate the handling of
+several valid and invalid encodings:
+
address@hidden
+"address@hidden:address@hidden"      @result{} "@@"
+"address@hidden unicode:address@hidden"     @result{} "address@hidden 
unicode:address@hidden"
+"address@hidden:address@hidden"      @result{} "@@"
+"address@hidden:address@hidden" @result{} "@@"
+"address@hidden:address@hidden"      @result{} "@@"
+"address@hidden:address@hidden"    @result{} "address@hidden:address@hidden"
+"address@hidden:address@hidden"  @result{} error
+"address@hidden:address@hidden     @result{} error
address@hidden example
+
address@hidden relational
address@hidden 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:
+
address@hidden @columnfractions 0.2 0.8
address@hidden @samp{"gt"} @tab greater than (@samp{>})
address@hidden @samp{"ge"} @tab greater than or equal (@samp{>=})
address@hidden @samp{"lt"} @tab less than (@samp{<})
address@hidden @samp{"le"} @tab less than or equal (@samp{<=})
address@hidden @samp{"eq"} @tab equal to (@samp{==})
address@hidden @samp{"ne"} @tab not equal to (@samp{!=})
address@hidden 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,
+
address@hidden
+require ["relational", "fileinto"];
+
+if header :value "gt" :comparator "i;ascii-numeric"
+                ["x-spam-level] ["5"]
address@hidden
+  fileinto "spam";
address@hidden  
address@hidden 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:
+
address@hidden
+require "relational";
+
+if address :count "ge" :comparator "i;ascii-numeric"
+                      ["to", "cc"] ["10"]
address@hidden
+    discard;
address@hidden
address@hidden example
+
address@hidden variables
address@hidden 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:
+
address@hidden Action {} set address@hidden @var{name}(string) 
@var{value}(string)
+Stores the specified @var{value} in the variable identified by
address@hidden  Optional @var{modifiers} are applied on @var{value} before it
+is stored in the variable.
+
+The following modifiers are available:
+
address@hidden @code
address@hidden :lower
+Convert value to lower case letters.
address@hidden :upper
+Convert value to upper case letters.
+
address@hidden :lowerfirst
+Convert the first character in value to lower case.
+
address@hidden :upperfirst
+Convert the first character in value to upper case.
+
address@hidden :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}.
+
address@hidden :length
+The value is the decimal number of characters in the expansion,
+converted to a string.
address@hidden table
+
+When several modifiers are present, they are applied in the following
+order of precedence (largest value first):
+
address@hidden @columnfractions 0.2 0.8
address@hidden precedence @tab modifiers
address@hidden 40 @tab @code{:lower} or @code{:upper}
address@hidden 30 @tab @code{:lowerfirst} or @code{:upperfirst}
address@hidden 20 @tab @code{:quotewildcard}
address@hidden 10 @tab @code{:length}
address@hidden multitable
+
+Modifiers having the same precedence (i.e. listed on the same row in
+the above table) cannot be used together.
address@hidden deftypefn
+
+Variables are referenced within text strings using the construct
address@hidden@address@hidden@}}, where @var{name} is the name of the variable
+as it appeared in the first parameter to the @code{set} statement.
+For example:
+
address@hidden
+require "variables";
+
+set "sender" "address@hidden":
+
+if envelope :matches "address@hidden@}"
address@hidden
+   ...
address@hidden
address@hidden example
+
address@hidden 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
address@hidden@address@hidden refers to the entire matched expression.  The 
variable
address@hidden@address@hidden refers to the substring matching the first 
occurrence of
+the wildcard (@samp{?} and @samp{*}), @address@hidden@}} refers to the
+second occurrence and so on.  The wildcards match as little as possible
+(non-greedy matching).  For example:
+
address@hidden
+require ["variables", "fileinto"];
+
+if header :matches "List-ID" "*<address@hidden" @{
+   fileinto "address@hidden@}";
+   stop;
address@hidden
address@hidden example
+
+If @code{:regex} match is used, the match variables starting from
address@hidden@address@hidden refer to the substrings of the argument value 
matching
+subsequent parenthesized groups of the regular expression.  
+
address@hidden Test {} string address@hidden @
+                          address@hidden @
+                          @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.
address@hidden deftypefn
+
address@hidden environment
address@hidden environment
+
+The @samp{environment} extension complies with @cite{RFC 5183}.  It is
+a built-in extension.  It introduces the following test:
+
address@hidden Test {} environment address@hidden @
+                               address@hidden @
+                               @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}.
address@hidden deftypefn
+
+The following environment items are defined:
+
address@hidden @asis
address@hidden domain
+The primary DNS domain of the machine where the Sieve script is
+executing.
+
address@hidden host
+The fully-qualified domain name of the host where the Sieve script is
+executing. 
+
address@hidden location
+Type of service that is evaluating the script.   Depending on the
+utility that is evaluating the script it is:
+
address@hidden @columnfractions 0.6 0.4
address@hidden Utility @tab Location
address@hidden sieve @tab @samp{"MUA"}, or set with the @option{--environment} 
option.
address@hidden maidag @tab @samp{"MDA"}
address@hidden inc @tab @samp{"MUA"}
address@hidden multitable
+
address@hidden name
+The string @samp{GNU Mailutils}
+
address@hidden 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:
+
address@hidden @columnfractions 0.6 0.4
address@hidden Utility @tab Location
address@hidden sieve @tab @samp{post} unless set with the 
@option{--environment} option.
address@hidden maidag @tab @samp{"during"}
address@hidden inc @tab @samp{"post"}
address@hidden multitable
+
address@hidden version
+Mailutils version string (e.g. @address@hidden).
address@hidden table
+
address@hidden numaddr
address@hidden The numaddr extension
+
+This is an example loadable extension.  @ref{External Tests, numaddr}.
+
address@hidden editheader
address@hidden The editheader extension
+
+The @code{editheader} extension complies with @cite{RFC 5293}.  It
+provides the following actions:
+
address@hidden 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
address@hidden:last} is specified, it is appended at the end.
address@hidden deftypefn
+
address@hidden Action {} deleteheader" [:index @var{fieldno}(number) :last] @
+                                   address@hidden @
+                                   address@hidden @
+                                   @var{field-name}(string) @
+                                   address@hidden(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
address@hidden 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
+
address@hidden
+deleteheader :index 1 :contains "Delivered-To" "bob@@example.com";
address@hidden example
+
address@hidden
+would delete the first @samp{Delivered-To} header field if it contains
+the string @samp{bob@@example.com}.
address@hidden deftypefn
+
address@hidden list
address@hidden The list extension
+
address@hidden Tests, list}.
+
address@hidden moderator
address@hidden The moderator extension
+
+A loadable extension implementing a moderator robot for Mailman-driven
+mail archives.  @ref{External Actions, moderator}.
+
address@hidden pipe
address@hidden The pipe extension
+
+A loadable extension for external command execution.  It provides the
address@hidden action (@pxref{External Actions, pipe}) and test
+(@pxref{External Tests, pipe}).  
+
address@hidden spamd
address@hidden The spamd extension
+
+Implements a test which interfaces to SpamAssassin filter.  This is a
+loadable extension.  @pxref{External Tests, spamd}.
+
address@hidden timestamp
address@hidden The timestamp extension
+
+The loadable extension @code{timestamp} implements a test for 
+comparing the value of a structured date header field with the given
+date.
+
+Note: this extension will probably phase away in favor of the
address@hidden Sieve extension (@cite{RFC 5260}).
+
address@hidden vacation
address@hidden The vacation extension
+
+The loadable extension @code{vacation} provides the action intended to
+inform the sender that the recipient is not currently reading his mail.
+
address@hidden Actions,vacation}.
+
 @node GNU Extensions
 @section GNU Extensions
 
diff --git a/examples/nntpclient.c b/examples/nntpclient.c
index 1e53b86..4b3da10 100644
--- a/examples/nntpclient.c
+++ b/examples/nntpclient.c
@@ -953,7 +953,7 @@ com_info (char *arg)
 
   if (!printed)
     {
-      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+      printf ("No commands match `%s'.  Possibilities are:\n", arg);
 
       for (i = 0; commands[i].name; i++)
        {
diff --git a/imap4d/uid.c b/imap4d/uid.c
index 97f8088..bc5d7b5 100644
--- a/imap4d/uid.c
+++ b/imap4d/uid.c
@@ -49,7 +49,7 @@ imap4d_uid (struct imap4d_session *session,
     rc = imap4d_search0 (tok, 1, &err_text);
   else
     {
-      err_text = "Uknown uid command";
+      err_text = "Unknown uid command";
       rc = RESP_BAD;
     }
   return io_completion_response (command, rc, "%s %s", cmd, err_text);
diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h
index 4e07497..fbe545d 100644
--- a/include/mailutils/sieve.h
+++ b/include/mailutils/sieve.h
@@ -279,9 +279,13 @@ void mu_sieve_set_data (mu_sieve_machine_t mach, void *);
 mu_message_t mu_sieve_get_message (mu_sieve_machine_t mach);
 size_t mu_sieve_get_message_num (mu_sieve_machine_t mach);
 
+mu_mailbox_t mu_sieve_get_mailbox (mu_sieve_machine_t mach);
+
 int mu_sieve_is_dry_run (mu_sieve_machine_t mach);
 int mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val);
 
+void mu_sieve_get_argc (mu_sieve_machine_t mach, size_t *args, size_t *tags);
+
 mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t mach);
 int mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *);
 char *mu_sieve_get_daemon_email (mu_sieve_machine_t mach);
diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c
index b570ccf..c072a5b 100644
--- a/libmailutils/string/wordsplit.c
+++ b/libmailutils/string/wordsplit.c
@@ -1332,7 +1332,6 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t 
len,
       struct mu_wordsplit ws;
 
       rc = _wsplt_subsplit (wsp, &ws, str, j,
-                           MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
                            MU_WRDSF_WS | MU_WRDSF_QUOTE);
       if (rc)
        {
@@ -2064,30 +2063,42 @@ mu_wordsplit_c_quote_copy (char *dst, const char *src, 
int quote_hex)
        }
     }
 }
+
 
+/* This structure describes a single expansion phase */
 struct exptab
 {
-  char *descr;
-  int flag;
-  int opt;
-  int (*expansion) (struct mu_wordsplit *wsp);
+  char *descr;     /* Textual description (for debugging) */
+  int flag;        /* MU_WRDSF_ bit that controls this phase */
+  int opt;         /* Entry-specific options (see EXPOPT_ flags below */
+  int (*expansion) (struct mu_wordsplit *wsp); /* expansion function */
 };
 
+/* The following options control expansions: */
+/* Normally the exptab entry is run if its flag bit is set in struct
+   wordsplit.  The EXPOPT_NEG option negates this test so that expansion
+   is performed if its associated flag bit is not set in struct wordsplit. */
 #define EXPOPT_NEG      0x01
+/* Coalesce the input list before running the expansion. */
 #define EXPOPT_COALESCE 0x02
 
 static struct exptab exptab[] = {
-  { N_("WS trimming"),          MU_WRDSF_WS,         0, mu_wordsplit_trimws },
-  { N_("tilde expansion"),      MU_WRDSF_PATHEXPAND, 0, 
mu_wordsplit_tildexpand },
+  { N_("WS trimming"),          MU_WRDSF_WS,         0,
+    mu_wordsplit_trimws },
+  { N_("command substitution"), MU_WRDSF_NOCMD,      
EXPOPT_NEG|EXPOPT_COALESCE,
+    mu_wordsplit_cmdexp },
+  { N_("coalesce list"),        0,                   
EXPOPT_NEG|EXPOPT_COALESCE,
+    NULL },
+  { N_("tilde expansion"),      MU_WRDSF_PATHEXPAND, 0,
+    mu_wordsplit_tildexpand },
   { N_("variable expansion"),   MU_WRDSF_NOVAR,      EXPOPT_NEG,
     mu_wordsplit_varexp },
-  { N_("quote removal"),        0,                EXPOPT_NEG,
+  { N_("quote removal"),        0,                   EXPOPT_NEG,
     wsnode_quoteremoval },
-  { N_("command substitution"), MU_WRDSF_NOCMD,      
EXPOPT_NEG|EXPOPT_COALESCE,
-    mu_wordsplit_cmdexp },
-  { N_("coalesce list"),        0,                EXPOPT_NEG|EXPOPT_COALESCE,
+  { N_("coalesce list"),        0,                   
EXPOPT_NEG|EXPOPT_COALESCE,
     NULL },
-  { N_("path expansion"),       MU_WRDSF_PATHEXPAND, 0, 
mu_wordsplit_pathexpand },
+  { N_("path expansion"),       MU_WRDSF_PATHEXPAND, 0,
+    mu_wordsplit_pathexpand },
   { NULL }
 };
     
@@ -2335,7 +2346,7 @@ mu_wordsplit_perror (struct mu_wordsplit *wsp)
       break;
 
     default:
-      wsp->ws_error (mu_wordsplit_strerror (wsp));
+      wsp->ws_error ("%s", mu_wordsplit_strerror (wsp));
     }
 }
 
diff --git a/libmailutils/tests/wordsplit.at b/libmailutils/tests/wordsplit.at
index f2d4bf0..96d2b1f 100644
--- a/libmailutils/tests/wordsplit.at
+++ b/libmailutils/tests/wordsplit.at
@@ -420,5 +420,208 @@ NF: 1
 ],
 [input exhausted
 ])
-
+
+dnl Something that doesn't fit into TESTWSP
+
+AT_SETUP([simple command substitution])
+AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-1])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+wsp -nocmd <<'EOT'
+begin $(find dir) end
+EOT
+],
+[0],
+[NF: 4
+0: begin
+1: dir
+2: dir/file
+3: end
+])
+AT_CLEANUP
+
+AT_SETUP([quoted command substitution])
+AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-2])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+wsp -nocmd <<'EOT'
+begin "$(find dir)" end
+EOT
+],
+[0],
+[NF: 3
+0: begin
+1: "dir dir/file"
+2: end
+])
+AT_CLEANUP
+
+AT_SETUP([coalesced command substitution])
+AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-3])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+wsp -nocmd <<'EOT'
+begin($(find dir))end
+EOT
+],
+[0],
+[NF: 2
+0: begin(dir
+1: dir/file)end
+])
+AT_CLEANUP
+
+AT_SETUP([quoted coalesced command substitution])
+AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-4])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+wsp -nocmd <<'EOT'
+"begin($(find dir))end"
+EOT
+],
+[0],
+[NF: 1
+0: "begin(dir dir/file)end"
+])
+AT_CLEANUP
+
+AT_SETUP([variable and command substitution])
+AT_KEYWORDS([wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+DIR=dir wsp -nocmd -novar<<'EOT'
+begin $DIR $(find $DIR) end
+EOT
+],
+[0],
+[NF: 5
+0: begin
+1: dir
+2: dir
+3: dir/file
+4: end
+])
+AT_CLEANUP
+
+AT_SETUP([variable expansion and command substitution in quotes])
+AT_KEYWORDS([wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6])
+AT_CHECK([
+mkdir dir
+> dir/file
+
+DIR=dir BEGIN=begin wsp -nocmd -novar<<'EOT'
+"${BEGIN}($(find $DIR))end"
+EOT
+],
+[0],
+[NF: 1
+0: "begin(dir dir/file)end"
+])
+AT_CLEANUP
+
+AT_SETUP([nested commands])
+AT_KEYWORDS([wordsplit wsp wsp-cmd])
+AT_CHECK([
+AT_DATA([input],[foo
+bar
+baz
+])
+SUFFIX=put wsp -nocmd -novar <<'EOT'
+$(echo output $(cat in$SUFFIX))
+EOT
+],
+[0],
+[NF: 4
+0: output
+1: foo
+2: bar
+3: baz
+])
+AT_CLEANUP
+
+AT_SETUP([pathname expansion])
+AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1])
+AT_CHECK([
+mkdir dir
+> dir/1.c
+> dir/2.c
+> dir/3.b
+
+wsp pathexpand<<'EOT'
+begin dir/*.c end
+EOT
+],
+[0],
+[NF: 4
+0: begin
+1: dir/1.c
+2: dir/2.c
+3: end
+])
+AT_CLEANUP
+
+AT_SETUP([pathname expansion: no match])
+AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-2])
+AT_CHECK([
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp pathexpand<<'EOT'
+begin dir/*.d end
+EOT
+],
+[0],
+[NF: 3
+0: begin
+1: dir/*.d
+2: end
+])
+AT_CLEANUP
+
+AT_SETUP([pathname expansion: nullglob])
+AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-3])
+AT_CHECK([
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp pathexpand nullglob<<'EOT'
+begin dir/*.d end
+EOT
+],
+[0],
+[NF: 2
+0: begin
+1: end
+])
+AT_CLEANUP
+
+AT_SETUP([pathname expansion: failglob])
+AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-4])
+AT_CHECK([
+mkdir dir
+> dir/1.c
+> dir/2.b
+
+wsp pathexpand failglob<<'EOT'
+begin dir/*.d end
+EOT
+],
+[0],
+[],
+[no files match pattern dir/*.d
+])
+AT_CLEANUP
+
 m4_popdef([TESTWSP])
diff --git a/libmu_sieve/comparator.c b/libmu_sieve/comparator.c
index e0e12b3..e9936b8 100644
--- a/libmu_sieve/comparator.c
+++ b/libmu_sieve/comparator.c
@@ -225,12 +225,18 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach)
          compfun = comp_false;
          val = mu_sieve_get_arg_untyped (mach, 1);
          /* NOTE: Type of val is always SVT_STRING_LIST */
-         if (val->type != SVT_STRING_LIST)
-           abort ();
-         if (val->v.list.count > 1)
+         switch (val->type)
            {
+           case SVT_STRING:
+             break;
+             
+           case SVT_STRING_LIST:
+             if (val->v.list.count == 1)
+               break;
+             /* fall through */
+           default:
              mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                       _("second argument must be a list of one element"));
+                               _(":count requires second argument to be a list 
of one element"));
              mu_i_sv_error (mach);
              return 1;
            }
diff --git a/libmu_sieve/runtime.c b/libmu_sieve/runtime.c
index 264fa5f..b5739e0 100644
--- a/libmu_sieve/runtime.c
+++ b/libmu_sieve/runtime.c
@@ -183,6 +183,12 @@ mu_sieve_get_locus (mu_sieve_machine_t mach, struct 
mu_locus *loc)
   return 1;
 }
 
+mu_mailbox_t
+mu_sieve_get_mailbox (mu_sieve_machine_t mach)
+{
+  return mach->mailbox;
+}
+
 mu_message_t
 mu_sieve_get_message (mu_sieve_machine_t mach)
 {
@@ -203,6 +209,15 @@ mu_sieve_get_identifier (mu_sieve_machine_t mach)
   return mach->identifier;
 }
 
+void
+mu_sieve_get_argc (mu_sieve_machine_t mach, size_t *args, size_t *tags)
+{
+  if (args)
+    *args = mach->argcount;
+  if (tags)
+    *tags = mach->tagcount;
+}
+
 int
 mu_sieve_is_dry_run (mu_sieve_machine_t mach)
 {
diff --git a/libmu_sieve/sieve.y b/libmu_sieve/sieve.y
index 0a612f1..e39ac72 100644
--- a/libmu_sieve/sieve.y
+++ b/libmu_sieve/sieve.y
@@ -32,7 +32,6 @@ static struct mu_sieve_node *sieve_tree;
 
 static struct mu_sieve_node *node_alloc (enum mu_sieve_node_type,
                                         struct mu_locus_range *);
-static void cond_join (struct mu_sieve_node *node);
 
 #define YYLLOC_DEFAULT(Current, Rhs, N)                         \
   do                                                           \
@@ -158,17 +157,13 @@ statement    : REQUIRE stringorlist ';'
 
 else_part    : maybe_elsif
                {
-                cond_join ($1.head);
                 $$ = $1.head;
               }
              | maybe_elsif ELSE block
                {
-                $3->prev = $1.tail;
-                if ($1.head)
+                if ($1.tail)
                   {
-                    $1.tail->next = $3;
-                    $1.tail = $3;
-                    cond_join ($1.head);
+                    $1.tail->v.cond.iffalse = $3;
                     $$ = $1.head;
                   }
                 else
@@ -183,6 +178,8 @@ maybe_elsif  : /* empty */
              | elsif_branch
              ;
 
+/* elsif branches form a singly-linked version of node_list.  Nodes in
+   this list are linked by v.cond.iffalse pointer */
 elsif_branch : ELSIF cond block
                {
                 struct mu_sieve_node *node =
@@ -199,10 +196,10 @@ elsif_branch : ELSIF cond block
                 node->v.cond.expr = $3;
                 node->v.cond.iftrue = $4;
                 node->v.cond.iffalse = NULL;
-
-                node->prev = $1.tail;
-                $1.tail->next = node;
+                
+                $1.tail->v.cond.iffalse = node;
                 $1.tail = node;
+
                 $$ = $1;
               }
              ;
@@ -405,18 +402,6 @@ yyerror (const char *s)
   mu_i_sv_error (mu_sieve_machine);
   return 0;
 }
-
-static void
-cond_join (struct mu_sieve_node *node)
-{
-  while (node && node->type == mu_sieve_node_cond)
-    {
-      struct mu_sieve_node *next = node->next;
-      node->prev = node->next = NULL;
-      node->v.cond.iffalse = next;
-      node = next;
-    }
-}
 
 static struct mu_sieve_node *
 node_alloc (enum mu_sieve_node_type type, struct mu_locus_range *lr)
diff --git a/mail/mailvar.c b/mail/mailvar.c
index 803f32c..4d46e1d 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -121,7 +121,7 @@ struct mailvar_symbol mailvar_tab[] =
       N_("input message is terminated with a dot alone on a line") },
     { { "editheaders", },
       MAILVAR_TYPEMASK (mailvar_type_boolean),
-      N_("allow to edit message headers while composing") },
+      N_("allow editing message headers while composing") },
     { { "emptystart", },
       MAILVAR_TYPEMASK (mailvar_type_boolean),
       N_("start interactive mode if the mailbox is empty") },
diff --git a/mu/shell.c b/mu/shell.c
index ff4bd05..276057b 100644
--- a/mu/shell.c
+++ b/mu/shell.c
@@ -226,7 +226,7 @@ shell_help (int argc, char **argv)
        print_comtab (mu_strout, com);
       else
        {
-         mu_printf ("No commands match `%s'.  Possibilties are:\n", name);
+         mu_printf ("No commands match `%s'.  Possibilities are:\n", name);
          list_commands (shell_comtab, name);
        }
     }
diff --git a/sieve/sieve.c b/sieve/sieve.c
index edf3b75..dc429a6 100644
--- a/sieve/sieve.c
+++ b/sieve/sieve.c
@@ -484,6 +484,9 @@ main (int argc, char *argv[])
       mu_error (_("cannot initialize sieve machine: %s"), mu_strerror (rc));
       return EX_SOFTWARE;
     }
+
+  sieve_setenv ("location=MS", mach);
+  sieve_setenv ("phase=post", mach);
   mu_list_foreach (env_list, sieve_setenv, mach);
   mu_list_destroy (&env_list);
     
diff --git a/sieve/tests/pipetest.at b/sieve/tests/pipetest.at
index f839060..d09313f 100644
--- a/sieve/tests/pipetest.at
+++ b/sieve/tests/pipetest.at
@@ -17,7 +17,7 @@
 m4_pushdef([MUT_SIEVE_EXT_NAME],[pipe test])
 
 MUT_SIEVE_EXT_TEST([],[pipetest00],
-[require "test-pipe";
+[require "pipe";
 if pipe :header "$cwd/ckmsg"
   {
     discard;


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]