static int test_and_update_prop (mu_property_t prop, const char *from, time_t now, unsigned int days, mu_sieve_machine_t mach) { const char *result; char *timebuf; time_t last; int rc = mu_property_sget_value (prop, from, &result); switch (rc) { case MU_ERR_NOENT: break; case 0: if (days == 0) return 1; last = (time_t) strtoul (result, NULL, 0); if (last + (24 * 60 * 60 * days) > now) return 1; break; default: mu_sieve_error (mach, "%lu: mu_property_sget_value: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); return -1; } rc = mu_asprintf (&timebuf, "%lu", (unsigned long) now); if (rc) { mu_sieve_error (mach, "%lu: mu_asprintf: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); return -1; } rc = mu_property_set_value (prop, from, timebuf, 1); free (timebuf); if (rc) { mu_sieve_error (mach, "%lu: mu_property_set_value: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); return -1; } rc = mu_property_save (prop); if (rc) { mu_sieve_error (mach, "%lu: mu_property_save: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); return -1; } return 0; }
/* 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; }
static int moderator_discard_message (mu_sieve_machine_t mach, mu_message_t request, const char *from) { int rc; mu_message_t reply; mu_header_t repl_hdr, req_hdr; mu_mailer_t mailer; rc = mu_message_create (&reply, NULL); if (rc) return rc; rc = mu_message_get_header (reply, &repl_hdr); if (rc) { mu_message_destroy (&reply, NULL); return rc; } rc = mu_message_get_header (request, &req_hdr); if (rc) { mu_message_destroy (&reply, NULL); return rc; } if (copy_header (mach, repl_hdr, MU_HEADER_TO, req_hdr, MU_HEADER_FROM) || copy_header (mach, repl_hdr, MU_HEADER_SUBJECT, req_hdr, MU_HEADER_SUBJECT)) { mu_message_destroy (&reply, NULL); return rc; } if (from) mu_header_set_value (repl_hdr, MU_HEADER_FROM, from, 0); mailer = mu_sieve_get_mailer (mach); rc = mu_mailer_open (mailer, 0); if (rc) mu_sieve_error (mach, _("cannot open mailer: %s"), mu_strerror (rc)); else { rc = mu_mailer_send_message (mailer, reply, NULL, NULL); mu_mailer_close (mailer); if (rc) mu_sieve_error (mach, _("cannot send message: %s"), mu_strerror (rc)); } mu_message_destroy (&reply, NULL); return rc; }
int moderator_message_get_part (mu_sieve_machine_t mach, mu_message_t msg, size_t index, mu_message_t *pmsg) { int rc; mu_message_t tmp; mu_header_t hdr = NULL; char *value; if ((rc = mu_message_get_part (msg, index, &tmp))) { mu_sieve_error (mach, _("cannot get message part #%lu: %s"), (unsigned long) index, mu_strerror (rc)); return 1; } mu_message_get_header (tmp, &hdr); if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, &value) == 0 && memcmp (value, "message/rfc822", 14) == 0) { mu_stream_t str; mu_body_t body; free (value); mu_message_get_body (tmp, &body); mu_body_get_stream (body, &str); rc = mu_stream_to_message (str, pmsg); if (rc) { mu_sieve_error (mach, _("cannot convert MIME part stream to message: %s"), mu_strerror (rc)); return 1; } } else if (value) { mu_sieve_error (mach, _("expected message type message/rfc822, but found %s"), value); free (value); return 1; } else { mu_sieve_error (mach, _("no Content-Type header found")); return 1; } return 0; }
static int moderator_filter_message (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg, int *pdiscard) { int rc; mu_sieve_machine_t newmach; mu_attribute_t attr; mu_sieve_value_t *arg; if (mu_sieve_tag_lookup (tags, "source", &arg)) { rc = mu_sieve_machine_inherit (mach, &newmach); if (rc) { mu_sieve_error (mach, _("cannot initialize sieve machine: %s"), mu_strerror (rc)); return 1; } /* FIXME: This should be configurable: moderator :inherit moderator :debug 2 ... */ rc = mu_sieve_compile (newmach, arg->v.string); if (rc) mu_sieve_error (mach, _("cannot compile source `%s'"), arg->v.string); } else rc = mu_sieve_machine_dup (mach, &newmach); if (rc) return rc; mu_message_get_attribute (msg, &attr); mu_attribute_unset_deleted (attr); rc = mu_sieve_message (newmach, msg); if (rc) mu_sieve_error (newmach, _("failed to run inferior sieve machine")); else *pdiscard = mu_attribute_is_deleted (attr); mu_sieve_machine_destroy (&newmach); return rc; }
int mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox) { int rc; size_t total; mu_observer_t observer; mu_observable_t observable; if (!mach || !mbox) return EINVAL; mu_observer_create (&observer, mach); mu_observer_set_action (observer, _sieve_action, mach); mu_mailbox_get_observable (mbox, &observable); mu_observable_attach (observable, MU_EVT_MESSAGE_ADD, observer); mach->mailbox = mbox; mach->msgno = 0; rc = mu_mailbox_scan (mbox, 1, &total); if (rc) mu_sieve_error (mach, _("mu_mailbox_scan: %s"), mu_strerror (errno)); mu_observable_detach (observable, observer); mu_observer_destroy (&observer, mach); mach->mailbox = NULL; return rc; }
/* Add a reply prefix to the subject. *PSUBJECT points to the original subject, which must be allocated using malloc. Before returning its value is freed and replaced with the new one. Default reply prefix is "Re: ", unless overridden by "reply_prefix" tag. */ static void re_subject (mu_sieve_machine_t mach, mu_list_t tags, char **psubject) { char *subject; mu_sieve_value_t *arg; char *prefix = "Re"; if (mu_sieve_tag_lookup (tags, "reply_prefix", &arg)) { prefix = arg->v.string; } subject = malloc (strlen (*psubject) + strlen (prefix) + 3); if (!subject) { mu_sieve_error (mach, _("%lu: not enough memory"), (unsigned long) mu_sieve_get_message_num (mach)); return; } strcpy (subject, prefix); strcat (subject, ": "); strcat (subject, *psubject); free (*psubject); *psubject = subject; }
/* 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; }
static int copy_header (mu_sieve_machine_t mach, mu_header_t to_hdr, char *to, mu_header_t from_hdr, char *from) { int rc; const char *value = NULL; if ((rc = mu_header_sget_value (from_hdr, from, &value))) { mu_sieve_error (mach, _("cannot get `%s:' header: %s"), from, mu_strerror (rc)); return rc; } rc = mu_header_set_value (to_hdr, to, value, 0); return rc; }
void _mu_sv_instr_push (mu_sieve_machine_t mach) { if (INSTR_DEBUG (mach)) { mu_sieve_debug (mach, "%4lu: PUSH\n", (unsigned long)(mach->pc - 1)); 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_prepend (mach->stack, (void*) mach->reg); }
void _mu_sv_instr_pop (mu_sieve_machine_t mach) { if (INSTR_DEBUG (mach)) { mu_sieve_debug (mach, "%4lu: POP\n", (unsigned long)(mach->pc - 1)); 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_get (mach->stack, 0, (void **)&mach->reg); mu_list_remove (mach->stack, (void *)mach->reg); }
static int regex_comparator (void *item, void *data) { regex_t preg; int rc; struct regex_data *d = data; if (regcomp (&preg, item, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | REG_ICASE)) { mu_sieve_error (d->mach, _("%lu: cannot compile regular expression \"%s\""), (unsigned long) mu_sieve_get_message_num (d->mach), (char*) item); return 0; } rc = regexec (&preg, d->email, 0, NULL, 0) == 0; regfree (&preg); return rc; }
static lt_dlhandle load_module (mu_sieve_machine_t mach, const char *name) { lt_dlhandle handle; if (sieve_init_load_path ()) return NULL; handle = lt_dlopenext (name); if (handle) { sieve_module_init_t 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 { lt_dlclose (handle); handle = NULL; } } if (!handle) { mu_sieve_error (mach, "%s: %s", name, lt_dlerror ()); lt_dlexit (); } return handle; }
static int moderator_action (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags) { mu_message_t msg, orig; int rc; size_t nparts = 0; int discard = 0; int ismime; if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE) { mu_sieve_debug (mach, "moderator_test %lu", (unsigned long) mu_sieve_get_message_num (mach)); } msg = mu_sieve_get_message (mach); mu_message_is_multipart (msg, &ismime); if (!ismime) { mu_sieve_error (mach, _("message is not multipart")); mu_sieve_abort (mach); } mu_message_get_num_parts (msg, &nparts); if (nparts != 3) /* Mailman moderation requests have three parts */ { mu_sieve_error (mach, _("expected 3 parts, but found %lu"), (unsigned long) nparts); mu_sieve_abort (mach); } if ((rc = moderator_message_get_part (mach, msg, 2, &orig))) mu_sieve_abort (mach); rc = moderator_filter_message (mach, tags, orig, &discard); mu_message_unref (orig); if (rc) mu_sieve_abort (mach); if (discard && !mu_sieve_is_dry_run (mach)) { mu_message_t request; char *from = NULL; mu_sieve_value_t *arg; if ((rc = moderator_message_get_part (mach, msg, 3, &request))) { mu_sieve_error (mach, _("cannot get message part #3: %s"), mu_strerror (rc)); mu_sieve_abort (mach); } if (mu_sieve_tag_lookup (tags, "address", &arg)) from = arg->v.string; if (moderator_discard_message (mach, request, from)) discard = 0; else { if (!mu_sieve_tag_lookup (tags, "keep", NULL)) { mu_attribute_t attr = 0; if (mu_message_get_attribute (msg, &attr) == 0) mu_attribute_set_deleted (attr); } else discard = 0; } mu_message_unref (request); } mu_sieve_log_action (mach, "MODERATOR", discard ? _("discarding message") : _("keeping message")); return 0; }
/* 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; }
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; }
/* Generate and send the reply message */ static int vacation_reply (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg, char *text, char *to, char *from) { mu_mime_t mime = NULL; mu_message_t newmsg; mu_header_t newhdr; mu_address_t to_addr = NULL, from_addr = NULL; char *value; mu_mailer_t mailer; int rc; if (mu_sieve_tag_lookup (tags, "file", NULL)) { mu_stream_t instr; rc = mu_mapfile_stream_create (&instr, text, MU_STREAM_READ); if (rc) { mu_sieve_error (mach, _("%lu: cannot open message file %s: %s"), (unsigned long) mu_sieve_get_message_num (mach), text, mu_strerror (rc)); return -1; } rc = mu_stream_to_message (instr, &newmsg); mu_stream_unref (instr); if (rc) { mu_sieve_error (mach, _("%lu: cannot read message from file %s: %s"), (unsigned long) mu_sieve_get_message_num (mach), text, mu_strerror (rc)); return -1; } } else { if (build_mime (mach, tags, &mime, msg, text)) return -1; mu_mime_get_message (mime, &newmsg); mu_message_unref (newmsg); mu_message_get_header (newmsg, &newhdr); } rc = mu_address_create (&to_addr, to); if (rc) { mu_sieve_error (mach, _("%lu: cannot create recipient address <%s>: %s"), (unsigned long) mu_sieve_get_message_num (mach), from, mu_strerror (rc)); } else { mu_header_set_value (newhdr, MU_HEADER_TO, to, 0); vacation_subject (mach, tags, msg, newhdr); if (from) { if (mu_address_create (&from_addr, from)) from_addr = NULL; } else { from_addr = NULL; } if (mu_rfc2822_in_reply_to (msg, &value) == 0) { mu_header_set_value (newhdr, MU_HEADER_IN_REPLY_TO, value, 1); free (value); } if (mu_rfc2822_references (msg, &value) == 0) { mu_header_set_value (newhdr, MU_HEADER_REFERENCES, value, 1); free (value); } mailer = mu_sieve_get_mailer (mach); if (mailer) { rc = mu_mailer_send_message (mailer, newmsg, from_addr, to_addr); } else rc = MU_ERR_FAILURE; } mu_address_destroy (&to_addr); mu_address_destroy (&from_addr); mu_mime_destroy (&mime); return rc; }
static void vacation_subject (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg, mu_header_t newhdr) { mu_sieve_value_t *arg; char *value; char *subject; int subject_allocated = 0; mu_header_t hdr; if (mu_sieve_tag_lookup (tags, "subject", &arg)) subject = arg->v.string; else if (mu_message_get_header (msg, &hdr) == 0 && mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT, &value) == 0) { char *p; int rc = mu_rfc2047_decode (MU_SIEVE_CHARSET, value, &p); subject_allocated = 1; if (rc) { subject = value; value = NULL; } else { subject = p; } if (mu_sieve_tag_lookup (tags, "reply_regex", &arg)) { char *err = NULL; rc = mu_unre_set_regex (arg->v.string, 0, &err); if (rc) { mu_sieve_error (mach, _("%lu: cannot compile reply prefix regexp: %s: %s"), (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc), err ? err : ""); } } if (mu_unre_subject (subject, NULL)) re_subject (mach, tags, &subject); free (value); } else subject = "Re: Your mail"; if (mu_rfc2047_encode (MU_SIEVE_CHARSET, "quoted-printable", subject, &value)) mu_header_set_value (newhdr, MU_HEADER_SUBJECT, subject, 0); else { mu_header_set_value (newhdr, MU_HEADER_SUBJECT, value, 0); free (value); } if (subject_allocated) free (subject); }
/* Build a mime response message from original message MSG. TEXT is the message text. */ static int build_mime (mu_sieve_machine_t mach, mu_list_t tags, mu_mime_t *pmime, mu_message_t msg, const char *text) { mu_mime_t mime = NULL; mu_message_t newmsg; mu_stream_t stream, input; mu_header_t hdr; mu_body_t body; const char *header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n" "Content-Transfer-Encoding: 8bit\n\n"; int rc; mu_mime_create (&mime, NULL, 0); mu_message_create (&newmsg, NULL); mu_message_get_body (newmsg, &body); if ((rc = mu_static_memory_stream_create (&input, text, strlen (text)))) { mu_sieve_error (mach, _("cannot create temporary stream: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); return 1; } if (mu_sieve_tag_lookup (tags, "mime", NULL)) { mu_stream_t fstr; rc = mu_filter_create (&fstr, input, "base64", MU_FILTER_ENCODE, MU_STREAM_READ); mu_stream_unref (input); if (rc == 0) { header = "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n" "Content-Transfer-Encoding: base64\n\n"; input = fstr; } } rc = mu_body_get_streamref (body, &stream); if (rc) { mu_sieve_error (mach, _("cannot get input body stream: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); mu_stream_destroy (&input); return 1; } rc = mu_stream_copy (stream, input, 0, NULL); if (rc) { mu_sieve_error (mach, _("stream copy failed: %s"), mu_strerror (rc)); mu_mime_destroy (&mime); mu_message_destroy (&newmsg, NULL); mu_stream_destroy (&input); mu_stream_destroy (&stream); return 1; } mu_stream_destroy (&input); mu_header_create (&hdr, header, strlen (header)); mu_message_set_header (newmsg, hdr, NULL); mu_mime_add_part (mime, newmsg); mu_message_unref (newmsg); *pmime = mime; return 0; }
/* Check and update the vacation database. Return 0 if the mail should be answered, 0 if it should not, and throw exception if an error occurs. */ static int check_db (mu_sieve_machine_t mach, mu_list_t tags, char *from) { mu_property_t prop; char *file; mu_sieve_value_t *arg; unsigned int days; int rc; mu_stream_t str; mu_locker_t locker; if (mu_sieve_tag_lookup (tags, "days", &arg)) { days = arg->v.number; if (days > DAYS_MAX) days = DAYS_MAX; } else days = DAYS_DEFAULT; file = mu_tilde_expansion ("~/.vacation", MU_HIERARCHY_DELIMITER, NULL); if (!file) { mu_sieve_error (mach, _("%lu: cannot build db file name"), (unsigned long) mu_sieve_get_message_num (mach)); mu_sieve_abort (mach); } rc = mu_locker_create (&locker, file, 0); if (rc) { mu_sieve_error (mach, _("%lu: cannot lock %s: %s"), (unsigned long) mu_sieve_get_message_num (mach), file, mu_strerror (rc)); free (file); mu_sieve_abort (mach); } rc = mu_file_stream_create (&str, file, MU_STREAM_RDWR|MU_STREAM_CREAT); if (rc) { mu_sieve_error (mach, "%lu: mu_file_stream_create(%s): %s", (unsigned long) mu_sieve_get_message_num (mach), file, mu_strerror (rc)); mu_locker_destroy (&locker); free (file); mu_sieve_abort (mach); } free (file); rc = mu_property_create_init (&prop, mu_assoc_property_init, str); if (rc) { mu_sieve_error (mach, "%lu: mu_property_create_init: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); mu_locker_destroy (&locker); mu_sieve_abort (mach); } rc = mu_locker_lock (locker); if (rc) { mu_sieve_error (mach, "%lu: cannot lock vacation database: %s", (unsigned long) mu_sieve_get_message_num (mach), mu_strerror (rc)); mu_property_destroy (&prop); mu_sieve_abort (mach); } rc = test_and_update_prop (prop, from, time (NULL), days, mach); mu_property_destroy (&prop); mu_locker_unlock (locker); mu_locker_destroy (&locker); if (rc == -1) mu_sieve_abort (mach); return rc; }