bounce_notify_util.c [plain text]
#include <sys_defs.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include <msg.h>
#include <mymalloc.h>
#include <events.h>
#include <vstring.h>
#include <vstream.h>
#include <line_wrap.h>
#include <mail_queue.h>
#include <quote_822_local.h>
#include <mail_params.h>
#include <is_header.h>
#include <record.h>
#include <rec_type.h>
#include <post_mail.h>
#include <mail_addr.h>
#include <mail_error.h>
#include <bounce_log.h>
#include <mail_date.h>
#include <mail_proto.h>
#include <lex_822.h>
#include "bounce_service.h"
#define STR vstring_str
static BOUNCE_INFO *bounce_mail_alloc(const char *service,
const char *queue_name,
const char *queue_id,
const char *encoding,
int flush,
BOUNCE_LOG *log_handle)
{
BOUNCE_INFO *bounce_info;
int rec_type;
bounce_info = (BOUNCE_INFO *) mymalloc(sizeof(*bounce_info));
bounce_info->service = service;
bounce_info->queue_name = queue_name;
bounce_info->queue_id = queue_id;
if (strcmp(encoding, MAIL_ATTR_ENC_8BIT) == 0) {
bounce_info->mime_encoding = "8bit";
} else if (strcmp(encoding, MAIL_ATTR_ENC_7BIT) == 0) {
bounce_info->mime_encoding = "7bit";
} else {
if (strcmp(encoding, MAIL_ATTR_ENC_NONE) != 0)
msg_warn("%s: unknown encoding: %.200s",
bounce_info->queue_id, encoding);
bounce_info->mime_encoding = 0;
}
bounce_info->flush = flush;
bounce_info->buf = vstring_alloc(100);
bounce_info->arrival_time = 0;
bounce_info->orig_offs = 0;
bounce_info->log_handle = log_handle;
vstring_sprintf(bounce_info->buf, "%s.%lu/%s",
queue_id, (unsigned long) event_time(), var_myhostname);
bounce_info->mime_boundary = mystrdup(STR(bounce_info->buf));
if ((bounce_info->orig_fp = mail_queue_open(queue_name, queue_id,
O_RDONLY, 0)) == 0
&& errno != ENOENT)
msg_fatal("open %s %s: %m", service, queue_id);
if (bounce_info->orig_fp != 0) {
while ((rec_type = rec_get(bounce_info->orig_fp,
bounce_info->buf, 0)) > 0) {
if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) {
if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
bounce_info->arrival_time = 0;
} else if (rec_type == REC_TYPE_MESG) {
bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
break;
}
}
}
return (bounce_info);
}
BOUNCE_INFO *bounce_mail_init(const char *service,
const char *queue_name,
const char *queue_id,
const char *encoding,
int flush)
{
BOUNCE_INFO *bounce_info;
BOUNCE_LOG *log_handle;
if ((log_handle = bounce_log_open(service, queue_id, O_RDWR, 0)) == 0
&& errno != ENOENT)
msg_fatal("open %s %s: %m", service, queue_id);
bounce_info = bounce_mail_alloc(service, queue_name, queue_id,
encoding, flush, log_handle);
return (bounce_info);
}
BOUNCE_INFO *bounce_mail_one_init(const char *queue_name,
const char *queue_id,
const char *encoding,
const char *orig_recipient,
const char *why)
{
BOUNCE_INFO *bounce_info;
BOUNCE_LOG *log_handle;
#define REALLY_BOUNCE 1
log_handle = bounce_log_forge(orig_recipient, "5.0.0", why);
bounce_info = bounce_mail_alloc("none", queue_name, queue_id,
encoding, REALLY_BOUNCE, log_handle);
return (bounce_info);
}
void bounce_mail_free(BOUNCE_INFO *bounce_info)
{
if (bounce_info->log_handle && bounce_log_close(bounce_info->log_handle))
msg_warn("%s: read bounce log %s: %m",
bounce_info->queue_id, bounce_info->queue_id);
if (bounce_info->orig_fp && vstream_fclose(bounce_info->orig_fp))
msg_warn("%s: read message file %s %s: %m",
bounce_info->queue_id, bounce_info->queue_name,
bounce_info->queue_id);
vstring_free(bounce_info->buf);
myfree((char *) bounce_info->mime_boundary);
myfree((char *) bounce_info);
}
int bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
const char *dest)
{
#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
MAIL_ADDR_MAIL_DAEMON);
if (bounce_info->flush) {
post_mail_fputs(bounce, dest == var_bounce_rcpt
|| dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
"Subject: Postmaster Copy: Undelivered Mail" :
"Subject: Undelivered Mail Returned to Sender");
}
else {
post_mail_fputs(bounce, dest == var_bounce_rcpt
|| dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
"Subject: Postmaster Warning: Delayed Mail" :
"Subject: Delayed Mail (still being retried)");
}
post_mail_fprintf(bounce, "To: %s",
STR(quote_822_local(bounce_info->buf, dest)));
post_mail_fprintf(bounce, "MIME-Version: 1.0");
post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
"multipart/report", "delivery-status");
post_mail_fprintf(bounce, "\tboundary=\"%s\"", bounce_info->mime_boundary);
if (bounce_info->mime_encoding)
post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
post_mail_fprintf(bounce, "Content-Type: %s", "text/plain");
post_mail_fputs(bounce, "");
return (vstream_ferror(bounce));
}
int bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
post_mail_fprintf(bounce, "This is the %s program at host %s.",
var_mail_name, var_myhostname);
post_mail_fputs(bounce, "");
if (bounce_info->flush) {
post_mail_fputs(bounce,
"I'm sorry to have to inform you that the message returned");
post_mail_fputs(bounce,
"below could not be delivered to one or more destinations.");
} else {
post_mail_fputs(bounce,
"####################################################################");
post_mail_fputs(bounce,
"# THIS IS A WARNING ONLY. YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
post_mail_fputs(bounce,
"####################################################################");
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce,
"Your message could not be delivered for %.1f hours.",
var_delay_warn_time / 3600.0);
post_mail_fprintf(bounce,
"It will be retried until it is %.1f days old.",
var_max_queue_time / 86400.0);
}
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce,
"For further assistance, please send mail to <%s>",
MAIL_ADDR_POSTMASTER);
if (bounce_info->flush) {
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce,
"If you do so, please include this problem report. You can");
post_mail_fprintf(bounce,
"delete your own text from the message returned below.");
}
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
return (vstream_ferror(bounce));
}
static void bounce_print(const char *str, int len, int indent, char *context)
{
VSTREAM *bounce = (VSTREAM *) context;
post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
}
static void bounce_print_wrap(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
const char *format,...)
{
va_list ap;
#define LENGTH 79
#define INDENT 4
va_start(ap, format);
vstring_vsprintf(bounce_info->buf, format, ap);
va_end(ap);
line_wrap(STR(bounce_info->buf), LENGTH, INDENT,
bounce_print, (char *) bounce);
}
int bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
post_mail_fputs(bounce, "");
bounce_print_wrap(bounce, bounce_info, "<%s>: %s",
bounce_info->log_handle->recipient, bounce_info->log_handle->text);
return (vstream_ferror(bounce));
}
int bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
if (bounce_info->log_handle == 0
|| bounce_log_rewind(bounce_info->log_handle)) {
post_mail_fputs(bounce, "\t--- Delivery error report unavailable ---");
} else {
while (bounce_log_read(bounce_info->log_handle) != 0)
if (bounce_recipient_log(bounce, bounce_info) != 0)
break;
}
return (vstream_ferror(bounce));
}
int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
post_mail_fprintf(bounce, "Content-Description: %s",
"Delivery error report");
post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "Reporting-MTA: dns; %s", var_myhostname);
#if 0
post_mail_fprintf(bounce, "Received-From-MTA: dns; %s", "whatever");
#endif
if (bounce_info->arrival_time > 0)
post_mail_fprintf(bounce, "Arrival-Date: %s",
mail_date(bounce_info->arrival_time));
return (vstream_ferror(bounce));
}
int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
char *fixed_mail_name;
post_mail_fputs(bounce, "");
#if 0
post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s", "whatever");
#endif
post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s",
bounce_info->log_handle->recipient);
post_mail_fprintf(bounce, "Action: %s", bounce_info->flush ?
"failed" : "delayed");
post_mail_fprintf(bounce, "Status: %s", bounce_info->log_handle->status);
fixed_mail_name = mystrdup(var_mail_name);
translit(fixed_mail_name, " \t\r\n()<>@,;:\\\".[]", "-----------------");
bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-%s; %s",
fixed_mail_name, bounce_info->log_handle->text);
myfree(fixed_mail_name);
#if 0
post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
bounce_info->log_handle->log_time);
#endif
if (bounce_info->flush == 0)
post_mail_fprintf(bounce, "Will-Retry-Until: %s",
mail_date(bounce_info->arrival_time + var_max_queue_time));
return (vstream_ferror(bounce));
}
int bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
if (bounce_info->log_handle != 0
&& bounce_log_rewind(bounce_info->log_handle) == 0) {
while (bounce_log_read(bounce_info->log_handle) != 0)
if (bounce_recipient_dsn(bounce, bounce_info) != 0)
break;
}
return (vstream_ferror(bounce));
}
int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
int headers_only)
{
int status = 0;
int rec_type = 0;
int bounce_length;
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
post_mail_fprintf(bounce, "Content-Description: %s", headers_only ?
"Undelivered Message Headers" : "Undelivered Message");
post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
"text/rfc822-headers" : "message/rfc822");
if (bounce_info->mime_encoding)
post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
bounce_info->mime_encoding);
post_mail_fputs(bounce, "");
if (bounce_info->orig_offs == 0 || vstream_fseek(bounce_info->orig_fp,
bounce_info->orig_offs, SEEK_SET) < 0) {
post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
return (vstream_ferror(bounce));
}
#define IS_HEADER(s) (IS_SPACE_TAB(*(s)) || is_header(s))
bounce_length = 0;
while (status == 0 && (rec_type = rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0) {
if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
break;
if (headers_only && !IS_HEADER(vstring_str(bounce_info->buf)))
break;
if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) {
bounce_length += VSTRING_LEN(bounce_info->buf) + 2;
status = (REC_PUT_BUF(bounce, rec_type, bounce_info->buf) != rec_type);
} else
break;
}
post_mail_fputs(bounce, "");
post_mail_fprintf(bounce, "--%s--", bounce_info->mime_boundary);
return (status);
}