cleanup_extracted.c [plain text]
#include <sys_defs.h>
#include <unistd.h>
#include <errno.h>
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <argv.h>
#include <mymalloc.h>
#include <nvtable.h>
#include <cleanup_user.h>
#include <record.h>
#include <rec_type.h>
#include <mail_params.h>
#include <ext_prop.h>
#include <mail_proto.h>
#include "cleanup.h"
#define STR(x) vstring_str(x)
static void cleanup_extracted_process(CLEANUP_STATE *, int, char *, int);
void cleanup_extracted(CLEANUP_STATE *state, int type, char *buf, int len)
{
const char *encoding;
cleanup_out_string(state, REC_TYPE_XTRA, "");
if (state->filter != 0)
cleanup_out_string(state, REC_TYPE_FILT, state->filter);
if ((encoding = nvtable_find(state->attr, MAIL_ATTR_ENCODING)) != 0)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ENCODING, encoding);
cleanup_out_string(state, REC_TYPE_RRTO, state->return_receipt ?
state->return_receipt : "");
cleanup_out_string(state, REC_TYPE_ERTO, state->errors_to ?
state->errors_to : state->sender);
state->action = cleanup_extracted_process;
cleanup_extracted_process(state, type, buf, len);
}
static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf, int len)
{
char *myname = "cleanup_extracted_process";
VSTRING *clean_addr;
ARGV *rcpt;
char **cpp;
if (type != REC_TYPE_RCPT) {
if (state->orig_rcpt != 0) {
if (type != REC_TYPE_DONE)
msg_warn("%s: out-of-order original recipient record <%.200s>",
state->queue_id, buf);
myfree(state->orig_rcpt);
state->orig_rcpt = 0;
}
}
if (type == REC_TYPE_RCPT) {
clean_addr = vstring_alloc(100);
if (state->orig_rcpt == 0)
state->orig_rcpt = mystrdup(buf);
cleanup_rewrite_internal(clean_addr, *buf ? buf : var_empty_addr);
if (cleanup_rcpt_canon_maps)
cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
if (cleanup_comm_canon_maps)
cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
if (cleanup_masq_domains
&& (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT))
cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
cleanup_out_recipient(state, state->orig_rcpt, STR(clean_addr));
if (state->recip == 0)
state->recip = mystrdup(STR(clean_addr));
vstring_free(clean_addr);
myfree(state->orig_rcpt);
state->orig_rcpt = 0;
return;
} else if (type == REC_TYPE_DONE) {
return;
} else if (type == REC_TYPE_ORCP) {
state->orig_rcpt = mystrdup(buf);
return;
}
if (type != REC_TYPE_END) {
cleanup_out(state, type, buf, len);
return;
}
if (state->recip == 0 && (state->errs & CLEANUP_STAT_HOVFL) == 0) {
rcpt = (state->resent[0] ? state->resent_recip : state->recipients);
if (rcpt->argc >= var_extra_rcpt_limit) {
state->errs |= CLEANUP_STAT_ROVFL;
} else {
clean_addr = vstring_alloc(100);
if (*var_always_bcc && rcpt->argv[0]) {
cleanup_rewrite_internal(clean_addr, var_always_bcc);
if (cleanup_rcpt_canon_maps)
cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
if (cleanup_comm_canon_maps)
cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
argv_add(rcpt, STR(clean_addr), (char *) 0);
}
argv_terminate(rcpt);
for (cpp = rcpt->argv; CLEANUP_OUT_OK(state) && *cpp; cpp++) {
if (cleanup_masq_domains
&& (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) {
vstring_strcpy(clean_addr, *cpp);
cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
cleanup_out_recipient(state, STR(clean_addr),
STR(clean_addr));
} else
cleanup_out_recipient(state, *cpp, *cpp);
}
if (rcpt->argv[0])
state->recip = mystrdup(rcpt->argv[0]);
vstring_free(clean_addr);
}
}
cleanup_out_string(state, REC_TYPE_END, "");
state->end_seen = 1;
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);
if (vstream_fseek(state->dst, state->mesg_offset, SEEK_SET) < 0)
msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
cleanup_out_format(state, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT,
(REC_TYPE_MESG_CAST) state->xtra_offset);
}