/* Syntax: addheader [:last] <field-name: string> <value: string> */ int sieve_addheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *val; const char *field_name; const char *field_value; mu_message_t msg; mu_header_t hdr; int rc; val = mu_sieve_value_get (args, 0); if (!val) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get field name")); mu_sieve_abort (mach); } field_name = val->v.string; val = mu_sieve_value_get (args, 1); if (!val) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get field value")); mu_sieve_abort (mach); } field_value = val->v.string; 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_tag_lookup (tags, "last", 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; }
/* Handler for the numaddr test */ static int numaddr_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *h, *v; struct val_ctr vc; int rc; if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE) { mu_sieve_debug (mach, "NUMADDR"); } /* Retrieve required arguments: */ /* First argument: list of header names */ h = mu_sieve_value_get (args, 0); if (!h) { mu_sieve_error (mach, "numaddr: can't get argument 1"); mu_sieve_abort (mach); } /* Second argument: Limit on the number of addresses */ v = mu_sieve_value_get (args, 1); if (!v) { mu_sieve_error (mach, "numaddr: can't get argument 2"); mu_sieve_abort (mach); } /* Fill in the val_ctr structure */ mu_message_get_header (mu_sieve_get_message (mach), &vc.hdr); vc.count = 0; vc.limit = v->v.number; /* Count the addresses */ rc = mu_sieve_vlist_do (h, _count_items, &vc); /* Here rc >= 1 iff the counted number of addresses is greater or equal to vc.limit. If `:under' tag was given we reverse the return value */ if (mu_sieve_tag_lookup (tags, "under", NULL)) rc = !rc; return rc; }
int mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args) { mu_iterator_t itr; mu_sieve_runtime_tag_t *match = NULL; mu_sieve_runtime_tag_t *comp = NULL; mu_sieve_runtime_tag_t *tmp; mu_sieve_comparator_t compfun = NULL; char *compname = "false"; int matchtype; int err = 0; if (!tags || mu_list_get_iterator (tags, &itr)) return 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, "is") == 0 || strcmp (t->tag, "contains") == 0 || strcmp (t->tag, "matches") == 0 || strcmp (t->tag, "regex") == 0 || strcmp (t->tag, "count") == 0 || strcmp (t->tag, "value") == 0) { if (match) { mu_sv_compile_error (&mu_sieve_locus, _("match type specified twice in call to `%s'"), name); err = 1; } else match = t; } else if (strcmp (t->tag, "comparator") == 0) comp = t; } mu_iterator_destroy (&itr); if (err) return 1; if (!match || strcmp (match->tag, "is") == 0) matchtype = MU_SIEVE_MATCH_IS; else if (strcmp (match->tag, "contains") == 0) matchtype = MU_SIEVE_MATCH_CONTAINS; else if (strcmp (match->tag, "matches") == 0) matchtype = MU_SIEVE_MATCH_MATCHES; else if (strcmp (match->tag, "regex") == 0) matchtype = MU_SIEVE_MATCH_REGEX; else { char *str = match->arg->v.string; if (strcmp (match->tag, "count") == 0) { mu_sieve_value_t *val; char *str; size_t count; if (comp && strcmp (comp->arg->v.string, "i;ascii-numeric")) { mu_sv_compile_error (&mu_sieve_locus, /* TRANSLATORS: Do not translate ':count'. It is the name of a Sieve tag */ _("comparator %s is incompatible with " ":count in call to `%s'"), comp->arg->v.string, name); return 1; } matchtype = MU_SIEVE_MATCH_LAST; /* to not leave it undefined */ compfun = comp_false; val = mu_sieve_value_get (args, 1); if (!val) return 1; /* shouldn't happen */ /* NOTE: Type of v is always SVT_STRING_LIST */ mu_list_count (val->v.list, &count); if (count > 1) { mu_sv_compile_error (&mu_sieve_locus, _("second argument must be a list of one element")); return 1; } mu_list_get (val->v.list, 0, (void **) &str); count = strtoul (str, &str, 10); if (*str) { mu_sv_compile_error (&mu_sieve_locus, _("second argument cannot be converted to number")); return 1; } } else matchtype = MU_SIEVE_MATCH_EQ; if (mu_sieve_str_to_relcmp (str, NULL, NULL)) { mu_sv_compile_error (&mu_sieve_locus, _("invalid relational match `%s' in call to `%s'"), str, name); return 1; } } if (!compfun) { compname = comp ? comp->arg->v.string : "i;ascii-casemap"; compfun = mu_sieve_comparator_lookup (mu_sieve_machine, compname, matchtype); if (!compfun) { mu_sv_compile_error (&mu_sieve_locus, _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), compname, match ? match->tag : "is", name); return 1; } } tmp = mu_sieve_malloc (mu_sieve_machine, sizeof (*tmp)); tmp->tag = TAG_COMPFUN; tmp->arg = mu_sieve_value_create (SVT_POINTER, compfun); mu_list_append (tags, tmp); if (matchtype == MU_SIEVE_MATCH_REGEX) { /* To speed up things, compile all patterns at once. Notice that it is supposed that patterns are in arg 2 */ mu_sieve_value_t *val, *newval; struct regex_data rd; int rc; if (mu_list_get (args, 1, (void**)&val)) return 0; rd.flags = REG_EXTENDED; if (strcmp (compname, "i;ascii-casemap") == 0) rd.flags |= REG_ICASE; mu_list_create (&rd.list); rc = mu_sieve_vlist_do (val, _regex_compile, &rd); mu_sieve_machine_add_destructor (mu_sieve_machine, _free_reglist, rd.list); if (rc) return rc; newval = mu_sieve_value_create (SVT_STRING_LIST, rd.list); mu_list_replace (args, val, newval); } #ifndef FNM_CASEFOLD else if (matchtype == MU_SIEVE_MATCH_MATCHES && strcmp (compname, "i;ascii-casemap") == 0) { int rc; mu_sieve_value_t *val; if (mu_list_get (args, 1, (void**)&val)) return 0; rc = mu_sieve_vlist_do (val, _pattern_upcase, NULL); if (rc) return rc; } #endif return 0; }
int sieve_action_vacation (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { int rc; char *text, *from; mu_sieve_value_t *val; mu_message_t msg; mu_header_t hdr; char *my_address = mu_sieve_get_daemon_email (mach); if (diag (mach)) return 0; val = mu_sieve_value_get (args, 0); if (!val) { mu_sieve_error (mach, _("cannot get text!")); mu_sieve_abort (mach); } else text = val->v.string; msg = mu_sieve_get_message (mach); mu_message_get_header (msg, &hdr); if (mu_sieve_tag_lookup (tags, "sender", &val)) { /* Debugging hook: :sender sets fake reply address */ from = strdup (val->v.string); if (!from) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (ENOMEM)); mu_sieve_abort (mach); } } else if (mu_sieve_get_message_sender (msg, &from)) { mu_sieve_error (mach, _("%lu: cannot get sender address"), (unsigned long) mu_sieve_get_message_num (mach)); mu_sieve_abort (mach); } if (mu_sieve_tag_lookup (tags, "aliases", &val) && match_addresses (hdr, val, &my_address) == 0) return 0; if (noreply_address_p (mach, tags, from) || bulk_precedence_p (hdr) || check_db (mach, tags, from)) { free (from); return 0; } rc = vacation_reply (mach, tags, msg, text, from, my_address); free (from); if (rc == -1) mu_sieve_abort (mach); return rc; }
/* Syntax: deleteheader [:index <fieldno: number> [:last]] [COMPARATOR] [MATCH-TYPE] <field-name: string> [<value-patterns: string-list>] */ int sieve_deleteheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *val; const char *field_name; const char *field_pattern; mu_message_t msg; mu_header_t hdr; int rc; mu_sieve_comparator_t comp; mu_iterator_t itr; unsigned long i, idx = 0; val = mu_sieve_value_get (args, 0); if (!val) { mu_sieve_error (mach, "%lu: %s", (unsigned long) mu_sieve_get_message_num (mach), _("cannot get field name")); mu_sieve_abort (mach); } field_name = val->v.string; val = mu_sieve_value_get (args, 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); } } 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); } mu_header_get_iterator (hdr, &itr); if (mu_sieve_tag_lookup (tags, "last", NULL)) { int backwards = 1; mu_iterator_ctl (itr, mu_itrctl_set_direction, &backwards); } comp = mu_sieve_get_comparator (mach, tags); if (mu_sieve_tag_lookup (tags, "index", &val)) idx = val->v.number; 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 (field_pattern) { if (comp (field_pattern, fv)) mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } else mu_iterator_ctl (itr, mu_itrctl_delete, NULL); if (idx) break; } mu_iterator_destroy (&itr); return 0; }
/* Handler for the timestamp test */ static int timestamp_test (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_sieve_value_t *h, *v; mu_header_t hdr; char *val; time_t now = time (NULL); time_t tlimit, tval; int rc; if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE) { mu_sieve_locus_t locus; mu_sieve_get_locus (mach, &locus); mu_sieve_debug (mach, "%s:%lu: TIMESTAMP\n", locus.source_file, (unsigned long) locus.source_line); } /* Retrieve required arguments: */ /* First argument: header name */ h = mu_sieve_value_get (args, 0); if (!h) { mu_sieve_arg_error (mach, 1); mu_sieve_abort (mach); } /* Second argument: date displacement */ v = mu_sieve_value_get (args, 1); if (!v) { mu_sieve_arg_error (mach, 2); mu_sieve_abort (mach); } if (mu_parse_date (v->v.string, &tlimit, &now)) { mu_sieve_error (mach, _("cannot parse date specification (%s)"), v->v.string); mu_sieve_abort (mach); } rc = mu_message_get_header (mu_sieve_get_message (mach), &hdr); if (rc) { mu_sieve_error (mach, "mu_message_get_header: %s", mu_strerror (rc)); mu_sieve_abort (mach); } if (mu_header_aget_value (hdr, h->v.string, &val)) return 0; if (mu_parse_date (val, &tval, &now)) { mu_sieve_error (mach, "cannot parse header date specification (%s)", val); free (val); mu_sieve_abort (mach); } free (val); rc = tval > tlimit; if (mu_sieve_tag_lookup (tags, "before", NULL)) rc = !rc; return rc; }