Commit 15f6dbf6 15f6dbf66eed6bed5c084d97077e7cc5f8e192a7 by Sergey Poznyakoff

sieve: change string allocation and argument passing convention

Strings are allocated in a per-machine string space.  String and
argument lists form contiguous arrays of structures.  Regular ex-
pressions are compiled when they are needed. Compiled expressions
are cached for eventual reuse.
1 parent ed04bc83
......@@ -95,7 +95,7 @@ numaddr_test (mu_sieve_machine_t mach)
vc.count = 0;
/* Count the addresses */
rc = mu_sieve_vlist_do (h, _count_items, &vc);
rc = mu_sieve_vlist_do (mach, 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 */
......
......@@ -33,6 +33,13 @@ extern "C" {
typedef struct mu_sieve_machine *mu_sieve_machine_t;
typedef struct mu_sieve_string
{
char *orig;
char *exp;
void *rx;
} mu_sieve_string_t;
typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t mach);
typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t mach,
const char *action,
......@@ -40,13 +47,12 @@ typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t mach,
typedef int (*mu_sieve_relcmp_t) (int, int);
typedef int (*mu_sieve_relcmpn_t) (size_t, size_t);
typedef int (*mu_sieve_comparator_t) (const char *, const char *);
typedef int (*mu_sieve_comparator_t) (mu_sieve_machine_t mach,
mu_sieve_string_t *, const char *);
typedef int (*mu_sieve_retrieve_t) (void *item, void *data, int idx,
char **pval);
typedef void (*mu_sieve_destructor_t) (void *data);
typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach,
const char *name,
mu_list_t tags, mu_list_t args);
typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach);
typedef enum
{
......@@ -55,24 +61,29 @@ typedef enum
SVT_STRING,
SVT_STRING_LIST,
SVT_TAG,
SVT_IDENT,
SVT_POINTER
SVT_IDENT
}
mu_sieve_data_type;
typedef struct mu_sieve_runtime_tag mu_sieve_runtime_tag_t;
struct mu_sieve_slice
{
size_t first;
size_t count;
};
typedef struct mu_sieve_slice *mu_sieve_slice_t;
union mu_sieve_value_storage
{
char *string;
size_t number;
mu_list_t list;
void *ptr;
struct mu_sieve_slice list;
};
typedef struct
{
mu_sieve_data_type type;
char *tag;
union mu_sieve_value_storage v;
} mu_sieve_value_t;
......@@ -88,12 +99,6 @@ typedef struct
mu_sieve_tag_checker_t checker;
} mu_sieve_tag_group_t;
struct mu_sieve_runtime_tag
{
char *tag;
mu_sieve_value_t *arg;
};
typedef struct
{
const char *name;
......@@ -135,11 +140,9 @@ void *mu_sieve_realloc (mu_sieve_machine_t mach, void *ptr, size_t size);
void mu_sieve_reclaim_default (void *p);
void mu_sieve_reclaim_list (void *p);
void mu_sieve_reclaim_value (void *p);
void mu_sieve_reclaim_tag (void *p);
mu_sieve_value_t *mu_sieve_value_create (mu_sieve_machine_t mach,
size_t mu_sieve_value_create (mu_sieve_machine_t mach,
mu_sieve_data_type type, void *data);
void mu_sieve_slist_destroy (mu_list_t *plist);
/* Symbol space functions */
mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach,
......@@ -185,30 +188,41 @@ int mu_sieve_str_to_relcmp (const char *str, mu_sieve_relcmp_t *test,
mu_sieve_relcmpn_t *stest);
mu_sieve_relcmp_t mu_sieve_get_relcmp (mu_sieve_machine_t mach);
void mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist);
void mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list);
void mu_sieve_value_get (mu_sieve_machine_t mach, mu_sieve_value_t *val,
mu_sieve_data_type type, void *ret);
int mu_sieve_get_tag (mu_sieve_machine_t mach, char *name,
mu_sieve_data_type type, void *ret);
int mu_sieve_get_tag_untyped (mu_sieve_machine_t mach,
char *name, mu_sieve_value_t **ret);
mu_sieve_value_t *mu_sieve_get_tag_untyped (mu_sieve_machine_t mach,
char const *name);
mu_sieve_value_t *mu_sieve_get_tag_n (mu_sieve_machine_t mach, size_t n);
int mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags,
mu_list_t args);
int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags,
mu_list_t args);
int mu_sieve_match_part_checker (mu_sieve_machine_t mach);
/* Operations on value lists */
mu_sieve_value_t *mu_sieve_get_arg_optional (mu_sieve_machine_t mach,
size_t index);
mu_sieve_value_t *mu_sieve_get_arg_untyped (mu_sieve_machine_t mach,
size_t index);
int mu_sieve_get_arg (mu_sieve_machine_t mach, size_t index,
void mu_sieve_get_arg (mu_sieve_machine_t mach, size_t index,
mu_sieve_data_type type, void *ret);
int mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac,
char *mu_sieve_string (mu_sieve_machine_t mach,
mu_sieve_slice_t slice,
size_t i);
struct mu_sieve_string *mu_sieve_string_raw (mu_sieve_machine_t mach,
mu_sieve_slice_t slice,
size_t i);
int mu_sieve_vlist_do (mu_sieve_machine_t mach,
mu_sieve_value_t *val, mu_list_action_t ac,
void *data);
int mu_sieve_vlist_compare (mu_sieve_value_t *a, mu_sieve_value_t *b,
int mu_sieve_vlist_compare (mu_sieve_machine_t mach,
mu_sieve_value_t *a, mu_sieve_value_t *b,
mu_sieve_comparator_t comp,
mu_sieve_relcmp_t test, mu_sieve_retrieve_t ac,
void *data, size_t *count);
......
......@@ -42,6 +42,7 @@ libmu_sieve_la_SOURCES = \
sieve-gram.h\
sieve-lex.c\
strexp.c\
string.c\
tests.c\
util.c
libmu_sieve_la_LIBADD = ${MU_LIB_MAILUTILS} @LTDL_LIB@
......
......@@ -511,24 +511,22 @@ mu_sieve_data_type fileinto_args[] = {
};
static int
perms_tag_checker (mu_sieve_machine_t mach,
const char *name, mu_list_t tags, mu_list_t args)
perms_tag_checker (mu_sieve_machine_t mach)
{
mu_iterator_t itr;
size_t i;
int err = 0;
if (!tags || mu_list_get_iterator (tags, &itr))
if (mach->tagcount == 0)
return 0;
for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
for (i = 0; i < mach->tagcount; i++)
{
int flag;
const char *p;
mu_sieve_runtime_tag_t *t;
mu_iterator_current (itr, (void **)&t);
mu_sieve_value_t *t = mu_sieve_get_tag_n (mach, i);
if (strcmp (t->tag, "permissions") == 0)
{
if (mu_parse_stream_perm_string (&flag, t->arg->v.string, &p))
if (mu_parse_stream_perm_string (&flag, t->v.string, &p))
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("invalid permissions (near %s)"), p);
......@@ -537,7 +535,6 @@ perms_tag_checker (mu_sieve_machine_t mach,
}
}
}
mu_iterator_destroy (&itr);
return err;
}
......
......@@ -81,7 +81,6 @@ sieve_deleteheader (mu_sieve_machine_t mach)
{
mu_sieve_value_t *val;
const char *field_name;
const char *field_pattern;
mu_message_t msg;
mu_header_t hdr;
int rc;
......@@ -91,41 +90,9 @@ sieve_deleteheader (mu_sieve_machine_t mach)
mu_sieve_get_arg (mach, 0, SVT_STRING, &field_name);
val = mu_sieve_get_arg_optional (mach, 1);
if (!val)
{
field_pattern = NULL;
mu_sieve_log_action (mach, "DELETEHEADER", "%s", field_name);
}
else
{
switch (val->type)
{
case SVT_STRING_LIST:
if (mu_list_get (val->v.list, 0, (void**)&field_pattern))
{
mu_sieve_error (mach, "%lu: %s",
(unsigned long) mu_sieve_get_message_num (mach),
_("cannot get list item"));
mu_sieve_abort (mach);
}
mu_sieve_log_action (mach, "DELETEHEADER", "%s: (regexp)",
field_name);
break;
case SVT_STRING:
field_pattern = val->v.string;
mu_sieve_log_action (mach, "DELETEHEADER", "%s: %s", field_name,
field_pattern);
break;
default:
mu_sieve_error (mach, "%lu: %s: %d",
(unsigned long) mu_sieve_get_message_num (mach),
_("unexpected value type"), val->type);
mu_sieve_abort (mach);
}
}
mu_sieve_log_action (mach, "DELETEHEADER", "%s%s", field_name,
val ? " (values)" : "" );
if (mu_sieve_is_dry_run (mach))
return 0;
......@@ -141,7 +108,14 @@ sieve_deleteheader (mu_sieve_machine_t mach)
mu_sieve_abort (mach);
}
mu_header_get_iterator (hdr, &itr);
rc = mu_header_get_iterator (hdr, &itr);
if (rc)
{
mu_sieve_error (mach, "mu_header_get_iterator: %s",
mu_strerror (rc));
mu_sieve_abort (mach);
}
if (mu_sieve_get_tag (mach, "last", SVT_VOID, NULL))
{
int backwards = 1;
......@@ -162,10 +136,18 @@ sieve_deleteheader (mu_sieve_machine_t mach)
if (idx && ++i < idx)
continue;
if (field_pattern)
if (val)
{
for (i = 0; i < val->v.list.count; i++)
{
mu_sieve_string_t *s = mu_sieve_string_raw (mach,
&val->v.list, i);
if (comp (mach, s, fv))
{
if (comp (field_pattern, fv))
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
break;
}
}
}
else
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
......
......@@ -159,7 +159,7 @@ list_test (mu_sieve_machine_t mach)
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
mu_message_get_header (mu_sieve_get_message (mach), &clos.header);
result = mu_sieve_vlist_compare (h, v, comp,
result = mu_sieve_vlist_compare (mach, h, v, comp,
mu_sieve_get_relcmp (mach),
list_retrieve_header,
&clos, NULL) > 0;
......
......@@ -161,8 +161,8 @@ _compare (void *item, void *data)
of the originating mail. Return non-zero if so and store a pointer
to the matching address in *MY_ADDRESS. */
static int
match_addresses (mu_header_t hdr, char *email, mu_sieve_value_t *addresses,
char const **my_address)
match_addresses (mu_sieve_machine_t mach, mu_header_t hdr, char *email,
mu_sieve_value_t *addresses, char const **my_address)
{
int match = 0;
const char *str;
......@@ -176,7 +176,7 @@ match_addresses (mu_header_t hdr, char *email, mu_sieve_value_t *addresses,
if (_compare (email, &ad))
match = 1;
else if (addresses)
match += mu_sieve_vlist_do (addresses, _compare, &ad);
match += mu_sieve_vlist_do (mach, addresses, _compare, &ad);
mu_address_destroy (&ad.addr);
}
}
......@@ -188,7 +188,7 @@ match_addresses (mu_header_t hdr, char *email, mu_sieve_value_t *addresses,
if (_compare (email, &ad))
match = 1;
else if (addresses)
match += mu_sieve_vlist_do (addresses, _compare, &ad);
match += mu_sieve_vlist_do (mach, addresses, _compare, &ad);
mu_address_destroy (&ad.addr);
}
}
......@@ -249,8 +249,8 @@ noreply_address_p (mu_sieve_machine_t mach, char *email)
for (i = 0; rc == 0 && noreply_sender[i]; i++)
rc = regex_comparator (noreply_sender[i], &rd);
if (!rc && mu_sieve_get_tag_untyped (mach, "noreply", &arg))
rc = mu_sieve_vlist_do (arg, regex_comparator, &rd);
if (!rc && (arg = mu_sieve_get_tag_untyped (mach, "noreply")) != NULL)
rc = mu_sieve_vlist_do (mach, arg, regex_comparator, &rd);
return rc;
}
......@@ -716,12 +716,13 @@ vacation_reply (mu_sieve_machine_t mach, mu_message_t msg,
{
mu_header_set_value (newhdr, MU_HEADER_TO, to, 0);
if (mu_sieve_get_tag_untyped (mach, "header", &val))
val = mu_sieve_get_tag_untyped (mach, "header");
if (val)
{
struct header_closure hc;
hc.mach = mach;
hc.hdr = newhdr;
mu_sieve_vlist_do (val, add_header, &hc);
mu_sieve_vlist_do (mach, val, add_header, &hc);
}
vacation_subject (mach, msg, newhdr);
......@@ -807,9 +808,8 @@ sieve_action_vacation (mu_sieve_machine_t mach)
return_address = my_address;
else
{
mu_sieve_value_t *val = NULL;
mu_sieve_get_tag_untyped (mach, "aliases", &val);
if (match_addresses (hdr, my_address, val, &return_address) == 0)
mu_sieve_value_t *val = mu_sieve_get_tag_untyped (mach, "aliases");
if (match_addresses (mach, hdr, my_address, val, &return_address) == 0)
{
free (my_address);
return 0;
......
......@@ -197,10 +197,41 @@ mu_sieve_reclaim_value (void *p)
free (p);
}
/* Based on gnulib's x2nrealloc */
void
mu_sieve_reclaim_tag (void *p)
mu_i_sv_2nrealloc (mu_sieve_machine_t mach, void **pptr, size_t *pnmemb,
size_t size)
{
mu_sieve_runtime_tag_t *tag = p;
mu_sieve_reclaim_value (tag->arg);
}
void *ptr = *pptr;
size_t nmemb = *pnmemb;
if (!ptr)
{
if (!nmemb)
{
/* Initial allocation size */
nmemb = 16;
}
}
else
{
/* Set NMEMB = floor (1.5 * NMEMB) + 1 so that progress is made even
if NMEMB == 0.
Check for overflow, so that NMEMB * SIZE stays in size_t range.
The check may be slightly conservative, but an exact check isn't
worth the trouble. */
if ((size_t) -1 / 3 * 2 / size <= nmemb)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("requested too much memory %zu * %zu"),
nmemb, size);
mu_sieve_abort (mach);
}
nmemb += nmemb / 2 + 1;
}
ptr = mu_sieve_realloc (mach, ptr, nmemb * size);
*pptr = ptr;
*pnmemb = nmemb;
}
......
......@@ -24,25 +24,15 @@
#include <assert.h>
#include <sieve-priv.h>
int
void
mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op)
{
if (mach->pc >= mach->progsize)
{
size_t newsize = mach->progsize + SIEVE_CODE_INCR;
sieve_op_t *newprog =
mu_sieve_realloc (mach, mach->prog, newsize * sizeof mach->prog[0]);
if (!newprog)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, _("not enough memory"));
mu_i_sv_error (mach);
return 1;
}
mach->prog = newprog;
mach->progsize = newsize;
mu_i_sv_2nrealloc (mach, (void**) &mach->prog, &mach->progsize,
sizeof mach->prog[0]);
}
mach->prog[mach->pc++] = op;
return 0;
}
static int
......@@ -105,63 +95,66 @@ _compare_ptr (void *item, void *data)
struct check_arg
{
struct mu_sieve_machine *mach;
const char *name;
mu_list_t args;
mu_list_t tags;
struct mu_sieve_node *node;
};
static int
_run_checker (void *item, void *data)
{
struct check_arg *arg = data;
return (*(mu_sieve_tag_checker_t)item) (arg->mach, arg->name,
arg->tags, arg->args);
mu_sieve_machine_t mach = arg->mach;
struct mu_sieve_node *node = arg->node;
mu_sieve_tag_checker_t checker = item;
int rc;
mach->comparator = node->v.command.comparator;
mach->argstart = node->v.command.argstart;
mach->argcount = node->v.command.argcount;
mach->tagcount = node->v.command.tagcount;
mach->identifier = node->v.command.reg->name;
rc = checker (arg->mach);
/* checker is allowed to alter these values */
node->v.command.comparator = mach->comparator;
node->v.command.argcount = mach->argcount;
node->v.command.tagcount = mach->tagcount;
mach->argstart = 0;
mach->argcount = 0;
mach->tagcount = 0;
mach->identifier = NULL;
return rc;
}
static int
sv_code_command (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
void
mu_i_sv_lint_command (struct mu_sieve_machine *mach,
struct mu_sieve_node *node)
{
mu_iterator_t itr;
mu_list_t arg_list = NULL;
mu_list_t tag_list = NULL;
size_t i;
mu_sieve_register_t *reg = node->v.command.reg;
mu_sieve_value_t *start = mach->valspace + node->v.command.argstart;
mu_list_t chk_list = NULL;
mu_sieve_data_type *exp_arg;
int opt_args = 0;
int rc, err = 0;
static mu_sieve_data_type empty[] = { SVT_VOID };
if (mu_i_sv_code (mach, (sieve_op_t) reg->handler))
return 1;
exp_arg = reg->req_args ? reg->req_args : empty;
if (arglist)
{
rc = mu_list_get_iterator (arglist, &itr);
if (rc)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create iterator: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
return 1;
}
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
/* Pass 1: consolidation */
for (i = 0; i < node->v.command.argcount; i++)
{
mu_sieve_value_t *val;
mu_sieve_runtime_tag_t tagrec, *tagptr;
mu_iterator_current (itr, (void **)&val);
mu_sieve_value_t *val = start + i;
if (val->type == SVT_TAG)
{
mu_sieve_tag_checker_t cf;
mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string,
&cf);
mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string, &cf);
if (!tag)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
......@@ -172,21 +165,17 @@ sv_code_command (struct mu_sieve_machine *mach,
break;
}
if (!tag_list && (rc = mu_list_create (&tag_list)))
node->v.command.tagcount++;
if (tag->argtype == SVT_VOID)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create tag list: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
err = 1;
break;
val->type = SVT_VOID;
val->tag = val->v.string;
val->v.string = NULL;
}
tagrec.tag = tag->name;
if (tag->argtype != SVT_VOID)
else
{
mu_iterator_next (itr);
if (mu_iterator_is_done (itr))
if (i + 1 == node->v.command.argcount)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("required argument for tag %s is missing"),
......@@ -195,8 +184,15 @@ sv_code_command (struct mu_sieve_machine *mach,
err = 1;
break;
}
mu_iterator_current (itr, (void **)&tagrec.arg);
if (tagrec.arg->type != tag->argtype)
val[1].tag = val->v.string;
*val = val[1];
memmove (val + 1, val + 2,
(node->v.command.argcount - i - 2) * sizeof (val[0]));
mach->valcount--;
node->v.command.argcount--;
if (val->type != tag->argtype)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("type mismatch in argument to "
......@@ -205,18 +201,12 @@ sv_code_command (struct mu_sieve_machine *mach,
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("expected %s but passed %s"),
mu_sieve_type_str (tag->argtype),
mu_sieve_type_str (tagrec.arg->type));
mu_sieve_type_str (val->type));
mu_i_sv_error (mach);
err = 1;
break;
}
}
else
tagrec.arg = NULL;
tagptr = mu_sieve_malloc (mach, sizeof (*tagptr));
*tagptr = tagrec;
mu_list_append (tag_list, tagptr);
if (cf)
{
......@@ -229,6 +219,7 @@ sv_code_command (struct mu_sieve_machine *mach,
err = 1;
break;
}
//FIXME
if (mu_list_foreach (chk_list, _compare_ptr, cf) == 0)
mu_list_append (chk_list, cf);
}
......@@ -256,14 +247,7 @@ sv_code_command (struct mu_sieve_machine *mach,
if (*exp_arg != val->type)
{
if (*exp_arg == SVT_STRING_LIST && val->type == SVT_STRING)
{
mu_list_t list;
mu_list_create (&list);
mu_list_append (list, val->v.string);
mu_sieve_free (mach, val);
val = mu_sieve_value_create (mach, SVT_STRING_LIST, list);
}
/* compatible types */;
else
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
......@@ -279,27 +263,11 @@ sv_code_command (struct mu_sieve_machine *mach,
break;
}
}
if (!arg_list && (rc = mu_list_create (&arg_list)))
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create arg list: %s"),
mu_strerror (rc));
mu_i_sv_error (mach);
err = 1;
break;
}
mu_list_append (arg_list, val);
exp_arg++;
}
}
mu_iterator_destroy (&itr);
}
if (!err)
{
if (!opt_args && *exp_arg != SVT_VOID)
if (!err && !opt_args && *exp_arg != SVT_VOID)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("too few arguments in call to `%s'"),
......@@ -308,46 +276,66 @@ sv_code_command (struct mu_sieve_machine *mach,
err = 1;
}
if (chk_list)
if (err)
{
struct check_arg chk_arg;
mu_list_destroy (&chk_list);
return;
}
chk_arg.mach = mach;
chk_arg.name = reg->name;
chk_arg.tags = tag_list;
chk_arg.args = arg_list;
err = mu_list_foreach (chk_list, _run_checker, &chk_arg);
if (node->v.command.tagcount)
{
/* Move tags to the end of the list */
for (i = 1; i < node->v.command.argcount; i++)
{
int j;//FIXME
mu_sieve_value_t tmp = start[i];
for (j = i - 1; j >= 0; j--)
{
if (!tmp.tag && start[j].tag)
start[j + 1] = start[j];
else
break;
}
start[j + 1] = tmp;
}
}
if (!err)
err = mu_i_sv_code (mach, (sieve_op_t) arg_list)
|| mu_i_sv_code (mach, (sieve_op_t) tag_list)
|| mu_i_sv_code (mach, (sieve_op_t) (char*) reg->name);
node->v.command.argcount -= node->v.command.tagcount;
if (err)
if (chk_list)
{
mu_list_destroy (&arg_list);
mu_list_destroy (&tag_list);
mu_list_destroy (&chk_list);
struct check_arg chk_arg;
chk_arg.mach = mach;
chk_arg.node = node;
err = mu_list_foreach (chk_list, _run_checker, &chk_arg);
}
}
return err;
static void
sv_code_command (struct mu_sieve_machine *mach,
struct mu_sieve_node *node)
{
mu_i_sv_code (mach, (sieve_op_t) node->v.command.reg->handler);
mu_i_sv_code (mach, (sieve_op_t) node->v.command.argstart);
mu_i_sv_code (mach, (sieve_op_t) node->v.command.argcount);
mu_i_sv_code (mach, (sieve_op_t) node->v.command.tagcount);
mu_i_sv_code (mach, (sieve_op_t) (char*) node->v.command.reg->name);
mu_i_sv_code (mach, (sieve_op_t) node->v.command.comparator);
}
int
void
mu_i_sv_code_action (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
struct mu_sieve_node *node)
{
return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_action)
|| sv_code_command (mach, reg, arglist);
mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_action);
sv_code_command (mach, node);
}
int
mu_i_sv_code_test (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist)
void
mu_i_sv_code_test (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
{
return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_test)
|| sv_code_command (mach, reg, arglist);
mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_test);
sv_code_command (mach, node);
}
......
......@@ -38,7 +38,8 @@ DCL(ge,>=)
DCL(lt,<)
DCL(le,<=)
static struct reltest_tab {
static struct reltest_tab
{
char *name;
mu_sieve_relcmp_t test;
mu_sieve_relcmpn_t stest;
......
......@@ -27,30 +27,17 @@
#include <sieve-priv.h>
void
mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist)
mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list)
{
int status;
mu_iterator_t itr;
size_t i;
status = mu_list_get_iterator (slist, &itr);
if (status)
for (i = 0; i < list->count; i++)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("cannot create iterator: %s"),
mu_strerror (status));
mu_i_sv_error (mach);
return;
}
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
char *name;
struct mu_sieve_string *str = mu_sieve_string_raw (mach, list, i);
char *name = str->orig;
int (*reqfn) (mu_sieve_machine_t mach, const char *name) = NULL;
const char *text = NULL;
mu_iterator_current (itr, (void **)&name);
if (strncmp (name, "comparator-", 11) == 0)
{
name += 11;
......@@ -87,6 +74,5 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist)
mu_i_sv_error (mach);
}
}
mu_iterator_destroy (&itr);
}
......
......@@ -24,8 +24,8 @@
#include <assert.h>
#include <sieve-priv.h>
#define SIEVE_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
#define SIEVE_ADJUST(m,n) (m)->pc+=(n)
#define SIEVE_RT_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
#define SIEVE_RT_ADJUST(m,n) (m)->pc+=(n)
#define INSTR_DISASS(m) ((m)->state == mu_sieve_state_disass)
#define INSTR_DEBUG(m) \
......@@ -34,49 +34,53 @@
void
_mu_i_sv_instr_source (mu_sieve_machine_t mach)
{
mach->locus.mu_file = (char*) SIEVE_ARG (mach, 0, string);
mach->locus.mu_file = (char*) SIEVE_RT_ARG (mach, 0, string);
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS,
&mach->locus);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "SOURCE %s", mach->locus.mu_file);
SIEVE_ADJUST (mach, 1);
SIEVE_RT_ADJUST (mach, 1);
}
void
_mu_i_sv_instr_line (mu_sieve_machine_t mach)
{
mach->locus.mu_line = SIEVE_ARG (mach, 0, line);
mach->locus.mu_line = SIEVE_RT_ARG (mach, 0, line);
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS,
&mach->locus);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "LINE %u",
mach->locus.mu_line);
SIEVE_ADJUST (mach, 1);
SIEVE_RT_ADJUST (mach, 1);
}
static int
instr_run (mu_sieve_machine_t mach, char const *what)
{
int rc = 0;
mu_sieve_handler_t han = SIEVE_ARG (mach, 0, handler);
mach->arg_list = SIEVE_ARG (mach, 1, list);
mach->tag_list = SIEVE_ARG (mach, 2, list);
mach->identifier = SIEVE_ARG (mach, 3, string);
mu_sieve_handler_t han = SIEVE_RT_ARG (mach, 0, handler);
mach->argstart = SIEVE_RT_ARG (mach, 1, pc);
mach->argcount = SIEVE_RT_ARG (mach, 2, pc);
mach->tagcount = SIEVE_RT_ARG (mach, 3, pc);
mach->identifier = SIEVE_RT_ARG (mach, 4, string);
mach->comparator = SIEVE_RT_ARG (mach, 5, comp);
SIEVE_ADJUST (mach, 4);
SIEVE_RT_ADJUST (mach, 6);
if (INSTR_DEBUG (mach))
mu_i_sv_debug_command (mach, mach->pc - 1, what);
mu_i_sv_debug_command (mach, mach->pc - 7, what);
else
mu_i_sv_trace (mach, what);
if (!INSTR_DISASS (mach))
rc = han (mach);
mach->arg_list = NULL;
mach->tag_list = NULL;
mach->argstart = 0;
mach->argcount = 0;
mach->tagcount = 0;
mach->identifier = NULL;
mach->comparator = NULL;
return rc;
}
......@@ -138,9 +142,9 @@ _mu_i_sv_instr_not (mu_sieve_machine_t mach)
void
_mu_i_sv_instr_branch (mu_sieve_machine_t mach)
{
long num = SIEVE_ARG (mach, 0, number);
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_ADJUST (mach, 1);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRANCH %lu",
(unsigned long)(mach->pc + num));
......@@ -153,8 +157,8 @@ _mu_i_sv_instr_branch (mu_sieve_machine_t mach)
void
_mu_i_sv_instr_brz (mu_sieve_machine_t mach)
{
long num = SIEVE_ARG (mach, 0, number);
SIEVE_ADJUST (mach, 1);
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRZ %lu",
......@@ -169,8 +173,8 @@ _mu_i_sv_instr_brz (mu_sieve_machine_t mach)
void
_mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
{
long num = SIEVE_ARG (mach, 0, number);
SIEVE_ADJUST (mach, 1);
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRNZ %lu",
......
......@@ -19,8 +19,7 @@
#include <mailutils/sieve.h>
#include <setjmp.h>
#include <string.h>
#define SIEVE_CODE_INCR 128
#include <regex.h>
typedef void (*sieve_instr_t) (mu_sieve_machine_t mach);
......@@ -29,6 +28,7 @@ typedef union
sieve_instr_t instr;
mu_sieve_handler_t handler;
mu_sieve_value_t *val;
mu_sieve_comparator_t comp;
mu_list_t list;
long number;
size_t pc;
......@@ -74,6 +74,14 @@ struct mu_sieve_machine
mu_list_t comp_list; /* Comparators */
mu_list_t source_list; /* Source names (for diagnostics) */
mu_sieve_string_t *stringspace;
size_t stringcount;
size_t stringmax;
mu_sieve_value_t *valspace;
size_t valcount;
size_t valmax;
size_t progsize; /* Number of allocated program cells */
sieve_op_t *prog; /* Compiled program */
......@@ -85,8 +93,10 @@ struct mu_sieve_machine
/* Call environment */
const char *identifier; /* Name of action or test being executed */
mu_list_t arg_list; /* Positional arguments */
mu_list_t tag_list; /* Tagged arguments */
size_t argstart; /* Index of the first argument in valspace */
size_t argcount; /* Number of positional arguments */
size_t tagcount; /* Number of tagged arguments */
mu_sieve_comparator_t comparator; /* Comparator (for tests) */
int dry_run; /* Dry-run mode */
jmp_buf errbuf; /* Target location for non-local exits */
......@@ -146,7 +156,10 @@ struct mu_sieve_node
struct
{
mu_sieve_register_t *reg;
mu_list_t arg;
size_t argstart;
size_t argcount;
size_t tagcount;
mu_sieve_comparator_t comparator; /* Comparator (for tests) */
} command;
} v;
};
......@@ -161,18 +174,16 @@ void mu_i_sv_lex_finish (struct mu_sieve_machine *mach);
extern mu_sieve_machine_t mu_sieve_machine;
#define TAG_COMPFUN "__compfun__"
int mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op);
void mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op);
void mu_i_sv_compile_error (struct mu_sieve_machine *mach,
const char *fmt, ...) MU_PRINTFLIKE(2,3);
int mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr);
int mu_i_sv_code_action (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist);
int mu_i_sv_code_test (struct mu_sieve_machine *mach,
mu_sieve_register_t *reg, mu_list_t arglist);
void mu_i_sv_code_action (struct mu_sieve_machine *mach,
struct mu_sieve_node *node);
void mu_i_sv_code_test (struct mu_sieve_machine *mach,
struct mu_sieve_node *node);
/* Opcodes */
void _mu_i_sv_instr_action (mu_sieve_machine_t mach);
......@@ -203,8 +214,7 @@ void mu_i_sv_debug_command (mu_sieve_machine_t mach, size_t pc,
char const *what);
void mu_i_sv_trace (mu_sieve_machine_t mach, const char *what);
void mu_i_sv_argf (mu_stream_t str, mu_list_t list);
void mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val);
void mu_i_sv_valf (mu_sieve_machine_t mach, mu_stream_t str, mu_sieve_value_t *val);
typedef int (*mu_i_sv_interp_t) (char const *, size_t, char **, void *);
......@@ -216,4 +226,15 @@ int mu_i_sv_expand_encoded_char (char const *input, size_t len, char **exp, void
int mu_sieve_require_encoded_character (mu_sieve_machine_t mach,
const char *name);
void mu_i_sv_2nrealloc (mu_sieve_machine_t mach,
void **pptr, size_t *pnmemb, size_t size);
mu_sieve_value_t *mu_i_sv_mach_arg (mu_sieve_machine_t mach, size_t n);
mu_sieve_value_t *mu_i_sv_mach_tagn (mu_sieve_machine_t mach, size_t n);
void mu_i_sv_lint_command (struct mu_sieve_machine *mach,
struct mu_sieve_node *node);
size_t mu_i_sv_string_create (mu_sieve_machine_t mach, char *str);
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2002, 2005-2008, 2010-2012, 2014-2016 Free
Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <sieve-priv.h>
size_t
mu_i_sv_string_create (mu_sieve_machine_t mach, char *str)
{
size_t n;
mu_sieve_string_t *s;
if (mach->stringcount == mach->stringmax)
{
mu_i_sv_2nrealloc (mach, (void**) &mach->stringspace,
&mach->stringmax,
sizeof mach->stringspace[0]);
}
n = mach->stringcount++;
s = &mach->stringspace[n];
memset (s, 0, sizeof *s);
s->orig = str;
return n;
}
struct mu_sieve_string *
mu_sieve_string_raw (mu_sieve_machine_t mach, mu_sieve_slice_t slice,
size_t i)
{
if (i >= slice->count)
abort ();
return mach->stringspace + slice->first + i;
}
char *
mu_sieve_string (mu_sieve_machine_t mach, mu_sieve_slice_t slice,
size_t i)
{
return mu_sieve_string_raw (mach, slice, i)->orig;
}
......@@ -27,32 +27,24 @@
typedef int (*address_aget_t) (mu_address_t addr, size_t no, char **buf);
static int
_get_address_part (void *item, void *data)
address_aget_t
sieve_get_address_part (mu_sieve_machine_t mach)
{
mu_sieve_runtime_tag_t *t = item;
address_aget_t ret = NULL;
size_t i;
for (i = 0; i < mach->tagcount; i++)
{
mu_sieve_value_t *t = mu_sieve_get_tag_n (mach, i);
if (strcmp (t->tag, "all") == 0)
ret = mu_address_aget_email;
return mu_address_aget_email;
else if (strcmp (t->tag, "domain") == 0)
ret = mu_address_aget_domain;
return mu_address_aget_domain;
else if (strcmp (t->tag, "localpart") == 0)
ret = mu_address_aget_local_part;
if (ret)
{
*(address_aget_t*)data = ret;
return 1; /* break the loop */
return mu_address_aget_local_part;
}
return 0; /* continue */
}
address_aget_t
sieve_get_address_part (mu_list_t tags)
{
address_aget_t ret = mu_address_aget_email;
mu_list_foreach (tags, _get_address_part, &ret);
return ret;
/* RFC 3028, 2.7.4. Comparisons Against Addresses:
If an optional address-part is omitted, the default is ":all". */
return mu_address_aget_email;
}
/* Structure shared between address and envelope tests */
......@@ -72,11 +64,11 @@ do_count (mu_sieve_machine_t mach, size_t count, int retval)
{
size_t limit;
char *str;
mu_list_t list;
struct mu_sieve_slice slice;
mu_sieve_relcmpn_t stest;
mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &list);
mu_list_get (list, 0, (void **) &str);
mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &slice);
str = mu_sieve_string (mach, &slice, 0);
limit = strtoul (str, &str, 10);
mu_sieve_str_to_relcmp (relcmp, NULL, &stest);
......@@ -117,16 +109,16 @@ sieve_test_address (mu_sieve_machine_t mach)
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
struct address_closure clos;
int rc;
size_t count;
size_t count = 0;
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
mu_message_get_header (mu_sieve_get_message (mach), &header);
clos.data = header;
clos.aget = sieve_get_address_part (mach->tag_list);
clos.aget = sieve_get_address_part (mach);
clos.addr = NULL;
rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_address, &clos,
rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_address, &clos,
&count);
mu_address_destroy (&clos.addr);
......@@ -169,7 +161,7 @@ sieve_test_header (mu_sieve_machine_t mach)
mu_sieve_value_t *h, *v;
mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
size_t count, mcount = 0;
size_t count = 0, mcount = 0;
struct header_closure clos;
h = mu_sieve_get_arg_untyped (mach, 0);
......@@ -192,7 +184,7 @@ sieve_test_header (mu_sieve_machine_t mach)
if (mu_message_get_part (mach->msg, i, &message) == 0)
{
mu_message_get_header (message, &clos.header);
if (mu_sieve_vlist_compare (h, v, comp, test,
if (mu_sieve_vlist_compare (mach, h, v, comp, test,
retrieve_header, &clos, &mcount))
return 1;
}
......@@ -200,7 +192,7 @@ sieve_test_header (mu_sieve_machine_t mach)
}
}
mu_message_get_header (mach->msg, &clos.header);
if (mu_sieve_vlist_compare (h, v, comp, test, retrieve_header, &clos,
if (mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_header, &clos,
&count))
return 1;
......@@ -242,16 +234,16 @@ sieve_test_envelope (mu_sieve_machine_t mach)
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
struct address_closure clos;
int rc;
size_t count;
size_t count = 0;
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
mu_message_get_envelope (mu_sieve_get_message (mach),
(mu_envelope_t*)&clos.data);
clos.aget = sieve_get_address_part (mach->tag_list);
clos.aget = sieve_get_address_part (mach);
clos.addr = NULL;
rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_envelope, &clos,
rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_envelope, &clos,
&count);
mu_address_destroy (&clos.addr);
return do_count (mach, count, rc);
......@@ -261,19 +253,23 @@ int
sieve_test_size (mu_sieve_machine_t mach)
{
int rc = 1;
mu_sieve_runtime_tag_t *tag = NULL;
size_t size;
size_t arg;
mu_sieve_get_arg (mach, 0, SVT_NUMBER, &arg);
mu_message_size (mu_sieve_get_message (mach), &size);
mu_list_get (mach->tag_list, 0, (void **)&tag);
if (!tag)
rc = size == arg;
else if (strcmp (tag->tag, "over") == 0)
if (mach->tagcount)
{
mu_sieve_value_t *tag = mu_sieve_get_tag_n (mach, 0);
if (strcmp (tag->tag, "over") == 0)
rc = size > arg;
else if (strcmp (tag->tag, "under") == 0)
rc = size < arg;
else
abort ();
}
else
rc = size == arg;
return rc;
}
......@@ -295,7 +291,7 @@ sieve_test_exists (mu_sieve_machine_t mach)
mu_message_get_header (mu_sieve_get_message (mach), &header);
val = mu_sieve_get_arg_untyped (mach, 0);
return mu_sieve_vlist_do (val, _test_exists, header) == 0;
return mu_sieve_vlist_do (mach, val, _test_exists, header) == 0;
}
static mu_sieve_tag_def_t address_part_tags[] = {
......
......@@ -125,7 +125,7 @@ Subject: Ping
Test message, please discard.
],
[DELETEHEADER on msg uid 1: X-Agent: (regexp)
[DELETEHEADER on msg uid 1: X-Agent (values)
])
m4_popdef([MUT_SIEVE_EXT_NAME])
......
......@@ -19,7 +19,6 @@ AT_KEYWORDS([encoded-character enc-char])
AT_CHECK([
AT_DATA([prog],[[require ["reject", "encoded-character"];
reject "$${hex:40}";
reject "${hex: 40 }";
reject "${HEX: 40}";
......@@ -38,25 +37,25 @@ reject "Nested ${hex: 73 65 71 ${hex: 75 65 6E}}ce";
reject "Invalid ${hex: 73 RE}";
]])
sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -D prog | grep ACTION
sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -D prog | sed -n 's/.*ACTION: //p'
],
[0],
[ 9: ACTION: reject "$@"
16: ACTION: reject "@"
23: ACTION: reject "@"
30: ACTION: reject "${hex:40"
37: ACTION: reject "${hex:400}"
44: ACTION: reject "${hex:40}"
51: ACTION: reject "@"
58: ACTION: reject "${ unicode:40}"
65: ACTION: reject "@"
72: ACTION: reject "@"
79: ACTION: reject "@"
86: ACTION: reject "${Unicode:Cool}"
93: ACTION: reject "Now is the time"
100: ACTION: reject "Unbalanced ${hex: 73 65 71 uence"
107: ACTION: reject "Nested ${hex: 73 65 71 uen}ce"
114: ACTION: reject "Invalid ${hex: 73 RE}"
[reject "$@"
reject "@"
reject "@"
reject "${hex:40"
reject "${hex:400}"
reject "${hex:40}"
reject "@"
reject "${ unicode:40}"
reject "@"
reject "@"
reject "@"
reject "${Unicode:Cool}"
reject "Now is the time"
reject "Unbalanced ${hex: 73 65 71 uence"
reject "Nested ${hex: 73 65 71 uen}ce"
reject "Invalid ${hex: 73 RE}"
])
AT_CLEANUP
......