/* 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 */
}