Postfix 2.3 implements all the requests of Sendmail version 8
-Milter protocols up to version 4, except one: message body replacement.
+
Postfix version 2.4 implements all the requests of Sendmail
+version 8 Milter protocols up to version 4, including message body
+replacement (body replacement is not available with Postfix version
+2.3).
See, however, the workarounds and limitations sections at the end of this
document.
@@ -793,8 +795,8 @@ operation will log a warning like this:
- The solution is (to wait for) a Postfix version that supports
-the missing functionality.
+
The solution is to use a Postfix version that supports the
+missing functionality.
Most Milter configuration options are global. Future Postfix
versions may support per-Milter timeouts, per-Milter error handling,
diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in
index 2bf737122..563023324 100644
--- a/postfix/src/cleanup/Makefile.in
+++ b/postfix/src/cleanup/Makefile.in
@@ -3,12 +3,14 @@ SRCS = cleanup.c cleanup_out.c cleanup_envelope.c cleanup_message.c \
cleanup_extracted.c cleanup_state.c cleanup_rewrite.c \
cleanup_map11.c cleanup_map1n.c cleanup_masquerade.c \
cleanup_out_recipient.c cleanup_init.c cleanup_api.c \
- cleanup_addr.c cleanup_bounce.c cleanup_milter.c
+ cleanup_addr.c cleanup_bounce.c cleanup_milter.c \
+ cleanup_body_region.c
OBJS = cleanup.o cleanup_out.o cleanup_envelope.o cleanup_message.o \
cleanup_extracted.o cleanup_state.o cleanup_rewrite.o \
cleanup_map11.o cleanup_map1n.o cleanup_masquerade.o \
cleanup_out_recipient.o cleanup_init.o cleanup_api.o \
- cleanup_addr.o cleanup_bounce.o cleanup_milter.o
+ cleanup_addr.o cleanup_bounce.o cleanup_milter.o \
+ cleanup_body_region.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -59,15 +61,20 @@ cleanup_masquerade: cleanup_masquerade.o
mv junk cleanup_masquerade.o
CLEANUP_MILTER_OBJS = cleanup_state.o cleanup_out.o cleanup_addr.o \
- cleanup_out_recipient.o
+ cleanup_out_recipient.o cleanup_body_region.o
cleanup_milter: cleanup_milter.o $(CLEANUP_MILTER_OBJS) $(LIBS)
mv cleanup_milter.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(CLEANUP_MILTER_OBJS) $(LIBS) $(SYSLIBS)
mv junk cleanup_milter.o
-tests: cleanup_masquerade_test cleanup_milter_test bug_tests \
+tests: cleanup_masquerade_test milter_tests
+
+milter_tests: cleanup_milter_test bug_tests \
cleanup_milter_test2 cleanup_milter_test3 cleanup_milter_test4 \
- cleanup_milter_test5 cleanup_milter_test6 cleanup_milter_test7
+ cleanup_milter_test5 cleanup_milter_test6 cleanup_milter_test7 \
+ cleanup_milter_test8 cleanup_milter_test9 cleanup_milter_test10a \
+ cleanup_milter_test10b cleanup_milter_test10c cleanup_milter_test10d \
+ cleanup_milter_test10e
root_tests:
@@ -176,6 +183,7 @@ cleanup_milter_test6a: cleanup_milter test-queue-file6 cleanup_milter.in6a \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6a cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6b: cleanup_milter test-queue-file6 cleanup_milter.in6b \
cleanup_milter.ref6b test-queue-file6 ../postcat/postcat
@@ -184,6 +192,7 @@ cleanup_milter_test6b: cleanup_milter test-queue-file6 cleanup_milter.in6b \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6b cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6c: cleanup_milter test-queue-file6 cleanup_milter.in6c \
cleanup_milter.ref6c test-queue-file6 ../postcat/postcat
@@ -192,6 +201,7 @@ cleanup_milter_test6c: cleanup_milter test-queue-file6 cleanup_milter.in6c \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6c cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test7: cleanup_milter test-queue-file7 cleanup_milter.in7 \
cleanup_milter.ref7 test-queue-file7 ../postcat/postcat
@@ -200,6 +210,7 @@ cleanup_milter_test7: cleanup_milter test-queue-file7 cleanup_milter.in7 \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref7 cleanup_milter.tmp
+ rm -f test-queue-file7.tmp cleanup_milter.tmp
cleanup_milter_test8: cleanup_milter test-queue-file8 cleanup_milter.in8 \
cleanup_milter.ref8 test-queue-file8 ../postcat/postcat
@@ -208,6 +219,7 @@ cleanup_milter_test8: cleanup_milter test-queue-file8 cleanup_milter.in8 \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref8 cleanup_milter.tmp
+ rm -f test-queue-file8.tmp cleanup_milter.tmp
cleanup_milter_test9: cleanup_milter test-queue-file9 cleanup_milter.in9 \
cleanup_milter.ref9 test-queue-file9 ../postcat/postcat
@@ -216,6 +228,52 @@ cleanup_milter_test9: cleanup_milter test-queue-file9 cleanup_milter.in9 \
./cleanup_milter /dev/null >cleanup_milter.tmp
diff cleanup_milter.ref9 cleanup_milter.tmp
+ rm -f test-queue-file9.tmp cleanup_milter.tmp
+
+cleanup_milter_test10a: cleanup_milter test-queue-file10 cleanup_milter.in10a \
+ cleanup_milter.ref10a test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter /dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10a cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10b: cleanup_milter test-queue-file10 cleanup_milter.in10b \
+ cleanup_milter.ref10b test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter /dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10b cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10c: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10c test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter /dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10c cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10d: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10d test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter /dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10d cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10e: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10e test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter /dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10e cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
@@ -322,6 +380,7 @@ cleanup_api.o: ../../include/msg.h
cleanup_api.o: ../../include/msg_stats.h
cleanup_api.o: ../../include/mymalloc.h
cleanup_api.o: ../../include/nvtable.h
+cleanup_api.o: ../../include/rec_type.h
cleanup_api.o: ../../include/recipient_list.h
cleanup_api.o: ../../include/resolve_clnt.h
cleanup_api.o: ../../include/string_list.h
@@ -332,6 +391,33 @@ cleanup_api.o: ../../include/vstream.h
cleanup_api.o: ../../include/vstring.h
cleanup_api.o: cleanup.h
cleanup_api.o: cleanup_api.c
+cleanup_body_region.o: ../../include/argv.h
+cleanup_body_region.o: ../../include/been_here.h
+cleanup_body_region.o: ../../include/cleanup_user.h
+cleanup_body_region.o: ../../include/dict.h
+cleanup_body_region.o: ../../include/header_opts.h
+cleanup_body_region.o: ../../include/htable.h
+cleanup_body_region.o: ../../include/mail_conf.h
+cleanup_body_region.o: ../../include/mail_stream.h
+cleanup_body_region.o: ../../include/maps.h
+cleanup_body_region.o: ../../include/match_list.h
+cleanup_body_region.o: ../../include/match_ops.h
+cleanup_body_region.o: ../../include/milter.h
+cleanup_body_region.o: ../../include/mime_state.h
+cleanup_body_region.o: ../../include/msg.h
+cleanup_body_region.o: ../../include/mymalloc.h
+cleanup_body_region.o: ../../include/nvtable.h
+cleanup_body_region.o: ../../include/rec_type.h
+cleanup_body_region.o: ../../include/record.h
+cleanup_body_region.o: ../../include/resolve_clnt.h
+cleanup_body_region.o: ../../include/string_list.h
+cleanup_body_region.o: ../../include/sys_defs.h
+cleanup_body_region.o: ../../include/tok822.h
+cleanup_body_region.o: ../../include/vbuf.h
+cleanup_body_region.o: ../../include/vstream.h
+cleanup_body_region.o: ../../include/vstring.h
+cleanup_body_region.o: cleanup.h
+cleanup_body_region.o: cleanup_body_region.c
cleanup_bounce.o: ../../include/argv.h
cleanup_bounce.o: ../../include/attr.h
cleanup_bounce.o: ../../include/been_here.h
@@ -447,6 +533,7 @@ cleanup_extracted.o: cleanup.h
cleanup_extracted.o: cleanup_extracted.c
cleanup_init.o: ../../include/argv.h
cleanup_init.o: ../../include/been_here.h
+cleanup_init.o: ../../include/cleanup_user.h
cleanup_init.o: ../../include/dict.h
cleanup_init.o: ../../include/ext_prop.h
cleanup_init.o: ../../include/flush_clnt.h
@@ -536,6 +623,7 @@ cleanup_map1n.o: cleanup.h
cleanup_map1n.o: cleanup_map1n.c
cleanup_masquerade.o: ../../include/argv.h
cleanup_masquerade.o: ../../include/been_here.h
+cleanup_masquerade.o: ../../include/cleanup_user.h
cleanup_masquerade.o: ../../include/dict.h
cleanup_masquerade.o: ../../include/header_opts.h
cleanup_masquerade.o: ../../include/htable.h
@@ -716,6 +804,7 @@ cleanup_out_recipient.o: cleanup_out_recipient.c
cleanup_rewrite.o: ../../include/argv.h
cleanup_rewrite.o: ../../include/attr.h
cleanup_rewrite.o: ../../include/been_here.h
+cleanup_rewrite.o: ../../include/cleanup_user.h
cleanup_rewrite.o: ../../include/dict.h
cleanup_rewrite.o: ../../include/header_opts.h
cleanup_rewrite.o: ../../include/htable.h
@@ -746,6 +835,7 @@ cleanup_rewrite.o: cleanup_rewrite.c
cleanup_state.o: ../../include/argv.h
cleanup_state.o: ../../include/attr.h
cleanup_state.o: ../../include/been_here.h
+cleanup_state.o: ../../include/cleanup_user.h
cleanup_state.o: ../../include/dict.h
cleanup_state.o: ../../include/header_opts.h
cleanup_state.o: ../../include/htable.h
diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h
index 2c7637ecb..e31301f37 100644
--- a/postfix/src/cleanup/cleanup.h
+++ b/postfix/src/cleanup/cleanup.h
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
/*
* Milter library.
@@ -69,6 +70,7 @@ typedef struct CLEANUP_STATE {
void (*action) (struct CLEANUP_STATE *, int, const char *, ssize_t);
off_t data_offset; /* start of message content */
off_t xtra_offset; /* start of extra segment */
+ off_t cont_length; /* length including Milter edits */
off_t append_rcpt_pt_offset; /* append recipient here */
off_t append_rcpt_pt_target; /* target of above record */
off_t append_hdr_pt_offset; /* append header here */
@@ -89,6 +91,10 @@ typedef struct CLEANUP_STATE {
#ifdef DELAY_ACTION
int defer_delay; /* deferred delivery */
#endif
+
+ /*
+ * Miscellaneous Milter support.
+ */
MILTERS *milters; /* mail filters */
const char *client_name; /* real or ersatz client */
const char *reverse_name; /* real or ersatz client */
@@ -97,6 +103,13 @@ typedef struct CLEANUP_STATE {
const char *client_port; /* real or ersatz client */
VSTRING *milter_ext_from; /* externalized sender */
VSTRING *milter_ext_rcpt; /* externalized recipient */
+
+ /*
+ * Support for Milter body replacement requests.
+ */
+ struct CLEANUP_BODY_REGION *body_regions;
+ struct CLEANUP_BODY_REGION *curr_body_region;
+ off_t body_write_offs; /* body write position */
} CLEANUP_STATE;
/*
@@ -281,6 +294,20 @@ extern void cleanup_milter_emul_data(CLEANUP_STATE *, MILTERS *);
(((s)->flags & CLEANUP_FLAG_MILTER) != 0 \
&& (s)->errs == 0 && ((s)->flags & CLEANUP_FLAG_DISCARD) == 0)
+ /*
+ * cleanup_body_region.c
+ */
+typedef struct CLEANUP_BODY_REGION {
+ off_t start; /* start of region */
+ off_t len; /* length or zero (open-ended) */
+ struct CLEANUP_BODY_REGION *next;
+} CLEANUP_BODY_REGION;
+
+extern int cleanup_body_region_start(CLEANUP_STATE *);
+extern int cleanup_body_region_write(CLEANUP_STATE *, int, VSTRING *);
+extern int cleanup_body_region_finish(CLEANUP_STATE *);
+extern void cleanup_body_region_free(CLEANUP_STATE *);
+
/* LICENSE
/* .ad
/* .fi
diff --git a/postfix/src/cleanup/cleanup_api.c b/postfix/src/cleanup/cleanup_api.c
index 4769289b8..c06627436 100644
--- a/postfix/src/cleanup/cleanup_api.c
+++ b/postfix/src/cleanup/cleanup_api.c
@@ -111,6 +111,7 @@
#include
#include
#include
+#include
/* Milter library. */
@@ -198,6 +199,7 @@ void cleanup_control(CLEANUP_STATE *state, int flags)
int cleanup_flush(CLEANUP_STATE *state)
{
+ const char *myname = "cleanup_flush";
int status;
char *junk;
VSTRING *trace_junk;
@@ -234,6 +236,21 @@ int cleanup_flush(CLEANUP_STATE *state)
}
}
+ /*
+ * Update the preliminary message size and count fields with the actual
+ * values.
+ *
+ * XXX This ugly code was moved up here from a lower-level module.
+ */
+ 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,
+ (REC_TYPE_SIZE_CAST5) state->cont_length);
+
/*
* If there was an error that requires us to generate a bounce message
* (mail submitted with the Postfix sendmail command, mail forwarded by
diff --git a/postfix/src/cleanup/cleanup_body_region.c b/postfix/src/cleanup/cleanup_body_region.c
new file mode 100644
index 000000000..7ad47b05c
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_body_region.c
@@ -0,0 +1,266 @@
+/*++
+/* NAME
+/* cleanup_body_region 3
+/* SUMMARY
+/* manage body content regions
+/* SYNOPSIS
+/* #include "cleanup.h"
+/*
+/* int cleanup_body_region_start(state)
+/* CLEANUP_STATE *state;
+/*
+/* int cleanup_body_region_write(state, type, buf)
+/* CLEANUP_STATE *state;
+/* int type;
+/* VSTRING *buf;
+/*
+/* int cleanup_body_region_finish(state)
+/* CLEANUP_STATE *state;
+/*
+/* void cleanup_body_region_free(state)
+/* CLEANUP_STATE *state;
+/* DESCRIPTION
+/* This module maintains queue file regions with body content.
+/* Regions are created on the fly, and can be reused multiple
+/* times. This module must not be called until the queue file
+/* is complete.
+/*
+/* cleanup_body_region_start() performs initialization and
+/* sets the queue file write pointer to the start of the
+/* first body content segment.
+/*
+/* cleanup_body_region_write() adds a queue file record to the
+/* current queue file. When the current queue file region fills
+/* up, some other region is reused or a new one is created.
+/*
+/* cleanup_body_region_finish() makes some final adjustments
+/* after the last body content record is written.
+/*
+/* cleanup_body_region_free() frees up memory that was allocated
+/* by cleanup_body_region_start() and cleanup_body_region_write().
+/*
+/* Arguments:
+/* .IP state
+/* Queue file and message processing state. This state is updated
+/* as records are processed and as errors happen.
+/* .IP type
+/* Record type.
+/* .IP buf
+/* Record content.
+/* BUGS
+/* Currently, queue file region management is intertwined with
+/* body content management. Eventually the two should be
+/* decoupled, so that space freed up after body editing may
+/* be reused for header updates and vice versa.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+
+/* Global library. */
+
+#include
+#include
+
+/* Application-specific. */
+
+#include
+
+#define LEN(s) VSTRING_LEN(s)
+
+/* cleanup_body_region_alloc - create body content region */
+
+static CLEANUP_BODY_REGION *cleanup_body_region_alloc(off_t start, off_t len)
+{
+ CLEANUP_BODY_REGION *rp;
+
+ rp = (CLEANUP_BODY_REGION *) mymalloc(sizeof(*rp));
+ rp->start = start;
+ rp->len = len;
+ rp->next = 0;
+
+ return (rp);
+}
+
+/* cleanup_body_region_free - destroy all body content regions */
+
+void cleanup_body_region_free(CLEANUP_STATE *state)
+{
+ CLEANUP_BODY_REGION *rp;
+ CLEANUP_BODY_REGION *next;
+
+ for (rp = state->body_regions; rp != 0; rp = next) {
+ next = rp->next;
+ myfree((char *) rp);
+ }
+}
+
+/* cleanup_body_region_start - rewrite body buffer pool */
+
+int cleanup_body_region_start(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_body_region_write";
+
+ /*
+ * Calculate the payload size sans body.
+ */
+ state->cont_length = state->append_hdr_pt_target - state->data_offset;
+
+ /*
+ * Craft the first body region on the fly, from circumstantial evidence.
+ */
+ if (state->body_regions == 0)
+ state->body_regions =
+ cleanup_body_region_alloc(state->append_hdr_pt_target,
+ state->xtra_offset - state->append_hdr_pt_target);
+
+ /*
+ * Select the first region and initialize the write position.
+ */
+ state->curr_body_region = state->body_regions;
+ state->body_write_offs = state->curr_body_region->start;
+
+ /*
+ * Move the file write pointer to the start of the current region.
+ */
+ if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ return (0);
+}
+
+/* cleanup_body_region_write - add record to body buffer pool */
+
+int cleanup_body_region_write(CLEANUP_STATE *state, int rec_type,
+ VSTRING *buf)
+{
+ const char *myname = "cleanup_body_region_write";
+ CLEANUP_BODY_REGION *rp = state->curr_body_region;
+ off_t used;
+ ssize_t rec_len;
+ off_t start;
+
+ if (msg_verbose)
+ msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
+ myname, (long) state->body_write_offs, (long) LEN(buf),
+ (long) rp->start, (long) rp->len);
+
+ /*
+ * Switch to the next body region if we filled up the current one (we
+ * always append to an open-ended region). Besides space to write the
+ * specified record, we need to leave space for a final pointer record
+ * that will link this body region to the next region or to the content
+ * terminator record.
+ */
+ REC_SPACE_NEED(LEN(buf), rec_len);
+ if (rp->len > 0 && (used = state->body_write_offs - rp->start,
+ rec_len + REC_TYPE_PTR_SIZE > rp->len - used)) {
+
+ /*
+ * Allocate a new body region if we filled up the last one. A newly
+ * allocated region sits at the end of the queue file, and therefore
+ * it starts as open ended. We freeze the region size later.
+ *
+ * Don't use fstat() to figure out where the queue file ends, in case
+ * file sizes have magic in them. Instead we seek to the end and then
+ * back to where we were. We're not switching body regions often, so
+ * this is not performance critical.
+ */
+ if (rp->next == 0) {
+ if ((start = vstream_fseek(state->dst, (off_t) 0, SEEK_END)) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ rp->next = cleanup_body_region_alloc(start, 0);
+ }
+
+ /*
+ * Update the payload size and select the new body region.
+ */
+ state->cont_length += state->body_write_offs - rp->start;
+ state->curr_body_region = rp = rp->next;
+
+ /*
+ * Connect the filled up body region to its successor. By design a
+ * region has always space for a final pointer record.
+ */
+ if (msg_verbose)
+ msg_info("%s: link %ld -> %ld", myname,
+ (long) state->body_write_offs, (long) rp->start);
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) rp->start);
+ if (vstream_fseek(state->dst, rp->start, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ }
+
+ /*
+ * Finally, output the queue file record.
+ */
+ CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
+ state->body_write_offs = vstream_ftell(state->dst);
+
+ return (0);
+}
+
+/* cleanup_body_region_finish - wrap up body buffer pool */
+
+int cleanup_body_region_finish(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_body_region_finish";
+ CLEANUP_BODY_REGION *rp;
+
+ /*
+ * Link the last body region to the content terminator record.
+ */
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) state->xtra_offset);
+ state->body_write_offs = vstream_ftell(state->dst);
+
+ /*
+ * Update the payload size.
+ */
+ rp = state->curr_body_region;
+ state->cont_length += state->body_write_offs - rp->start;
+
+ /*
+ * Freeze the size of the last region if it is still open ended. The next
+ * Milter application may append more header records, therefore we must
+ * not assume that this region can grow further. Nor can we truncate the
+ * queue file to the end of this region, as this region may be followed
+ * by headers that were appended by an earlier Milter application.
+ *
+ * XXX Eventually, split a partially-used region so that the remainder can
+ * be returned to a free pool and reused for header updates.
+ */
+ if (rp->len == 0)
+ rp->len = state->body_write_offs - rp->start;
+ if (msg_verbose)
+ msg_info("%s: freeze start %ld len %ld",
+ myname, (long) rp->start, (long) rp->len);
+
+ return (CLEANUP_OUT_OK(state) ? 0 : -1);
+}
diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c
index eb4171bdf..ef4dbc7dc 100644
--- a/postfix/src/cleanup/cleanup_envelope.c
+++ b/postfix/src/cleanup/cleanup_envelope.c
@@ -89,10 +89,11 @@ void cleanup_envelope(CLEANUP_STATE *state, int type,
* first, for backwards compatibility reasons.
*/
cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
- (REC_TYPE_SIZE_CAST1) 0, /* content size */
+ (REC_TYPE_SIZE_CAST1) 0, /* extra offs - content offs */
(REC_TYPE_SIZE_CAST2) 0, /* content offset */
(REC_TYPE_SIZE_CAST3) 0, /* recipient count */
- (REC_TYPE_SIZE_CAST4) 0); /* qmgr options */
+ (REC_TYPE_SIZE_CAST4) 0, /* qmgr options */
+ (REC_TYPE_SIZE_CAST5) 0); /* content length */
/*
* Pass control to the actual envelope processing routine.
diff --git a/postfix/src/cleanup/cleanup_extracted.c b/postfix/src/cleanup/cleanup_extracted.c
index 60f0ab345..5f02e2585 100644
--- a/postfix/src/cleanup/cleanup_extracted.c
+++ b/postfix/src/cleanup/cleanup_extracted.c
@@ -316,16 +316,4 @@ void cleanup_extracted_finish(CLEANUP_STATE *state)
}
return;
}
-
- /*
- * Update the preliminary message size and count fields with the actual
- * values.
- */
- 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);
}
diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c
index 5e71c8b89..e777f455a 100644
--- a/postfix/src/cleanup/cleanup_message.c
+++ b/postfix/src/cleanup/cleanup_message.c
@@ -831,6 +831,7 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
state->mime_state = mime_state_free(state->mime_state);
if ((state->xtra_offset = vstream_ftell(state->dst)) < 0)
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
+ state->cont_length = state->xtra_offset - state->data_offset;
state->action = cleanup_extracted;
}
diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c
index da4fddb1f..348b3b790 100644
--- a/postfix/src/cleanup/cleanup_milter.c
+++ b/postfix/src/cleanup/cleanup_milter.c
@@ -1254,15 +1254,35 @@ static const char *cleanup_del_rcpt(void *context, char *ext_rcpt)
/* cleanup_repl_body - replace message body */
-static const char *cleanup_repl_body(void *context, VSTRING *body)
+static const char *cleanup_repl_body(void *context, int cmd, VSTRING *buf)
{
const char *myname = "cleanup_repl_body";
+ CLEANUP_STATE *state = (CLEANUP_STATE *) context;
+ static VSTRING empty;
/*
* XXX Sendmail compatibility: milters don't see the first body line, so
* don't expect they will send one.
*/
- msg_panic("%s: message body replace operation is not implemented", myname);
+ switch (cmd) {
+ case MILTER_BODY_LINE:
+ if (cleanup_body_region_write(state, REC_TYPE_NORM, buf) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ case MILTER_BODY_START:
+ VSTRING_RESET(&empty);
+ if (cleanup_body_region_start(state) < 0
+ || cleanup_body_region_write(state, REC_TYPE_NORM, &empty) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ case MILTER_BODY_END:
+ if (cleanup_body_region_finish(state) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ default:
+ msg_panic("%s: bad command: %d", myname, cmd);
+ }
+ return (CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, errno));
}
/* cleanup_milter_eval - expand macro */
@@ -1779,6 +1799,12 @@ static void open_queue_file(CLEANUP_STATE *state, const char *path)
}
}
}
+ if (state->append_rcpt_pt_offset < 0)
+ msg_fatal("file %s: no append recipient pointer record",
+ cleanup_path);
+ if (state->append_hdr_pt_offset < 0)
+ msg_fatal("file %s: no append header pointer record",
+ cleanup_path);
if (msg_verbose) {
msg_info("append_rcpt_pt_offset %ld append_rcpt_pt_target %ld",
(long) state->append_rcpt_pt_offset,
@@ -1819,7 +1845,7 @@ int main(int unused_argc, char **argv)
vstream_printf("- ");
vstream_fflush(VSTREAM_OUT);
}
- if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
+ if (vstring_fgets_nonl(inbuf, VSTREAM_IN) == 0)
break;
bufp = vstring_str(inbuf);
@@ -1903,6 +1929,25 @@ int main(int unused_argc, char **argv)
} else {
cleanup_del_rcpt(state, argv->argv[1]);
}
+ } else if (strcmp(argv->argv[0], "replbody") == 0) {
+ if (argv->argc != 2) {
+ msg_warn("bad replbody argument count: %d", argv->argc);
+ } else {
+ VSTREAM *fp;
+ VSTRING *buf;
+
+ if ((fp = vstream_fopen(argv->argv[1], O_RDONLY, 0)) == 0) {
+ msg_warn("open %s file: %m", argv->argv[1]);
+ } else {
+ buf = vstring_alloc(100);
+ cleanup_repl_body(state, MILTER_BODY_START, buf);
+ while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
+ cleanup_repl_body(state, MILTER_BODY_LINE, buf);
+ cleanup_repl_body(state, MILTER_BODY_END, buf);
+ vstring_free(buf);
+ vstream_fclose(fp);
+ }
+ }
} else {
msg_warn("bad command: %s", argv->argv[0]);
}
diff --git a/postfix/src/cleanup/cleanup_milter.in10a b/postfix/src/cleanup/cleanup_milter.in10a
new file mode 100644
index 000000000..997b8a7a6
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.in10a
@@ -0,0 +1,11 @@
+#
+# Replace a short body by a longer one. The result is two body
+# regions: the original region with the head of the new text, and
+# one region at the end of the queue file with the remainder of the
+# new text.
+#
+open test-queue-file10.tmp
+
+replbody loremipsum
+
+close
diff --git a/postfix/src/cleanup/cleanup_milter.in10b b/postfix/src/cleanup/cleanup_milter.in10b
new file mode 100644
index 000000000..ba3b07f36
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.in10b
@@ -0,0 +1,12 @@
+#
+# Replace a short body by a longer one, and then replace the longer
+# body by itself. The result should be identical to what we had after
+# one replacement.
+#
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum
+
+close
diff --git a/postfix/src/cleanup/cleanup_milter.in10c b/postfix/src/cleanup/cleanup_milter.in10c
new file mode 100644
index 000000000..79af0ce14
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.in10c
@@ -0,0 +1,14 @@
+#
+# Replace a short body by a longer one, and then clobber that with
+# an even longer body. The result is three body regions: the original
+# region, the region that contained the tail of the first replacement,
+# and a region that contains the tail of the second replacement.
+#
+
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum2
+
+close
diff --git a/postfix/src/cleanup/cleanup_milter.in10d b/postfix/src/cleanup/cleanup_milter.in10d
new file mode 100644
index 000000000..b7c515a8f
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.in10d
@@ -0,0 +1,14 @@
+#
+# As test 10c, but then replace the longer body by the shorter one. The
+# result is three regions: the original region, the region with the
+# tail of the shorter replacement, and an unused region that contained
+# the tail of the larger region.
+#
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum2
+replbody loremipsum
+
+close
diff --git a/postfix/src/cleanup/cleanup_milter.in10e b/postfix/src/cleanup/cleanup_milter.in10e
new file mode 100644
index 000000000..763f79b3b
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.in10e
@@ -0,0 +1,13 @@
+#
+# Replace a short body by increasingly longer ones and do header
+# updates in between.
+#
+#verbose on
+open test-queue-file10.tmp
+
+add_header foo1 foobar
+replbody loremipsum
+add_header foo2 foobar
+replbody loremipsum2
+
+close
diff --git a/postfix/src/cleanup/cleanup_milter.ref10a b/postfix/src/cleanup/cleanup_milter.ref10a
new file mode 100644
index 000000000..38c5c84fb
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.ref10a
@@ -0,0 +1,52 @@
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 1434 regular_text: pariatur?
+ 1446 regular_text:
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
diff --git a/postfix/src/cleanup/cleanup_milter.ref10b b/postfix/src/cleanup/cleanup_milter.ref10b
new file mode 100644
index 000000000..38c5c84fb
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.ref10b
@@ -0,0 +1,52 @@
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 1434 regular_text: pariatur?
+ 1446 regular_text:
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
diff --git a/postfix/src/cleanup/cleanup_milter.ref10c b/postfix/src/cleanup/cleanup_milter.ref10c
new file mode 100644
index 000000000..78704f2fc
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.ref10c
@@ -0,0 +1,82 @@
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 1434 regular_text: pariatur?
+ 1446 regular_text:
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 2320 pointer_record: 2337
+ 2337 regular_text:
+ 2340 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 2405 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 2472 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 2540 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 2609 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 2678 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 2744 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 2812 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 2879 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 2944 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 3018 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 3087 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 3155 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 3222 regular_text: pariatur?
+ 3234 regular_text:
+ 3237 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 3302 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 3367 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 3435 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 3502 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 3573 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 3640 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 3707 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 3776 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 3846 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 3912 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 3981 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 4047 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 4108 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
diff --git a/postfix/src/cleanup/cleanup_milter.ref10d b/postfix/src/cleanup/cleanup_milter.ref10d
new file mode 100644
index 000000000..38c5c84fb
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.ref10d
@@ -0,0 +1,52 @@
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 1434 regular_text: pariatur?
+ 1446 regular_text:
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
diff --git a/postfix/src/cleanup/cleanup_milter.ref10e b/postfix/src/cleanup/cleanup_milter.ref10e
new file mode 100644
index 000000000..81b05025d
--- /dev/null
+++ b/postfix/src/cleanup/cleanup_milter.ref10e
@@ -0,0 +1,86 @@
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 552
+ 552 regular_text: foo1: foobar
+ 566 pointer_record: 2368
+ 2368 regular_text: foo2: foobar
+ 2382 pointer_record: 485
+ 485 regular_text:
+ 487 pointer_record: 583
+ 583 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 648 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 715 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 783 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 852 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 921 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 987 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 1055 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 1122 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 1187 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 1261 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 1330 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 1398 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 1465 regular_text: pariatur?
+ 1477 regular_text:
+ 1480 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 1545 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 1610 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 1678 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 1745 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 1816 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 1883 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 1950 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 2019 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 2089 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 2155 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 2224 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 2290 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 2351 pointer_record: 2399
+ 2399 regular_text:
+ 2402 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+ 2467 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+ 2534 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae
+ 2602 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+ 2671 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+ 2740 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+ 2806 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ 2874 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore
+ 2941 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+ 3006 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+ 3080 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+ 3149 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+ 3217 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+ 3284 regular_text: pariatur?
+ 3296 regular_text:
+ 3299 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui
+ 3364 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos
+ 3429 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non
+ 3497 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia
+ 3564 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+ 3635 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis
+ 3702 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime
+ 3769 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+ 3838 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+ 3908 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+ 3974 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+ 4043 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+ 4109 regular_text: consequatur aut perferendis doloribus asperiores repellat.
+ 4170 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c
index 9a35f107d..e07bd2ace 100644
--- a/postfix/src/cleanup/cleanup_state.c
+++ b/postfix/src/cleanup/cleanup_state.c
@@ -89,6 +89,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src)
state->action = cleanup_envelope;
state->data_offset = -1;
state->xtra_offset = -1;
+ state->cont_length = 0;
state->append_rcpt_pt_offset = -1;
state->append_rcpt_pt_target = -1;
state->append_hdr_pt_offset = -1;
@@ -115,6 +116,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src)
state->client_port = 0;
state->milter_ext_from = 0;
state->milter_ext_rcpt = 0;
+ state->body_regions = state->curr_body_region = 0;
return (state);
}
@@ -165,5 +167,7 @@ void cleanup_state_free(CLEANUP_STATE *state)
vstring_free(state->milter_ext_from);
if (state->milter_ext_rcpt)
vstring_free(state->milter_ext_rcpt);
+ if (state->body_regions)
+ cleanup_body_region_free(state);
myfree((char *) state);
}
diff --git a/postfix/src/cleanup/loremipsum b/postfix/src/cleanup/loremipsum
new file mode 100644
index 000000000..774f86deb
--- /dev/null
+++ b/postfix/src/cleanup/loremipsum
@@ -0,0 +1,28 @@
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+quae ab illo inventore veritatis et quasi architecto beatae vitae
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+velit, sed quia non numquam eius modi tempora incidunt ut labore
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+pariatur?
+
+At vero eos et accusamus et iusto odio dignissimos ducimus qui
+blanditiis praesentium voluptatum deleniti atque corrupti quos
+dolores et quas molestias excepturi sint occaecati cupiditate non
+provident, similique sunt in culpa qui officia deserunt mollitia
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+est et expedita distinctio. Nam libero tempore, cum soluta nobis
+est eligendi optio cumque nihil impedit quo minus id quod maxime
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+consequatur aut perferendis doloribus asperiores repellat.
diff --git a/postfix/src/cleanup/loremipsum2 b/postfix/src/cleanup/loremipsum2
new file mode 100644
index 000000000..93cfa6796
--- /dev/null
+++ b/postfix/src/cleanup/loremipsum2
@@ -0,0 +1,57 @@
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+quae ab illo inventore veritatis et quasi architecto beatae vitae
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+velit, sed quia non numquam eius modi tempora incidunt ut labore
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+pariatur?
+
+At vero eos et accusamus et iusto odio dignissimos ducimus qui
+blanditiis praesentium voluptatum deleniti atque corrupti quos
+dolores et quas molestias excepturi sint occaecati cupiditate non
+provident, similique sunt in culpa qui officia deserunt mollitia
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+est et expedita distinctio. Nam libero tempore, cum soluta nobis
+est eligendi optio cumque nihil impedit quo minus id quod maxime
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+consequatur aut perferendis doloribus asperiores repellat.
+
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
+quae ab illo inventore veritatis et quasi architecto beatae vitae
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+velit, sed quia non numquam eius modi tempora incidunt ut labore
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
+pariatur?
+
+At vero eos et accusamus et iusto odio dignissimos ducimus qui
+blanditiis praesentium voluptatum deleniti atque corrupti quos
+dolores et quas molestias excepturi sint occaecati cupiditate non
+provident, similique sunt in culpa qui officia deserunt mollitia
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis
+est et expedita distinctio. Nam libero tempore, cum soluta nobis
+est eligendi optio cumque nihil impedit quo minus id quod maxime
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias
+consequatur aut perferendis doloribus asperiores repellat.
diff --git a/postfix/src/cleanup/test-queue-file10 b/postfix/src/cleanup/test-queue-file10
new file mode 100644
index 000000000..f5a7b0194
Binary files /dev/null and b/postfix/src/cleanup/test-queue-file10 differ
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index f3097f91a..49e288d89 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -273,7 +273,7 @@ tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
namadr_list_test mail_conf_time_test
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
- mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3
+ mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
root_tests: rewrite_clnt_test resolve_clnt_test
@@ -337,6 +337,11 @@ mime_garb3: mime_state mime_garb3.in mime_garb3.ref
diff mime_garb3.ref mime_cvt.tmp
rm -f mime_cvt.tmp
+mime_garb4: mime_state mime_garb4.in mime_garb4.ref
+ ./mime_state mime_cvt.tmp
+ diff mime_garb4.ref mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
tok822_limit_test: tok822_parse tok822_limit.in tok822_limit.ref
./tok822_parse tok822_limit.tmp
diff tok822_limit.ref tok822_limit.tmp
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 1bce4ac68..4dac78e6c 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070113"
+#define MAIL_RELEASE_DATE "20070116"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
diff --git a/postfix/src/global/mime_garb3.ref b/postfix/src/global/mime_garb3.ref
index 873ef91fa..ee8ef36b8 100644
--- a/postfix/src/global/mime_garb3.ref
+++ b/postfix/src/global/mime_garb3.ref
@@ -9,7 +9,7 @@ MAIN 95 |Content-Type: Multipart/Mixed;
boundary="Boundary-00=_mvhpFky0yqNhsa4"
HEADER END
mime_state: garbage in primary header
-BODY N -1 |
+BODY N 0 |
BODY N 0 |junk in primary header
BODY N 23 |
BODY N 24 |--Boundary-00=_mvhpFky0yqNhsa4
diff --git a/postfix/src/global/mime_garb4.in b/postfix/src/global/mime_garb4.in
new file mode 100644
index 000000000..16dcfc64e
--- /dev/null
+++ b/postfix/src/global/mime_garb4.in
@@ -0,0 +1,34 @@
+From: Some One
+To: Some One
+Subject: Test
+MIME-Version: 1.0
+Content-Type: Multipart/Mixed;
+ boundary="top-level-boundary"
+
+--top-level-boundary
+Content-Type: message/rfc822;
+ name="forwarded message"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+To: user@example.com
+=46rom: Some One
+Subject: Forwarded Test
+Content-Type: Multipart/Mixed;
+ boundary=3D"nested-level-boundary"
+
+--nested-level-boundary
+Content-Type: text/plain;
+Content-Transfer-Encoding: quoted-printable
+
+Blah
+
+--nested-level-boundary--
+
+--top-level-boundary
+Content-Type: text/plain;
+ charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+This is a test
diff --git a/postfix/src/global/mime_garb4.ref b/postfix/src/global/mime_garb4.ref
new file mode 100644
index 000000000..bd0e5ccda
--- /dev/null
+++ b/postfix/src/global/mime_garb4.ref
@@ -0,0 +1,50 @@
+MAIN 0 |From: Some One
+MAIN 32 |To: Some One
+MAIN 46 |Subject: Test
+MAIN 64 |MIME-Version: 1.0
+mime_state: header_token: Multipart / Mixed
+mime_state: header_token: boundary = top-level-boundary
+mime_state: PUSH boundary top-level-boundary
+MAIN 95 |Content-Type: Multipart/Mixed;
+ boundary="top-level-boundary"
+HEADER END
+BODY N 0 |
+BODY N 1 |--top-level-boundary
+mime_state: header_token: message / rfc822
+MULT 0 |Content-Type: message/rfc822;
+ name="forwarded message"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+mime_state: warning: invalid message/* or multipart/* encoding domain: quoted-printable
+BODY N 0 |
+NEST 0 |To: user@example.com
+NEST 36 |=46rom: Some One
+NEST 60 |Subject: Forwarded Test
+mime_state: header_token: Multipart / Mixed
+mime_state: header_token: boundary = 3D
+mime_state: PUSH boundary 3D
+NEST 91 |Content-Type: Multipart/Mixed;
+ boundary=3D"nested-level-boundary"
+BODY N 0 |
+BODY N 1 |--nested-level-boundary
+BODY N 25 |Content-Type: text/plain;
+BODY N 51 |Content-Transfer-Encoding: quoted-printable
+BODY N 95 |
+BODY N 96 |Blah
+BODY N 101 |
+BODY N 102 |--nested-level-boundary--
+BODY N 128 |
+mime_state: POP boundary 3D
+BODY N 129 |--top-level-boundary
+mime_state: header_token: text / plain
+MULT 0 |Content-Type: text/plain;
+ charset="utf-8"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+BODY N 0 |
+BODY N 1 |This is a test
+BODY END
+mime_state: warning: improper message/* or multipart/* encoding domain
+mime_state: POP boundary top-level-boundary
diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c
index b81fc1f90..4b4bf69f9 100644
--- a/postfix/src/global/mime_state.c
+++ b/postfix/src/global/mime_state.c
@@ -499,6 +499,7 @@ MIME_STATE *mime_state_alloc(int flags,
/* Volatile members. */
state->err_flags = 0;
+ state->body_offset = 0; /* XXX */
SET_MIME_STATE(state, MIME_STATE_PRIMARY,
MIME_CTYPE_TEXT, MIME_STYPE_PLAIN,
MIME_ENC_7BIT, MIME_ENC_7BIT);
@@ -938,6 +939,15 @@ int mime_state_update(MIME_STATE *state, int rec_type,
* messages. Otherwise, treat such headers as part of the "body". Set
* the proper encoding information for the multipart prolog.
*
+ * XXX We parse headers inside message/* content even when the encoding
+ * is invalid (encoding != domain). With base64 we won't recognize
+ * any headers, and with quoted-printable we won't recognize MIME
+ * boundary strings, but the MIME processor will still resynchronize
+ * when it runs into the higher-level boundary string at the end of
+ * the message/* content. Although we will treat some headers as body
+ * text, we will still do a better job than if we were treating the
+ * entire message/* content as body text.
+ *
* XXX This changes state to MIME_STATE_NESTED and then outputs a body
* line, so that the body offset is not properly reset.
*
@@ -973,13 +983,14 @@ int mime_state_update(MIME_STATE *state, int rec_type,
* separator, nor does the Milter protocol pass it on to Milter
* applications.
*
- * XXX We don't insert a blank line separator with attachments, as
- * this breaks digital signatures. Postfix shall not do a worse
- * mail delivery job than crappy MTAs that can't even parse MIME.
- * But we switch to the body state anyway.
+ * XXX We don't insert a blank line separator into attachments, to
+ * avoid breaking digital signatures. Postfix shall not do a
+ * worse mail delivery job than MTAs that can't even parse MIME.
+ * We switch to body state anyway, to avoid treating body text as
+ * header text, and mis-interpreting or truncating it. The code
+ * below for initial From_ lines is for educational purposes.
*
- * People who worry about MIME evasion can use a MIME normalizer,
- * and knowlingly corrupt legitimate email for their users.
+ * Sites concerned about MIME evasion can use a MIME normalizer.
* Postfix has a different mission.
*/
else {
@@ -989,9 +1000,25 @@ int mime_state_update(MIME_STATE *state, int rec_type,
state->curr_state == MIME_STATE_PRIMARY ? "primary" :
state->curr_state == MIME_STATE_NESTED ? "nested" :
"other");
- if (state->curr_state == MIME_STATE_PRIMARY)
+ switch (state->curr_state) {
+ case MIME_STATE_PRIMARY:
BODY_OUT(state, REC_TYPE_NORM, "", 0);
- SET_CURR_STATE(state, MIME_STATE_BODY);
+ SET_CURR_STATE(state, MIME_STATE_BODY);
+ break;
+#if 0
+ case MIME_STATE_NESTED:
+ if (state->body_offset <= 1
+ && rec_type == REC_TYPE_NORM
+ && len > 7
+ && (strncmp(text + (*text == '>'), "From ", 5) == 0
+ || strncmp(text, "=46rom ", 7) == 0))
+ break;
+ /* FALLTHROUGH */
+#endif
+ default:
+ SET_CURR_STATE(state, MIME_STATE_BODY);
+ break;
+ }
}
}
diff --git a/postfix/src/global/rec_type.h b/postfix/src/global/rec_type.h
index bf158f934..cd0873f9e 100644
--- a/postfix/src/global/rec_type.h
+++ b/postfix/src/global/rec_type.h
@@ -121,11 +121,12 @@
*
* See also: REC_TYPE_PTR_FORMAT below.
*/
-#define REC_TYPE_SIZE_FORMAT "%15ld %15ld %15ld %15ld"
-#define REC_TYPE_SIZE_CAST1 long
-#define REC_TYPE_SIZE_CAST2 long /* Postfix 1.0, a.k.a. 20010228 */
-#define REC_TYPE_SIZE_CAST3 long /* Postfix 1.0, a.k.a. 20010228 */
-#define REC_TYPE_SIZE_CAST4 long /* Postfix 2.1 */
+#define REC_TYPE_SIZE_FORMAT "%15ld %15ld %15ld %15ld %15ld"
+#define REC_TYPE_SIZE_CAST1 long /* Vmailer extra offs - data offs */
+#define REC_TYPE_SIZE_CAST2 long /* Postfix 1.0 data offset */
+#define REC_TYPE_SIZE_CAST3 long /* Postfix 1.0 recipient count */
+#define REC_TYPE_SIZE_CAST4 long /* Postfix 2.1 qmgr flags */
+#define REC_TYPE_SIZE_CAST5 long /* Postfix 2.4 content length */
/*
* The warn record specifies when the next warning that the message was
diff --git a/postfix/src/global/record.c b/postfix/src/global/record.c
index 3ef7ca7b5..12dbac4ba 100644
--- a/postfix/src/global/record.c
+++ b/postfix/src/global/record.c
@@ -52,6 +52,10 @@
/* int rec_goto(stream, where)
/* VSTREAM *stream;
/* const char *where;
+/*
+/* REC_SPACE_NEED(buflen, reclen)
+/* ssize_t buflen;
+/* ssize_t reclen;
/* DESCRIPTION
/* This module reads and writes typed variable-length records.
/* Each record contains a 1-byte type code (0..255), a length
@@ -102,6 +106,10 @@
/* the file pointer to the specified location. A zero position
/* means do nothing. The result is REC_TYPE_ERROR in case of
/* failure.
+/*
+/* REC_SPACE_NEED(buflen, reclen) converts the specified buffer
+/* length into a record length. This macro modifies its second
+/* argument.
/* DIAGNOSTICS
/* Panics: interface violations. Fatal errors: insufficient memory.
/* Warnings: corrupted file.
diff --git a/postfix/src/global/record.h b/postfix/src/global/record.h
index 6e75734a3..a5e8b8ced 100644
--- a/postfix/src/global/record.h
+++ b/postfix/src/global/record.h
@@ -41,7 +41,7 @@ extern int rec_goto(VSTREAM *, const char *);
#define REC_PUT_BUF(v, t, b) rec_put((v), (t), vstring_str(b), VSTRING_LEN(b))
-#define REC_FLAG_NONE (0)
+#define REC_FLAG_NONE (0)
#define REC_FLAG_FOLLOW_PTR (1<<0) /* follow PTR records */
#define REC_FLAG_SKIP_DTXT (1<<1) /* skip DTXT records */
#define REC_FLAG_SEEK_END (1<<2) /* seek EOF after END record */
@@ -52,6 +52,13 @@ extern int rec_goto(VSTREAM *, const char *);
#define rec_get(fp, buf, limit) \
rec_get_raw((fp), (buf), (limit), REC_FLAG_DEFAULT)
+#define REC_SPACE_NEED(buflen, reclen) do { \
+ ssize_t _c, _l; \
+ for (_c = 1, _l = (buflen); _l != 0; _l >>= 7U, _c++) \
+ ; \
+ (reclen) = 1 + _c + (buflen); \
+ } while (0)
+
/*
* Stuff that needs
*/
diff --git a/postfix/src/milter/milter.c b/postfix/src/milter/milter.c
index f006ffc71..51f968d80 100644
--- a/postfix/src/milter/milter.c
+++ b/postfix/src/milter/milter.c
@@ -280,7 +280,7 @@ void milter_edit_callback(MILTERS *milters,
const char *(*del_header) (void *, ssize_t, char *),
const char *(*add_rcpt) (void *, char *),
const char *(*del_rcpt) (void *, char *),
- const char *(*repl_body) (void *, VSTRING *),
+ const char *(*repl_body) (void *, int, VSTRING *),
void *chg_context)
{
milters->add_header = add_header;
diff --git a/postfix/src/milter/milter.h b/postfix/src/milter/milter.h
index 9e480193a..676322d4a 100644
--- a/postfix/src/milter/milter.h
+++ b/postfix/src/milter/milter.h
@@ -67,7 +67,7 @@ typedef struct MILTERS {
const char *(*ins_header) (void *, ssize_t, char *, char *);
const char *(*add_rcpt) (void *, char *);
const char *(*del_rcpt) (void *, char *);
- const char *(*repl_body) (void *, VSTRING *);
+ const char *(*repl_body) (void *, int, VSTRING *);
} MILTERS;
typedef const char *(*MILTER_MAC_LOOKUP_FN) (const char *, void *);
@@ -75,7 +75,7 @@ typedef const char *(*MILTER_ADD_HEADER_FN) (void *, char *, char *);
typedef const char *(*MILTER_EDIT_HEADER_FN) (void *, ssize_t, char *, char *);
typedef const char *(*MILTER_DEL_HEADER_FN) (void *, ssize_t, char *);
typedef const char *(*MILTER_EDIT_RCPT_FN) (void *, char *);
-typedef const char *(*MILTER_EDIT_BODY_FN) (void *, VSTRING *);
+typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, VSTRING *);
extern MILTERS *milter_create(const char *, int, int, int,
const char *, const char *,
@@ -103,6 +103,13 @@ extern int milter_send(MILTERS *, VSTREAM *);
extern MILTERS *milter_receive(VSTREAM *, int);
extern void milter_free(MILTERS *);
+ /*
+ * Milter body edit commands.
+ */
+#define MILTER_BODY_START 1 /* start message body */
+#define MILTER_BODY_LINE 2 /* message body line */
+#define MILTER_BODY_END 3 /* end message body */
+
/*
* Sendmail 8 macro names. We support forms with and without the {}.
*/
diff --git a/postfix/src/milter/milter8.c b/postfix/src/milter/milter8.c
index 96f637b49..2ccd7e749 100644
--- a/postfix/src/milter/milter8.c
+++ b/postfix/src/milter/milter8.c
@@ -196,6 +196,7 @@
/* Global library. */
+#include /* var_line_limit */
#include
#include
#include
@@ -866,9 +867,12 @@ static const char *milter8_event(MILTER8 *milter, int event,
ssize_t data_size;
const char *smfic_name;
const char *smfir_name;
- MILTERS *parent;
+ MILTERS *parent = milter->m.parent;
UINT32_TYPE index;
- const char *edit_resp;
+ const char *edit_resp = 0;
+ const char *retval = 0;
+ VSTRING *body_line_buf = 0;
+ int done = 0;
#define DONT_SKIP_REPLY 0
@@ -970,17 +974,30 @@ static const char *milter8_event(MILTER8 *milter, int event,
/*
* Receive the reply or replies.
*
+ * Intercept all loop exits so that we can do post body replacement
+ * processing.
+ *
* XXX Bound the loop iteration count.
*/
#define IN_CONNECT_EVENT(e) ((e) == SMFIC_CONNECT || (e) == SMFIC_HELO)
- for (;;) {
+ /*
+ * XXX Don't evaluate this macro's argument multiple times. Since we use
+ * "continue" the macro can't be enclosed in do .. while (0).
+ */
+#define MILTER8_EVENT_BREAK(s) { \
+ retval = (s); \
+ done = 1; \
+ continue; \
+ }
+
+ while (done == 0) {
char *cp;
char *rp;
char ch;
if (milter8_read_resp(milter, event, &cmd, &data_size) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if (msg_verbose)
msg_info("reply: %s data %ld bytes",
(smfir_name = str_name_code(smfir_table, cmd)) != 0 ?
@@ -1001,7 +1018,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
case SMFIR_CONTINUE:
if (data_size != 0)
break;
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
/*
* Decision: accept this message, or accept all further commands
@@ -1021,7 +1038,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
/* No more events for this message. */
milter->state = MILTER8_STAT_ACCEPT_MSG;
}
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
/*
* Decision: accept and silently discard this message. According
@@ -1036,11 +1053,11 @@ static const char *milter8_event(MILTER8 *milter, int event,
msg_warn("milter %s: DISCARD action is not allowed "
"for connect or helo", milter->m.name);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
} else {
/* No more events for this message. */
milter->state = MILTER8_STAT_ACCEPT_MSG;
- return ("D");
+ MILTER8_EVENT_BREAK("D");
}
/*
@@ -1055,9 +1072,9 @@ static const char *milter8_event(MILTER8 *milter, int event,
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, "550 5.7.1 Command rejected"));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, "550 5.7.1 Command rejected"));
} else {
- return ("550 5.7.1 Command rejected");
+ MILTER8_EVENT_BREAK("550 5.7.1 Command rejected");
}
/*
@@ -1072,10 +1089,10 @@ static const char *milter8_event(MILTER8 *milter, int event,
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter,
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter,
"451 4.7.1 Service unavailable - try again later"));
} else {
- return ("451 4.7.1 Service unavailable - try again later");
+ MILTER8_EVENT_BREAK("451 4.7.1 Service unavailable - try again later");
}
/*
@@ -1090,7 +1107,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, "S"));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, "S"));
#endif
/*
@@ -1107,7 +1124,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if ((STR(milter->buf)[0] != '4' && STR(milter->buf)[0] != '5')
|| !ISDIGIT(STR(milter->buf)[1])
|| !ISDIGIT(STR(milter->buf)[2])
@@ -1116,7 +1133,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
msg_warn("milter %s: malformed reply: %s",
milter->m.name, STR(milter->buf));
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if ((rp = cp = strchr(STR(milter->buf), '%')) != 0) {
for (;;) {
@@ -1132,9 +1149,9 @@ static const char *milter8_event(MILTER8 *milter, int event,
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, STR(milter->buf)));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, STR(milter->buf)));
} else {
- return (STR(milter->buf));
+ MILTER8_EVENT_BREAK(STR(milter->buf));
}
/*
@@ -1148,8 +1165,8 @@ static const char *milter8_event(MILTER8 *milter, int event,
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- return ("H");
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ MILTER8_EVENT_BREAK("H");
#endif
/*
@@ -1170,8 +1187,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
/* XXX Sendmail 8 compatibility. */
if (index == 0)
index = 1;
@@ -1179,13 +1195,13 @@ static const char *milter8_event(MILTER8 *milter, int event,
msg_warn("milter %s: bad change header index: %ld",
milter->m.name, (long) index);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if (LEN(milter->buf) == 0) {
msg_warn("milter %s: null change header name",
milter->m.name);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if (STR(milter->body)[0])
edit_resp = parent->upd_header(parent->chg_context,
@@ -1197,7 +1213,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
(ssize_t) index,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
#endif
@@ -1209,13 +1225,12 @@ static const char *milter8_event(MILTER8 *milter, int event,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->add_header(parent->chg_context,
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
@@ -1231,20 +1246,19 @@ static const char *milter8_event(MILTER8 *milter, int event,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if ((ssize_t) index + 1 < 1) {
msg_warn("milter %s: bad insert header index: %ld",
milter->m.name, (long) index);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
- parent = milter->m.parent;
edit_resp = parent->ins_header(parent->chg_context,
(ssize_t) index + 1,
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
#endif
@@ -1255,12 +1269,11 @@ static const char *milter8_event(MILTER8 *milter, int event,
if (milter8_read_data(milter, data_size,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->add_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
@@ -1270,31 +1283,47 @@ static const char *milter8_event(MILTER8 *milter, int event,
if (milter8_read_data(milter, data_size,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->del_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
* Modification request: replace the message body, and
* update the message size.
*/
-#if 0
case SMFIR_REPLBODY:
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
- edit_resp = parent->repl_body(parent->chg_context,
- milter->body);
- if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ /* Start body replacement. */
+ if (body_line_buf == 0) {
+ body_line_buf = vstring_alloc(var_line_limit);
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_START,
+ (VSTRING *) 0);
+ }
+ /* Extract lines from the on-the-wire CRLF format. */
+ for (cp = STR(milter->body); edit_resp == 0
+ && cp < vstring_end(milter->body); cp++) {
+ ch = *(unsigned char *) cp;
+ if (ch == '\n') {
+ if (LEN(body_line_buf) > 0
+ && vstring_end(body_line_buf)[-1] == '\r')
+ vstring_truncate(body_line_buf,
+ LEN(body_line_buf) - 1);
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_LINE,
+ body_line_buf);
+ VSTRING_RESET(body_line_buf);
+ } else {
+ VSTRING_ADDCH(body_line_buf, ch);
+ }
+ }
continue;
-#endif
}
}
msg_warn("milter %s: unexpected filter response %s after event %s",
@@ -1304,7 +1333,7 @@ static const char *milter8_event(MILTER8 *milter, int event,
(smfic_name = str_name_code(smfic_table, event)) != 0 ?
smfic_name : "(unknown MTA event)");
milter8_comm_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
/*
@@ -1315,8 +1344,40 @@ static const char *milter8_event(MILTER8 *milter, int event,
milter->m.name, (smfir_name = str_name_code(smfir_table, cmd)) != 0 ?
smfir_name : "unknown", (long) data_len);
milter8_comm_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ }
+
+ /*
+ * Finish message body replacement.
+ */
+ if (body_line_buf != 0) {
+ if (edit_resp == 0) {
+ /* In case the last body replacement line didn't end in CRLF. */
+ if (LEN(body_line_buf) > 0)
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_LINE,
+ body_line_buf);
+ if (edit_resp == 0)
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_END,
+ (VSTRING *) 0);
+ }
+ vstring_free(body_line_buf);
+
+ /*
+ * Override a non-reject/discard result value after body replacement
+ * failure.
+ *
+ * XXX Some cleanup clients ask the cleanup server to bounce mail for
+ * them. In that case we must override a hard reject retval result
+ * after queue file update failure. This is not a big problem; the
+ * odds are small that a Milter application sends a hard reject after
+ * replacing the message body.
+ */
+ if (edit_resp && (retval == 0 || strchr("DS4", retval[0]) == 0))
+ retval = edit_resp;
}
+ return (retval);
}
/* milter8_connect - connect to filter */
@@ -1332,7 +1393,7 @@ static void milter8_connect(MILTER8 *milter)
int fd;
const UINT32_TYPE my_actions = (SMFIF_ADDHDRS | SMFIF_ADDRCPT
| SMFIF_DELRCPT | SMFIF_CHGHDRS
- /* Not yet: | SMFIF_CHGBODY */
+ | SMFIF_CHGBODY
#ifdef SMFIF_QUARANTINE
| SMFIF_QUARANTINE
#endif
@@ -1651,6 +1712,7 @@ static const char *milter8_helo_event(MILTER *m, const char *helo_name,
return (milter->def_reply);
case MILTER8_STAT_ENVELOPE:
case MILTER8_STAT_ACCEPT_MSG:
+ /* With HELO after MAIL, smtpd(8) calls milter8_abort() next. */
if (msg_verbose)
msg_info("%s: milter %s: helo %s",
myname, milter->m.name, helo_name);
diff --git a/postfix/src/milter/test-milter.c b/postfix/src/milter/test-milter.c
index ad76eb800..ba7289f66 100644
--- a/postfix/src/milter/test-milter.c
+++ b/postfix/src/milter/test-milter.c
@@ -1,34 +1,52 @@
- /*
- * Simple test mail filter program.
- *
- * Options:
- *
- * -a accept|tempfail|reject|discard|ddd x.y.z text
- *
- * Specifies a non-default reply. The default is to always continue.
- *
- * -d Enable libmilter debugging.
- *
- * -c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort
- *
- * When to send the non-default reply. The default is "connect".
- *
- * -i "index header-label header-value"
- *
- * Insert header at specified position.
- *
- * -p inet:port@host|unix:/path/name
- *
- * The mail filter listen endpoint.
- *
- * -r "index header-label header-value"
- *
- * Replace header at specified position.
- *
- * -C count
- *
- * Terminate after count connections.
- */
+/*++
+/* NAME
+/* test-milter 1
+/* SUMMARY
+/* Simple test mail filter program.
+/* SYNOPSIS
+/* .fi
+/* \fBtest-milter\fR [\fIoptions\fR] -p \fBinet:\fIport\fB@\fIhost\fR
+/*
+/* \fBtest-milter\fR [\fIoptions\fR] -p \fBunix:\fIpathname\fR
+/* DESCRIPTION
+/* \fBtest-milter\fR is a Milter (mail filter) application that
+/* exercises selected features.
+/*
+/* Note: this is an unsupported test program. No attempt is made
+/* to maintain compatibility between successive versions.
+/*
+/* Arguments (multiple alternatives are separated by "\fB|\fR"):
+/* .IP "\fB-a accept|tempfail|reject|discard|\fIddd x.y.z text\fR"
+/* Specifies a non-default reply. The default is to continue
+/* (i.e. \fBtempfail\fR).
+/* .IP "\fB-d\fI level\fR"
+/* Enable libmilter debugging at the specified level.
+/* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
+/* When to send the non-default reply specified with \fB-a\fR.
+/* The default protocol stage is \fBconnect\fR.
+/* .IP "\fB-C\fI count\fR"
+/* Terminate after \fIcount\fR connections.
+/* .IP "\fB-i \"\fIindex header-label header-value\"\fR"
+/* Insert header at specified position.
+/* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR"
+/* The mail filter listen endpoint.
+/* .IP "\fB-r "index header-label header-value"
+/* Replace the message header at the specified position.
+/* .IP "\fB-R pathname
+/* Replace the message body by the content of the specified file.
+/* .IP "\fB-v\fR"
+/* Make the program more verbose.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
#include
#include
#include
@@ -110,12 +128,17 @@ static char *chg_val;
#endif
+#ifdef SMFIR_REPLBODY
+static char *body_file;
+
+#endif
+
static int test_reply(SMFICTX *ctx, int code)
{
(void) fflush(stdout); /* In case output redirected. */
if (code == SMFIR_REPLYCODE) {
- if (smfi_setreply(ctx, reply_code, reply_dsn, reply_message) != MI_SUCCESS)
+ if (smfi_setreply(ctx, reply_code, reply_dsn, reply_message) == MI_FAILURE)
fprintf(stderr, "smfi_setreply failed\n");
return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT);
} else {
@@ -227,6 +250,34 @@ static sfsistat test_eom(SMFICTX *ctx)
#ifdef SMFIR_CHGHEADER
if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
fprintf(stderr, "smfi_chgheader failed");
+#endif
+#ifdef SMFIR_REPLBODY
+ if (body_file) {
+ char buf[BUFSIZ + 2];
+ FILE *fp;
+ size_t len;
+ int count;
+
+ if ((fp = fopen(body_file, "r")) == 0) {
+ perror(body_file);
+ } else {
+ printf("replace body with content of %s\n", body_file);
+ for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
+ len = strcspn(buf, "\n");
+ buf[len+0] = '\r';
+ buf[len+1] = '\n';
+ if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
+ fprintf(stderr, "body replace failure\n");
+ exit(1);
+ }
+ if (verbose)
+ printf("%.*s\n", (int) len, buf);
+ }
+ if (count == 0)
+ perror("fgets");
+ (void) fclose(fp);
+ }
+ }
#endif
return (test_reply(ctx, test_eom_reply));
}
@@ -271,7 +322,7 @@ static struct smfiDesc smfilter =
{
"test-milter",
SMFI_VERSION,
- SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS,
+ SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS | SMFIF_CHGBODY,
test_connect,
test_helo,
test_mail,
@@ -314,7 +365,7 @@ int main(int argc, char **argv)
int ch;
int code;
- while ((ch = getopt(argc, argv, "a:c:d:i:p:r:vC:")) > 0) {
+ while ((ch = getopt(argc, argv, "a:c:C:d:i:p:r:R:v")) > 0) {
switch (ch) {
case 'a':
action = optarg;
@@ -364,6 +415,15 @@ int main(int argc, char **argv)
case 'C':
conn_count = atoi(optarg);
break;
+#ifdef SMFIR_REPLBODY
+ case 'R':
+ if (body_file) {
+ fprintf(stderr, "too many -R options\n");
+ exit(1);
+ }
+ body_file = optarg;
+#endif
+ break;
default:
fprintf(stderr,
"usage: %s [-dv] \n"
@@ -373,6 +433,7 @@ int main(int argc, char **argv)
"\t-p port milter application\n"
"\t[-r 'index label value'] replace header\n"
"\t[-C conn_count] when to exit\n",
+ "\t[-R body_text] replace body\n",
argv[0]);
exit(1);
}
diff --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h
index 73744c5d8..20f8c3a18 100644
--- a/postfix/src/oqmgr/qmgr.h
+++ b/postfix/src/oqmgr/qmgr.h
@@ -230,7 +230,8 @@ struct QMGR_MESSAGE {
char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
char *redirect_addr; /* info@spammer.tld */
- long data_size; /* message content size */
+ long data_size; /* data segment size */
+ long cont_length; /* message content length */
long rcpt_offset; /* more recipients here */
char *client_name; /* client hostname */
char *client_addr; /* client address */
diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c
index 8d3b682ab..7e06b5dc5 100644
--- a/postfix/src/oqmgr/qmgr_deliver.c
+++ b/postfix/src/oqmgr/qmgr_deliver.c
@@ -158,7 +158,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->cont_length,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c
index 8e56e56e4..a646daef9 100644
--- a/postfix/src/oqmgr/qmgr_message.c
+++ b/postfix/src/oqmgr/qmgr_message.c
@@ -172,6 +172,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
message->inspect_xport = 0;
message->redirect_addr = 0;
message->data_size = 0;
+ message->cont_length = 0;
message->warn_offset = 0;
message->warn_time = 0;
message->rcpt_offset = 0;
@@ -506,9 +507,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
continue;
if (rec_type == REC_TYPE_SIZE) {
if (message->data_offset == 0) {
- if ((count = sscanf(start, "%ld %ld %d %d",
+ if ((count = sscanf(start, "%ld %ld %d %d %ld",
&message->data_size, &message->data_offset,
- &nrcpt, &message->rflags)) >= 3) {
+ &nrcpt, &message->rflags,
+ &message->cont_length)) >= 3) {
/* Postfix >= 1.0 (a.k.a. 20010228). */
if (message->data_offset <= 0 || message->data_size <= 0) {
msg_warn("%s: invalid size record: %.100s",
@@ -533,6 +535,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
break;
}
}
+ /* Postfix < 2.4 compatibility. */
+ if (message->cont_length == 0) {
+ message->cont_length = message->data_size;
+ } else if (message->cont_length < 0) {
+ msg_warn("%s: invalid size record: %.100s",
+ message->queue_id, start);
+ rec_type = REC_TYPE_ERROR;
+ break;
+ }
continue;
}
if (rec_type == REC_TYPE_TIME) {
@@ -567,7 +578,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
if (message->sender == 0) {
message->sender = mystrdup(start);
opened(message->queue_id, message->sender,
- message->data_size, nrcpt,
+ message->cont_length, nrcpt,
"queue %s", message->queue_name);
}
continue;
diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h
index 5582ef81a..f4b354602 100644
--- a/postfix/src/qmgr/qmgr.h
+++ b/postfix/src/qmgr/qmgr.h
@@ -139,7 +139,8 @@ struct QMGR_TRANSPORT {
int rcpt_per_stack; /* extra slots reserved for jobs put
* on the job stack */
int rcpt_unused; /* available in-core recipient slots */
- int refill_limit; /* recipient batch size for message refill */
+ int refill_limit; /* recipient batch size for message
+ * refill */
int refill_delay; /* delay before message refill */
int slot_cost; /* cost of new preemption slot (# of
* selected entries) */
@@ -259,7 +260,8 @@ struct QMGR_MESSAGE {
struct timeval active_time; /* time of entry into active queue */
time_t queued_time; /* sanitized time when moved to the
* active queue */
- time_t refill_time; /* sanitized time of last message refill */
+ time_t refill_time; /* sanitized time of last message
+ * refill */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warning to be sent */
long data_offset; /* data seek offset */
@@ -273,7 +275,8 @@ struct QMGR_MESSAGE {
char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
char *redirect_addr; /* info@spammer.tld */
- long data_size; /* message content size */
+ long data_size; /* data segment size */
+ long cont_length; /* message content length */
long rcpt_offset; /* more recipients here */
char *client_name; /* client hostname */
char *client_addr; /* client address */
diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c
index c0589e16d..2785e59a9 100644
--- a/postfix/src/qmgr/qmgr_deliver.c
+++ b/postfix/src/qmgr/qmgr_deliver.c
@@ -163,7 +163,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->cont_length,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c
index ae0dd174d..9be26ec1c 100644
--- a/postfix/src/qmgr/qmgr_message.c
+++ b/postfix/src/qmgr/qmgr_message.c
@@ -183,6 +183,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
message->inspect_xport = 0;
message->redirect_addr = 0;
message->data_size = 0;
+ message->cont_length = 0;
message->warn_offset = 0;
message->warn_time = 0;
message->rcpt_offset = 0;
@@ -547,9 +548,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
continue;
if (rec_type == REC_TYPE_SIZE) {
if (message->data_offset == 0) {
- if ((count = sscanf(start, "%ld %ld %d %d",
+ if ((count = sscanf(start, "%ld %ld %d %d %ld",
&message->data_size, &message->data_offset,
- &message->rcpt_unread, &message->rflags)) >= 3) {
+ &message->rcpt_unread, &message->rflags,
+ &message->cont_length)) >= 3) {
/* Postfix >= 1.0 (a.k.a. 20010228). */
if (message->data_offset <= 0 || message->data_size <= 0) {
msg_warn("%s: invalid size record: %.100s",
@@ -574,6 +576,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
break;
}
}
+ /* Postfix < 2.4 compatibility. */
+ if (message->cont_length == 0) {
+ message->cont_length = message->data_size;
+ } else if (message->cont_length < 0) {
+ msg_warn("%s: invalid size record: %.100s",
+ message->queue_id, start);
+ rec_type = REC_TYPE_ERROR;
+ break;
+ }
continue;
}
if (rec_type == REC_TYPE_TIME) {
@@ -608,7 +619,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
if (message->sender == 0) {
message->sender = mystrdup(start);
opened(message->queue_id, message->sender,
- message->data_size, message->rcpt_unread,
+ message->cont_length, message->rcpt_unread,
"queue %s", message->queue_name);
}
continue;
diff --git a/postfix/src/smtpd/smtpd_exp.ref b/postfix/src/smtpd/smtpd_exp.ref
index 75b6c84f3..c04381ba8 100644
--- a/postfix/src/smtpd/smtpd_exp.ref
+++ b/postfix/src/smtpd/smtpd_exp.ref
@@ -107,8 +107,8 @@ OK
>>> mail sname@sdomain
OK
>>> rcpt rname@rdomain
-./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld; from= to= proto=SMTP helo=
-554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld
+./smtpd_check: : reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain; from= to= proto=SMTP helo=
+554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain
>>> #
>>> # Check MX access
>>> #