Commit e2bd3a05 e2bd3a059eb8268d156baf59e41909cae1e28297 by Sergey Poznyakoff

sieve: redo symbol registry support.

The purpose is to simplify the machine structure and to ensure its
clones are completely independent of the master instance.

* include/mailutils/sieve.h (mu_sieve_command): New struct.
(mu_sieve_record): New enum
(mu_sieve_registry_t): Generalize for storing various types of objects.
(mu_sieve_test_lookup,mu_sieve_action_lookup)
(mu_sieve_require_action,mu_sieve_require_test)
(mu_sieve_require_comparator): Remove.
(mu_sieve_register_test_ext,mu_sieve_register_test)
(mu_sieve_register_action_ext,mu_sieve_register_action)
(mu_sieve_register_comparator)
(mu_sieve_load_ext): Change return type.
(mu_sieve_registry_require,mu_sieve_unload_ext): New functions.
(mu_sieve_machine_inherit): Rename to mu_sieve_machine_clone.
* libmu_sieve/sieve-priv.h (mu_sieve_machine): Remove source_list,
test_list, action_list, and comp_list.  Add a single registry list
instead.
Add space for file and command (action and test) names: idspace,
idcount, idmax.
Remove unused field "stack";
(mu_i_sv_lex_finish): Change prototype.
(_mu_i_sv_instr_push,_mu_i_sv_instr_pop): Remove protos.
(mu_i_sv_id_canon,mu_i_sv_id_num)
(mu_i_sv_id_str,mu_i_sv_free_idspace): New protos.
* libmu_sieve/register.c: Rename to registry.c
* libmu_sieve/registry.c (mu_sieve_test_lookup)
(mu_sieve_action_lookup): Remove.
(mu_sieve_require_test,mu_sieve_require_action): Remove.
(mu_sieve_registry_require): New function.
(mu_sieve_registry_add,mu_sieve_registry_lookup): New functions.
* libmu_sieve/Makefile.am: Update.
* libmu_sieve/comparator.c: Rewrite using new registry functions.
* libmu_sieve/load.c (mu_sieve_load_ext): Return module handle.
(mu_sieve_unload_ext): New function.
* libmu_sieve/mem.c (mu_sieve_free): Gracefully handle NULL argument.
(mu_i_sv_id_canon,mu_i_sv_id_num,mu_i_sv_id_str): New functions.
* libmu_sieve/prog.c (mu_i_sv_locus): Store index of the file name in
the id space, instead of pointer to the name itself.

* libmu_sieve/require.c (mu_sieve_require): Rewrite.
* libmu_sieve/runtime.c (_mu_i_sv_instr_source): Expect ID index
as argument.
(_mu_i_sv_instr_push)
(_mu_i_sv_instr_pop): Remove unused instructions.

* libmu_sieve/sieve.l (file_names): Remove.  Use mu_sieve_machine
idspace instead.
* libmu_sieve/sieve.y (mu_sieve_machine_clone)
(mu_sieve_machine_dup): Rewrite.
(mu_sieve_machine_destroy): Free idspace and registry

