/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2012-2021 Free Software Foundation, Inc.
GNU Mailutils 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, or (at your option)
any later version.
GNU Mailutils 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 GNU Mailutils. If not, see
. */
/* This module implements the Editheader Extension (RFC 5293) */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
/* Syntax: addheader [:last]
*/
int
sieve_addheader (mu_sieve_machine_t mach)
{
const char *field_name;
const char *field_value;
mu_message_t msg;
mu_header_t hdr;
int rc;
mu_sieve_get_arg (mach, 0, SVT_STRING, &field_name);
mu_sieve_get_arg (mach, 1, SVT_STRING, &field_value);
mu_sieve_log_action (mach, "ADDHEADER", "%s: %s", field_name, field_value);
if (mu_sieve_is_dry_run (mach))
return 0;
msg = mu_sieve_get_message (mach);
rc = mu_message_get_header (msg, &hdr);
if (rc)
{
mu_sieve_error (mach, "%lu: %s: %s",
(unsigned long) mu_sieve_get_message_num (mach),
_("cannot get message header"),
mu_strerror (rc));
mu_sieve_abort (mach);
}
rc = (mu_sieve_get_tag (mach, "last", SVT_VOID, NULL) ?
mu_header_append : mu_header_prepend) (hdr, field_name, field_value);
if (rc)
{
mu_sieve_error (mach, "%lu: %s: %s",
(unsigned long) mu_sieve_get_message_num (mach),
_("cannot append message header"),
mu_strerror (rc));
mu_sieve_abort (mach);
}
return 0;
}
/* Syntax: deleteheader [:index [:last]]
[COMPARATOR] [MATCH-TYPE]
[]
*/
int
sieve_deleteheader (mu_sieve_machine_t mach)
{
mu_sieve_value_t *val;
const char *field_name;
mu_message_t msg;
mu_header_t hdr;
int rc;
mu_sieve_comparator_t comp;
mu_iterator_t itr;
size_t i, idx = 0;
mu_sieve_get_arg (mach, 0, SVT_STRING, &field_name);
val = mu_sieve_get_arg_optional (mach, 1);
mu_sieve_log_action (mach, "DELETEHEADER", "%s%s", field_name,
val ? " (values)" : "" );
if (mu_sieve_is_dry_run (mach))
return 0;
msg = mu_sieve_get_message (mach);
rc = mu_message_get_header (msg, &hdr);
if (rc)
{
mu_sieve_error (mach, "%lu: %s: %s",
(unsigned long) mu_sieve_get_message_num (mach),
_("cannot get message header"),
mu_strerror (rc));
mu_sieve_abort (mach);
}
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;
mu_iterator_ctl (itr, mu_itrctl_set_direction, &backwards);
}
comp = mu_sieve_get_comparator (mach);
mu_sieve_get_tag (mach, "index", SVT_NUMBER, &idx);
for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
const char *fn, *fv;
mu_iterator_current_kv (itr, (const void **)&fn, (void **)&fv);
if (strcmp (field_name, fn))
continue;
if (idx && ++i < idx)
continue;
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))
{
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
break;
}
}
}
else
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
if (idx)
break;
}
mu_iterator_destroy (&itr);
return 0;
}
/* addheader tagged arguments: */
static mu_sieve_tag_def_t addheader_tags[] = {
{ "last", SVT_VOID },
{ NULL }
};
static mu_sieve_tag_group_t addheader_tag_groups[] = {
{ addheader_tags, NULL },
{ NULL }
};
/* addheader required arguments: */
static mu_sieve_data_type addheader_args[] = {
SVT_STRING, /* field name */
SVT_STRING, /* field value */
SVT_VOID
};
#if 0
/* FIXME: The checker interface should be redone. Until then this function
is commented out. Problems:
1. Checkers are called per group, there's no way to call them per tag.
2. See FIXMEs in the code.
*/
static int
index_checker (const char *name, mu_list_t tags, mu_list_t args)
{
mu_iterator_t itr;
mu_sieve_runtime_tag_t *match = NULL;
int err;
if (!tags || mu_list_get_iterator (tags, &itr))
return 0;
err = 0;
for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
mu_sieve_runtime_tag_t *t;
mu_iterator_current (itr, (void **)&t);
if (strcmp (t->tag, "index") == 0)
{
if (match)
{
/* FIXME: 1. This function must be public.
2. locus should be included in t
*/
mu_sv_compile_error (&mu_sieve_locus,
_("index specified twice in call to `%s'"),
name);
err = 1;
break;
}
}
}
mu_iterator_destroy (&itr);
if (err)
return 1;
if (match)
{
if (match->arg->v.number < 1)
{
// See FIXME above
mu_sv_compile_error (&mu_sieve_locus,
_("invalid index value: %s"),
match->arg->v.string);
return 1;
}
}
return 0;
}
#endif
static mu_sieve_tag_def_t match_part_tags[] = {
{ "is", SVT_VOID },
{ "contains", SVT_VOID },
{ "matches", SVT_VOID },
{ "regex", SVT_VOID },
{ "count", SVT_STRING },
{ "value", SVT_STRING },
{ "comparator", SVT_STRING },
{ NULL }
};
/* deleteheader tagged arguments: */
static mu_sieve_tag_def_t deleteheader_tags[] = {
{ "last", SVT_VOID },
{ "index", SVT_NUMBER },
{ NULL }
};
static mu_sieve_tag_group_t deleteheader_tag_groups[] = {
{ deleteheader_tags, NULL },
{ match_part_tags, mu_sieve_match_part_checker },
{ NULL }
};
/* deleteheader required arguments: */
static mu_sieve_data_type deleteheader_args[] = {
SVT_STRING, /* field name or value pattern */
SVT_VOID
};
int
SIEVE_EXPORT (editheader, init) (mu_sieve_machine_t mach)
{
/* This dummy record is required by libmu_sieve */
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;
}