#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>
static int deliver_pass_initial_reply(VSTREAM *stream)
{
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_NUM, 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, const char *orcpt,
const char *addr, long offs)
{
int stat;
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset,
ATTR_TYPE_LONG, MAIL_ATTR_SIZE, request->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, request->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, request->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, request->return_receipt,
ATTR_TYPE_LONG, MAIL_ATTR_TIME, request->arrival_time,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, request->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, request->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, request->client_proto,
ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, request->client_helo,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, offs,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, addr,
ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0,
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, VSTRING *reason)
{
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_WHY, reason,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
stat = -1;
}
return (stat);
}
int deliver_pass(const char *class, const char *service,
DELIVER_REQUEST *request, const char *orig_addr,
const char *addr, long offs)
{
VSTREAM *stream;
VSTRING *reason;
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);
reason = vstring_alloc(1);
if ((status = deliver_pass_initial_reply(stream)) == 0
&& (status = deliver_pass_send_request(stream, request, nexthop,
orig_addr, addr, offs)) == 0)
status = deliver_pass_final_reply(stream, reason);
vstream_fclose(stream);
vstring_free(reason);
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->orig_addr, rcpt->address,
rcpt->offset);
return (status);
}