Commit dd3598aa dd3598aa1d82c29132a24663781738fd321ceb8c by Sergey Poznyakoff

sieve: fix the mu_sieve_vlist_compare API

* libmu_sieve/util.c (mu_sieve_vlist_compare): Rewrite.
* include/mailutils/sieve.h (mu_sieve_retrieve_t): Change signature.
All uses changed.
(mu_sieve_relational_count): Remove.
(mu_sieve_vlist_compare): Change signature.
* libmu_sieve/extensions/list.c (list_retrieve_header): Always
return meaningful status.
* libmu_sieve/tests.c (mu_sieve_relational_count): Remove.
(retrieve_address,retrieve_envelope): Return meaningful status.
(retrieve_header): Iterate over all mime parts, if required.
(sieve_test_address,sieve_test_header): Rewrite.
* libmu_sieve/variables.c (sieve_test_string): Rewrite using
mu_sieve_vlist_compare.
1 parent 38951839
gint @ 42f47120
Subproject commit fd86bf7d44b0c970771830692ae7491447ebe8b1
Subproject commit 42f4712085b40173eaea58e14b1a579291a6fe3a
......
......@@ -51,7 +51,7 @@ typedef int (*mu_sieve_relcmp_t) (int, int);
typedef int (*mu_sieve_relcmpn_t) (size_t, size_t);
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,
typedef int (*mu_sieve_retrieve_t) (void *item, void *data, size_t idx,
char **pval);
typedef void (*mu_sieve_destructor_t) (void *data);
typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach);
......@@ -201,8 +201,6 @@ void mu_sieve_register_comparator (mu_sieve_machine_t mach, const char *name,
mu_sieve_comparator_t eq);
int mu_sieve_require_relational (mu_sieve_machine_t mach, const char *name);
int mu_sieve_relational_count (mu_sieve_machine_t mach, size_t count,
int retval);
int mu_sieve_require_variables (mu_sieve_machine_t mach);
int mu_sieve_has_variables (mu_sieve_machine_t mach);
......@@ -254,9 +252,8 @@ int mu_sieve_vlist_do (mu_sieve_machine_t mach,
void *data);
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);
mu_sieve_retrieve_t ac, mu_list_folder_t fold,
void *data);
/* Functions to create and destroy sieve machine */
int mu_sieve_machine_create (mu_sieve_machine_t *mach);
......
......@@ -93,7 +93,7 @@ retrieve_next_header (struct header_closure *hc, char *name, char **pval)
}
static int
list_retrieve_header (void *item, void *data, int idx, char **pval)
list_retrieve_header (void *item, void *data, size_t idx, char **pval)
{
struct header_closure *hc = data;
char *p;
......@@ -106,7 +106,7 @@ list_retrieve_header (void *item, void *data, int idx, char **pval)
if (!hc->valv)
{
if (retrieve_next_header (hc, (char*) item, &p))
return 1;
return MU_ERR_NOENT;
}
else if (hc->vali == hc->valc)
{
......@@ -117,11 +117,11 @@ list_retrieve_header (void *item, void *data, int idx, char **pval)
p = hc->valv[hc->vali++];
if ((*pval = strdup (p)) == NULL)
return 1;
return errno;
return 0;
}
return 1;
return MU_ERR_NOENT;
}
......@@ -148,7 +148,6 @@ static int
list_test (mu_sieve_machine_t mach)
{
mu_sieve_value_t *h, *v;
mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
struct header_closure clos;
int result;
......@@ -159,10 +158,8 @@ 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 (mach, h, v, comp,
mu_sieve_get_relcmp (mach),
list_retrieve_header,
&clos, NULL) > 0;
result = mu_sieve_vlist_compare (mach, h, v, list_retrieve_header, NULL,
&clos);
cleanup (&clos);
return result;
}
......
......@@ -55,35 +55,8 @@ struct address_closure
mu_address_t addr; /* Obtained address */
};
int
mu_sieve_relational_count (mu_sieve_machine_t mach, size_t count, int retval)
{
char *relcmp;
if (mu_sieve_get_tag (mach, "count", SVT_STRING, &relcmp))
{
size_t limit;
char *str, *p;
struct mu_sieve_slice slice;
mu_sieve_relcmpn_t stest;
mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &slice);
str = mu_sieve_string (mach, &slice, 0);
limit = strtoul (str, &p, 10);
if (*p)
{
mu_sieve_error (mach, _("%s: not an integer"), str);
mu_sieve_abort (mach);
}
mu_sieve_str_to_relcmp (relcmp, NULL, &stest);
return stest (count, limit);
}
return retval;
}
int
retrieve_address (void *item, void *data, int idx, char **pval)
static int
retrieve_address (void *item, void *data, size_t idx, char **pval)
{
struct address_closure *ap = data;
char *val;
......@@ -91,8 +64,9 @@ retrieve_address (void *item, void *data, int idx, char **pval)
if (!ap->addr)
{
if (mu_header_aget_value ((mu_header_t)ap->data, (char*)item, &val))
return 1;
rc = mu_header_aget_value ((mu_header_t)ap->data, (char*)item, &val);
if (rc)
return rc;
rc = mu_address_create (&ap->addr, val);
free (val);
if (rc)
......@@ -110,11 +84,8 @@ sieve_test_address (mu_sieve_machine_t mach)
{
mu_sieve_value_t *h, *v;
mu_header_t header = NULL;
mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
struct address_closure clos;
int rc;
size_t count = 0;
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
......@@ -123,89 +94,105 @@ sieve_test_address (mu_sieve_machine_t mach)
clos.data = header;
clos.aget = sieve_get_address_part (mach);
clos.addr = NULL;
rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_address, &clos,
&count);
rc = mu_sieve_vlist_compare (mach, h, v, retrieve_address, NULL, &clos);
mu_address_destroy (&clos.addr);
return mu_sieve_relational_count (mach, count, rc);
return rc;
}
struct header_closure
{
mu_message_t message;
size_t nparts;
size_t part;
mu_header_t header;
int index;
size_t index;
};
int
retrieve_header (void *item, void *data, int idx, char **pval)
retrieve_header (void *item, void *data, size_t idx, char **pval)
{
struct header_closure *hc = data;
char buf[512];
size_t n;
char const *hname;
int rc;
if (idx == 0)
hc->index = 1;
while (!mu_header_get_field_name (hc->header, hc->index, buf, sizeof(buf), &n))
{
int i = hc->index++;
if (mu_c_strcasecmp (buf, (char*)item) == 0)
rc = mu_message_get_header (hc->message, &hc->header);
if (rc)
return rc;
hc->index = 1;
hc->part = 1;
}
do
{
if (!hc->header)
{
if (mu_header_aget_field_value_unfold (hc->header, i, pval))
if (hc->part <= hc->nparts)
{
mu_message_t msg;
rc = mu_message_get_part (hc->message, hc->part, &msg);
if (rc)
return rc;
hc->part++;
rc = mu_message_get_header (msg, &hc->header);
if (rc)
return rc;
hc->index = 1;
}
else
return 1;
return 0;
}
}
while (!mu_header_sget_field_name (hc->header, hc->index, &hname))
{
int i = hc->index++;
if (mu_c_strcasecmp (hname, (char*)item) == 0)
{
if (mu_header_aget_field_value_unfold (hc->header, i, pval))
return -1;
return 0;
}
}
return 1;
hc->header = NULL;
}
while (hc->part <= hc->nparts);
return MU_ERR_NOENT;
}
int
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 = 0, mcount = 0;
int rc;
struct header_closure clos;
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
clos.message = mach->msg;
if (mu_sieve_get_tag (mach, "mime", SVT_VOID, NULL))
{
int ismime = 0;
mu_message_is_multipart (mach->msg, &ismime);
if (ismime)
{
size_t i, nparts = 0;
mu_message_get_num_parts (mach->msg, &nparts);
for (i = 1; i <= nparts; i++)
{
mu_message_t message = NULL;
if (mu_message_get_part (mach->msg, i, &message) == 0)
{
mu_message_get_header (message, &clos.header);
if (mu_sieve_vlist_compare (mach, h, v, comp, test,
retrieve_header, &clos, &mcount))
return 1;
}
}
}
mu_message_get_num_parts (mach->msg, &clos.nparts);
}
mu_message_get_header (mach->msg, &clos.header);
if (mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_header, &clos,
&count))
return 1;
return mu_sieve_relational_count (mach, count + mcount, 0);
else
clos.nparts = 0;
rc = mu_sieve_vlist_compare (mach, h, v, retrieve_header, NULL, &clos);
return rc;
}
int
retrieve_envelope (void *item, void *data, int idx, char **pval)
retrieve_envelope (void *item, void *data, size_t idx, char **pval)
{
struct address_closure *ap = data;
int rc;
......@@ -215,10 +202,11 @@ retrieve_envelope (void *item, void *data, int idx, char **pval)
const char *buf;
if (mu_c_strcasecmp ((char*)item, "from") != 0)
return 1;
return MU_ERR_NOENT;
if (mu_envelope_sget_sender ((mu_envelope_t)ap->data, &buf))
return 1;
rc = mu_envelope_sget_sender ((mu_envelope_t)ap->data, &buf);
if (rc)
return rc;
rc = mu_address_create (&ap->addr, buf);
if (rc)
......@@ -235,11 +223,8 @@ int
sieve_test_envelope (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);
struct address_closure clos;
int rc;
size_t count = 0;
h = mu_sieve_get_arg_untyped (mach, 0);
v = mu_sieve_get_arg_untyped (mach, 1);
......@@ -248,10 +233,9 @@ sieve_test_envelope (mu_sieve_machine_t mach)
(mu_envelope_t*)&clos.data);
clos.aget = sieve_get_address_part (mach);
clos.addr = NULL;
rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_envelope, &clos,
&count);
rc = mu_sieve_vlist_compare (mach, h, v, retrieve_envelope, NULL, &clos);
mu_address_destroy (&clos.addr);
return mu_sieve_relational_count (mach, count, rc);
return rc;
}
int
......
......@@ -358,49 +358,112 @@ mu_sieve_vlist_do (mu_sieve_machine_t mach, mu_sieve_value_t *val,
return EINVAL;
}
}
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 retr,
void *data, size_t *count)
mu_sieve_retrieve_t retr, mu_list_folder_t fold,
void *data)
{
int rc = 0;
size_t i;
mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
char *relcmp;
mu_list_t tmp;
switch (a->type)
if (!(a->type == SVT_STRING_LIST || a->type == SVT_STRING))
abort ();
rc = mu_list_create (&tmp);
if (rc)
{
case SVT_STRING_LIST:
case SVT_STRING:
for (i = 0; i < a->v.list.count; i++)
mu_sieve_error (mach, "mu_list_create: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
mu_list_set_destroy_item (tmp, mu_list_free_item);
for (i = 0; i < a->v.list.count; i++)
{
char *item = mu_sieve_string (mach, &a->v.list, i);
char *sample;
size_t j;
for (j = 0; (rc = retr (item, data, j, &sample)) == 0; j++)
{
char *item = mu_sieve_string (mach, &a->v.list, i);
char *sample;
size_t j, k;
for (j = 0; rc == 0 && retr (item, data, j, &sample) == 0; j++)
rc = mu_list_append (tmp, sample);
if (rc)
{
if (count)
(*count)++;
for (k = 0; k < b->v.list.count; k++)
{
mu_sieve_string_t *s = mu_sieve_string_raw (mach, &b->v.list, k);
rc = test (comp (mach, s, sample), 0);
if (rc)
{
free (sample);
return rc;
}
}
free (sample);
mu_list_destroy (&tmp);
mu_sieve_error (mach, "mu_list_append: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
}
break;
if (rc != MU_ERR_NOENT)
{
mu_list_destroy (&tmp);
mu_sieve_error (mach, "retriever failure: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
}
if (mu_sieve_get_tag (mach, "count", SVT_STRING, &relcmp))
{
size_t limit;
size_t count;
mu_sieve_relcmpn_t stest;
struct mu_sieve_slice slice;
char *str, *p;
default:
abort ();
if (fold)
{
count = 0;
rc = mu_list_fold (tmp, fold, data, &count, &count);
if (rc)
{
mu_sieve_error (mach, "mu_list_fold: %s", mu_strerror (rc));
mu_sieve_abort (mach);
}
}
else
mu_list_count (tmp, &count);
mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &slice);
str = mu_sieve_string (mach, &slice, 0);
limit = strtoul (str, &p, 10);
if (*p)
{
mu_sieve_error (mach, _("%s: not an integer"), str);
mu_sieve_abort (mach);
}
mu_sieve_str_to_relcmp (relcmp, NULL, &stest);
rc = stest (count, limit);
}
else
{
mu_iterator_t itr;
mu_list_get_iterator (tmp, &itr);
rc = 0;
for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
char const *val;
mu_iterator_current (itr, (void**)&val);
for (i = 0; i < b->v.list.count; i++)
{
mu_sieve_string_t *s = mu_sieve_string_raw (mach, &b->v.list, i);
rc = test (comp (mach, s, val), 0);
if (rc)
break;
}
}
mu_iterator_destroy (&itr);
}
mu_list_destroy (&tmp);
return rc;
}
......
......@@ -243,43 +243,45 @@ static mu_sieve_data_type set_args[] = {
SVT_VOID
};
static int
retrieve_string (void *item, void *data, size_t idx, char **pval)
{
if (idx)
return MU_ERR_NOENT;
*pval = strdup ((char*)item);
if (!*pval)
return errno;
return 0;
}
int
fold_string (void *item, void *data, void *prev, void **ret)
{
char *str = item;
size_t count = *(size_t*) prev;
/* The "relational" extension [RELATIONAL] adds a match type called
":count". The count of a single string is 0 if it is the empty
string, or 1 otherwise. The count of a string list is the sum of the
counts of the member strings.
*/
if (*str)
++count;
*(size_t*)ret = count;
return 0;
}
/* RFC 5229, 5. Test string */
int
sieve_test_string (mu_sieve_machine_t mach)
{
mu_sieve_value_t *source, *key_list;
mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
size_t count = 0;
int rc = 0;
size_t i;
source = mu_sieve_get_arg_untyped (mach, 0);
key_list = mu_sieve_get_arg_untyped (mach, 1);
for (i = 0; i < source->v.list.count; i++)
{
char *item = mu_sieve_string (mach, &source->v.list, i);
size_t k;
/* The "relational" extension [RELATIONAL] adds a match type called
":count". The count of a single string is 0 if it is the empty
string, or 1 otherwise. The count of a string list is the sum of the
counts of the member strings.
*/
if (item[0])
count++;
for (k = 0; k < key_list->v.list.count; k++)
{
mu_sieve_string_t *s =
mu_sieve_string_raw (mach, &key_list->v.list, k);
rc = test (comp (mach, s, item), 0);
if (rc)
return rc;
}
}
return mu_sieve_relational_count (mach, count, 0);
return mu_sieve_vlist_compare (mach, source, key_list,
retrieve_string, fold_string, mach);
}
mu_sieve_data_type string_args[] = {
......