#include <sys_defs.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <setjmp.h>
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <argv.h>
#include <stringops.h>
#include <line_wrap.h>
#include <mymalloc.h>
#include <recipient_list.h>
#include <deliver_request.h>
#include <smtp_stream.h>
#include <mail_params.h>
#include <mail_addr.h>
#include <post_mail.h>
#include <mail_error.h>
#include "smtp.h"
#define STR(x) ((char *) vstring_str(x))
#define LEN VSTRING_LEN
void smtp_chat_reset(SMTP_STATE *state)
{
if (state->history) {
argv_free(state->history);
state->history = 0;
}
}
static void smtp_chat_append(SMTP_STATE *state, char *direction, char *data)
{
char *line;
if (state->history == 0)
state->history = argv_alloc(10);
line = concatenate(direction, data, (char *) 0);
argv_add(state->history, line, (char *) 0);
myfree(line);
}
void smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
{
SMTP_SESSION *session = state->session;
va_list ap;
va_start(ap, fmt);
vstring_vsprintf(state->buffer, fmt, ap);
va_end(ap);
smtp_chat_append(state, "Out: ", STR(state->buffer));
if (msg_verbose)
msg_info("> %s: %s", session->namaddr, STR(state->buffer));
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
#if 0
if (time((time_t *) 0) - vstream_ftime(session->stream) > 10)
vstream_fflush(session->stream);
if (vstream_ftimeout(session->stream))
vstream_longjmp(session->stream, SMTP_ERR_TIME);
if (vstream_ferror(session->stream))
vstream_longjmp(session->stream, SMTP_ERR_EOF);
#endif
}
SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
{
SMTP_SESSION *session = state->session;
static SMTP_RESP rdata;
char *cp;
int last_char;
if (rdata.buf == 0)
rdata.buf = vstring_alloc(100);
VSTRING_RESET(rdata.buf);
for (;;) {
last_char = smtp_get(state->buffer, session->stream, var_line_limit);
printable(STR(state->buffer), '?');
if (last_char != '\n')
msg_warn("%s: response longer than %d: %.30s...",
session->namaddr, var_line_limit, STR(state->buffer));
if (msg_verbose)
msg_info("< %s: %.100s", session->namaddr, STR(state->buffer));
if (LEN(rdata.buf) < var_line_limit) {
if (VSTRING_LEN(rdata.buf))
VSTRING_ADDCH(rdata.buf, '\n');
vstring_strcat(rdata.buf, STR(state->buffer));
smtp_chat_append(state, "In: ", STR(state->buffer));
}
for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
;
if (cp - STR(state->buffer) == 3) {
if (*cp == '-')
continue;
if (*cp == ' ' || *cp == 0)
break;
}
state->error_mask |= MAIL_ERROR_PROTOCOL;
}
rdata.code = atoi(STR(state->buffer));
VSTRING_TERMINATE(rdata.buf);
rdata.str = STR(rdata.buf);
return (&rdata);
}
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 smtp_chat_notify(SMTP_STATE *state)
{
char *myname = "smtp_chat_notify";
SMTP_SESSION *session = state->session;
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 LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
CLEANUP_FLAG_MASK_INTERNAL,
NULL_TRACE_FLAGS);
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 client: errors from %s",
var_mail_name, session->namaddr);
post_mail_fputs(notice, "");
post_mail_fprintf(notice, "Unexpected response from %s.", session->namaddr);
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);
(void) post_mail_fclose(notice);
}