#include <sys_defs.h>
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <split_at.h>
#include <mymalloc.h>
#include <mail_params.h>
#include <deliver_pass.h>
#include <dsb_scan.h>
#include <defer.h>
#include <rcpt_print.h>
#define DELIVER_PASS_DEFER 1
#define DELIVER_PASS_UNKNOWN 2
static int deliver_pass_initial_reply(VSTREAM *stream)
{
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_STATUS, &stat),
ATTR_TYPE_END) != 1) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
stat = -1;
}
return (stat);
}
static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
const char *nexthop,
RECIPIENT *rcpt)
{
int stat;
attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request->flags),
SEND_ATTR_STR(MAIL_ATTR_QUEUE, request->queue_name),
SEND_ATTR_STR(MAIL_ATTR_QUEUEID, request->queue_id),
SEND_ATTR_LONG(MAIL_ATTR_OFFSET, request->data_offset),
SEND_ATTR_LONG(MAIL_ATTR_SIZE, request->data_size),
SEND_ATTR_STR(MAIL_ATTR_NEXTHOP, nexthop),
SEND_ATTR_STR(MAIL_ATTR_ENCODING, request->encoding),
SEND_ATTR_INT(MAIL_ATTR_SMTPUTF8, request->smtputf8),
SEND_ATTR_STR(MAIL_ATTR_SENDER, request->sender),
SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, request->dsn_envid),
SEND_ATTR_INT(MAIL_ATTR_DSN_RET, request->dsn_ret),
SEND_ATTR_FUNC(msg_stats_print, (void *) &request->msg_stats),
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_NAME, request->client_name),
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr),
SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_PORT, request->client_port),
SEND_ATTR_STR(MAIL_ATTR_LOG_PROTO_NAME, request->client_proto),
SEND_ATTR_STR(MAIL_ATTR_LOG_HELO_NAME, request->client_helo),
SEND_ATTR_STR(MAIL_ATTR_SASL_METHOD, request->sasl_method),
SEND_ATTR_STR(MAIL_ATTR_SASL_USERNAME, request->sasl_username),
SEND_ATTR_STR(MAIL_ATTR_SASL_SENDER, request->sasl_sender),
SEND_ATTR_STR(MAIL_ATTR_LOG_IDENT, request->log_ident),
SEND_ATTR_STR(MAIL_ATTR_RWR_CONTEXT, request->rewrite_context),
SEND_ATTR_INT(MAIL_ATTR_RCPT_COUNT, 1),
ATTR_TYPE_END);
attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_FUNC(rcpt_print, (void *) rcpt),
ATTR_TYPE_END);
if (vstream_fflush(stream)) {
msg_warn("%s: bad write: %m", VSTREAM_PATH(stream));
stat = -1;
} else {
stat = 0;
}
return (stat);
}
static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb)
{
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_FUNC(dsb_scan, (void *) dsb),
RECV_ATTR_INT(MAIL_ATTR_STATUS, &stat),
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_PASS_UNKNOWN);
} else {
return (stat ? DELIVER_PASS_DEFER : 0);
}
}
int deliver_pass(const char *class, const char *service,
DELIVER_REQUEST *request,
RECIPIENT *rcpt)
{
VSTREAM *stream;
DSN_BUF *dsb;
DSN dsn;
int status;
char *saved_service;
char *transport;
char *nexthop;
transport = saved_service = mystrdup(service);
if ((nexthop = split_at(saved_service, ':')) == 0 || *nexthop == 0)
nexthop = request->nexthop;
if (*transport == 0)
msg_fatal("missing transport name in \"%s\"", service);
stream = mail_connect_wait(class, transport);
dsb = dsb_create();
if (deliver_pass_initial_reply(stream) != 0
|| deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) {
(void) DSN_SIMPLE(&dsn, "4.3.0", "mail transport unavailable");
status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, &request->msg_stats,
rcpt, "none", &dsn);
} else if ((status = deliver_pass_final_reply(stream, dsb))
== DELIVER_PASS_UNKNOWN) {
(void) DSN_SIMPLE(&dsn, "4.3.0", "unknown mail transport error");
status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, &request->msg_stats,
rcpt, "none", &dsn);
}
vstream_fclose(stream);
dsb_free(dsb);
myfree(saved_service);
return (status);
}
int deliver_pass_all(const char *class, const char *service,
DELIVER_REQUEST *request)
{
RECIPIENT_LIST *list;
RECIPIENT *rcpt;
int status = 0;
list = &request->rcpt_list;
for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
status |= deliver_pass(class, service, request, rcpt);
return (status);
}