#include <sys_defs.h>
#include <setjmp.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <msg.h>
#include <argv.h>
#include <vstring.h>
#include <vstream.h>
#include <stringops.h>
#include <line_wrap.h>
#include <mymalloc.h>
#include <smtp_stream.h>
#include <record.h>
#include <rec_type.h>
#include <mail_proto.h>
#include <mail_params.h>
#include <mail_addr.h>
#include <post_mail.h>
#include <mail_error.h>
#include "smtpd.h"
#include "smtpd_chat.h"
#define STR vstring_str
#define LEN VSTRING_LEN
void smtpd_chat_reset(SMTPD_STATE *state)
{
if (state->history) {
argv_free(state->history);
state->history = 0;
}
}
static void smtp_chat_append(SMTPD_STATE *state, char *direction)
{
char *line;
if (state->notify_mask == 0)
return;
if (state->history == 0)
state->history = argv_alloc(10);
line = concatenate(direction, STR(state->buffer), (char *) 0);
argv_add(state->history, line, (char *) 0);
myfree(line);
}
void smtpd_chat_query(SMTPD_STATE *state)
{
int last_char;
last_char = smtp_get(state->buffer, state->client, var_line_limit);
smtp_chat_append(state, "In: ");
if (last_char != '\n')
msg_warn("%s[%s]: request longer than %d: %.30s...",
state->name, state->addr, var_line_limit,
printable(STR(state->buffer), '?'));
if (msg_verbose)
msg_info("< %s[%s]: %s", state->name, state->addr, STR(state->buffer));
}
void smtpd_chat_reply(SMTPD_STATE *state, const char *format,...)
{
va_list ap;
int delay = 0;
va_start(ap, format);
vstring_vsprintf(state->buffer, format, ap);
va_end(ap);
if (var_soft_bounce && STR(state->buffer)[0] == '5') {
STR(state->buffer)[0] = '4';
if (STR(state->buffer)[4] == '5')
STR(state->buffer)[4] = '4';
}
smtp_chat_append(state, "Out: ");
if (msg_verbose)
msg_info("> %s[%s]: %s", state->name, state->addr, STR(state->buffer));
if (state->error_count >= var_smtpd_soft_erlim)
sleep(delay = var_smtpd_err_sleep);
smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
if (delay || time((time_t *) 0) - vstream_ftime(state->client) > 10)
vstream_fflush(state->client);
if (vstream_ftimeout(state->client))
vstream_longjmp(state->client, SMTP_ERR_TIME);
if (vstream_ferror(state->client))
vstream_longjmp(state->client, SMTP_ERR_EOF);
if (strncmp(STR(state->buffer), "421", 3) == 0)
state->flags |= SMTPD_FLAG_HANGUP;
}
static void print_line(const char *str, int len, int indent, char *context)
{
VSTREAM *notice = (VSTREAM *) context;
post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
}
void smtpd_chat_notify(SMTPD_STATE *state)
{
const char *myname = "smtpd_chat_notify";
VSTREAM *notice;
char **cpp;
if (state->history == 0)
msg_panic("%s: no conversation history", myname);
if (msg_verbose)
msg_info("%s: notify postmaster", myname);
#define NULL_TRACE_FLAGS 0
#define NO_QUEUE_ID ((VSTRING *) 0)
#define LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
INT_FILT_NOTIFY,
NULL_TRACE_FLAGS, NO_QUEUE_ID);
if (notice == 0) {
msg_warn("postmaster notify: %m");
return;
}
post_mail_fprintf(notice, "From: %s (Mail Delivery System)",
mail_addr_mail_daemon());
post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
post_mail_fprintf(notice, "Subject: %s SMTP server: errors from %s[%s]",
var_mail_name, state->name, state->addr);
post_mail_fputs(notice, "");
post_mail_fputs(notice, "Transcript of session follows.");
post_mail_fputs(notice, "");
argv_terminate(state->history);
for (cpp = state->history->argv; *cpp; cpp++)
line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
(char *) notice);
post_mail_fputs(notice, "");
if (state->reason)
post_mail_fprintf(notice, "Session aborted, reason: %s", state->reason);
(void) post_mail_fclose(notice);
}