/* wydawca - automatic release submission daemon Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff Wydawca is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Wydawca 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 General Public License for more details. You should have received a copy of the GNU General Public License along with wydawca. If not, see . */ #include "wydawca.h" #include #include int mailer_opened; mu_mailer_t mailer; mu_address_t admin_address; mu_address_t from_address; unsigned long mail_admin_mask; unsigned long owner_notification_flags; char *user_message_template[MAX_EVENT]; char *admin_stat_message; void mail_init () { if (!mailer) { int rc; if ((rc = mu_mailer_create (&mailer, NULL))) { const char *url = NULL; mu_mailer_get_url_default (&url); logmsg (LOG_ERR, _("cannot create default mailer `%s': %s"), url, mu_strerror (rc)); } } } void mail_send_message (mu_address_t rcpt, const char *text) { int rc; mu_message_t msg; mu_stream_t stream = NULL; mu_header_t hdr; int mailer_flags = 0; static char *x_mailer = "wydawca (" PACKAGE_STRING ")"; size_t size; char *buf; mu_message_create (&msg, NULL); mu_message_get_stream (msg, &stream); mu_stream_write (stream, text, strlen (text), 0, NULL); mu_message_get_header (msg, &hdr); mu_header_append (hdr, "X-Mailer", x_mailer); mu_address_to_string (rcpt, NULL, 0, &size); buf = xmalloc (size + 1); mu_address_to_string (rcpt, buf, size + 1, NULL); mu_header_set_value (hdr, "To", buf, 1); free (buf); if (debug_level > 1) { mu_debug_t debug; mu_mailer_get_debug (mailer, &debug); mu_debug_set_level (debug, MU_DEBUG_TRACE | MU_DEBUG_PROT); if (debug_level > 2) mailer_flags = MAILER_FLAG_DEBUG_DATA; } if (!mailer_opened) { if ((rc = mu_mailer_open (mailer, mailer_flags))) { mu_url_t url = NULL; mu_mailer_get_url (mailer, &url); logmsg (LOG_CRIT, _("opening mailer `%s' failed: %s"), url ? mu_url_to_string (url) : "(unknown URL)", mu_strerror (rc)); return; } mailer_opened = 1; } rc = mu_mailer_send_message (mailer, msg, from_address, rcpt); if (rc) logmsg (LOG_CRIT, _("cannot send message: %s"), mu_strerror (rc)); mu_message_destroy (&msg, mu_message_get_owner (msg)); } void mail_finish () { if (mailer_opened) { mu_mailer_close (mailer); mailer_opened = 0; } } struct message_template { char *name; char *text; /* int mime; for future use */ }; static Hash_table *tmpl_table; /* Calculate the hash of a string. */ static size_t tmpl_hasher (void const *data, unsigned n_buckets) { struct message_template const *tmpl = data; return hash_string (tmpl->name, n_buckets); } /* Compare two strings for equality. */ static bool tmpl_compare (void const *data1, void const *data2) { struct message_template const *tmpl1 = data1; struct message_template const *tmpl2 = data2; return strcmp (tmpl1->name, tmpl2->name) == 0; } static void tmpl_free (void *data) { free (data); } struct message_template * alloc_message_template (const char *name, const char *text) { struct message_template *tmpl = xmalloc (sizeof (tmpl[0]) + strlen (name) + 1 + strlen (text) + 1); char *p = (char*) (tmpl + 1); tmpl->name = p; strcpy (tmpl->name, name); p += strlen (p) + 1; tmpl->text = p; strcpy (tmpl->text, text); return tmpl; } /* Register a template. FIXME: Issue a warning if it is already registered. */ void register_message_template (const char *name, const char *text) { struct message_template *tmpl, *s; s = alloc_message_template (name, text); if (!((tmpl_table || (tmpl_table = hash_initialize (0, 0, tmpl_hasher, tmpl_compare, tmpl_free))) && (tmpl = hash_insert (tmpl_table, s)))) xalloc_die (); if (s != tmpl) tmpl_free (s); } const char * resolve_message_template (const char *name) { if (name[0] == '@') { if (name[1] == '@') return name + 1; else if (!tmpl_table) return NULL; else { struct message_template *p, tmpl; tmpl.name = (char*) name + 1; p = hash_lookup (tmpl_table, &tmpl); return p ? p->text : NULL; } } return name; } void mail_stats () { struct metadef *exp; time_t t; const char *tmpl; char *text; size_t tc; if (!admin_stat_message || !stat_mask_p (mail_admin_mask) || !mailer) return; if (!admin_address) { logmsg (LOG_ERR, _("cannot mail statistics: admin-address not defined")); return; } if (debug_level) { size_t size; char *buf; mu_address_to_string (admin_address, NULL, 0, &size); buf = xmalloc (size + 1); mu_address_to_string (admin_address, buf, size + 1, NULL); logmsg (LOG_DEBUG, _("sending stats to %s"), buf); free (buf); } if (dry_run_mode) return; tc = timer_get_count () * 3; exp = make_stat_expansion (tc + 1); time (&t); exp[0].kw = "date"; exp[0].value = exp[0].storage = xstrdup (ctime (&t)); exp[0].value [strlen (exp[0].value) - 1] = 0; timer_fill_meta (exp + 1, tc); tmpl = resolve_message_template (admin_stat_message); if (!tmpl) { logmsg (LOG_ERR, _("undefined message reference: %s"), admin_stat_message); return; } text = meta_expand_string (tmpl, exp, NULL); mail_send_message (admin_address, text); free (text); meta_free (exp); timer_free_meta (exp + 1, tc); free (exp); } mu_address_t get_recipient (struct access_method *method, struct file_triplet *trp, char **errp) { unsigned nrows, ncols, i; struct metadef def[5]; mu_address_t rcpt = NULL; char *text; int rc; void *md; if (method->type == method_none) { *errp = N_("access method is not configured"); return NULL; } md = method_open (method); if (!md) { *errp = N_("failed to open access method"); return NULL; } make_default_meta (def, trp->user, trp->project); meta_escape (method, md, def); text = meta_expand_string (method->query, def, NULL); meta_free (def); rc = method_run (method, md, text); free (text); if (rc) { *errp = N_("cannot obtain recipient emails"); method_close (method, md); return NULL; } nrows = method_num_rows (method); ncols = method_num_cols (method); if (nrows == 0) { *errp = N_("cannot obtain recipient emails"); return NULL; } for (i = 0; i < nrows; i++) { mu_address_t addr; const char *str = method_result (method, md, i, 0); if (mu_address_create (&addr, str)) continue; if (ncols > 0) { str = method_result (method, md, i, 1); if (str) mu_address_set_personal (addr, 1, str); } mu_address_union (&rcpt, addr); mu_address_destroy (&addr); } method_close (method, md); return rcpt; } void do_notify (struct file_triplet *trp, enum notification_event ev, struct notification *ntf) { mu_address_t rcpt = NULL; char *errp; switch (ntf->tgt) { case notify_admin: rcpt = admin_address; break; case notify_user: rcpt = get_recipient (trp->spool->access_method[user_data_method], trp, &errp); break; case notify_owner: rcpt = get_recipient (trp->spool->access_method[project_owner_method], trp, &errp); } if (!rcpt) { logmsg (LOG_ERR, _("not notifying %s (project %s) about %s: %s"), notification_target_str (ntf->tgt), trp->project, notification_event_str (ev), gettext (errp)); return; } if (debug_level) { size_t size; char *buf; mu_address_to_string (rcpt, NULL, 0, &size); buf = xmalloc (size + 1); mu_address_to_string (rcpt, buf, size + 1, NULL); logmsg (LOG_DEBUG, _("notifying %s (project %s) about %s"), buf, trp->project, notification_event_str (ev)); free (buf); } if (!dry_run_mode) { const char *msg = resolve_message_template (ntf->msg); if (!msg) logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg); else { char *text = triplet_expand_param (msg, trp); mail_send_message (rcpt, text); free (text); } } mu_address_destroy (&rcpt); } void notify (struct notification *notification_list, struct file_triplet *trp, enum notification_event ev) { struct notification *p; fill_project_name (trp); for (p = notification_list; p; p = p->next) if (p->ev == ev) do_notify (trp, ev, p); /* FIXME */ }