Previous: Compiling and Executing the Script, Up: libsieve


3.4.7 Writing Loadable Commands

This section contains an example of how to write external loadable commands for gnu libsieve.

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     /*  This is an example on how to write extension tests for GNU sieve.
         It provides test "numaddr".
     
         Syntax:   numaddr [":over" / ":under"] <header-names: string-list>
                   <limit: number>
     
         The "numaddr" test counts Internet addresses in structured headers
         that contain addresses.  It returns true if the total number of
         addresses satisfies the requested relation:
     
         If the argument is ":over" and the number of addresses is greater than
         the number provided, the test is true; otherwise, it is false.
     
         If the argument is ":under" and the number of addresses is less than
         the number provided, the test is true; otherwise, it is false.
     
         If the argument is empty, ":over" is assumed. */
     
     #ifdef HAVE_CONFIG_H
     # include <config.h>
     #endif
     
     #include <stdlib.h>
     #include <mailutils/libsieve.h>
     
     struct val_ctr {  /* Data passed to the counter function */
       mu_header_t hdr;   /* Headers of the current message */
       size_t limit;   /* Limit for the number of addresses */
       size_t count;   /* Number of addresses counted so far */
     };
     
     /* Count addresses in a single header value.
     
        Input:
          ITEM is the name of the header to scan.
          DATA is a pointer to the val_ctr structure
        Return value:
          non-zero if the limit on the number of addresses has been reached. */
     
     static int
     _count_items (void *item, void *data)
     {
       char *name = item;
       struct val_ctr *vp = data;
       char *val;
       mu_address_t addr;
       size_t count = 0;
     
       if (mu_header_aget_value (vp->hdr, name, &val))
         return 0;
       if (mu_address_create (&addr, val) == 0)
         {
           mu_address_get_count (addr, &count);
           mu_address_destroy (&addr);
           vp->count += count;
         }
       free (val);
       return vp->count >= vp->limit;
     }
     
     /* Handler for the numaddr test */
     static int
     numaddr_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
     {
       mu_sieve_value_t *h, *v;
       struct val_ctr vc;
       int rc;
     
       if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
         {
           mu_sieve_locus_t locus;
           mu_sieve_get_locus (mach, &locus);
           mu_sieve_debug (mach, "%s:%lu: NUMADDR\n",
     		   locus.source_file,
     		   (unsigned long) locus.source_line);
         }
     
       /* Retrieve required arguments: */
       /* First argument: list of header names */
       h = mu_sieve_value_get (args, 0);
       if (!h)
         {
           mu_sieve_error (mach, "numaddr: can't get argument 1");
           mu_sieve_abort (mach);
         }
       /* Second argument: Limit on the number of addresses */
       v = mu_sieve_value_get (args, 1);
       if (!v)
         {
           mu_sieve_error (mach, "numaddr: can't get argument 2");
           mu_sieve_abort (mach);
         }
     
       /* Fill in the val_ctr structure */
       mu_message_get_header (mu_sieve_get_message (mach), &vc.hdr);
       vc.count = 0;
       vc.limit = v->v.number;
     
       /* Count the addresses */
       rc = mu_sieve_vlist_do (h, _count_items, &vc);
     
       /* Here rc >= 1 iff the counted number of addresses is greater or equal
          to vc.limit. If `:under' tag was given we reverse the return value */
       if (mu_sieve_tag_lookup (tags, "under", NULL))
         rc = !rc;
       return rc;
     }
     
     /* Syntactic definitions for the numaddr test */
     
     /* Required arguments: */
     static mu_sieve_data_type numaddr_req_args[] = {
       SVT_STRING_LIST,
       SVT_NUMBER,
       SVT_VOID
     };
     
     /* Tagged arguments: */
     static mu_sieve_tag_def_t numaddr_tags[] = {
       { "over", SVT_VOID },
       { "under", SVT_VOID },
       { NULL }
     };
     
     static mu_sieve_tag_group_t numaddr_tag_groups[] = {
       { numaddr_tags, NULL },
       { NULL }
     };
     
     /* Initialization function. It is the only function exported from this
        module. */
     int
     SIEVE_EXPORT(numaddr,init) (mu_sieve_machine_t mach)
     {
       return mu_sieve_register_test (mach, "numaddr", numaddr_test,
                                   numaddr_req_args, numaddr_tag_groups, 1);
     }