* examples/numaddr.c: Reflect changes.
* libmu_sieve/extensions/editheader.c: Likewise.
* libmu_sieve/extensions/list.c: Likewise.
* libmu_sieve/extensions/moderator.c: Likewise.
* libmu_sieve/extensions/pipe.c: Likewise.
* libmu_sieve/extensions/spamd.c: Likewise.
* libmu_sieve/extensions/timestamp.c: Likewise.
* libmu_sieve/extensions/vacation.c: Likewise.
1 parent fdf02db3
......@@ -131,6 +131,7 @@ static mu_sieve_tag_group_t numaddr_tag_groups[] = {
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);
mu_sieve_register_test (mach, "numaddr", numaddr_test,
numaddr_req_args, numaddr_tag_groups, 1);
return 0;
}
......
......@@ -100,17 +100,13 @@ typedef struct
mu_sieve_tag_checker_t checker;
} mu_sieve_tag_group_t;
typedef struct
struct mu_sieve_command /* test or action */
{
const char *name;
int required;
mu_sieve_handler_t handler;
mu_sieve_data_type *req_args;
mu_sieve_data_type *opt_args;
mu_sieve_tag_group_t *tags;
} mu_sieve_register_t;
#define MU_SIEVE_CHARSET "UTF-8"
};
#define MU_SIEVE_MATCH_IS 1
#define MU_SIEVE_MATCH_CONTAINS 2
......@@ -119,6 +115,28 @@ typedef struct
#define MU_SIEVE_MATCH_EQ 5
#define MU_SIEVE_MATCH_LAST 6
enum mu_sieve_record
{
mu_sieve_record_action,
mu_sieve_record_test,
mu_sieve_record_comparator
};
typedef struct
{
const char *name;
int required;
void *handle;
enum mu_sieve_record type;
union
{
struct mu_sieve_command command;
mu_sieve_comparator_t comp[MU_SIEVE_MATCH_LAST];
} v;
} mu_sieve_registry_t;
#define MU_SIEVE_CHARSET "UTF-8"
extern mu_debug_handle_t mu_sieve_debug_handle;
extern mu_list_t mu_sieve_include_path;
extern mu_list_t mu_sieve_library_path;
......@@ -143,41 +161,46 @@ size_t mu_sieve_value_create (mu_sieve_machine_t mach,
mu_sieve_data_type type, void *data);
/* Symbol space functions */
mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach,
const char *name);
mu_sieve_register_t *mu_sieve_action_lookup (mu_sieve_machine_t mach,
const char *name);
int mu_sieve_register_test_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required);
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);
int mu_sieve_register_action_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required);
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);
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);
int mu_sieve_require_action (mu_sieve_machine_t mach, const char *name);
int mu_sieve_require_test (mu_sieve_machine_t mach, const char *name);
int mu_sieve_require_comparator (mu_sieve_machine_t mach, const char *name);
mu_sieve_registry_t *mu_sieve_registry_add (mu_sieve_machine_t mach,
const char *name);
mu_sieve_registry_t *mu_sieve_registry_lookup (mu_sieve_machine_t mach,
const char *name,
enum mu_sieve_record type);
int mu_sieve_registry_require (mu_sieve_machine_t mach, const char *name,
enum mu_sieve_record type);
void mu_sieve_register_test_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required);
void 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);
void mu_sieve_register_action_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required);
void 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);
void 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);
int mu_sieve_require_relational (mu_sieve_machine_t mach, const char *name);
int mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
void *mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
void mu_sieve_unload_ext (void *handle);
int mu_sieve_match_part_checker (mu_sieve_machine_t mach);
mu_sieve_comparator_t mu_sieve_comparator_lookup (mu_sieve_machine_t mach,
......@@ -229,7 +252,7 @@ int mu_sieve_vlist_compare (mu_sieve_machine_t mach,
int mu_sieve_machine_create (mu_sieve_machine_t *mach);
int mu_sieve_machine_dup (mu_sieve_machine_t const in,
mu_sieve_machine_t *out);
int mu_sieve_machine_inherit (mu_sieve_machine_t const in,
int mu_sieve_machine_clone (mu_sieve_machine_t const in,
mu_sieve_machine_t *out);
void mu_sieve_machine_destroy (mu_sieve_machine_t *pmach);
void mu_sieve_machine_add_destructor (mu_sieve_machine_t mach,
......
......@@ -34,7 +34,7 @@ libmu_sieve_la_SOURCES = \
load.c\
mem.c\
prog.c\
register.c\
registry.c\
relational.c\
require.c\
runtime.c\
......
......@@ -30,13 +30,7 @@
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
typedef struct {
const char *name;
int required;
mu_sieve_comparator_t comp[MU_SIEVE_MATCH_LAST];
} sieve_comparator_record_t;
int
void
mu_sieve_register_comparator (mu_sieve_machine_t mach,
const char *name,
int required,
......@@ -46,70 +40,26 @@ mu_sieve_register_comparator (mu_sieve_machine_t mach,
mu_sieve_comparator_t regex,
mu_sieve_comparator_t eq)
{
sieve_comparator_record_t *rp;
if (!mach->comp_list)
{
int rc = mu_list_create (&mach->comp_list);
if (rc)
return rc;
}
rp = mu_sieve_malloc (mach, sizeof (*rp));
rp->required = required;
rp->name = name;
rp->comp[MU_SIEVE_MATCH_IS] = is;
rp->comp[MU_SIEVE_MATCH_CONTAINS] = contains;
rp->comp[MU_SIEVE_MATCH_MATCHES] = matches;
rp->comp[MU_SIEVE_MATCH_REGEX] = regex;
rp->comp[MU_SIEVE_MATCH_EQ] = eq;
return mu_list_append (mach->comp_list, rp);
}
sieve_comparator_record_t *
_lookup (mu_list_t list, const char *name)
{
mu_iterator_t itr;
sieve_comparator_record_t *reg;
if (!list || mu_list_get_iterator (list, &itr))
return NULL;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&reg);
if (strcmp (reg->name, name) == 0)
break;
else
reg = NULL;
}
mu_iterator_destroy (&itr);
return reg;
}
int
mu_sieve_require_comparator (mu_sieve_machine_t mach, const char *name)
{
sieve_comparator_record_t *reg = _lookup (mach->comp_list, name);
if (!reg)
{
if (!(mu_sieve_load_ext (mach, name) == 0
&& (reg = _lookup (mach->comp_list, name)) != NULL))
return 1;
}
reg->required = 1;
return 0;
mu_sieve_registry_t *reg = mu_sieve_registry_add (mach, name);
reg->type = mu_sieve_record_comparator;
reg->required = required;
reg->name = name;
reg->v.comp[MU_SIEVE_MATCH_IS] = is;
reg->v.comp[MU_SIEVE_MATCH_CONTAINS] = contains;
reg->v.comp[MU_SIEVE_MATCH_MATCHES] = matches;
reg->v.comp[MU_SIEVE_MATCH_REGEX] = regex;
reg->v.comp[MU_SIEVE_MATCH_EQ] = eq;
}
mu_sieve_comparator_t
mu_sieve_comparator_lookup (mu_sieve_machine_t mach, const char *name,
int matchtype)
{
sieve_comparator_record_t *reg = _lookup (mach->comp_list, name);
if (reg && reg->comp[matchtype])
return reg->comp[matchtype];
mu_sieve_registry_t *reg =
mu_sieve_registry_lookup (mach, name, mu_sieve_record_comparator);
if (reg && reg->v.comp[matchtype])
return reg->v.comp[matchtype];
return NULL;
}
......
......@@ -272,22 +272,13 @@ static mu_sieve_data_type deleteheader_args[] = {
int
SIEVE_EXPORT (editheader, init) (mu_sieve_machine_t mach)
{
int rc;
/* This dummy record is required by libmu_sieve */
rc = mu_sieve_register_action (mach, "editheader", NULL, NULL, NULL, 1);
if (rc)
return rc;
rc = mu_sieve_register_action (mach, "addheader", sieve_addheader,
addheader_args, addheader_tag_groups, 1);
if (rc)
return rc;
rc = mu_sieve_register_action_ext (mach, "deleteheader", sieve_deleteheader,
deleteheader_args, deleteheader_args,
deleteheader_tag_groups,
1);
if (rc)
return rc;
return rc;
mu_sieve_register_action (mach, "editheader", NULL, NULL, NULL, 1);
mu_sieve_register_action (mach, "addheader", sieve_addheader,
addheader_args, addheader_tag_groups, 1);
mu_sieve_register_action_ext (mach, "deleteheader", sieve_deleteheader,
deleteheader_args, deleteheader_args,
deleteheader_tag_groups,
1);
return 0;
}
......
......@@ -203,8 +203,9 @@ static mu_sieve_tag_group_t list_tag_groups[] = {
int
SIEVE_EXPORT(list,init) (mu_sieve_machine_t mach)
{
return mu_sieve_register_test (mach, "list", list_test,
list_req_args, list_tag_groups, 1);
mu_sieve_register_test (mach, "list", list_test,
list_req_args, list_tag_groups, 1);
return 0;
}
/* End of list.c */
......
......@@ -84,7 +84,7 @@ moderator_filter_message (mu_sieve_machine_t mach,
if (mu_sieve_get_tag (mach, "source", SVT_STRING, &arg))
{
rc = mu_sieve_machine_inherit (mach, &newmach);
rc = mu_sieve_machine_clone (mach, &newmach);
if (rc)
{
mu_sieve_error (mach, _("cannot initialize sieve machine: %s"),
......@@ -105,7 +105,7 @@ moderator_filter_message (mu_sieve_machine_t mach,
{
struct mu_locus locus;
rc = mu_sieve_machine_inherit (mach, &newmach);
rc = mu_sieve_machine_clone (mach, &newmach);
if (rc)
{
mu_sieve_error (mach, _("cannot initialize sieve machine: %s"),
......@@ -363,8 +363,9 @@ static mu_sieve_tag_group_t moderator_tag_groups[] = {
int
SIEVE_EXPORT(moderator,init) (mu_sieve_machine_t mach)
{
return mu_sieve_register_action (mach, "moderator", moderator_action,
moderator_req_args,
moderator_tag_groups, 1);
mu_sieve_register_action (mach, "moderator", moderator_action,
moderator_req_args,
moderator_tag_groups, 1);
return 0;
}
......
......@@ -275,11 +275,9 @@ static mu_sieve_data_type pipe_args[] = {
int
SIEVE_EXPORT (pipe, init) (mu_sieve_machine_t mach)
{
int rc;
rc = mu_sieve_register_action (mach, "pipe", sieve_action_pipe,
pipe_args, pipe_action_tag_groups, 1);
if (rc)
return rc;
return mu_sieve_register_test (mach, "pipe", sieve_test_pipe,
pipe_args, pipe_test_tag_groups, 1);
mu_sieve_register_action (mach, "pipe", sieve_action_pipe,
pipe_args, pipe_action_tag_groups, 1);
mu_sieve_register_test (mach, "pipe", sieve_test_pipe,
pipe_args, pipe_test_tag_groups, 1);
return 0;
}
......
......@@ -544,7 +544,8 @@ static mu_sieve_tag_group_t spamd_tag_groups[] = {
int
SIEVE_EXPORT(spamd,init) (mu_sieve_machine_t mach)
{
return mu_sieve_register_test (mach, "spamd", spamd_test,
spamd_req_args, spamd_tag_groups, 1);
mu_sieve_register_test (mach, "spamd", spamd_test,
spamd_req_args, spamd_tag_groups, 1);
return 0;
}
......
......@@ -123,6 +123,7 @@ static mu_sieve_tag_group_t timestamp_tag_groups[] = {
int
SIEVE_EXPORT(timestamp,init) (mu_sieve_machine_t mach)
{
return mu_sieve_register_test (mach, "timestamp", timestamp_test,
timestamp_req_args, timestamp_tag_groups, 1);
mu_sieve_register_test (mach, "timestamp", timestamp_test,
timestamp_req_args, timestamp_tag_groups, 1);
return 0;
}
......
......@@ -868,6 +868,7 @@ static mu_sieve_data_type vacation_args[] = {
int SIEVE_EXPORT (vacation, init) (mu_sieve_machine_t mach)
{
return mu_sieve_register_action (mach, "vacation", sieve_action_vacation,
vacation_args, vacation_tag_groups, 1);
mu_sieve_register_action (mach, "vacation", sieve_action_vacation,
vacation_args, vacation_tag_groups, 1);
return 0;
}
......
......@@ -31,16 +31,6 @@
typedef int (*sieve_module_init_t) (mu_sieve_machine_t mach);
#if 0
/* FIXME: See comment below */
static void
_free_loaded_module (void *data)
{
lt_dlclose ((lt_dlhandle)data);
lt_dlexit ();
}
#endif
static int _add_load_dir (void *, void *);
static int
......@@ -61,8 +51,7 @@ sieve_init_load_path ()
}
return 0;
}
static lt_dlhandle
load_module (mu_sieve_machine_t mach, const char *name)
{
......@@ -74,18 +63,12 @@ load_module (mu_sieve_machine_t mach, const char *name)
handle = lt_dlopenext (name);
if (handle)
{
sieve_module_init_t init = (sieve_module_init_t)
lt_dlsym (handle, "init");
sieve_module_init_t init;
init = (sieve_module_init_t) lt_dlsym (handle, "init");
if (init)
{
init (mach);
/* FIXME: We used to have this:
mu_sieve_machine_add_destructor (mach, _free_loaded_module,
handle);
However, unloading modules can lead to random segfaults in
case they allocated any global-access data (e.g. mach->msg).
In particular, this was the case with extensions/pipe.c.
*/
return handle;
}
else
......@@ -114,7 +97,7 @@ fix_module_name (char *name)
}
}
int
void *
mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name)
{
lt_dlhandle handle;
......@@ -122,11 +105,18 @@ mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name)
modname = strdup (name);
if (!modname)
return 1;
return NULL;
fix_module_name (modname);
handle = load_module (mach, modname);
free (modname);
return handle == NULL;
return handle;
}
void
mu_sieve_unload_ext (void *data)
{
if (data)
lt_dlclose ((lt_dlhandle)data);
}
static int
......
......@@ -83,6 +83,9 @@ mu_sieve_free (mu_sieve_machine_t mach, void *ptr)
int rc;
struct memory_cell mcell;
if (!ptr)
return;
mcell.ptr = ptr;
rc = mu_list_remove (mach->memory_pool, &mcell);
if (rc)
......@@ -228,3 +231,65 @@ mu_i_sv_2nrealloc (mu_sieve_machine_t mach, void **pptr, size_t *pnmemb,
*pptr = ptr;
*pnmemb = nmemb;
}
char *
mu_i_sv_id_canon (mu_sieve_machine_t mach, char const *name)
{
size_t i;
char *p;
if (!name)
return NULL;
for (i = 0; i < mach->idcount; i++)
{
if (strcmp (mach->idspace[i], name) == 0)
return mach->idspace[i];
}
if (mach->idcount == mach->idmax)
{
mu_i_sv_2nrealloc (mach,
(void **) &mach->idspace,
&mach->idmax,
sizeof mach->idspace[0]);
}
p = mu_sieve_strdup (mach, name);
mach->idspace[mach->idcount++] = p;
return p;
}
size_t
mu_i_sv_id_num (mu_sieve_machine_t mach, char const *name)
{
size_t i;
for (i = 0; i < mach->idcount; i++)
{
if (mach->idspace[i] == name || strcmp (mach->idspace[i], name) == 0)
return i;
}
abort ();
}
char *
mu_i_sv_id_str (mu_sieve_machine_t mach, size_t n)
{
if (n >= mach->idcount)
abort ();
return mach->idspace[n];
}
void
mu_i_sv_free_idspace (mu_sieve_machine_t mach)
{
size_t i;
for (i = 0; i < mach->idcount; i++)
mu_sieve_free (mach, mach->idspace[i]);
mach->idcount = 0;
}
......
......@@ -52,7 +52,7 @@ mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr)
if (!file_eq (mach->locus.mu_file, lr->beg.mu_file))
{
mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_source);
mu_i_sv_code (mach, (sieve_op_t) lr->beg.mu_file);
mu_i_sv_code (mach, (sieve_op_t) mu_i_sv_id_num (mach, lr->beg.mu_file));
}
if (mach->locus.mu_line != lr->beg.mu_line)
{
......@@ -133,8 +133,8 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
struct mu_sieve_node *node)
{
size_t i;
mu_sieve_register_t *reg = node->v.command.reg;
mu_sieve_registry_t *reg = node->v.command.reg;
mu_sieve_value_t *start = mach->valspace + node->v.command.argstart;
mu_list_t chk_list = NULL;
......@@ -142,8 +142,11 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
int opt_args = 0;
int rc, err = 0;
static mu_sieve_data_type empty[] = { SVT_VOID };
if (!reg)
return;
exp_arg = reg->req_args ? reg->req_args : empty;
exp_arg = reg->v.command.req_args ? reg->v.command.req_args : empty;
/* Pass 1: consolidation */
for (i = 0; i < node->v.command.argcount; i++)
......@@ -153,7 +156,8 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
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->v.command.tags,
val->v.string, &cf);
if (!tag)
{
......@@ -228,9 +232,9 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
{
if (*exp_arg == SVT_VOID)
{
if (reg->opt_args)
if (reg->v.command.opt_args)
{
exp_arg = reg->opt_args;
exp_arg = reg->v.command.opt_args;
opt_args = 1;
}
else
......@@ -252,7 +256,7 @@ mu_i_sv_lint_command (struct mu_sieve_machine *mach,
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("type mismatch in argument %lu to `%s'"),
(unsigned long) (exp_arg - reg->req_args + 1),
(unsigned long) (exp_arg - reg->v.command.req_args + 1),
reg->name);
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("expected %s but passed %s"),
......@@ -316,7 +320,7 @@ 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.reg->v.command.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);
......
......@@ -26,115 +26,116 @@
#include <string.h>
#include <sieve-priv.h>
static mu_sieve_register_t *
reg_lookup (mu_list_t list, const char *name)
{
mu_iterator_t itr;
mu_sieve_register_t *reg;
if (!list || mu_list_get_iterator (list, &itr))
return NULL;
for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&reg);
if (strcmp (reg->name, name) == 0)
break;
else
reg = NULL;
}
mu_iterator_destroy (&itr);
return reg;
}
mu_sieve_register_t *
mu_sieve_test_lookup (mu_sieve_machine_t mach, const char *name)
{
mu_sieve_register_t *reg = reg_lookup (mach->test_list, name);
return (reg && reg->handler) ? reg : NULL;
}
mu_sieve_register_t *
mu_sieve_action_lookup (mu_sieve_machine_t mach, const char *name)
int
mu_sieve_registry_require (mu_sieve_machine_t mach, const char *name,
enum mu_sieve_record type)
{
mu_sieve_register_t *reg = reg_lookup (mach->action_list, name);
return (reg && reg->handler) ? reg : NULL;
}
mu_sieve_registry_t *reg;
static int
reg_require (mu_sieve_machine_t mach, mu_list_t list, const char *name)
{
mu_sieve_register_t *reg = reg_lookup (list, name);
reg = mu_sieve_registry_lookup (mach, name, type);
if (!reg)
{
if (!(mu_sieve_load_ext (mach, name) == 0
&& (reg = reg_lookup (list, name)) != NULL))
void *handle = mu_sieve_load_ext (mach, name);
if (!handle)
return 1;
reg = mu_sieve_registry_lookup (mach, name, type);
if (!reg)
return 1;
reg->handle = handle;
}
reg->required = 1;
return 0;
}
int
mu_sieve_require_action (mu_sieve_machine_t mach, const char *name)
static void
regunload (void *data)
{
return reg_require (mach, mach->action_list, name);
mu_sieve_registry_t *reg = data;
mu_sieve_unload_ext (reg->handle);
}
int
mu_sieve_require_test (mu_sieve_machine_t mach, const char *name)
static int
regcmp (void const *a, void const *b)
{
return reg_require (mach, mach->test_list, name);
mu_sieve_registry_t const *rega = a;
mu_sieve_registry_t const *regb = b;
if (rega->type != regb->type)
return rega->type - regb->type;
return strcmp (rega->name, regb->name);
}
static int
sieve_register (mu_sieve_machine_t mach,
mu_list_t *list,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_arg_types,
mu_sieve_data_type *opt_arg_types,
mu_sieve_tag_group_t *tags, int required)
mu_sieve_registry_t *
mu_sieve_registry_add (mu_sieve_machine_t mach, const char *name)
{
mu_sieve_register_t *reg = mu_sieve_malloc (mach, sizeof (*reg));
if (!reg)
return ENOMEM;
reg->name = name;
reg->handler = handler;
reg->req_args = req_arg_types;
reg->opt_args = opt_arg_types;
reg->tags = tags;
reg->required = required;
mu_sieve_registry_t *reg;
int rc;
if (!*list)
if (!mach->registry)
{
int rc = mu_list_create (list);
rc = mu_list_create (&mach->registry);
if (rc)
{
free (reg);
return rc;
mu_sieve_error (mach, "mu_list_create: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
mu_list_set_destroy_item (mach->registry, regunload);
mu_list_set_comparator (mach->registry, regcmp);
}
return mu_list_append (*list, reg);
reg = mu_sieve_malloc (mach, sizeof (*reg));
reg->name = name;
reg->handle = NULL;
reg->required = 0;
memset (&reg->v, 0, sizeof reg->v);
rc = mu_list_append (mach->registry, reg);
if (rc)
{
mu_sieve_error (mach, "mu_list_append: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
return reg;
}
mu_sieve_registry_t *
mu_sieve_registry_lookup (mu_sieve_machine_t mach, const char *name,
enum mu_sieve_record type)
{
mu_sieve_registry_t key, *reg;
int rc;
key.name = name;
key.type = type;
int
rc = mu_list_locate (mach->registry, &key, (void**) &reg);
if (rc == MU_ERR_NOENT)
return NULL;
else if (rc)
{
mu_sieve_error (mach, _("registry lookup failed: %s"), mu_strerror (rc));
mu_sieve_abort (mach);
}
return reg;
}
void
mu_sieve_register_test_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required)
{
return sieve_register (mach,
&mach->test_list, name, handler,
req_args, opt_args, tags, required);
mu_sieve_registry_t *reg = mu_sieve_registry_add (mach, name);
reg->type = mu_sieve_record_test;
reg->required = required;
reg->v.command.handler = handler;
reg->v.command.req_args = req_args;
reg->v.command.opt_args = opt_args;
reg->v.command.tags = tags;
}
int
void
mu_sieve_register_test (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *arg_types,
......@@ -146,19 +147,24 @@ mu_sieve_register_test (mu_sieve_machine_t mach,
required);
}
int
void
mu_sieve_register_action_ext (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *req_args,
mu_sieve_data_type *opt_args,
mu_sieve_tag_group_t *tags, int required)
{
return sieve_register (mach,
&mach->action_list, name, handler,
req_args, opt_args, tags, required);
mu_sieve_registry_t *reg = mu_sieve_registry_add (mach, name);
reg->type = mu_sieve_record_action;
reg->required = required;
reg->v.command.handler = handler;
reg->v.command.req_args = req_args;
reg->v.command.opt_args = opt_args;
reg->v.command.tags = tags;
}
int
void
mu_sieve_register_action (mu_sieve_machine_t mach,
const char *name, mu_sieve_handler_t handler,
mu_sieve_data_type *arg_types,
......
......@@ -35,42 +35,26 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list)
{
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;
int rc;
if (strncmp (name, "comparator-", 11) == 0)
{
name += 11;
reqfn = mu_sieve_require_comparator;
text = _("required comparator");
}
else if (strncmp (name, "test-", 5) == 0) /* GNU extension */
{
name += 5;
reqfn = mu_sieve_require_test;
text = _("required test");
}
else if (strcmp (name, "relational") == 0) /* RFC 3431 */
{
reqfn = mu_sieve_require_relational;
text = "";
}
if (strcmp (name, "relational") == 0) /* RFC 3431 */
rc = mu_sieve_require_relational (mach, name);
else if (strcmp (name, "encoded-character") == 0) /* RFC 5228, 2.4.2.4 */
{
reqfn = mu_sieve_require_encoded_character;
text = "";
}
rc = mu_sieve_require_encoded_character (mach, name);
else if (strncmp (name, "comparator-", 11) == 0)
rc = mu_sieve_registry_require (mach, name + 11,
mu_sieve_record_comparator);
else if (strncmp (name, "test-", 5) == 0) /* GNU extension */
rc = mu_sieve_registry_require (mach, name + 5,
mu_sieve_record_test);
else
{
reqfn = mu_sieve_require_action;
text = _("required action");
}
rc = mu_sieve_registry_require (mach, name, mu_sieve_record_action);
if (reqfn (mach, name))
if (rc)
{
mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
_("source for the %s %s is not available"),
text, name);
_("can't require %s is not available"),
name);
mu_i_sv_error (mach);
}
}
......
......@@ -34,7 +34,7 @@
void
_mu_i_sv_instr_source (mu_sieve_machine_t mach)
{
mach->locus.mu_file = (char*) SIEVE_RT_ARG (mach, 0, string);
mach->locus.mu_file = mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 0, pc));
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS,
&mach->locus);
......@@ -98,38 +98,6 @@ _mu_i_sv_instr_test (mu_sieve_machine_t mach)
}
void
_mu_i_sv_instr_push (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "PUSH");
if (INSTR_DISASS (mach))
return;
if (!mach->stack && mu_list_create (&mach->stack))
{
mu_sieve_error (mach, _("cannot create stack"));
mu_sieve_abort (mach);
}
mu_list_push (mach->stack, (void*) mach->reg);
}
void
_mu_i_sv_instr_pop (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "POP");
if (INSTR_DISASS (mach))
return;
if (!mach->stack || mu_list_is_empty (mach->stack))
{
mu_sieve_error (mach, _("stack underflow"));
mu_sieve_abort (mach);
}
mu_list_pop (mach->stack, (void **)&mach->reg);
}
void
_mu_i_sv_instr_not (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
......@@ -207,7 +175,7 @@ mu_sieve_get_data (mu_sieve_machine_t mach)
int
mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus *loc)
{
if (mach->source_list)
if (mach->locus.mu_file)
{
*loc = mach->locus;
return 0;
......
......@@ -68,11 +68,12 @@ struct mu_sieve_machine
/* Symbol space: */
mu_opool_t string_pool; /* String constants */
mu_list_t source_list; /* Source names (for diagnostics) */
mu_list_t test_list; /* Tests */
mu_list_t action_list; /* Actions */
mu_list_t comp_list; /* Comparators */
mu_list_t registry; /* Tests, Actions, Comparators */
char **idspace; /* Source and identifier names */
size_t idcount;
size_t idmax;
mu_sieve_string_t *stringspace;
size_t stringcount;
size_t stringmax;
......@@ -88,7 +89,6 @@ struct mu_sieve_machine
enum mu_sieve_state state; /* Machine state */
size_t pc; /* Current program counter */
long reg; /* Numeric register */
mu_list_t stack; /* Runtime stack */
/* Call environment */
const char *identifier; /* Name of action or test being executed */
......@@ -152,7 +152,7 @@ struct mu_sieve_node
} cond;
struct
{
mu_sieve_register_t *reg;
mu_sieve_registry_t *reg;
size_t argstart;
size_t argcount;
size_t tagcount;
......@@ -167,7 +167,7 @@ int mu_sieve_yylex (void);
int mu_i_sv_lex_begin (const char *name);
int mu_i_sv_lex_begin_string (const char *buf, int bufsize,
const char *fname, int line);
void mu_i_sv_lex_finish (struct mu_sieve_machine *mach);
void mu_i_sv_lex_finish (void);
extern mu_sieve_machine_t mu_sieve_machine;
......@@ -182,8 +182,6 @@ void mu_i_sv_code_test (struct mu_sieve_machine *mach,
/* Opcodes */
void _mu_i_sv_instr_action (mu_sieve_machine_t mach);
void _mu_i_sv_instr_test (mu_sieve_machine_t mach);
void _mu_i_sv_instr_push (mu_sieve_machine_t mach);
void _mu_i_sv_instr_pop (mu_sieve_machine_t mach);
void _mu_i_sv_instr_not (mu_sieve_machine_t mach);
void _mu_i_sv_instr_branch (mu_sieve_machine_t mach);
void _mu_i_sv_instr_brz (mu_sieve_machine_t mach);
......@@ -230,3 +228,9 @@ void mu_i_sv_lint_command (struct mu_sieve_machine *mach,
size_t mu_i_sv_string_create (mu_sieve_machine_t mach, char *str);
char *mu_i_sv_id_canon (mu_sieve_machine_t mach, char const *name);
size_t mu_i_sv_id_num (mu_sieve_machine_t mach, char const *name);
char *mu_i_sv_id_str (mu_sieve_machine_t mach, size_t n);
void mu_i_sv_free_idspace (mu_sieve_machine_t mach);
......
......@@ -56,7 +56,6 @@ static int isemptystr (char *text);
static ino_t sieve_source_inode;
struct mu_locus mu_sieve_locus;
static int newline;
static mu_list_t file_names;
static mu_stream_t input_stream;
......@@ -90,35 +89,10 @@ fillbuf (char *buf, size_t max_size)
yy_switch_to_buffer (s); \
} while (0)
static int
file_name_cmp (const void *a, const void *b)
{
return strcmp (a, b);
}
static void
init_locus (char const *name, ino_t ino)
{
mu_sieve_locus.mu_file = NULL;
if (name)
{
if (!file_names)
{
mu_list_create (&file_names);
mu_list_set_comparator (file_names, file_name_cmp);
mu_list_set_destroy_item (file_names, mu_list_free_item);
}
else
{
mu_list_locate (file_names, (void*) name,
(void**) &mu_sieve_locus.mu_file);
}
if (!mu_sieve_locus.mu_file)
{
mu_sieve_locus.mu_file = strdup (name);//FIXME: Error checking
mu_list_append (file_names, mu_sieve_locus.mu_file);
}
}
mu_sieve_locus.mu_file = mu_i_sv_id_canon (mu_sieve_machine, name);
mu_sieve_locus.mu_line = 1;
mu_sieve_locus.mu_col = 0;
newline = 0;
......@@ -496,12 +470,10 @@ mu_i_sv_lex_begin_string (const char *buf, int bufsize,
}
void
mu_i_sv_lex_finish (struct mu_sieve_machine *mach)
mu_i_sv_lex_finish (void)
{
while (pop_source () == 0)
;
mach->source_list = file_names;
file_names = NULL;
}
static int
......
......@@ -245,10 +245,11 @@ cond : test
test : command
{
mu_sieve_register_t *reg;
mu_sieve_registry_t *reg;
mu_sieve_machine->locus = @1.beg;
reg = mu_sieve_test_lookup (mu_sieve_machine, $1.ident);
reg = mu_sieve_registry_lookup (mu_sieve_machine, $1.ident,
mu_sieve_record_test);
if (!reg)
{
mu_diag_at_locus (MU_LOG_ERROR, &@1.beg,
......@@ -292,10 +293,11 @@ command : IDENT maybe_arglist
action : command
{
mu_sieve_register_t *reg;
mu_sieve_registry_t *reg;
mu_sieve_machine->locus = @1.beg;
reg = mu_sieve_action_lookup (mu_sieve_machine, $1.ident);
reg = mu_sieve_registry_lookup (mu_sieve_machine, $1.ident,
mu_sieve_record_action);
if (!reg)
{
......@@ -999,8 +1001,6 @@ mu_sieve_machine_create (mu_sieve_machine_t *pmach)
return rc;
}
mach->source_list = NULL;
mach->data = NULL;
mu_sieve_set_diag_stream (mach, mu_strerr);
......@@ -1053,10 +1053,8 @@ mu_sieve_machine_reset (mu_sieve_machine_t mach)
mu_list_clear (mach->memory_pool);
mu_list_clear (mach->destr_list);
mu_opool_free (mach->string_pool, NULL);
mu_list_clear (mach->source_list);
mu_list_clear (mach->test_list);
mu_list_clear (mach->action_list);
mu_list_clear (mach->comp_list);
mu_i_sv_free_idspace (mach);
mu_list_clear (mach->registry);
mach->stringspace = NULL;
mach->stringcount = 0;
......@@ -1074,22 +1072,19 @@ mu_sieve_machine_reset (mu_sieve_machine_t mach)
return 0;
}
int
mu_sieve_machine_inherit (mu_sieve_machine_t const parent,
mu_sieve_machine_t *pmach)
static int
regdup (void *item, void *data)
{
mu_sieve_machine_t child;
int rc;
if (!parent || parent->state == mu_sieve_state_error)
return EINVAL;
rc = mu_sieve_machine_create (&child);
if (rc)
return rc;
mu_sieve_registry_t *reg = item;
mu_sieve_machine_t mach = data;
child->dry_run = parent->dry_run;
mu_sieve_registry_require (mach, reg->name, reg->type);
return 0;
}
static void
copy_stream_state (mu_sieve_machine_t child, mu_sieve_machine_t parent)
{
child->state_flags = parent->state_flags;
child->err_mode = parent->err_mode;
child->err_locus = parent->err_locus;
......@@ -1105,13 +1100,97 @@ mu_sieve_machine_inherit (mu_sieve_machine_t const parent,
mu_stream_ref (child->errstream);
child->dbgstream = parent->dbgstream;
mu_stream_ref (child->dbgstream);
}
int
mu_sieve_machine_clone (mu_sieve_machine_t const parent,
mu_sieve_machine_t *pmach)
{
size_t i;
mu_sieve_machine_t child;
int rc;
if (!parent || parent->state == mu_sieve_state_error)
return EINVAL;
child->data = parent->data;
child->logger = parent->logger;
child->daemon_email = parent->daemon_email;
rc = mu_sieve_machine_create (&child);
if (rc)
return rc;
*pmach = child;
return 0;
rc = setjmp (child->errbuf);
if (rc == 0)
{
child->state = mu_sieve_state_init;
mu_i_sv_register_standard_actions (child);
mu_i_sv_register_standard_tests (child);
mu_i_sv_register_standard_comparators (child);
/* Load necessary modules */
mu_list_foreach (parent->registry, regdup, child);
/* Copy identifiers */
child->idspace = mu_sieve_calloc (child, parent->idcount,
sizeof (child->idspace[0]));
child->idcount = child->idmax = parent->idcount;
for (i = 0; i < child->idcount; i++)
child->idspace[i] = mu_sieve_strdup (parent, parent->idspace[i]);
/* Copy string constants */
child->stringspace = mu_sieve_calloc (child, parent->stringcount,
sizeof (child->stringspace[0]));
child->stringcount = child->stringmax = parent->stringcount;
for (i = 0; i < parent->stringcount; i++)
{
memset (&child->stringspace[i], 0, sizeof (child->stringspace[0]));
child->stringspace[i].orig =
mu_sieve_strdup (parent, parent->stringspace[i].orig);
}
/* Copy value space */
child->valspace = mu_sieve_calloc (parent, parent->valcount,
sizeof child->valspace[0]);
child->valcount = child->valmax = parent->valcount;
for (i = 0; i < child->valcount; i++)
{
child->valspace[i].type = parent->valspace[i].type;
child->valspace[i].tag =
mu_sieve_strdup (parent, parent->valspace[i].tag);
switch (child->valspace[i].type)
{
case SVT_TAG:
child->valspace[i].v.string =
mu_sieve_strdup (parent, parent->valspace[i].v.string);
break;
default:
child->valspace[i].v = parent->valspace[i].v;
}
}
/* Copy progspace */
child->progsize = parent->progsize;
child->prog = mu_sieve_calloc (child, parent->progsize,
sizeof child->prog[0]);
memcpy (child->prog, parent->prog,
parent->progsize * sizeof (child->prog[0]));
/* Copy user-defined settings */
child->dry_run = parent->dry_run;
copy_stream_state (child, parent);
child->data = parent->data;
child->logger = parent->logger;
child->daemon_email = parent->daemon_email;
*pmach = child;
}
else
mu_sieve_machine_destroy (&child);
return rc;
}
int
......@@ -1133,9 +1212,7 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
return rc;
}
mach->destr_list = NULL;
mach->test_list = NULL;
mach->action_list = NULL;
mach->comp_list = NULL;
mach->registry = NULL;
mach->progsize = in->progsize;
mach->prog = in->prog;
......@@ -1150,30 +1227,34 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out)
default:
mach->state = in->state;
}
mach->pc = 0;
mach->reg = 0;
mach->stack = NULL;
mach->dry_run = in->dry_run;
rc = setjmp (mach->errbuf);
mach->state_flags = in->state_flags;
mach->err_mode = in->err_mode;
mach->err_locus = in->err_locus;
mach->dbg_mode = in->dbg_mode;
mach->dbg_locus = in->dbg_locus;
if (rc == 0)
{
mach->pc = 0;
mach->reg = 0;
mach->errstream = in->errstream;
mu_stream_ref (mach->errstream);
mach->dbgstream = in->dbgstream;
mu_stream_ref (mach->dbgstream);
mach->dry_run = in->dry_run;
mach->state_flags = in->state_flags;
mach->err_mode = in->err_mode;
mach->err_locus = in->err_locus;
mach->dbg_mode = in->dbg_mode;
mach->dbg_locus = in->dbg_locus;
copy_stream_state (mach, in);
mach->data = in->data;
mach->logger = in->logger;
mach->daemon_email = in->daemon_email;
mach->data = in->data;
mach->logger = in->logger;
mach->daemon_email = in->daemon_email;
*out = mach;
return 0;
*out = mach;
}
else
mu_sieve_machine_destroy (&mach);
return rc;
}
void
......@@ -1334,14 +1415,13 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
mu_sieve_machine_t mach = *pmach;
mu_i_sv_free_stringspace (mach);
mu_sieve_free (mach, mach->stringspace);
mu_stream_destroy (&mach->errstream);
mu_stream_destroy (&mach->dbgstream);
mu_mailer_destroy (&mach->mailer);
mu_list_destroy (&mach->destr_list);
mu_list_destroy (&mach->action_list);
mu_list_destroy (&mach->test_list);
mu_list_destroy (&mach->comp_list);
mu_list_destroy (&mach->source_list);
mu_list_destroy (&mach->registry);
mu_sieve_free (mach, mach->idspace);
mu_opool_destroy (&mach->string_pool);
mu_list_destroy (&mach->memory_pool);
free (mach);
......@@ -1397,7 +1477,7 @@ sieve_parse (void)
yydebug = mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE3);
rc = yyparse ();
mu_i_sv_lex_finish (mu_sieve_machine);
mu_i_sv_lex_finish ();
if (rc)
mu_i_sv_error (mu_sieve_machine);
if (mu_sieve_machine->state == mu_sieve_state_init)
......
......@@ -378,13 +378,13 @@ mu_i_sv_register_standard_tests (mu_sieve_machine_t mach)
{
/* true and false are built-ins */
mu_sieve_register_test (mach, "address", sieve_test_address,
address_req_args, address_tag_groups, 1);
address_req_args, address_tag_groups, 1);
mu_sieve_register_test (mach, "size", sieve_test_size,
size_req_args, size_tag_groups, 1);
size_req_args, size_tag_groups, 1);
mu_sieve_register_test (mach, "envelope", sieve_test_envelope,
address_req_args, envelope_tag_groups, 1);
address_req_args, envelope_tag_groups, 1);
mu_sieve_register_test (mach, "exists", sieve_test_exists,
exists_req_args, NULL, 1);
exists_req_args, NULL, 1);
mu_sieve_register_test (mach, "header", sieve_test_header,
address_req_args, header_tag_groups, 1);
address_req_args, header_tag_groups, 1);
}
......