cleanup_extracted.c [plain text]
#include <sys_defs.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <mymalloc.h>
#include <nvtable.h>
#include <cleanup_user.h>
#include <qmgr_user.h>
#include <record.h>
#include <rec_type.h>
#include <mail_params.h>
#include <mail_proto.h>
#include "cleanup.h"
#define STR(x) vstring_str(x)
static void cleanup_extracted_process(CLEANUP_STATE *, int, const char *, int);
static void cleanup_extracted_finish(CLEANUP_STATE *);
void cleanup_extracted(CLEANUP_STATE *state, int type,
const char *buf, int len)
{
cleanup_out_string(state, REC_TYPE_XTRA, "");
state->action = cleanup_extracted_process;
cleanup_extracted_process(state, type, buf, len);
}
void cleanup_extracted_process(CLEANUP_STATE *state, int type,
const char *buf, int len)
{
const char *encoding;
const char generated_by_cleanup[] = {
REC_TYPE_FILT, REC_TYPE_RDR, REC_TYPE_ATTR,
REC_TYPE_RRTO, REC_TYPE_ERTO, 0,
};
if (msg_verbose)
msg_info("extracted envelope %c %.*s", type, len, buf);
if (strchr(REC_TYPE_EXTRACT, type) == 0) {
msg_warn("%s: message rejected: "
"unexpected record type %d in extracted envelope",
state->queue_id, type);
state->errs |= CLEANUP_STAT_BAD;
return;
}
if ((state->flags & CLEANUP_FLAG_INRCPT) == 0
&& strchr(REC_TYPE_EXT_RECIPIENT, type) != 0) {
if (state->filter != 0)
cleanup_out_string(state, REC_TYPE_FILT, state->filter);
if (state->redirect != 0)
cleanup_out_string(state, REC_TYPE_RDR, state->redirect);
if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ENCODING, encoding);
if (state->return_receipt)
cleanup_out_string(state, REC_TYPE_RRTO, state->return_receipt);
if (state->errors_to)
cleanup_out_string(state, REC_TYPE_ERTO, state->errors_to);
state->flags |= CLEANUP_FLAG_INRCPT;
}
if (type == REC_TYPE_RCPT) {
if (state->sender == 0) {
msg_warn("%s: message rejected: envelope recipient precedes sender",
state->queue_id);
state->errs |= CLEANUP_STAT_BAD;
return;
}
if (state->orig_rcpt == 0)
state->orig_rcpt = mystrdup(buf);
cleanup_addr_recipient(state, buf);
myfree(state->orig_rcpt);
state->orig_rcpt = 0;
return;
}
if (type == REC_TYPE_DONE) {
if (state->orig_rcpt != 0) {
myfree(state->orig_rcpt);
state->orig_rcpt = 0;
}
return;
}
if (state->orig_rcpt != 0) {
msg_warn("%s: ignoring out-of-order original recipient record <%.200s>",
state->queue_id, buf);
myfree(state->orig_rcpt);
state->orig_rcpt = 0;
}
if (type == REC_TYPE_ORCP) {
state->orig_rcpt = mystrdup(buf);
return;
}
if (type == REC_TYPE_END) {
state->flags &= ~CLEANUP_FLAG_INRCPT;
state->flags |= CLEANUP_FLAG_END_SEEN;
cleanup_extracted_finish(state);
return;
}
if (state->flags & CLEANUP_FLAG_INRCPT)
state->qmgr_opts |= QMGR_READ_FLAG_MIXED_RCPT_OTHER;
if (strchr(generated_by_cleanup, type) != 0) {
return;
} else {
cleanup_out(state, type, buf, len);
return;
}
}
void cleanup_extracted_finish(CLEANUP_STATE *state)
{
const char myname[] = "cleanup_extracted_finish";
if ((state->flags & CLEANUP_FLAG_BCC_OK)
&& state->recip != 0 && *var_always_bcc)
cleanup_addr_bcc(state, var_always_bcc);
cleanup_out_string(state, REC_TYPE_END, "");
if (vstream_fflush(state->dst)) {
if (errno == EFBIG) {
msg_warn("%s: queue file size limit exceeded", state->queue_id);
state->errs |= CLEANUP_STAT_SIZE;
} else {
msg_warn("%s: write queue file: %m", state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
}
return;
}
if (vstream_fseek(state->dst, 0L, SEEK_SET) < 0)
msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
(REC_TYPE_SIZE_CAST1) (state->xtra_offset - state->data_offset),
(REC_TYPE_SIZE_CAST2) state->data_offset,
(REC_TYPE_SIZE_CAST3) state->rcpt_count,
(REC_TYPE_SIZE_CAST4) state->qmgr_opts);
}