Libmu_sieve is GNU implementation of the mail filtering language Sieve. The library is built around a Sieve Machine --- an abstract computer constructed specially to handle mail filtering tasks. This computer has two registers: program counter and numeric accumulator; a runtime stack of unlimited depth and the code segment. A set of functions is provided for creating and destroying instances of Sieve Machine, manipulating its internal data, compiling and executing a sieve program.

The following is a typical scenario of using libmu_sieve:

 1. Application program creates the instance of sieve machine.

 2. Then mu_sieve_compile function is called to translate the Sieve source into an equivalent program executable by the Machine

 3. A mailbox is opened and associated with the Machine

 4. The Machine executes the program over the mailbox

 5. When the execution of the program is finished, all messages upon which an action was executed other than keep are marked with the delete flag. Thus, running mailbox_expunge upon the mailbox finishes the job, leaving in the mailbox only those messages that were preserved by the filter.

 6. Finally, the instance of Sieve Machine is destroyed and the resources allocated for it are reclaimed.

The following sections describe in detail the functions from the Sieve Library.

Sieve Data Types
----------------

 -- Data Type: mu_sieve_machine_t
     This is an opaque data type representing a pointer to an instance of sieve machine. The mu_sieve_machine_t keeps all information necessary for compiling and executing the script.

     It is created by mu_sieve_machine_create() and destroyed by mu_sieve_machine_destroy(). The functions for manipulating this data type are described in Manipulating the Sieve Machine.

 -- Data Type: mu_sieve_data_type
     This enumeration keeps the possible types of sieve data. These are:

     SVT_VOID
          No datatype.

     SVT_NUMBER
          Numeric type.

     SVT_STRING
          Character string.

     SVT_STRING_LIST
          A list of strings.

     SVT_TAG
          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.

 -- Data Type: mu_sieve_value_t
     The mu_sieve_value_t keeps an instance of sieve data. It is defined as follows:

            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;

     Depending on the value of type member, following members of the union v keep the actual value:

     SVT_VOID
          No associated value.

     SVT_NUMBER
          The numeric value is kept in the number member.

     SVT_STRING_LIST
     SVT_STRING
          The list is identified by the list member of the union mu_sieve_value_storage.  This member is defined as follows:

               struct mu_sieve_slice
               {
                 size_t first;            /* Index of the first string */
                 size_t count;            /* Number of strings */
               };

          The first member identifies the first string in the list. The count member gives the number of strings in the list.  If the data type is SVT_STRING, count is guaranteed to be 1.

          The string itself can be accessed using the mu_sieve_string function (see String Accessors).  For example, the following code fragment iterates over all strings in the list:

               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);
                   ...
                 }

     SVT_TAG
          Never appears.

 -- Data Type: mu_sieve_tag_def_t
     This structure represents a definition of a tagged (optional) argument to a sieve action or test. It is defined as follows:

          typedef struct
          {
            char *name;                 /* Tag name */
            mu_sieve_data_type argtype; /* Type of tag argument. */
          }
          mu_sieve_tag_def_t;

     The name member points to the tag's name without leading colon. The argtype is set to SVT_VOID if the tag does not take argument, or to the type of the argument otherwise.

 -- Data Type: mu_sieve_handler_t

     This is a pointer to function handler for a sieve action or test. It is defined as follows:

          typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t MACH);

     The MACH argument is the machine being worked upon.  The rest of data can be obtained from it.

      -- Data Type: mu_sieve_action_log_t
          A pointer to the application-specific logging function:

               typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t MACH,
               				       const char *ACTION,
               				       const char *FMT,
                                                      va_list AP);

          nach
               The sieve machine.

          action
               The name of the action.

          fmt
               A printf-style format string.

          ap
               Arguments for the format.

      -- Data Type: mu_sieve_relcmp_t
      -- Data Type: mu_sieve_relcmpn_t

               typedef int (*mu_sieve_relcmp_t) (int, int);
               typedef int (*mu_sieve_relcmpn_t) (size_t, size_t);

      -- Data Type: mu_sieve_comparator_t

               typedef int (*mu_sieve_comparator_t) (const char *, const char *);

          A pointer to the comparator handler function. The function compares its two operands and returns 1 if they are equal, and 0 otherwise. Notice, that the sense of the return value is inverted in comparison with most standard libc functions like stcmp(), etc.

      -- Data Type: mu_sieve_retrieve_t

               typedef int (*mu_sieve_retrieve_t) (void *item, void *data, int idx,
                                                   char **pval);

          A pointer to generic retriever function. See description of mu_sieve_vlist_compare() for details of its usage.

      -- Data Type: mu_sieve_destructor_t

               typedef void (*mu_sieve_destructor_t) (void *data);

          A pointer to destructor function. The function frees any resources associated with data. See the description of mu_sieve_machine_add_destructor() for more information.

      -- Data Type: mu_sieve_tag_checker_t

               typedef int (*mu_sieve_tag_checker_t) (const char *NAME)

          A pointer to tag checker function. The purpose of the function is to perform compilation-time consistency test on tags.

          The function is allowed to make any changes in TAGS and ARGS. It should return 0 if the syntax is correct and non-zero otherwise. It is responsible for issuing the diagnostics in the latter case. [FIXME: describe how to do that]

