#include <sys_defs.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <stringops.h>
#include <mail_proto.h>
#include <mail_queue.h>
#include <mail_params.h>
#include <mail_conf.h>
#include <bounce.h>
#include <mail_addr.h>
#include <mail_server.h>
#include "bounce_service.h"
int var_bounce_limit;
int var_max_queue_time;
int var_delay_warn_time;
char *var_notify_classes;
char *var_bounce_rcpt;
char *var_2bounce_rcpt;
char *var_delay_rcpt;
static VSTRING *queue_id;
static VSTRING *queue_name;
static VSTRING *orig_rcpt;
static VSTRING *recipient;
static VSTRING *encoding;
static VSTRING *sender;
static VSTRING *verp_delims;
static VSTRING *dsn_status;
static VSTRING *dsn_action;
static VSTRING *why;
#define STR vstring_str
static int bounce_append_proto(char *service_name, VSTREAM *client)
{
char *myname = "bounce_append_proto";
int flags;
long offset;
if (mail_command_server(client,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 8) {
msg_warn("malformed request");
return (-1);
}
if (mail_queue_id_ok(STR(queue_id)) == 0) {
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
return (-1);
}
if (msg_verbose)
msg_info("%s: flags=0x%x service=%s id=%s org_to=%s to=%s off=%ld stat=%s act=%s why=%s",
myname, flags, service_name, STR(queue_id), STR(orig_rcpt),
STR(recipient), offset, STR(dsn_status),
STR(dsn_action), STR(why));
if (flags & BOUNCE_FLAG_CLEAN)
bounce_cleanup_register(service_name, STR(queue_id));
return (bounce_append_service(flags, service_name, STR(queue_id),
STR(orig_rcpt), STR(recipient), offset,
STR(dsn_status), STR(dsn_action),
STR(why)));
}
static int bounce_notify_proto(char *service_name, VSTREAM *client,
int (*service) (int, char *, char *, char *, char *, char *))
{
char *myname = "bounce_notify_proto";
int flags;
if (mail_command_server(client,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_END) != 5) {
msg_warn("malformed request");
return (-1);
}
if (mail_queue_name_ok(STR(queue_name)) == 0) {
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
return (-1);
}
if (mail_queue_id_ok(STR(queue_id)) == 0) {
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
return (-1);
}
if (msg_verbose)
msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s",
myname, flags, service_name, STR(queue_name), STR(queue_id),
STR(encoding), STR(sender));
if (flags & BOUNCE_FLAG_CLEAN)
bounce_cleanup_register(service_name, STR(queue_id));
return (service(flags, service_name, STR(queue_name),
STR(queue_id), STR(encoding),
STR(sender)));
}
static int bounce_verp_proto(char *service_name, VSTREAM *client)
{
char *myname = "bounce_verp_proto";
int flags;
if (mail_command_server(client,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
ATTR_TYPE_END) != 6) {
msg_warn("malformed request");
return (-1);
}
if (mail_queue_name_ok(STR(queue_name)) == 0) {
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
return (-1);
}
if (mail_queue_id_ok(STR(queue_id)) == 0) {
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
return (-1);
}
if (strlen(STR(verp_delims)) != 2) {
msg_warn("malformed verp delimiter string: %s",
printable(STR(verp_delims), '?'));
return (-1);
}
if (msg_verbose)
msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s delim=%s",
myname, flags, service_name, STR(queue_name), STR(queue_id),
STR(encoding), STR(sender), STR(verp_delims));
if (flags & BOUNCE_FLAG_CLEAN)
bounce_cleanup_register(service_name, STR(queue_id));
if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
msg_warn("request to send VERP-style notification of bounced mail");
return (bounce_notify_service(flags, service_name, STR(queue_name),
STR(queue_id), STR(encoding),
STR(sender)));
} else
return (bounce_notify_verp(flags, service_name, STR(queue_name),
STR(queue_id), STR(encoding),
STR(sender), STR(verp_delims)));
}
static int bounce_one_proto(char *service_name, VSTREAM *client)
{
char *myname = "bounce_one_proto";
int flags;
long offset;
if (mail_command_server(client,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 11) {
msg_warn("malformed request");
return (-1);
}
if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) {
msg_warn("wrong service name \"%s\" for one-recipient bouncing",
service_name);
return (-1);
}
if (mail_queue_name_ok(STR(queue_name)) == 0) {
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
return (-1);
}
if (mail_queue_id_ok(STR(queue_id)) == 0) {
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
return (-1);
}
if (msg_verbose)
msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s orig_to=%s to=%s off=%ld stat=%s act=%s why=%s",
myname, flags, STR(queue_name), STR(queue_id), STR(encoding),
STR(sender), STR(orig_rcpt), STR(recipient), offset,
STR(dsn_status), STR(dsn_action), STR(why));
return (bounce_one_service(flags, STR(queue_name), STR(queue_id),
STR(encoding), STR(sender), STR(orig_rcpt),
STR(recipient), offset, STR(dsn_status),
STR(dsn_action), STR(why)));
}
static void bounce_service(VSTREAM *client, char *service_name, char **argv)
{
int command;
int status;
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
if (mail_queue_name_ok(service_name) == 0)
msg_fatal("malformed service name: %s", service_name);
if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, &command, 0) != 1) {
msg_warn("malformed request");
status = -1;
} else if (command == BOUNCE_CMD_VERP) {
status = bounce_verp_proto(service_name, client);
} else if (command == BOUNCE_CMD_FLUSH) {
status = bounce_notify_proto(service_name, client,
bounce_notify_service);
} else if (command == BOUNCE_CMD_WARN) {
status = bounce_notify_proto(service_name, client,
bounce_warn_service);
} else if (command == BOUNCE_CMD_TRACE) {
status = bounce_notify_proto(service_name, client,
bounce_trace_service);
} else if (command == BOUNCE_CMD_APPEND) {
status = bounce_append_proto(service_name, client);
} else if (command == BOUNCE_CMD_ONE) {
status = bounce_one_proto(service_name, client);
} else {
msg_warn("unknown command: %d", command);
status = -1;
}
attr_print(client, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
vstream_fflush(client);
if (bounce_cleanup_path) {
if (status || vstream_ferror(client))
bounce_cleanup_log();
bounce_cleanup_unregister();
}
}
static void post_jail_init(char *unused_name, char **unused_argv)
{
queue_id = vstring_alloc(10);
queue_name = vstring_alloc(10);
orig_rcpt = vstring_alloc(10);
recipient = vstring_alloc(10);
encoding = vstring_alloc(10);
sender = vstring_alloc(10);
verp_delims = vstring_alloc(10);
dsn_status = vstring_alloc(10);
dsn_action = vstring_alloc(10);
why = vstring_alloc(10);
}
int main(int argc, char **argv)
{
static CONFIG_INT_TABLE int_table[] = {
VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
0,
};
static CONFIG_TIME_TABLE time_table[] = {
VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
0,
};
static CONFIG_STR_TABLE str_table[] = {
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0,
0,
};
single_server_main(argc, argv, bounce_service,
MAIL_SERVER_INT_TABLE, int_table,
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_TIME_TABLE, time_table,
MAIL_SERVER_POST_INIT, post_jail_init,
MAIL_SERVER_UNLIMITED,
0);
}