aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-03-10 22:39:23 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2013-03-10 22:39:23 +0200
commit87602f5492b842f734dffe22f4e2f85dbc6ce713 (patch)
tree3e7e04bca15e8af5c981a78619e2d95f03b45c67
parent826bb71c57d903f760c89406f93d19fe0c131de0 (diff)
downloadwydawca-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.
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac7
-rw-r--r--modules/Makefile.am4
-rw-r--r--modules/mailutils/Makefile.am8
-rw-r--r--modules/mailutils/mod_mailutils.c (renamed from src/mail.c)647
-rw-r--r--src/Makefile.am5
-rw-r--r--src/config.c271
-rw-r--r--src/dictionary.c6
-rw-r--r--src/directive.c14
-rw-r--r--src/diskio.c16
-rw-r--r--src/event.c28
-rw-r--r--src/exec.c2
-rw-r--r--src/gpg.c10
-rw-r--r--src/job.c17
-rw-r--r--src/mail.h27
-rw-r--r--src/module.c141
-rw-r--r--src/net.c4
-rw-r--r--src/null.c8
-rw-r--r--src/process.c8
-rw-r--r--src/sql.c2
-rw-r--r--src/tcpwrap.c2
-rw-r--r--src/triplet.c28
-rw-r--r--src/verify.c6
-rw-r--r--src/watcher.c18
-rw-r--r--src/wydawca.c21
-rw-r--r--src/wydawca.h46
27 files changed, 771 insertions, 580 deletions
diff --git a/.gitignore b/.gitignore
index 812393e..239baf7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,12 @@
*.a
+*.la
+*.lo
*.o
*.tar.*
*~
.bootstrap
.deps
+.libs
.emacs.desktop
.emacsrc
ABOUT-NLS
diff --git a/Makefile.am b/Makefile.am
index a226f0f..3ae6fc6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,7 +16,7 @@
ACLOCAL_AMFLAGS = -I m4 -I grecs/am -I imprimatur
-SUBDIRS=grecs libltdl src imprimatur doc etc tests
+SUBDIRS=grecs libltdl src modules imprimatur doc etc tests
# We never remove files from the configuration directory
distuninstallcheck_listfiles = \
diff --git a/configure.ac b/configure.ac
index a439400..e165dea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,8 +68,9 @@ AC_CHECK_FUNCS([fchdir memset strchr strdup strerror strrchr setegid setregid\
# Mailutils
# **********************
-AM_GNU_MAILUTILS(2.0, [mailer], [:])
-
+AM_GNU_MAILUTILS(2.0, [mailer], [status_mailutils=yes], [status_mailutils=no])
+AM_CONDITIONAL([COND_MAILUTILS],[test $status_mailutils = yes])
+
# **********************
# MySQL
# **********************
@@ -171,6 +172,8 @@ fi
AC_CONFIG_FILES([Makefile
doc/Makefile
src/Makefile
+ modules/Makefile
+ modules/mailutils/Makefile
etc/Makefile])
AC_OUTPUT
diff --git a/modules/Makefile.am b/modules/Makefile.am
new file mode 100644
index 0000000..d430de8
--- /dev/null
+++ b/modules/Makefile.am
@@ -0,0 +1,4 @@
+if COND_MAILUTILS
+ MAILUTILS = mailutils
+endif
+SUBDIRS = $(MAILUTILS) \ No newline at end of file
diff --git a/modules/mailutils/Makefile.am b/modules/mailutils/Makefile.am
new file mode 100644
index 0000000..7582f81
--- /dev/null
+++ b/modules/mailutils/Makefile.am
@@ -0,0 +1,8 @@
+moddir=@WYDAWCA_MODDIR@
+
+mod_LTLIBRARIES=mod_mailutils.la
+
+mod_mailutils_la_SOURCES = mod_mailutils.c
+mod_mailutils_la_LIBADD = @MAILUTILS_LIBS@
+AM_LDFLAGS = -module -avoid-version -no-undefined
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir)/src @GRECS_INCLUDES@ @MAILUTILS_INCLUDES@
diff --git a/src/mail.c b/modules/mailutils/mod_mailutils.c
index dd16510..96accc7 100644
--- a/src/mail.c
+++ b/modules/mailutils/mod_mailutils.c
@@ -14,36 +14,114 @@
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 <config.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <gpgme.h>
+#if 0
+/* FIXME */
+#include <wydawca/types.h>
+#include <wydawca/grecs.h>
+#else
+#include "grecs.h"
+#include "wydawca.h"
+#endif
+#include <mailutils/mailutils.h>
-int mailer_opened;
-mu_mailer_t mailer;
-mu_address_t admin_address;
-mu_address_t from_address;
+static int mailer_opened;
+static mu_mailer_t mailer;
+static mu_address_t admin_address;
+static 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;
+static char *admin_stat_message;
+static char *admin_stat_sign_key;
+
+struct message_template {
+ char *name;
+ char *text;
+ /* int mime; for future use */
+};
+
+static struct grecs_symtab *tmpl_table;
+/* Register a template. */
void
-mail_init()
+register_message_template(const char *name, const char *text)
{
- 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));
+ 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;
}
+
+static int
+cb_define_message(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ const char *ident;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
+ if (cmd != grecs_callback_set_value) {
+ grecs_error(locus, 0, _("Unexpected block statement"));
+ return 1;
+ }
+ if (!value || value->type != GRECS_TYPE_ARRAY || value->v.arg.c != 2) {
+ grecs_error(locus, 0, _("expected two arguments"));
+ return 1;
+ }
+
+ if (value->v.arg.v[0]->type != GRECS_TYPE_STRING) {
+ grecs_error(&value->v.arg.v[0]->locus, 0,
+ _("first argument not a string"));
+ return 1;
+ }
+ ident = value->v.arg.v[0]->v.string;
+
+ if (value->v.arg.v[1]->type != GRECS_TYPE_STRING) {
+ grecs_error(&value->v.arg.v[1]->locus, 0,
+ _("second argument not a string"));
+ return 1;
+ }
+ register_message_template(ident, value->v.arg.v[1]->v.string);
+ return 0;
+}
+
static ssize_t
mu_stream_data_read_cb(void *handle, void *buffer, size_t size)
{
@@ -139,7 +217,7 @@ gpg_sign(gpgme_data_t * output, gpgme_data_t input, const char *sign_keys)
GPGME_SIG_MODE_CLEAR);
#if 0
/* FIXME: */
- if (debug_level > 1)
+ if (wy_debug_level > 1)
gpgme_debug_info(ctx);
#endif
}
@@ -149,7 +227,7 @@ gpg_sign(gpgme_data_t * output, gpgme_data_t input, const char *sign_keys)
}
static int
-sign_message(mu_message_t * pmsg, const char *key)
+sign_message(mu_message_t *pmsg, const char *key)
{
mu_message_t msg = *pmsg;
mu_message_t newmsg;
@@ -164,11 +242,11 @@ sign_message(mu_message_t * pmsg, const char *key)
size_t size = 0;
size_t nread;
- if (debug_level)
+ if (wy_debug_level)
logmsg(LOG_DEBUG, _("signing message as %s"), key);
if (wydawca_gpg_homedir) {
- if (debug_level > 1)
+ if (wy_debug_level > 1)
logmsg(LOG_DEBUG,
_("setting GNUPG home directory: %s"),
wydawca_gpg_homedir);
@@ -241,14 +319,13 @@ sign_message(mu_message_t * pmsg, const char *key)
return rc;
}
-void
+static 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));
@@ -260,7 +337,7 @@ mail_send_message(mu_address_t rcpt, const char *text, const char *signer_key)
return;
}
mu_message_get_header(msg, &hdr);
- mu_header_append(hdr, "X-Mailer", x_mailer);
+ mu_header_append(hdr, "X-Mailer", wy_version);
if (rcpt) {
const char *s;
@@ -274,13 +351,13 @@ mail_send_message(mu_address_t rcpt, const char *text, const char *signer_key)
}
}
- if (debug_level > 1) {
+ if (wy_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)
+ if (wy_debug_level > 2)
level |= MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE7);
mu_debug_set_category_level(MU_DEBCAT_MAILER, level);
}
@@ -309,123 +386,360 @@ mail_send_message(mu_address_t rcpt, const char *text, const char *signer_key)
mu_message_destroy(&msg, mu_message_get_owner(msg));
}
+
+static int
+cb_mailer(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ int rc;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
+ if (wy_assert_string_arg(locus, cmd, value))
+ return 1;
+ rc = mu_mailer_create(&mailer, value->v.string);
+ if (rc)
+ grecs_error(&value->locus, 0,
+ _("cannot create mailer `%s': %s"),
+ value->v.string,
+ mu_strerror(rc));
+ return rc;
+}
-void
-mail_finish()
+static int
+cb_email_address(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
- if (mailer_opened) {
- mu_mailer_close(mailer);
- mailer_opened = 0;
+ int rc = 1;
+ mu_address_t addr = NULL;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+ struct grecs_list_entry *ep;
+
+ switch (value->type) {
+ case GRECS_TYPE_STRING:
+ rc = mu_address_create(&addr, value->v.string);
+ if (rc) {
+ grecs_error(&value->locus, 0,
+ _("%s: invalid email address: %s"),
+ value->v.string, mu_strerror(rc));
+ return rc;
+ }
+ break;
+
+ case GRECS_TYPE_LIST:
+ for (ep = value->v.list->head; ep; ep = ep->next) {
+ const grecs_value_t *vp = ep->data;
+ mu_address_t a;
+ if (wy_assert_string_arg(locus, cmd, vp))
+ return 1;
+
+ rc = mu_address_create(&a, vp->v.string);
+ if (rc == 0)
+ rc = mu_address_union(&addr, a);
+ else {
+ grecs_error(&value->locus, 0,
+ _("%s: invalid email address: %s"),
+ vp->v.string,
+ mu_strerror(rc));
+ }
+ mu_address_destroy(&a);
+ if (rc)
+ break;
+ }
+ break;
+
+ case GRECS_TYPE_ARRAY:
+ grecs_error(locus, 0, _("too many arguments"));
+ return 1;
}
+
+ *(mu_address_t *) varptr = addr;
+ return rc;
}
-
-struct message_template {
- char *name;
- char *text;
- /* int mime; for future use */
-};
-static struct grecs_symtab *tmpl_table;
+static struct mu_kwd stat_tab[] = {
+ { "errors", STAT_ERRORS },
+ { "warnings", STAT_WARNINGS },
+ { "bad-signatures", STAT_BAD_SIGNATURE },
+ { "access-violations", STAT_ACCESS_VIOLATIONS },
+ { "complete-triplets", STAT_COMPLETE_TRIPLETS },
+ { "incomplete-triplets", STAT_INCOMPLETE_TRIPLETS },
+ { "bad-triplets", STAT_BAD_TRIPLETS },
+ { "expired-triplets", STAT_EXPIRED_TRIPLETS },
+ { "triplet-success", STAT_TRIPLET_SUCCESS },
+ { "uploads", STAT_UPLOADS },
+ { "archives", STAT_ARCHIVES },
+ { "symlinks", STAT_SYMLINKS },
+ { "rmsymlinks", STAT_RMSYMLINKS },
+ { NULL },
+};
-/* Register a template. */
-void
-register_message_template(const char *name, const char *text)
+static int
+parse_single_statmask(grecs_locus_t *locus, const grecs_value_t *val,
+ unsigned long *pmask, int *invert)
{
- struct message_template key, *tmpl;
- int install = 1;
+ const char *arg;
+ int x;
- key.name = (char *)text;
+ if (val->type != GRECS_TYPE_STRING) {
+ grecs_error(&val->locus, 0,
+ _("expected scalar value but found list"));
+ return 1;
+ }
- if (!tmpl_table) {
- tmpl_table = grecs_symtab_create_default(sizeof(key));
- if (!tmpl_table)
- grecs_alloc_die();
+ arg = val->v.string;
+
+ if (strcmp(arg, "all") == 0) {
+ *pmask = STAT_MASK_ALL;
+ *invert = 1;
+ return 0;
+ } else if (strcmp(arg, "none") == 0) {
+ *pmask = STAT_MASK_NONE;
+ *invert = 0;
+ return 0;
}
- 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);
+ if (mu_kwd_xlat_name(stat_tab, arg, &x)) {
+ grecs_error(&val->locus, 0, _("unknown statistics type: %s"),
+ arg);
+ return 1;
+ }
+ *pmask = STAT_MASK(x);
+ return 0;
}
-const char *
-resolve_message_template(const char *name)
+static int
+parse_statmask(grecs_locus_t *loc, grecs_value_t *val, unsigned long *pmask)
{
- if (name[0] == '@') {
- if (name[1] == '@')
- return name + 1;
- else if (!tmpl_table)
- return NULL;
- else {
- struct message_template *p, key;
+ int err = 0;
+ int invert = 0;
+ unsigned long mask = 0;
+ int i;
+ struct grecs_list_entry *ep;
+
+ switch (val->type) {
+ case GRECS_TYPE_STRING:
+ err = parse_single_statmask(loc, val, &mask, &invert);
+ break;
- key.name = (char *)name + 1;
- p = grecs_symtab_lookup_or_install(tmpl_table, &key,
- NULL);
- return p ? p->text : NULL;
+ case GRECS_TYPE_ARRAY:
+ for (i = 0; i < val->v.arg.c; i++) {
+ unsigned long x;
+ if (parse_single_statmask(loc, val->v.arg.v[i],
+ &x, &invert))
+ err = 1;
+ else if (invert)
+ mask &= ~x;
+ else
+ mask |= x;
}
+ break;
+
+ case GRECS_TYPE_LIST:
+ for (ep = val->v.list->head; ep; ep = ep->next) {
+ const grecs_value_t *vp = ep->data;
+ unsigned long x;
+
+ if (parse_single_statmask(loc, vp, &x, &invert))
+ err = 1;
+ else if (invert)
+ mask &= ~x;
+ else
+ mask |= x;
+ }
+ break;
}
- return name;
+ if (!err)
+ *pmask = mask;
+ return err;
}
-
+
+static int
+cb_statistics(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ return parse_statmask(&node->locus, node->v.value, varptr);
+}
+
+static struct grecs_keyword mail_statistics_kw[] = {
+ { "message", N_("text"),
+ N_("Message text"),
+ grecs_type_string, GRECS_DFLT, &admin_stat_message },
+ { "statistics", N_("items"),
+ N_("Send mail if one or more of these items are set"),
+ grecs_type_string, GRECS_DFLT, &mail_admin_mask, 0, cb_statistics },
+ { "gpg-sign",
+ N_("key"), N_("Sign message with this key"),
+ grecs_type_string, GRECS_DFLT, &admin_stat_sign_key },
+ { NULL }
+};
+
+static struct grecs_keyword mail_kw[] = {
+ { "mailer", N_("url"), N_("Set mailer URL"),
+ grecs_type_string, GRECS_DFLT, &mailer, 0, cb_mailer },
+ { "admin-address", N_("email"), N_("Set admin email address"),
+ grecs_type_string, GRECS_DFLT, &admin_address, 0, cb_email_address },
+ { "from-address", N_("email"), N_("Set sender email address"),
+ grecs_type_string, GRECS_DFLT, &from_address, 0, cb_email_address },
+ { "define-message", N_("ident: string> <text: string"),
+ N_("Define message text"),
+ grecs_type_string, GRECS_DFLT, NULL, 0, cb_define_message },
+ { "mail-statistics", NULL, N_("Send statistics"),
+ grecs_type_section, GRECS_DFLT, NULL, 0, NULL, NULL,
+ mail_statistics_kw },
+
+ { NULL }
+};
+
void
-mail_stats()
+mod_mailutils_LTX_help(void)
{
- struct metadef *exp;
- time_t t;
- const char *tmpl;
- char *text;
- size_t tc;
+ /* FIXME */
+}
- if (!admin_stat_message || !stat_mask_p(mail_admin_mask) || !mailer)
- return;
+int
+mod_mailutils_LTX_open(grecs_node_t *node)
+{
+ int rc = 0;
- if (!admin_address) {
+ mu_register_all_mailer_formats();
+ mu_stdstream_setup(MU_STDSTREAM_RESET_NONE);
+ mu_log_tag = syslog_tag;
+ mu_log_facility = log_facility;
+ mu_stdstream_strerr_setup(log_to_stderr ?
+ MU_STRERR_STDERR : MU_STRERR_SYSLOG);
+
+ if (node) {
+ rc = grecs_tree_process(node->down, mail_kw);
+ if (rc)
+ return rc;
+ }
+ if (!mailer && (rc = mu_mailer_create(&mailer, NULL))) {
+ const char *url = NULL;
+ mu_mailer_get_url_default(&url);
logmsg(LOG_ERR,
- _("cannot mail statistics: admin-address not defined"));
- return;
+ _("cannot create default mailer `%s': %s"), url,
+ mu_strerror(rc));
}
+ return rc;
+}
+
+/* Replaces enum notification_target */
+enum ntfrcpt {
+ notify_read, /* Read recipients from the message headers */
+ notify_admin, /* System administrator */
+ notify_owner, /* Project admin */
+ notify_user /* User (uploader) */
+};
+struct mailevt {
+ enum ntfrcpt rcpt; /* whom to notify */
+ const char *msg; /* message template */
+ const char *sign_keys; /* GPG keys to sign the message with */
+};
- if (debug_level) {
- const char *s;
+static struct mu_kwd target_tab[] = {
+ { "read", notify_read }, /* Read recipients from the message
+ headers */
+ { "message", notify_read },
+ { "admin", notify_admin }, /* System administrator */
+ { "owner", notify_owner }, /* Project admin */
+ { "user", notify_user }, /* User (uploader) */
+ { NULL }
+};
- if (mu_address_sget_printable(admin_address, &s) == 0)
- logmsg(LOG_DEBUG, _("sending stats to %s"), s);
+static const char *
+ntfrcpt_str(enum ntfrcpt tgt)
+{
+ const char *ret;
+
+ if (mu_kwd_xlat_tok(target_tab, tgt, &ret)) {
+ grecs_error(NULL, 0,
+ _("INTERNAL ERROR: "
+ "unknown notification target number: %d"),
+ tgt);
+ return NULL;
}
+ return ret;
+}
- 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;
+static int
+string_to_ntfrcpt(grecs_locus_t *locus, const char *val, enum ntfrcpt *pret)
+{
+ int res;
+ if (mu_kwd_xlat_name(target_tab, val, &res)) {
+ grecs_error(locus, 0,
+ _("unknown notification target: %s"), val);
+ return 1;
}
- text = meta_expand_string(tmpl, exp, NULL, NULL, NULL);
+ *pret = res;
+ return 0;
+}
- mail_send_message(admin_address, text, admin_stat_sign_key);
+static int
+cb_recipient(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ enum ntfrcpt *tgt = varptr;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
- free(text);
- meta_free(exp);
- timer_free_meta(exp + 1, tc);
- free(exp);
+ if (wy_assert_string_arg(locus, cmd, value))
+ return 1;
+ string_to_ntfrcpt(&value->locus, value->v.string, tgt);
+ return 0;
+}
+
+static struct grecs_keyword notify_event_kw[] = {
+ { "recipient", N_("who"), N_("Notify this recipient"),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof(struct mailevt, rcpt),
+ cb_recipient },
+ { "gpg-sign", N_("key"),
+ N_("Sign message with this key"),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof(struct mailevt, sign_keys) },
+ { "message", N_("text-or-id"),
+ N_("Text of the notification or identifier of a defined "
+ "message template"),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof(struct mailevt, msg) },
+ { NULL }
+};
+
+void *
+mod_mailutils_LTX_config(grecs_node_t *node)
+{
+ int i;
+ struct mailevt *evt = grecs_malloc(sizeof(*evt));
+
+ for (i = 0; notify_event_kw[i].ident; i++)
+ notify_event_kw[i].varptr = evt;
+ if (grecs_tree_process(node->down, notify_event_kw)) {
+ free(evt);
+ evt = NULL;
+ }
+ return evt;
+}
+
+void
+mod_mailutils_LTX_flush()
+{
+ if (mailer_opened) {
+ mu_mailer_close(mailer);
+ mailer_opened = 0;
+ }
}
-mu_address_t
-get_uploader_email(struct uploader_info * info, struct file_triplet * trp,
+static mu_address_t
+get_uploader_email(struct uploader_info const *info,
+ struct file_triplet const *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);
@@ -444,8 +758,8 @@ get_uploader_email(struct uploader_info * info, struct file_triplet * trp,
return rcpt;
}
-mu_address_t
-get_recipient(struct dictionary * dict, struct file_triplet * trp,
+static mu_address_t
+get_recipient(struct dictionary *dict, struct file_triplet const *trp,
const char **errp)
{
unsigned nrows, ncols, i;
@@ -501,20 +815,15 @@ get_recipient(struct dictionary * dict, struct file_triplet * trp,
return rcpt;
}
-void
-do_notify(struct file_triplet *trp, enum notification_event ev,
- struct notification *ntf)
+static void
+t_notify(struct mailevt *evt, int ev, struct file_triplet const *trp)
{
mu_address_t rcpt = NULL;
const char *errp;
+ char *text;
const char *msg;
-
- if (ntf->modname) {
- module_notify(ntf->modname, ntf->modcfg, ev, trp);
- return;
- }
- switch (ntf->tgt) {
+ switch (evt->rcpt) {
case notify_read:
rcpt = NULL;
break;
@@ -532,16 +841,16 @@ do_notify(struct file_triplet *trp, enum notification_event ev,
trp, &errp);
}
- if (!rcpt && ntf->tgt != notify_read) {
+ if (!rcpt && evt->rcpt != notify_read) {
logmsg(LOG_ERR,
_("not notifying %s (project %s) about %s: %s"),
- notification_target_str(ntf->tgt),
+ ntfrcpt_str(evt->rcpt),
trp->project, notification_event_str(ev),
gettext(errp));
return;
}
- if (debug_level) {
+ if (wy_debug_level) {
if (rcpt) {
const char *s;
@@ -557,59 +866,75 @@ do_notify(struct file_triplet *trp, enum notification_event ev,
trp->project, notification_event_str(ev));
}
- msg = resolve_message_template(ntf->msg);
+ msg = resolve_message_template(evt->msg);
if (!msg)
logmsg(LOG_ERR, _("undefined message reference: %s"),
- ntf->msg);
+ evt->msg);
else {
- char *text = triplet_expand_param(msg, trp);
- mail_send_message(rcpt, text, ntf->sign_keys);
+ text = triplet_expand_param(msg, trp);
+ mail_send_message(rcpt, text, evt->sign_keys);
free(text);
}
-
+
mu_address_destroy(&rcpt);
}
-void
-notify(struct notification *notification_list,
- struct file_triplet *trp, enum notification_event ev)
+
+static void
+mail_stats(struct mailevt *evt)
{
- struct notification *p;
+ struct metadef *exp;
+ time_t t;
+ const char *tmpl;
+ char *text;
+ size_t tc;
- for (p = notification_list; p; p = p->next)
- if (p->ev == ev)
- do_notify(trp, ev, p);
-}
+ if (!admin_stat_message || !stat_mask_p(mail_admin_mask) || !mailer)
+ return;
-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;
-}
+ if (!admin_address) {
+ logmsg(LOG_ERR,
+ _("cannot mail statistics: admin-address not defined"));
+ return;
+ }
-const char *
-expand_email_owner(struct metadef *def, void *data)
-{
- struct file_triplet *trp = data;
- mu_address_t addr;
- const char *errp;
+ if (wy_debug_level) {
+ const char *s;
- 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);
+ 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;
}
- return def->value;
+ 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);
+}
+
+void
+mod_mailutils_LTX_notify(void *data, int ev, struct file_triplet const *trp)
+{
+ struct mailevt *evt = data;
+ if (trp)
+ t_notify(evt, ev, trp);
+ else if (ev == ev_statistics)
+ mail_stats(evt);
}
diff --git a/src/Makefile.am b/src/Makefile.am
index d7241e9..7b350e5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,7 @@ wydawca_SOURCES=\
directive.c\
diskio.c\
exec.c\
+ event.c\
gpg.c\
interval.c\
job.c\
@@ -48,8 +49,6 @@ wydawca_SOURCES=\
verify.c\
wydawca.c\
wydawca.h\
- mail.h\
- mail.c\
vtab.c\
null.c\
timer.c\
@@ -68,7 +67,7 @@ SUFFIXES=.opt .c .h
incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = $(PP_SETUP_FILE)
-LDADD=../grecs/src/libgrecs.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@ @LIBLTDL@
+LDADD=../grecs/src/libgrecs.a @SQLLIB@ @GPGMELIB@ @LIBLTDL@
AM_CPPFLAGS= \
-I$(top_srcdir)/grecs/src/ @MAILUTILS_INCLUDES@\
-DSYSCONFDIR=\"$(sysconfdir)\"\
diff --git a/src/config.c b/src/config.c
index 05d76de..4da18c5 100644
--- a/src/config.c
+++ b/src/config.c
@@ -16,7 +16,7 @@
#include "wydawca.h"
#include "sql.h"
-#include <mail.h>
+
struct keyword {
char *name;
@@ -118,7 +118,7 @@ static struct archive_descr default_archive_descr = {
};
static struct dictionary *default_dictionary[dictionary_count];
-static struct notification *default_notification = NULL;
+struct notification *default_notification = NULL;
/* safe_file_name: convert a file nam