/* This file is part of mailfromd. -*- c -*- Copyright (C) 2006, 2007 Sergey Poznyakoff This program 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, or (at your option) any later version. This program 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 this program. If not, see . */ static int _send(eval_environ_t env, const char *mailer_url, char *to, char *from, mu_message_t msg, void (*destroy)(void*), void *ptr) { int status; mu_mailer_t mailer; mu_address_t to_addr; mu_address_t from_addr = NULL; if (!mailer_url) mu_mailer_get_url_default(&mailer_url); status = mu_mailer_create(&mailer, mailer_url); if (status) { destroy(ptr); MF_THROW(mf_failure, _("Cannot create mailer `%s': %s"), mailer_url, mu_strerror(status)); } status = mu_address_create(&to_addr, to); if (status) { destroy(ptr); mu_mailer_destroy(&mailer); MF_THROW(mf_failure, _("Bad recipient address `%s': %s"), to, mu_strerror(status)); } if (!from || from[0] == 0) from = "<>"; status = mu_address_create(&from_addr, from); if (status) { mu_address_destroy(&to_addr); mu_mailer_destroy(&mailer); destroy(ptr); MF_THROW(mf_failure, _("Bad sender address `%s': %s"), from, mu_strerror(status)); } /* FIXME: mailer flags? */ status = mu_mailer_open(mailer, 0); if (status) { mu_address_destroy(&to_addr); mu_address_destroy(&from_addr); mu_mailer_destroy(&mailer); destroy(ptr); MF_THROW(mf_failure, _("Opening mailer `%s' failed: %s"), mailer_url, mu_strerror (status)); } status = mu_mailer_send_message(mailer, msg, from_addr, to_addr); mu_address_destroy(&to_addr); mu_address_destroy(&from_addr); mu_mailer_destroy(&mailer); destroy(ptr); MF_ASSERT(status == 0, mf_failure, _("Cannot send message: %s"), mu_strerror(status)); return 0; } static void _destroy_msg(void *ptr) { mu_message_t msg = ptr; mu_message_destroy(&msg, mu_message_get_owner(msg)); } MF_DEFUN(send_mail, VOID, STRING text, STRING to, OPTIONAL, STRING from, STRING mailer_url) { mu_message_t msg = NULL; mu_stream_t stream = NULL; mu_message_create(&msg, NULL); mu_message_get_stream(msg, &stream); mu_stream_write(stream, text, strlen(text), 0, NULL); _send(env, MF_OPTVAL(mailer_url, NULL), to, MF_OPTVAL(from, NULL), msg, _destroy_msg, msg); } END static void add_headers(mu_message_t msg, char *headers) { mu_stream_t stream = NULL; mu_header_t hdr = NULL; size_t len; if (!headers) return; len = strlen(headers); mu_message_get_header(msg, &hdr); mu_header_get_stream(hdr, &stream); mu_stream_write(stream, headers, len, 0, NULL); if (len < 2 || memcmp(headers + len - 2, "\n\n", 2)) { if (len > 1 && headers[len-1] == '\n') mu_stream_write(stream, "\n", 1, len, NULL); else mu_stream_write(stream, "\n\n", 2, len, NULL); } } MF_DEFUN(send_text, VOID, STRING text, STRING headers, STRING to, OPTIONAL, STRING from, STRING mailer_url) { mu_message_t msg = NULL; mu_body_t body = NULL; mu_stream_t stream = NULL; mu_message_create(&msg, NULL); mu_message_get_body(msg, &body); mu_body_get_stream(body, &stream); mu_stream_write(stream, text, strlen(text), 0, NULL); add_headers(msg, headers); _send(env, MF_OPTVAL(mailer_url, NULL), to, MF_OPTVAL(from, NULL), msg, _destroy_msg, msg); } END static int _stream_printf(mu_stream_t stream, const char *fmt, ...) { va_list ap; char *buf = NULL; size_t size; va_start(ap, fmt); vasprintf(&buf, fmt, ap); va_end(ap); size = strlen(buf); return mu_stream_sequential_write(stream, buf, size); } static void mime_create_reason(mu_mime_t mime, const char *sender, const char *text) { mu_message_t newmsg; mu_stream_t stream; time_t t; struct tm *tm; mu_body_t body; mu_header_t hdr; char datestr[80]; static char *content_header = "Content-Type: text/plain;charset=US-ASCII\n" /* FIXME! */ "Content-Transfer-Encoding: 8bit\n"; mu_message_create(&newmsg, NULL); mu_message_get_body(newmsg, &body); mu_body_get_stream(body, &stream); time(&t); tm = localtime(&t); mu_strftime(datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tm); _stream_printf(stream, "\n" "The original message was received at %s from %s.\n", datestr, sender); mu_stream_sequential_write(stream, text, strlen(text)); mu_stream_close(stream); mu_header_create(&hdr, content_header, strlen(content_header), newmsg); mu_message_set_header(newmsg, hdr, NULL); mu_mime_add_part(mime, newmsg); mu_message_unref(newmsg); } static void mime_create_ds(mu_mime_t mime, char *recpt) { mu_message_t newmsg; mu_stream_t stream; mu_header_t hdr; mu_body_t body; char datestr[80]; time_t t; struct tm *tm; time(&t); tm = localtime(&t); mu_strftime(datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tm); mu_message_create(&newmsg, NULL); mu_message_get_header(newmsg, &hdr); mu_header_set_value(hdr, "Content-Type", "message/delivery-status", 1); mu_message_get_body(newmsg, &body); mu_body_get_stream(body, &stream); _stream_printf(stream, "Reporting-UA: %s\n", PACKAGE_STRING); _stream_printf(stream, "Arrival-Date: %s\n", datestr); _stream_printf(stream, "Final-Recipient: RFC822; %s\n", recpt ? recpt : "unknown"); _stream_printf(stream, "%s", "Action: deleted\n"); _stream_printf(stream, "%s", "Disposition: automatic-action/" "MDN-sent-automatically;deleted\n"); _stream_printf(stream, "Last-Attempt-Date: %s\n", datestr); mu_stream_close(stream); mu_mime_add_part(mime, newmsg); mu_message_unref(newmsg); } /* Quote original message */ static int mime_create_quote(mu_mime_t mime, mu_stream_t istream) { mu_message_t newmsg; mu_stream_t ostream; mu_header_t hdr; size_t ioff = 0, ooff = 0, n; char buffer[512]; mu_body_t body; mu_message_create(&newmsg, NULL); mu_message_get_header(newmsg, &hdr); mu_header_set_value(hdr, "Content-Type", "message/rfc822", 1); mu_message_get_body (newmsg, &body); mu_body_get_stream(body, &ostream); while (mu_stream_read(istream, buffer, sizeof buffer - 1, ioff, &n) == 0 && n != 0) { size_t sz; mu_stream_write(ostream, buffer, n, ooff, &sz); if (sz != n) return EIO; ooff += n; ioff += n; } mu_stream_close(ostream); mu_mime_add_part(mime, newmsg); mu_message_unref(newmsg); return 0; } static int build_mime(mu_mime_t *pmime, mu_stream_t msgstr, char *sender, char *recpt, char *text) { mu_mime_t mime = NULL; int status; mu_mime_create(&mime, NULL, 0); mime_create_reason(mime, sender, text); mime_create_ds(mime, recpt); status = mime_create_quote(mime, msgstr); if (status) { mu_mime_destroy (&mime); return status; } *pmime = mime; return 0; } static void _destroy_mime(void *ptr) { mu_mime_t mime = ptr; mu_mime_destroy(&mime); } MF_STATE(eom) MF_CAPTURE MF_DEFUN(send_dsn, VOID, STRING to, STRING sender, STRING recpt, STRING text, OPTIONAL, STRING headers, STRING from, STRING mailer_url) { int status; mu_mime_t mime; mu_message_t newmsg; status = build_mime(&mime, env_get_stream(env), sender, recpt, text); MF_ASSERT(status == 0, mf_failure, _("Cannot create DSN: %s"), mu_strerror(status)); mu_mime_get_message(mime, &newmsg); add_headers(newmsg, MF_OPTVAL(headers, NULL)); _send(env, MF_OPTVAL(mailer_url, NULL), to, MF_OPTVAL(from, NULL), newmsg, _destroy_mime, mime); } END MF_INIT