#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <msg.h>
#include <mymalloc.h>
#include <vstream.h>
#include <vstring.h>
#include <vstring_vstream.h>
#include <stringops.h>
#include <mail_params.h>
#include <mail_proto.h>
#include <mail_queue.h>
#include <dsn_mask.h>
#include <bounce_log.h>
#define STR(x) vstring_str(x)
BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id,
int flags, mode_t mode)
{
BOUNCE_LOG *bp;
VSTREAM *fp;
#define STREQ(x,y) (strcmp((x),(y)) == 0)
if ((fp = mail_queue_open(queue_name, queue_id, flags, mode)) == 0) {
return (0);
} else {
bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp));
bp->fp = fp;
bp->buf = vstring_alloc(100);
if (STREQ(queue_name, MAIL_QUEUE_DEFER)) {
bp->compat_status = mystrdup("4.0.0");
bp->compat_action = mystrdup("delayed");
} else {
bp->compat_status = mystrdup("5.0.0");
bp->compat_action = mystrdup("failed");
}
return (bp);
}
}
BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
DSN_BUF *dsn_buf)
{
char *recipient;
char *text;
char *cp;
int state;
#define START 0
#define FOUND 1
state = START;
rcpb_reset(rcpt_buf);
dsb_reset(dsn_buf);
for (;;) {
if ((vstring_get_nonl(bp->buf, bp->fp) == VSTREAM_EOF))
return (0);
if (STR(bp->buf)[0] == 0) {
if (state == FOUND)
break;
state = START;
continue;
}
cp = printable(STR(bp->buf), '?');
if (state == START)
state = FOUND;
if (ISALNUM(*cp)) {
const char *err;
char *name;
char *value;
long offset;
int notify;
if ((err = split_nameval(cp, &name, &value)) != 0) {
msg_warn("%s: malformed record: %s", VSTREAM_PATH(bp->fp), err);
continue;
}
if (STREQ(name, MAIL_ATTR_RECIP)) {
vstring_strcpy(rcpt_buf->address, *value ?
value : "(MAILER-DAEMON)");
} else if (STREQ(name, MAIL_ATTR_ORCPT)) {
vstring_strcpy(rcpt_buf->orig_addr, *value ?
value : "(MAILER-DAEMON)");
} else if (STREQ(name, MAIL_ATTR_DSN_ORCPT)) {
vstring_strcpy(rcpt_buf->dsn_orcpt, value);
} else if (STREQ(name, MAIL_ATTR_DSN_NOTIFY)) {
if ((notify = atoi(value)) > 0 && DSN_NOTIFY_OK(notify))
rcpt_buf->dsn_notify = notify;
} else if (STREQ(name, MAIL_ATTR_OFFSET)) {
if ((offset = atol(value)) > 0)
rcpt_buf->offset = offset;
} else if (STREQ(name, MAIL_ATTR_DSN_STATUS)) {
vstring_strcpy(dsn_buf->status, value);
} else if (STREQ(name, MAIL_ATTR_DSN_ACTION)) {
vstring_strcpy(dsn_buf->action, value);
} else if (STREQ(name, MAIL_ATTR_DSN_DTYPE)) {
vstring_strcpy(dsn_buf->dtype, value);
} else if (STREQ(name, MAIL_ATTR_DSN_DTEXT)) {
vstring_strcpy(dsn_buf->dtext, value);
} else if (STREQ(name, MAIL_ATTR_DSN_MTYPE)) {
vstring_strcpy(dsn_buf->mtype, value);
} else if (STREQ(name, MAIL_ATTR_DSN_MNAME)) {
vstring_strcpy(dsn_buf->mname, value);
} else if (STREQ(name, MAIL_ATTR_WHY)) {
vstring_strcpy(dsn_buf->reason, value);
} else {
msg_warn("%s: unknown attribute name: %s, ignored",
VSTREAM_PATH(bp->fp), name);
}
continue;
}
if (*cp != '<') {
msg_warn("%s: malformed record: %.30s...",
VSTREAM_PATH(bp->fp), cp);
continue;
}
recipient = cp + 1;
if ((cp = strstr(recipient, ">: ")) == 0) {
msg_warn("%s: malformed record: %.30s...",
VSTREAM_PATH(bp->fp), cp);
continue;
}
*cp = 0;
vstring_strcpy(rcpt_buf->address, *recipient ?
recipient : "(MAILER-DAEMON)");
text = cp + 2;
while (*text && ISSPACE(*text))
text++;
vstring_strcpy(dsn_buf->reason, text);
}
#define BUF_NODATA(buf) (STR(buf)[0] == 0)
#define BUF_ASSIGN(buf, text) vstring_strcpy((buf), (text))
if (BUF_NODATA(rcpt_buf->address))
BUF_ASSIGN(rcpt_buf->address, "(recipient address unavailable)");
if (BUF_NODATA(dsn_buf->status))
BUF_ASSIGN(dsn_buf->status, bp->compat_status);
if (BUF_NODATA(dsn_buf->action))
BUF_ASSIGN(dsn_buf->action, bp->compat_action);
if (BUF_NODATA(dsn_buf->reason))
BUF_ASSIGN(dsn_buf->reason, "(description unavailable)");
(void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf);
(void) DSN_FROM_DSN_BUF(dsn_buf);
return (bp);
}
int bounce_log_close(BOUNCE_LOG *bp)
{
int ret;
ret = vstream_fclose(bp->fp);
vstring_free(bp->buf);
myfree(bp->compat_status);
myfree(bp->compat_action);
myfree((void *) bp);
return (ret);
}