Manipulating the Sieve Machine
------------------------------

This subsection describes functions used to create an instance of the sieve machine, read or alter its internal fields and destroy it.

 -- Function: int mu_sieve_machine_create (mu_sieve_machine_t *MACH)

     The mu_sieve_machine_create() function creates an instance of a sieve machine.  A pointer to the instance itself is returned in the argument MACH. The function returns 0 on success, and a non-zero error code otherwise.

 -- Function: void mu_sieve_machine_destroy (mu_sieve_machine_t *PMACH)

     This function destroys the instance of sieve machine pointed to by MACH parameter. After execution of mu_sieve_machine_destroy() PMACH contains NULL. The destructors registered with mu_sieve_machine_add_destructor() are executed in LIFO order.

 -- Function: int mu_sieve_machine_add_destructor (mu_sieve_machine_t MACH, mu_sieve_destructor_t DESTR, void *PTR);

     This function registers a destructor function DEST. The purpose of the destructor is to free any resources associated with the item 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 mu_sieve_machine_destroy().

      -- Function: void * mu_sieve_get_data (mu_sieve_machine_t MACH)
          This function returns the application-specific data associated with the instance of sieve machine. See mu_sieve_machine_create().

      -- Function: mu_message_t mu_sieve_get_message (mu_sieve_machine_t MACH)
          This function returns the current message.

      -- Function: size_t mu_sieve_get_message_num (mu_sieve_machine_t MACH)
          This function returns the current message number in the mailbox. If there are no mailbox, i.e. the execution of the sieve code is started with mu_sieve_message, this function returns 1.

      -- Function: int mu_sieve_get_debug_level (mu_sieve_machine_t MACH)
          Returns the debug level set for this instance of sieve machine.

      -- Function: mu_mailer_t mu_sieve_get_mailer (mu_sieve_machine_t MACH)
          Returns the mailer.

      -- Function: int mu_sieve_get_locus (mu_sieve_machine_t MACH,
          struct mu_locus *LOCUS)
          Returns the locus in the Sieve source file corresponding to the code pointer where the Sieve machine currently is.

      -- Function: char * mu_sieve_get_daemon_email (mu_sieve_machine_t MACH)
          This function returns the daemon email associated with this instance of sieve machine. The daemon email is an email address used in envelope from addresses of automatic reply messages. By default its local part is <MAILER-DAEMON> and the domain part is the machine name.

      -- Function: void mu_sieve_get_diag_stream (mu_sieve_machine_t MACH,
          mu_stream_t *PSTR)
          Get a reference to the machine's diagnostic stream.  The obtained stream must be dereferenced by using mu_stream_unref or mu_stream_destroy, when no longer needed.

      -- Function: void mu_sieve_set_diag_stream (mu_sieve_machine_t MACH,
          mu_stream_t STREAM Register STREAM as the diagnostic stream for this machine.  The reference count of STREAM is increased.

      -- Function: void mu_sieve_get_dbg_stream (mu_sieve_machine_t MACH,
          mu_stream_t *PSTR)
          Get a reference to the machine's debug output stream.  The obtained stream must be dereferenced by using mu_stream_unref or mu_stream_destroy, when no longer needed.

      -- Function: void mu_sieve_set_dbg_stream (mu_sieve_machine_t MACH,
          mu_stream_t STREAM) Register STREAM as the debug output stream for this machine.  The reference count of STREAM is increased.

      -- Function: void mu_sieve_set_logger (mu_sieve_machine_t MACH, mu_sieve_action_log_t LOGGER)
          This function sets the logger function. By default the logger function is NULL, which means that the executed actions are not logged.

      -- Function: void mu_sieve_set_mailer (mu_sieve_machine_t MACH, mu_mailer_t MAILER)
          This function sets the mailer. The default mailer is "sendmail:".

      -- Function: void mu_sieve_set_daemon_email (mu_sieve_machine_t MACH, const char *EMAIL)
          This functions sets the daemon email for reject and redirect actions.

      -- Function: int mu_sieve_is_dry_run (mu_sieve_machine_t MACH)
          The mu_sieve_is_dry_run() returns 1 if the machine is in dry run state, i.e. it will only log the actions that would have been executed without actually executing them. The dry run state is set by calling mu_sieve_set_debug_level() if its last argument has the MU_SIEVE_DRY_RUN bit set.

      -- Function: const char * mu_sieve_type_str (mu_sieve_data_type TYPE)
          Returns the string representation for the given sieve data type. The return value is a pointer to a static constant string.

Logging and Diagnostic Functions
--------------------------------

 -- Function: void mu_sieve_error (mu_sieve_machine_t MACH, const char *FMT, ...)
     Format and output an error message using error printer of the machine MACH.

 -- Function: void mu_sieve_debug (mu_sieve_machine_t MACH, const char *FMT, ...)
     Format and output a debug message using debug printer of the machine MACH.

 -- Function: void mu_sieve_log_action (mu_sieve_machine_t MACH, const char *ACTION, const char *FMT, ...)
     Log a sieve action using logger function associated with the machine MACH.

 -- Function: void mu_sieve_abort (mu_sieve_machine_t MACH)
     Immediately abort the execution of the script.

String Accessors
----------------

Strings are stored in a special memory area within the Sieve machine, which is called 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:

     struct mu_sieve_slice
     {
       size_t first;            /* Index of the first object */
       size_t count;            /* Number of objects */
     };

A single sieve string is represented by an array of strings with zero count.

To obtain actual value of a string, use the mu_sieve_string function:

 -- Function: char * mu_sieve_string (mu_sieve_machine_t MACH,
     mu_sieve_slice_t SLICE,
     size_t N)
     Return actual textual value of the Nth string in the array SLICE of the Sieve machine MACH.

     If the variables extension is required, the returned value will have variables expanded.

Two functions are provided for manipulating raw string values.  Each string in the string space is kept in the following structure:

     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;

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:

 -- Field of 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.

 -- Field of struct mu_sieve_string: unsigned changed
     This field is 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 constant == 1, then changed == 0.

 -- Field of struct mu_sieve_string: char * orig
     A pointer to the original string value, as it appeared in the Sieve script source file.

 -- Field of struct mu_sieve_string: char * exp
     A pointer to the string value after expansion.  Valid only if constant == 0.

 -- Field of 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 :match or :regex tag.

The raw string values are accessed via the following two functions:

 -- Function: mu_sieve_string_t * mu_sieve_string_raw (mu_sieve_machine_t MACH,
     mu_sieve_slice_t SLICE,
     size_t N)
     Returns pointer to the structure representing Nth string in slice SLICE.  A runtime exception is raised if N is out of range represented by SLICE.

     Extension writers should treat this as a constant object.

 -- Function: char * mu_sieve_string_get (mu_sieve_machine_t MACH,
     mu_sieve_string_t *STRING)
     Evaluate STRING and return its textual representation.  If the variables extension is required, this function performs variable substitution.

Argument Accessors
------------------

Symbol Space Functions
----------------------

 -- Function: mu_sieve_register_t * mu_sieve_test_lookup (mu_sieve_machine_t MACH, const char *NAME)
     Find a register object describing the test NAME. Returns NULL if no such test exists.

 -- Function: mu_sieve_register_t * mu_sieve_action_lookup (mu_sieve_machine_t MACH, const char *NAME)
     Find a register object describing the action NAME. Returns NULL if no such action exists.

 -- Function: int mu_sieve_register_test (mu_sieve_machine_t MACH, const char *NAME, mu_sieve_handler_t HANDLER, mu_sieve_data_type *ARG_TYPES, mu_sieve_tag_group_t *TAGS, int REQUIRED)

 -- Function: int mu_sieve_register_action (mu_sieve_machine_t MACH, const char *NAME, mu_sieve_handler_t HANDLER, mu_sieve_data_type *ARG_TYPES, mu_sieve_tag_group_t *TAGS, int REQUIRED)

 -- Function: int mu_sieve_register_comparator (mu_sieve_machine_t MACH, const char *NAME, int REQUIRED, mu_sieve_comparator_t IS, mu_sieve_comparator_t CONTAINS, mu_sieve_comparator_t MATCHES, mu_sieve_comparator_t REGEX, mu_sieve_comparator_t EQ)

 -- Function: int mu_sieve_tag_lookup (mu_list_t TAGLIST, char *NAME, mu_sieve_value_t **ARG)

 -- Function: int mu_sieve_load_ext (mu_sieve_machine_t MACH, const char *NAME)

Memory Allocation
-----------------

The following functions act as their libc counterparts. The allocated memory is associated with the MACH argument and is automatically freed upon the call to mu_sieve_machine_destroy (MACH).

 -- Function: void * mu_sieve_malloc (mu_sieve_machine_t MACH, size_t SIZE)
     Allocates SIZE bytes and returns a pointer to the allocated memory.

 -- Function: char * mu_sieve_strdup (mu_sieve_machine_t MACH, const char *STR)
     This function returns a pointer to a new string  which is a duplicate of the string STR.

 -- Function: void * mu_sieve_realloc (mu_sieve_machine_t MACH, void *PTR, size_t SIZE)
     Changes the size of the memory block pointed to by PTR to SIZE bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If PTR is NULL, the call is equivalent to mu_sieve_malloc(MACH, SIZE); if SIZE is equal to zero, the call is equivalent to mu_sieve_free(PTR). Unless PTR is NULL, it must have been returned by an earlier call to mu_sieve_malloc() or mu_sieve_realloc().

 -- Function: void mu_sieve_free (mu_sieve_machine_t MACH, void *PTR)
     mu_sieve_free() frees the memory space pointed to by PTR and detaches it from the destructor list of MACH. The PTR must have been returned by a previous call to mu_sieve_malloc() or mu_sieve_realloc(). Otherwise, or if mu_sieve_mfree(PTR) has already been called before, undefined behaviour occurs.

     If PTR is NULL, no operation is performed.

Compiling and Executing the Script
----------------------------------

 -- Function: int mu_sieve_compile (mu_sieve_machine_t MACH, const char *NAME)
     Compile the sieve script from the file NAME.

 -- Function: int mu_sieve_mailbox (mu_sieve_machine_t MACH, mu_mailbox_t MBOX)
     Execute the code from the given instance of sieve machine MACH over each message in the mailbox MBOX.

 -- Function: int mu_sieve_message (mu_sieve_machine_t MACH, mu_message_t MESSAGE)
     Execute the code from the given instance of sieve machine MACH over the MESSAGE.

 -- Function: int mu_sieve_disass (mu_sieve_machine_t MACH)
     Dump the disassembled code of the sieve machine MACH.

Writing Loadable Commands
-------------------------

This section contains an example of how to write external loadable commands for GNU libmu_sieve.

          [file numaddr.inc not included]