#include <sys_defs.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <msg.h>
#include <vstream.h>
#include <vstring.h>
#include <mymalloc.h>
#include <iostuff.h>
#include <myflock.h>
#include "mail_queue.h"
#include "mail_proto.h"
#include "mail_open_ok.h"
#include "recipient_list.h"
#include "deliver_request.h"
static int deliver_request_initial(VSTREAM *stream)
{
int err;
if (msg_verbose)
msg_info("deliver_request_initial: send initial status");
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, 0,
ATTR_TYPE_END);
if ((err = vstream_fflush(stream)) != 0)
if (msg_verbose)
msg_warn("send initial status: %m");
return (err);
}
static int deliver_request_final(VSTREAM *stream, char *reason, int status)
{
int err;
if (reason == 0)
reason = "";
if (msg_verbose)
msg_info("deliver_request_final: send: \"%s\" %d", reason, status);
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_WHY, reason,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
if ((err = vstream_fflush(stream)) != 0)
if (msg_verbose)
msg_warn("send final status: %m");
(void) VSTREAM_GETC(stream);
return (err);
}
static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
{
char *myname = "deliver_request_get";
const char *path;
struct stat st;
static VSTRING *queue_name;
static VSTRING *queue_id;
static VSTRING *nexthop;
static VSTRING *encoding;
static VSTRING *orig_addr;
static VSTRING *address;
static VSTRING *errors_to;
static VSTRING *return_receipt;
static VSTRING *client_name;
static VSTRING *client_addr;
static VSTRING *client_proto;
static VSTRING *client_helo;
long offset;
if (queue_name == 0) {
queue_name = vstring_alloc(10);
queue_id = vstring_alloc(10);
nexthop = vstring_alloc(10);
encoding = vstring_alloc(10);
orig_addr = vstring_alloc(10);
address = vstring_alloc(10);
errors_to = vstring_alloc(10);
return_receipt = vstring_alloc(10);
client_name = vstring_alloc(10);
client_addr = vstring_alloc(10);
client_proto = vstring_alloc(10);
client_helo = vstring_alloc(10);
}
if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, 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, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, return_receipt,
ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, client_proto,
ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, client_helo,
ATTR_TYPE_END) != 15) {
msg_warn("%s: error receiving common attributes", myname);
return (-1);
}
if (mail_open_ok(vstring_str(queue_name),
vstring_str(queue_id), &st, &path) == 0)
return (-1);
request->queue_name = mystrdup(vstring_str(queue_name));
request->queue_id = mystrdup(vstring_str(queue_id));
request->nexthop = mystrdup(vstring_str(nexthop));
request->encoding = mystrdup(vstring_str(encoding));
request->sender = mystrdup(vstring_str(address));
request->errors_to = mystrdup(vstring_str(errors_to));
request->return_receipt = mystrdup(vstring_str(return_receipt));
request->client_name = mystrdup(vstring_str(client_name));
request->client_addr = mystrdup(vstring_str(client_addr));
request->client_proto = mystrdup(vstring_str(client_proto));
request->client_helo = mystrdup(vstring_str(client_helo));
for (;;) {
if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
ATTR_TYPE_END) != 1) {
msg_warn("%s: error receiving offset attribute", myname);
return (-1);
}
if (offset == 0)
break;
if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_addr,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, address,
ATTR_TYPE_END) != 2) {
msg_warn("%s: error receiving recipient attributes", myname);
return (-1);
}
recipient_list_add(&request->rcpt_list, offset,
vstring_str(orig_addr),
vstring_str(address));
}
#define DELIVER_LOCK_MODE (MYFLOCK_OP_SHARED | MYFLOCK_OP_NOWAIT)
request->fp =
mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0);
if (request->fp == 0) {
if (errno != ENOENT)
msg_fatal("open %s %s: %m", request->queue_name, request->queue_id);
msg_warn("open %s %s: %m", request->queue_name, request->queue_id);
return (-1);
}
if (msg_verbose)
msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp));
if (myflock(vstream_fileno(request->fp), INTERNAL_LOCK, DELIVER_LOCK_MODE) < 0)
msg_fatal("shared lock %s: %m", VSTREAM_PATH(request->fp));
close_on_exec(vstream_fileno(request->fp), CLOSE_ON_EXEC);
return (0);
}
static DELIVER_REQUEST *deliver_request_alloc(void)
{
DELIVER_REQUEST *request;
request = (DELIVER_REQUEST *) mymalloc(sizeof(*request));
request->fp = 0;
request->queue_name = 0;
request->queue_id = 0;
request->nexthop = 0;
request->encoding = 0;
request->sender = 0;
request->errors_to = 0;
request->return_receipt = 0;
request->data_offset = 0;
request->data_size = 0;
recipient_list_init(&request->rcpt_list);
request->hop_status = 0;
request->client_name = 0;
request->client_addr = 0;
request->client_proto = 0;
request->client_helo = 0;
return (request);
}
static void deliver_request_free(DELIVER_REQUEST *request)
{
if (request->fp)
vstream_fclose(request->fp);
if (request->queue_name)
myfree(request->queue_name);
if (request->queue_id)
myfree(request->queue_id);
if (request->nexthop)
myfree(request->nexthop);
if (request->encoding)
myfree(request->encoding);
if (request->sender)
myfree(request->sender);
if (request->errors_to)
myfree(request->errors_to);
if (request->return_receipt)
myfree(request->return_receipt);
recipient_list_free(&request->rcpt_list);
if (request->hop_status)
myfree(request->hop_status);
if (request->client_name)
myfree(request->client_name);
if (request->client_addr)
myfree(request->client_addr);
if (request->client_proto)
myfree(request->client_proto);
if (request->client_helo)
myfree(request->client_helo);
myfree((char *) request);
}
DELIVER_REQUEST *deliver_request_read(VSTREAM *stream)
{
DELIVER_REQUEST *request;
if (deliver_request_initial(stream) != 0)
return (0);
(void) read_wait(vstream_fileno(stream), -1);
if (peekfd(vstream_fileno(stream)) <= 0)
return (0);
#define XXX_DEFER_STATUS -1
request = deliver_request_alloc();
if (deliver_request_get(stream, request) < 0) {
deliver_request_done(stream, request, XXX_DEFER_STATUS);
request = 0;
}
return (request);
}
int deliver_request_done(VSTREAM *stream, DELIVER_REQUEST *request, int status)
{
int err;
err = deliver_request_final(stream, request->hop_status, status);
deliver_request_free(request);
return (err);
}