diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-03-10 22:39:23 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-03-10 22:39:23 +0200 |
commit | 87602f5492b842f734dffe22f4e2f85dbc6ce713 (patch) | |
tree | 3e7e04bca15e8af5c981a78619e2d95f03b45c67 /src/mail.c | |
parent | 826bb71c57d903f760c89406f93d19fe0c131de0 (diff) | |
download | wydawca-87602f5492b842f734dffe22f4e2f85dbc6ce713.tar.gz wydawca-87602f5492b842f734dffe22f4e2f85dbc6ce713.tar.bz2 |
Replace mail notification with module event notification framework.
The new framework is to be general-purpose; the mail notification
is implemented as a module.
Althoug the program is operational, the change is not completed yet.
In particular, the docs are out of date and the tests will mostly
fail.
* .gitignore: Update.
* Makefile.am (SUBDIRS): Add modules.
* configure.ac: Mailutils is now optional (though highly
recommended).
(AC_CONFIG_FILES): Build modules/Makefile and modules/mailutils/Makefile.
* modules/Makefile.am: New file.
* modules/mailutils/Makefile.am: New file.
* modules/mailutils/mod_mailutils.c: New file.
* src/mail.c: Remove.
* src/mail.h: Remove.
* src/event.c: New file.
* src/Makefile.am (wydawca_SOURCES): Update.
(LDADD): Remove MAILUTILS_LIBS.
* src/config.c: Remove mail-related configuration statements.
Add module-related ones instead.
* src/wydawca.h (notification_event) <ev_statistics>: New event.
(notification_target): Remove.
(notification) <tgt,sign_keys,msg>: Remove.
<statmask>: New member.
(register_message_template): Remove.
(notify_stats,notify_flush): New protos.
(notification_target_str): Remove.
(format_fn): Remove.
(module) <next,modinit,open>
<flush,close>: New members.
<notify>: Change signature.
(modules_close, module_set_init)
(module_flush): New protos.
(debug_level): Rename to wy_debug_level. All uses changed.
(wy_version): New extern.
(admin_stat_message,admin_stat_sign_key): Remove.
(default_notification): New global.
(triplet_expand_param,triplet_expand_dictionary_query): The
file_triplet argument is const pointer.
(assert_string_arg): Rename to wy_assert_string_arg.
* src/wydawca.c (debug_level): Rename to wy_debug_level.
(wy_version): New global.
(logstats): Call notify_stats.
(main): Call modules_close.
* src/module.c: Keep modules in a singly-linked list instead
of a symtab.
Provide new functions.
* src/net.c: Update.
* src/dictionary.c: Update.
* src/directive.c: Update.
* src/diskio.c: Update.
* src/exec.c: Update.
* src/gpg.c: Update.
* src/job.c (wydawca_scanner): Call notify_flush.
* src/null.c: Update.
* src/process.c: Update.
* src/sql.c: Update.
* src/tcpwrap.c: Update.
* src/triplet.c: Update.
* src/verify.c: Update.
* src/watcher.c: Update.
Diffstat (limited to 'src/mail.c')
-rw-r--r-- | src/mail.c | 615 |
1 files changed, 0 insertions, 615 deletions
diff --git a/src/mail.c b/src/mail.c deleted file mode 100644 index dd16510..0000000 --- a/src/mail.c +++ /dev/null @@ -1,615 +0,0 @@ -/* wydawca - automatic release submission daemon - Copyright (C) 2007-2013 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 <http://www.gnu.org/licenses/>. */ - -#include "wydawca.h" -#include <mail.h> -#include <gpgme.h> - -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; -char *admin_stat_sign_key; - -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)); - } - } -} - -static ssize_t -mu_stream_data_read_cb(void *handle, void *buffer, size_t size) -{ - mu_stream_t str = handle; - size_t nread; - int rc; - - rc = mu_stream_read(str, buffer, size, &nread); - if (rc) { - logmsg(LOG_ERR, "mu_stream_read: %s", mu_strerror(rc)); - errno = EIO; - return -1; - } - return nread; -} - -static int -check_sign_result(gpgme_sign_result_t result, gpgme_sig_mode_t type) -{ - gpgme_new_signature_t sign; - - if (result->invalid_signers) { - logmsg(LOG_ERR, _("GPGME: invalid signer found: %s"), - result->invalid_signers->fpr); - return 1; - } - - if (!result->signatures) { - logmsg(LOG_ERR, _("GPGME: no signatures created")); - return 1; - } - - for (sign = result->signatures; sign; sign = sign->next) { - if (sign->type != type) { - logmsg(LOG_ERR, - _("GPGME: wrong type of signature created")); - return 1; - } - } - /* FIXME: fingerprint? */ - return 0; -} - -static int -gpg_sign(gpgme_data_t * output, gpgme_data_t input, const char *sign_keys) -{ - gpgme_ctx_t ctx; - gpgme_error_t err = 0; - gpgme_key_t key; - int ret; - - err = gpgme_new(&ctx); - if (err) { - logmsg(LOG_ERR, _("GPGME: cannot create context: %s"), - gpgme_strerror(err)); - return 1; - } - - err = gpgme_op_keylist_start(ctx, sign_keys, 0); - if (!err) { - while ((err = gpgme_op_keylist_next(ctx, &key)) == 0) { - err = gpgme_signers_add(ctx, key); - gpgme_key_release(key); - } - } - - if (err && gpg_err_code(err) != GPG_ERR_EOF) { - logmsg(LOG_ERR, _("GPGME: cannot list keys: %s"), - gpgme_strerror(err)); - gpgme_release(ctx); - return 1; - } - - err = gpgme_data_new(output); - if (err) { - logmsg(LOG_ERR, _("%s: GPGME error: %s"), - "gpgme_data_new", gpgme_strerror(err)); - gpgme_release(ctx); - return 1; - } - - /* FIXME: Passphrase */ - gpgme_set_textmode(ctx, 1); - gpgme_set_armor(ctx, 1); - - err = gpgme_op_sign(ctx, input, *output, GPGME_SIG_MODE_CLEAR); - if (err) { - logmsg(LOG_ERR, _("%s: GPGME error: %s"), - "gpgme_op_sign", gpgme_strerror(err)); - ret = 1; - } else { - ret = check_sign_result(gpgme_op_sign_result(ctx), - GPGME_SIG_MODE_CLEAR); -#if 0 - /* FIXME: */ - if (debug_level > 1) - gpgme_debug_info(ctx); -#endif - } - - gpgme_release(ctx); - return ret; -} - -static int -sign_message(mu_message_t * pmsg, const char *key) -{ - mu_message_t msg = *pmsg; - mu_message_t newmsg; - mu_body_t body; - mu_header_t hdr; - mu_stream_t istr, ostr, bodystr; - int rc; - struct gpgme_data_cbs cbs; - gpgme_data_t input, output; - gpgme_error_t err; - char *buf = NULL; - size_t size = 0; - size_t nread; - - if (debug_level) - logmsg(LOG_DEBUG, _("signing message as %s"), key); - - if (wydawca_gpg_homedir) { - if (debug_level > 1) - logmsg(LOG_DEBUG, - _("setting GNUPG home directory: %s"), - wydawca_gpg_homedir); - setenv("GNUPGHOME", wydawca_gpg_homedir, 1); - } - - if ((rc = mu_message_get_body(msg, &body))) { - logmsg(LOG_ERR, "mu_message_get_body: %s", mu_strerror(rc)); - return 1; - } - - if ((rc = mu_body_get_streamref(body, &bodystr))) { - logmsg(LOG_ERR, "mu_message_get_stream: %s", mu_strerror(rc)); - return 1; - } - - memset(&cbs, 0, sizeof(cbs)); - cbs.read = mu_stream_data_read_cb; - - err = gpgme_data_new_from_cbs(&input, &cbs, &bodystr); - if (err) { - logmsg(LOG_ERR, "gpgme_data_new_from_cbs: %s", - gpgme_strerror(rc)); - return 1; - } - - rc = gpg_sign(&output, input, key); - mu_stream_unref(bodystr); - if (rc) - return 1; - - if (gpgme_data_seek(output, 0, SEEK_SET) == -1) { - logmsg(LOG_ERR, "gpgme_data_seek: %s", strerror(errno)); - return 1; - } - - mu_message_create(&newmsg, NULL); - mu_message_get_streamref(newmsg, &ostr); - - /* Copy headers */ - mu_message_get_header(msg, &hdr); - mu_header_get_streamref(hdr, &istr); - - rc = mu_stream_copy(ostr, istr, 0, NULL); - if (rc) - logmsg(LOG_ERR, "mu_stream_copy: %s", mu_strerror(rc)); - else { - while ((nread = gpgme_data_read(output, buf, size)) > 0) { - rc = mu_stream_write(ostr, buf, nread, NULL); - if (rc) { - logmsg(LOG_ERR, "mu_stream_write: %s", - mu_strerror(rc)); - break; - } - } - - if (rc == 0) { - mu_message_destroy(&msg, mu_message_get_owner(msg)); - *pmsg = newmsg; - } - } - mu_stream_unref(istr); - mu_stream_unref(ostr); - - if (rc) - mu_message_destroy(&newmsg, mu_message_get_owner(msg)); - gpgme_data_release(output); - free(buf); - - return rc; -} - -void -mail_send_message(mu_address_t rcpt, const char *text, const char *signer_key) -{ - int rc; - mu_message_t msg; - mu_stream_t stream = NULL; - mu_header_t hdr; - static char *x_mailer = "wydawca (" PACKAGE_STRING ")"; - const char *sval; - - mu_static_memory_stream_create(&stream, text, strlen(text)); - rc = mu_stream_to_message(stream, &msg); - mu_stream_unref(stream); - if (rc) { - logmsg(LOG_CRIT, _("cannot create message: %s"), - mu_strerror(rc)); - return; - } - mu_message_get_header(msg, &hdr); - mu_header_append(hdr, "X-Mailer", x_mailer); - - if (rcpt) { - const char *s; - - if (mu_address_sget_printable(rcpt, &s) == 0) - mu_header_set_value(hdr, "To", s, 1); - - if (from_address && mu_header_sget_value(hdr, "From", &sval)) { - if (mu_address_sget_printable(from_address, &s) == 0) - mu_header_set_value(hdr, "From", s, 1); - } - } - - if (debug_level > 1) { - mu_debug_level_t level; - - mu_debug_get_category_level(MU_DEBCAT_MAILER, &level); - level |= MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE0) | - MU_DEBUG_LEVEL_MASK(MU_DEBUG_PROT); - if (debug_level > 2) - level |= MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE7); - mu_debug_set_category_level(MU_DEBCAT_MAILER, level); - } - - if (!mailer_opened) { - if ((rc = mu_mailer_open(mailer, 0))) { - 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; - } - - if (signer_key) - sign_message(&msg, signer_key); - - if (!dry_run_mode) { - 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 struct grecs_symtab *tmpl_table; - -/* Register a template. */ -void -register_message_template(const char *name, const char *text) -{ - struct message_template key, *tmpl; - int install = 1; - - key.name = (char *)text; - - if (!tmpl_table) { - tmpl_table = grecs_symtab_create_default(sizeof(key)); - if (!tmpl_table) - grecs_alloc_die(); - } - - tmpl = grecs_symtab_lookup_or_install(tmpl_table, &key, &install); - if (!tmpl) - grecs_alloc_die(); - if (!install) - grecs_warning(NULL, 0, "template %s already registered", text); -} - -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, key; - - key.name = (char *)name + 1; - p = grecs_symtab_lookup_or_install(tmpl_table, &key, - NULL); - 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) { - const char *s; - - if (mu_address_sget_printable(admin_address, &s) == 0) - logmsg(LOG_DEBUG, _("sending stats to %s"), s); - } - - tc = timer_get_count() * 3; - exp = make_stat_expansion(tc + 1); - time(&t); - exp[0].kw = "date"; - exp[0].value = exp[0].storage = grecs_strdup(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, NULL, NULL); - - mail_send_message(admin_address, text, admin_stat_sign_key); - - free(text); - meta_free(exp); - timer_free_meta(exp + 1, tc); - free(exp); -} - -mu_address_t -get_uploader_email(struct uploader_info * info, struct file_triplet * trp, - const char **errp) -{ - mu_address_t addr; - mu_address_t rcpt = NULL; - int rc; - - if (!info) - return NULL; - rc = mu_address_create(&addr, info->email); - if (rc) { - *errp = mu_strerror(rc); - return NULL; - } - - mu_address_set_personal(addr, 1, info->realname); - - /* This hack makes sure that mu_address_to_string (rcpt) will - return full email address (with personal part) */ - mu_address_union(&rcpt, addr); - mu_address_destroy(&addr); - - return rcpt; -} - -mu_address_t -get_recipient(struct dictionary * dict, struct file_triplet * trp, - const char **errp) -{ - unsigned nrows, ncols, i; - mu_address_t rcpt = NULL; - char *text; - int rc; - void *md; - - if (dict->type == dictionary_none) { - *errp = N_("dictionary is not configured"); - return NULL; - } - - md = dictionary_open(dict); - if (!md) { - *errp = N_("failed to open dictionary"); - return NULL; - } - - text = triplet_expand_dictionary_query(dict, md, trp); - - rc = dictionary_lookup(dict, md, text); - free(text); - if (rc) { - *errp = N_("cannot obtain recipient emails"); - dictionary_close(dict, md); - return NULL; - } - - nrows = dictionary_num_rows(dict); - ncols = dictionary_num_cols(dict); - - if (nrows == 0) { - *errp = N_("cannot obtain recipient emails"); - return NULL; - } - - for (i = 0; i < nrows; i++) { - mu_address_t addr; - const char *str = dictionary_result(dict, md, i, 0); - if (mu_address_create(&addr, str)) - continue; - if (ncols > 0) { - str = dictionary_result(dict, md, i, 1); - if (str) - mu_address_set_personal(addr, 1, str); - } - mu_address_union(&rcpt, addr); - mu_address_destroy(&addr); - } - dictionary_close(dict, md); - - return rcpt; -} - -void -do_notify(struct file_triplet *trp, enum notification_event ev, - struct notification *ntf) -{ - mu_address_t rcpt = NULL; - const char *errp; - const char *msg; - - if (ntf->modname) { - module_notify(ntf->modname, ntf->modcfg, ev, trp); - return; - } - - switch (ntf->tgt) { - case notify_read: - rcpt = NULL; - break; - - case notify_admin: - rcpt = mu_address_dup(admin_address); - break; - - case notify_user: - rcpt = get_uploader_email(trp->uploader, trp, &errp); - break; - - case notify_owner: - rcpt = get_recipient(trp->spool->dictionary[project_owner_dict], - trp, &errp); - } - - if (!rcpt && ntf->tgt != notify_read) { - 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) { - if (rcpt) { - const char *s; - - if (mu_address_sget_printable(rcpt, &s) == 0) - logmsg(LOG_DEBUG, - _("notifying %s (project %s) about %s"), - s, trp->project, - notification_event_str(ev)); - } else - logmsg(LOG_DEBUG, - _("notifying message recipients (project %s) " - "about %s"), - trp->project, notification_event_str(ev)); - } - - 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, ntf->sign_keys); - free(text); - } - - mu_address_destroy(&rcpt); -} - -void -notify(struct notification *notification_list, - struct file_triplet *trp, enum notification_event ev) -{ - struct notification *p; - - for (p = notification_list; p; p = p->next) - if (p->ev == ev) - do_notify(trp, ev, p); -} - -const char * -expand_email_admin(struct metadef *def, void *data) -{ - if (mu_address_aget_printable(admin_address, &def->storage) == 0) - def->value = def->storage; - else - def->value = ""; - return def->value; -} - -const char * -expand_email_owner(struct metadef *def, void *data) -{ - struct file_triplet *trp = data; - mu_address_t addr; - const char *errp; - - addr = get_recipient(trp->spool->dictionary[project_owner_dict], - trp, &errp); - if (!addr) { - logmsg(LOG_ERR, _("cannot get email of the %s's owner: %s"), - trp->project, gettext(errp)); - def->value = ""; - } else { - if (mu_address_aget_printable(addr, &def->storage) == 0) - def->value = def->storage; - else - def->value = ""; - mu_address_destroy(&addr); - } - return def->value; -} |