aboutsummaryrefslogtreecommitdiff
path: root/src/mail.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mail.c')
-rw-r--r--src/mail.c244
1 files changed, 222 insertions, 22 deletions
diff --git a/src/mail.c b/src/mail.c
index 91ea502..15c2937 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -14,22 +14,24 @@
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 <hash.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)
{
@@ -41,14 +43,209 @@ mail_init ()
logmsg (LOG_ERR, _("cannot create default mailer `%s': %s"),
url, mu_strerror (rc));
}
}
}
+struct mu_stream_handle
+{
+ mu_stream_t str;
+ mu_off_t off;
+};
+
+static ssize_t
+mu_stream_data_read_cb (void *handle, void *buffer, size_t size)
+{
+ struct mu_stream_handle *mhp = handle;
+ size_t nread;
+ int rc;
+
+ rc = mu_stream_read (mhp->str, buffer, size, mhp->off, &nread);
+ if (rc)
+ {
+ logmsg (LOG_ERR, "mu_stream_read: %s", mu_strerror (rc));
+ errno = EIO;
+ return -1;
+ }
+
+ mhp->off += nread;
+ return nread;
+}
+
+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;
+
+ 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));
+#if 0
+ /* FIXME: */
+ else if (debug_level > 1)
+ gpgme_debug_info (ctx);
+#endif
+
+ gpgme_release (ctx);
+ return err != 0;
+}
+
+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;
+ struct mu_stream_handle mhn;
+ mu_stream_t istr, ostr;
+ 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_stream (body, &mhn.str)))
+ {
+ logmsg (LOG_ERR, "mu_message_get_stream: %s", mu_strerror (rc));
+ return 1;
+ }
+
+ mu_stream_seek (mhn.str, 0, SEEK_SET);
+ mhn.off = 0;
+
+ memset (&cbs, 0, sizeof (cbs));
+ cbs.read = mu_stream_data_read_cb;
+
+ err = gpgme_data_new_from_cbs (&input, &cbs, &mhn);
+ if (err)
+ {
+ logmsg (LOG_ERR, "gpgme_data_new_from_cbs: %s",
+ gpgme_strerror (rc));
+ return 1;
+ }
+
+ rc = gpg_sign (&output, input, key);
+
+ 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_stream (newmsg, &ostr);
+
+ /* Copy headers */
+ mu_message_get_header (msg, &hdr);
+ mu_header_get_stream (hdr, &istr);
+ mu_stream_seek (istr, 0, SEEK_SET);
+ while ((rc = mu_stream_sequential_getline (istr, &buf, &size, &nread)) == 0
+ && nread)
+ {
+ rc = mu_stream_sequential_write (ostr, buf, nread);
+ if (rc)
+ {
+ logmsg (LOG_ERR, "mu_stream_sequential_write: %s",
+ mu_strerror (rc));
+ break;
+ }
+ }
+
+ if (rc == 0)
+ {
+ while ((nread = gpgme_data_read (output, buf, size)) > 0)
+ {
+ rc = mu_stream_sequential_write (ostr, buf, nread);
+ if (rc)
+ {
+ logmsg (LOG_ERR, "mu_stream_sequential_write: %s",
+ mu_strerror (rc));
+ break;
+ }
+ }
+
+ if (rc == 0)
+ {
+ mu_message_destroy (&msg, mu_message_get_owner (msg));
+ *pmsg = newmsg;
+ }
+ }
+
+ gpgme_data_release (output);
+ free (buf);
+
+ return rc;
+}
+
void
-mail_send_message (mu_address_t rcpt, const char *text)
+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;
int mailer_flags = 0;
@@ -88,13 +285,13 @@ mail_send_message (mu_address_t rcpt, const char *text)
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);
@@ -103,16 +300,22 @@ mail_send_message (mu_address_t rcpt, const char *text)
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));
-
+ 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 ()
{
@@ -241,15 +444,12 @@ mail_stats ()
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;
@@ -261,13 +461,13 @@ mail_stats ()
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);
+ mail_send_message (admin_address, text, admin_stat_sign_key);
free (text);
meta_free (exp);
timer_free_meta (exp + 1, tc);
free (exp);
}
@@ -363,12 +563,14 @@ get_recipient (struct access_method *method, struct file_triplet *trp,
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;
+
switch (ntf->tgt)
{
case notify_read:
rcpt = NULL;
break;
@@ -405,27 +607,25 @@ do_notify (struct file_triplet *trp, enum notification_event ev,
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);
}
else
- logmsg (LOG_DEBUG, _("notifying message recipients (project %s) about %s"),
+ logmsg (LOG_DEBUG,
+ _("notifying message recipients (project %s) about %s"),
trp->project, notification_event_str (ev));
}
-
- if (!dry_run_mode)
+
+ msg = resolve_message_template (ntf->msg);
+ if (!msg)
+ logmsg (LOG_ERR, _("undefined message reference: %s"), ntf->msg);
+ else
{
- 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);
- }
+ char *text = triplet_expand_param (msg, trp);
+ mail_send_message (rcpt, text, ntf->sign_keys);
+ free (text);
}
mu_address_destroy (&rcpt);
}
void

Return to:

Send suggestions and report system problems to the System administrator.