processes. See also change 20060217. Files: postlock/postlock.c,
master/multi_server.c, global/mail_run.c, util/vstream_popen.c.
+20060310
+
+ Bugfix: the MIME processor assumed that input was null
+ terminated. This broke with CRLF input to the "sendmail -t"
+ command in Postfix 2.1 and later (see change 20030416).
+ Found by Leandro Santi. Based on patch by Victor Duchovni.
+ Files: global/mime_state.c, global/is_header.c.
+
+20060313
+
+ Cleanup: the message arrival time (start of the receive
+ transaction) no longer controls message expiration or
+ delivery attempts. Instead, expiration and delivery are
+ now controlled by the time when the cleanup server creates
+ a queue file. This closes a problem that was introduced
+ with the 20051104 change that introduced higher-resolution
+ delay time keeping: as a result, "postsuper -r" could no
+ longer manipulate the mail expiration schedule, so that
+ mail "on hold" could expire too soon.
+
Wish list:
+ The sendmail command should not return non-std exit status
+ after fatal error in some internal library routine.
+
Log DSN original recipient when rejecting mail.
Keep whitespace between label and ":"?
dsb_formal -> dsb_form_all, dsb_status -> dsb_form_status
- "postsuper -r" no longer resets the message arrival time,
- because pickup(8) no longer overrides queue file time stamp
- information. This can be a problem when mail "on hold" is
- released after a long time.
-
Is it safe to cache a connection after it has been used for
more than some number of address verification probes?
Options:
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- The <b>main.cf</b> configuration file is in the named
+ The <a href="postconf.5.html"><b>main.cf</b></a> configuration file is in the named
directory instead of the default configuration
directory.
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program.
The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
The location of the Postfix top-level queue direc-
cleanup_bounce.o: ../../include/deliver_request.h
cleanup_bounce.o: ../../include/dict.h
cleanup_bounce.o: ../../include/dsn.h
-cleanup_bounce.o: ../../include/dsn_attr_map.h
cleanup_bounce.o: ../../include/dsn_buf.h
cleanup_bounce.o: ../../include/dsn_mask.h
cleanup_bounce.o: ../../include/dsn_util.h
cleanup_bounce.o: ../../include/msg_stats.h
cleanup_bounce.o: ../../include/mymalloc.h
cleanup_bounce.o: ../../include/nvtable.h
+cleanup_bounce.o: ../../include/rec_attr_map.h
cleanup_bounce.o: ../../include/rec_type.h
cleanup_bounce.o: ../../include/recipient_list.h
cleanup_bounce.o: ../../include/record.h
cleanup_envelope.o: ../../include/been_here.h
cleanup_envelope.o: ../../include/cleanup_user.h
cleanup_envelope.o: ../../include/dict.h
-cleanup_envelope.o: ../../include/dsn_attr_map.h
cleanup_envelope.o: ../../include/dsn_mask.h
cleanup_envelope.o: ../../include/header_opts.h
cleanup_envelope.o: ../../include/htable.h
cleanup_envelope.o: ../../include/mymalloc.h
cleanup_envelope.o: ../../include/nvtable.h
cleanup_envelope.o: ../../include/qmgr_user.h
+cleanup_envelope.o: ../../include/rec_attr_map.h
cleanup_envelope.o: ../../include/rec_type.h
cleanup_envelope.o: ../../include/record.h
cleanup_envelope.o: ../../include/resolve_clnt.h
cleanup_extracted.o: ../../include/been_here.h
cleanup_extracted.o: ../../include/cleanup_user.h
cleanup_extracted.o: ../../include/dict.h
-cleanup_extracted.o: ../../include/dsn_attr_map.h
cleanup_extracted.o: ../../include/dsn_mask.h
cleanup_extracted.o: ../../include/header_opts.h
cleanup_extracted.o: ../../include/htable.h
cleanup_extracted.o: ../../include/mymalloc.h
cleanup_extracted.o: ../../include/nvtable.h
cleanup_extracted.o: ../../include/qmgr_user.h
+cleanup_extracted.o: ../../include/rec_attr_map.h
cleanup_extracted.o: ../../include/rec_type.h
cleanup_extracted.o: ../../include/record.h
cleanup_extracted.o: ../../include/resolve_clnt.h
#include <rec_type.h>
#include <dsn_mask.h>
#include <mail_queue.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Application-specific. */
if (split_nameval(STR(buf), &attr_name, &attr_value) != 0
|| *attr_value == 0)
continue;
- /* Map DSN attribute names to pseudo record type. */
- if ((junk = dsn_attr_map(attr_name)) != 0) {
+ /* Map attribute names to pseudo record type. */
+ if ((junk = rec_attr_map(attr_name)) != 0) {
start = attr_value;
rec_type = junk;
}
#include <verp_sender.h>
#include <mail_proto.h>
#include <dsn_mask.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Application-specific. */
state->flags |= extra_opts;
return;
}
-
#ifdef DELAY_ACTION
if (type == REC_TYPE_DELAY) {
/* Not part of queue file format. */
state->queue_id, attr_name);
return;
}
- if ((junk = dsn_attr_map(attr_name)) != 0) {
+ if ((junk = rec_attr_map(attr_name)) != 0) {
mapped_buf = attr_value;
mapped_type = junk;
}
if (type == REC_TYPE_SIZE)
/* Use our own SIZE record instead. */
return;
+ if (mapped_type == REC_TYPE_CTIME)
+ /* Use our own expiration time base record instead. */
+ return;
if (type == REC_TYPE_TIME) {
/* First instance wins. */
if (state->arrival_time.tv_sec == 0) {
REC_TYPE_TIME_SCAN(buf, state->arrival_time);
cleanup_out(state, type, buf, len);
}
+ /* Generate our own expiration time base record. */
+ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%ld",
+ MAIL_ATTR_CREATE_TIME, (long) time((time_t *) 0));
return;
}
if (type == REC_TYPE_FULL) {
#include <mail_params.h>
#include <mail_proto.h>
#include <dsn_mask.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Application-specific. */
state->queue_id, attr_name);
return;
}
- if ((junk = dsn_attr_map(attr_name)) != 0) {
+ if ((junk = rec_attr_map(attr_name)) != 0) {
buf = attr_value;
type = junk;
}
scache_clnt.c scache_multi.c user_acl.c mkmap_cdb.c mkmap_sdbm.c \
ehlo_mask.c \
wildcard_inet_addr.c valid_mailhost_addr.c dsn_util.c dsn_mask.c \
- dsn_attr_map.c dsn.c dsn_buf.c rcpt_buf.c rcpt_print.c dsn_print.c \
+ rec_attr_map.c dsn.c dsn_buf.c rcpt_buf.c rcpt_print.c dsn_print.c \
dsb_scan.c mail_conf_long.c msg_stats_print.c msg_stats_scan.c \
conv_time.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
scache_clnt.o scache_multi.o user_acl.o mkmap_cdb.o mkmap_sdbm.o \
ehlo_mask.o \
wildcard_inet_addr.o valid_mailhost_addr.o dsn_util.o dsn_mask.o \
- dsn_attr_map.o dsn.o dsn_buf.o rcpt_buf.o rcpt_print.o dsn_print.o \
+ rec_attr_map.o dsn.o dsn_buf.o rcpt_buf.o rcpt_print.o dsn_print.o \
dsb_scan.o mail_conf_long.o msg_stats_print.o msg_stats_scan.o \
conv_time.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
trace.h verify.h verify_clnt.h verp_sender.h \
xtext.h scache.h user_acl.h ehlo_mask.h db_common.h \
wildcard_inet_addr.h valid_mailhost_addr.h dsn_util.h dsn_mask.h \
- dsn_attr_map.h dsn.h dsn_buf.h rcpt_buf.h rcpt_print.h dsn_print.h \
+ rec_attr_map.h dsn.h dsn_buf.h rcpt_buf.h rcpt_print.h dsn_print.h \
dsb_scan.h msg_stats.h conv_time.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
dsn.o: ../../include/sys_defs.h
dsn.o: dsn.c
dsn.o: dsn.h
-dsn_attr_map.o: ../../include/attr.h
-dsn_attr_map.o: ../../include/iostuff.h
-dsn_attr_map.o: ../../include/sys_defs.h
-dsn_attr_map.o: ../../include/vbuf.h
-dsn_attr_map.o: ../../include/vstream.h
-dsn_attr_map.o: dsn_attr_map.c
-dsn_attr_map.o: dsn_attr_map.h
-dsn_attr_map.o: mail_proto.h
-dsn_attr_map.o: rec_type.h
dsn_buf.o: ../../include/msg.h
dsn_buf.o: ../../include/mymalloc.h
dsn_buf.o: ../../include/sys_defs.h
rec2stream.o: rec_streamlf.h
rec2stream.o: rec_type.h
rec2stream.o: record.h
+rec_attr_map.o: ../../include/attr.h
+rec_attr_map.o: ../../include/iostuff.h
+rec_attr_map.o: ../../include/sys_defs.h
+rec_attr_map.o: ../../include/vbuf.h
+rec_attr_map.o: ../../include/vstream.h
+rec_attr_map.o: mail_proto.h
+rec_attr_map.o: rec_attr_map.c
+rec_attr_map.o: rec_attr_map.h
+rec_attr_map.o: rec_type.h
rec_streamlf.o: ../../include/sys_defs.h
rec_streamlf.o: ../../include/vbuf.h
rec_streamlf.o: ../../include/vstream.h
/* SYNOPSIS
/* #include <is_header.h>
/*
-/* int is_header(string)
+/* ssize_t is_header(string)
/* const char *string;
+/*
+/* ssize_t is_header_buf(string, len)
+/* const char *string;
+/* ssize_t len;
/* DESCRIPTION
/* is_header() examines the given string and returns non-zero (true)
/* when it begins with a mail header name + optional space + colon.
/* The result is the length of the mail header name.
+/*
+/* is_header_buf() is a more elaborate interface for use with strings
+/* that may not be null terminated.
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* LICENSE
#include "is_header.h"
-/* is_header - determine if this can be a header line */
+/* is_header_buf - determine if this can be a header line */
-int is_header(const char *str)
+ssize_t is_header_buf(const char *str, ssize_t str_len)
{
const unsigned char *cp;
int state;
int c;
- int len;
+ ssize_t len;
#define INIT 0
#define IN_CHAR 1
/*
* XXX RFC 2822 Section 4.5, Obsolete header fields: whitespace may
* appear between header label and ":" (see: RFC 822, Section 3.4.2.).
+ *
+ * XXX Don't run off the end in case some non-standard iscntrl()
+ * implementation considers null a non-control character...
*/
- for (len = 0, state = INIT, cp = CU_CHAR_PTR(str); (c = *cp) != 0; cp++) {
- switch (c) {
+ for (len = 0, state = INIT, cp = CU_CHAR_PTR(str); /* see below */; cp++) {
+ if (str_len != IS_HEADER_NULL_TERMINATED && str_len-- <= 0)
+ return (0);
+ switch (c = *cp) {
default:
- if (!ISASCII(c) || ISCNTRL(c))
+ if (c == 0 || !ISASCII(c) || ISCNTRL(c))
return (0);
if (state == INIT)
state = IN_CHAR;
/* External interface. */
-extern int is_header(const char *);
+#define IS_HEADER_NULL_TERMINATED (-1)
+#define is_header(str) is_header_buf(str, IS_HEADER_NULL_TERMINATED)
+
+extern ssize_t is_header_buf(const char *, ssize_t);
/* LICENSE
/* .ad
-10 seconds = 1
+10 seconds = 10
10 minutes = 600
10 hours = 36000
10 days = 864000
#define MAIL_ATTR_ERRTO "errors-to"
#define MAIL_ATTR_RRCPT "return-receipt"
#define MAIL_ATTR_TIME "time"
+#define MAIL_ATTR_CREATE_TIME "create_time"
#define MAIL_ATTR_RULE "rule"
#define MAIL_ATTR_ADDR "address"
#define MAIL_ATTR_TRANSPORT "transport"
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20060307"
+#define MAIL_RELEASE_DATE "20060313"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT
if (input_is_text) {
if (state->prev_rec_type == REC_TYPE_CONT) {
if (LEN(state->output_buffer) < var_header_limit) {
- vstring_strcat(state->output_buffer, text);
+ vstring_strncat(state->output_buffer, text, len);
} else {
if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER)
REPORT_ERROR(state, MIME_ERR_TRUNC_HEADER,
if (IS_SPACE_TAB(*text)) {
if (LEN(state->output_buffer) < var_header_limit) {
vstring_strcat(state->output_buffer, "\n");
- vstring_strcat(state->output_buffer, text);
+ vstring_strncat(state->output_buffer, text, len);
} else {
if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER)
REPORT_ERROR(state, MIME_ERR_TRUNC_HEADER,
* clean slate.
*/
if (input_is_text) {
- int header_len;
+ ssize_t header_len;
/*
* See if this input is (the beginning of) a message header.
+ *
* Normalize obsolete "name space colon" syntax to "name colon".
* Things would be too confusing otherwise.
+ *
+ * Don't assume that the input is null terminated.
*/
- if ((header_len = is_header(text)) > 0) {
+ if ((header_len = is_header_buf(text, len)) > 0) {
vstring_strncpy(state->output_buffer, text, header_len);
- for (text += header_len; IS_SPACE_TAB(*text); text++)
+ for (text += header_len, len -= header_len;
+ len > 0 && IS_SPACE_TAB(*text);
+ text++, len--)
/* void */ ;
- vstring_strcat(state->output_buffer, text);
+ vstring_strncat(state->output_buffer, text, len);
SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type);
}
}
*
* XXX This changes state to MIME_STATE_NESTED and then outputs a body
* line, so that the body offset is not properly reset.
+ *
+ * Don't assume that the input is null terminated.
*/
if (input_is_text) {
- if (*text == 0) {
+ if (len == 0) {
state->body_offset = 0; /* XXX */
if (state->curr_ctype == MIME_CTYPE_MESSAGE) {
if (state->curr_stype == MIME_STYPE_RFC822
* string.
*
* Don't look for boundary strings at the start of a continued record.
+ *
+ * Don't assume that the input is null terminated.
*/
case MIME_STATE_BODY:
if (input_is_text) {
}
}
if (state->stack && state->prev_rec_type != REC_TYPE_CONT
- && text[0] == '-' && text[1] == '-') {
+ && len > 2 && text[0] == '-' && text[1] == '-') {
for (sp = state->stack; sp != 0; sp = sp->next) {
- if (strncmp(text + 2, sp->boundary, sp->bound_len) == 0) {
+ if (len >= 2 + sp->bound_len &&
+ strncmp(text + 2, sp->boundary, sp->bound_len) == 0) {
while (sp != state->stack)
mime_state_pop(state);
- if (strncmp(text + 2 + sp->bound_len, "--", 2) == 0) {
+ if (len >= 4 + sp->bound_len &&
+ strncmp(text + 2 + sp->bound_len, "--", 2) == 0) {
mime_state_pop(state);
SET_MIME_STATE(state, MIME_STATE_BODY,
MIME_CTYPE_OTHER, MIME_STYPE_OTHER,
/*++
/* NAME
-/* dsn_attr_map 3
+/* rec_attr_map 3
/* SUMMARY
-/* map named attribute to pseudo record type
+/* map named attribute record type to pseudo record type
/* SYNOPSIS
-/* #include <dsn_attr_map.h>
+/* #include <rec_attr_map.h>
/*
-/* int dsn_attr_map(attr_name)
+/* int rec_attr_map(attr_name)
/* const char *attr_name;
/* DESCRIPTION
-/* dsn_attr_map() maps the record type of a named attribute to
+/* rec_attr_map() maps the record type of a named attribute to
/* a pseudo record type, if such a mapping exists. The result
/* is the pseudo record type in case of success, 0 on failure.
/* LICENSE
#include <mail_proto.h>
#include <rec_type.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
-/* dsn_attr_map - map named attribute to pseudo record type */
+/* rec_attr_map - map named attribute to pseudo record type */
-int dsn_attr_map(const char *attr_name)
+int rec_attr_map(const char *attr_name)
{
if (strcmp(attr_name, MAIL_ATTR_DSN_ORCPT) == 0) {
return (REC_TYPE_DSN_ORCPT);
return (REC_TYPE_DSN_ENVID);
} else if (strcmp(attr_name, MAIL_ATTR_DSN_RET) == 0) {
return (REC_TYPE_DSN_RET);
+ } else if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) {
+ return (REC_TYPE_CTIME);
} else {
return (0);
}
-#ifndef _DSN_ATTR_MAP_H_INCLUDED_
-#define _DSN_ATTR_MAP_H_INCLUDED_
+#ifndef _REC_ATTR_MAP_H_INCLUDED_
+#define _REC_ATTR_MAP_H_INCLUDED_
/*++
/* NAME
-/* dsn_attr_map 3h
+/* rec_attr_map 3h
/* SUMMARY
-/* map named attribute to pseudo record type
+/* map named attribute record type to pseudo record type
/* SYNOPSIS
-/* #include <dsn_attr_map.h>
+/* #include <rec_attr_map.h>
/* DESCRIPTION
/* .nf
/*
* External interface.
*/
-extern int dsn_attr_map(const char *);
+extern int rec_attr_map(const char *);
/* LICENSE
/* .ad
REC_TYPE_ERROR, "error", /* not Postfix-specific. */
REC_TYPE_SIZE, "message_size",
REC_TYPE_TIME, "message_arrival_time",
+ REC_TYPE_CTIME, "queue_file_create_time",
REC_TYPE_FULL, "sender_fullname",
REC_TYPE_INSP, "content_inspector",
REC_TYPE_FILT, "content_filter",
* constant, and it is too late to change that now.
*/
#define REC_TYPE_SIZE 'C' /* first record, created by cleanup */
-#define REC_TYPE_TIME 'T' /* time stamp, required */
+#define REC_TYPE_TIME 'T' /* arrival time, required */
+#define REC_TYPE_CTIME 'c' /* create time, optional */
#define REC_TYPE_FULL 'F' /* full name, optional */
#define REC_TYPE_INSP 'I' /* inspector transport */
#define REC_TYPE_FILT 'L' /* loop filter transport */
* Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L'
* constant, and it is too late to change that now.
*/
-#define REC_TYPE_ENVELOPE "MCTFILSDROWVA>K<ion"
+#define REC_TYPE_ENVELOPE "MCTcFILSDROWVA>K<ion"
#define REC_TYPE_CONTENT "XLN"
#define REC_TYPE_EXTRACT "EDROPreAFIL>Kon"
qmgr_message.o: ../../include/deliver_request.h
qmgr_message.o: ../../include/dict.h
qmgr_message.o: ../../include/dsn.h
-qmgr_message.o: ../../include/dsn_attr_map.h
qmgr_message.o: ../../include/dsn_buf.h
qmgr_message.o: ../../include/dsn_mask.h
qmgr_message.o: ../../include/iostuff.h
qmgr_message.o: ../../include/mymalloc.h
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/qmgr_user.h
+qmgr_message.o: ../../include/rec_attr_map.h
qmgr_message.o: ../../include/rec_type.h
qmgr_message.o: ../../include/recipient_list.h
qmgr_message.o: ../../include/record.h
VSTREAM *fp; /* open queue file or null */
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
- struct timeval arrival_time; /* time when queued */
+ struct timeval arrival_time; /* start of receive transaction */
+ time_t create_time; /* queue file create time */
struct timeval active_time; /* time of entry into active queue */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warning to be sent */
* daemon waits for the qmgr to accept the "new mail" trigger.
*/
if (message->flags) {
- if (event_time() >= message->arrival_time.tv_sec +
+ if (event_time() >= message->create_time +
(*message->sender ? var_max_queue_time : var_dsn_queue_time)) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
* queue scans is finite.
*/
if (message->flags) {
- if (message->arrival_time.tv_sec > 0) {
- delay = event_time() - message->arrival_time.tv_sec;
+ if (message->create_time > 0) {
+ delay = event_time() - message->create_time;
if (delay > var_max_backoff_time)
delay = var_max_backoff_time;
if (delay < var_min_backoff_time)
#include <qmgr_user.h>
#include <split_addr.h>
#include <dsn_mask.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Client stubs. */
message->refcount = 0;
message->single_rcpt = 0;
message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0;
+ message->create_time = 0;
GETTIMEOFDAY(&message->active_time);
message->data_offset = 0;
message->queue_id = mystrdup(queue_id);
rec_type = REC_TYPE_ERROR;
break;
}
- if ((n = dsn_attr_map(name)) != 0) {
+ if ((n = rec_attr_map(name)) != 0) {
start = value;
rec_type = n;
}
REC_TYPE_TIME_SCAN(start, message->arrival_time);
continue;
}
+ if (rec_type == REC_TYPE_CTIME) {
+ if (message->create_time == 0)
+ message->create_time = atol(start);
+ continue;
+ }
if (rec_type == REC_TYPE_FILT) {
if (message->filter_xport != 0)
myfree(message->filter_xport);
message->sasl_sender = mystrdup("");
if (message->rewrite_context == 0)
message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL);
+ /* Postfix < 2.3 compatibility. */
+ if (message->create_time == 0)
+ message->create_time = message->arrival_time.tv_sec;
/*
* Clean up.
# do not edit below this line - it is generated by 'make depend'
pickup.o: ../../include/attr.h
pickup.o: ../../include/cleanup_user.h
-pickup.o: ../../include/dsn_attr_map.h
pickup.o: ../../include/input_transp.h
pickup.o: ../../include/iostuff.h
pickup.o: ../../include/lex_822.h
pickup.o: ../../include/mail_server.h
pickup.o: ../../include/msg.h
pickup.o: ../../include/mymalloc.h
+pickup.o: ../../include/rec_attr_map.h
pickup.o: ../../include/rec_type.h
pickup.o: ../../include/record.h
pickup.o: ../../include/safe_open.h
#include <rec_type.h>
#include <lex_822.h>
#include <input_transp.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Single-threaded server skeleton. */
* mail system against unreasonable inputs. This also requires that we
* limit the size of envelope records written by the local posting agent.
*
- * As time stamp we use the scrutinized queue file modification time, and
- * ignore the time stamp embedded in the queue file.
- *
* Allow attribute records if the queue file is owned by the mail system
* (postsuper -r) or if the attribute specifies the MIME body type
* (sendmail -B).
saved_attr = mystrdup(vstring_str(buf));
skip_attr = (split_nameval(saved_attr,
&attr_name, &attr_value) == 0
- && dsn_attr_map(attr_name) == 0);
+ && rec_attr_map(attr_name) == 0);
myfree(saved_attr);
/* Discard other/header/body action after "postsuper -r". */
if (skip_attr)
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
+postcat.o: ../../include/attr.h
+postcat.o: ../../include/iostuff.h
postcat.o: ../../include/mail_conf.h
postcat.o: ../../include/mail_params.h
+postcat.o: ../../include/mail_proto.h
postcat.o: ../../include/mail_queue.h
postcat.o: ../../include/msg.h
postcat.o: ../../include/msg_vstream.h
postcat.o: ../../include/rec_type.h
postcat.o: ../../include/record.h
+postcat.o: ../../include/stringops.h
postcat.o: ../../include/sys_defs.h
postcat.o: ../../include/vbuf.h
postcat.o: ../../include/vstream.h
#include <vstring.h>
#include <msg_vstream.h>
#include <vstring_vstream.h>
+#include <stringops.h>
/* Global library. */
#include <mail_queue.h>
#include <mail_conf.h>
#include <mail_params.h>
+#include <mail_proto.h>
/* Application-specific. */
int ch;
off_t offset;
int in_message = 0;
+ const char *error_text;
+ char *attr_name;
+ char *attr_value;
#define TEXT_RECORD(rec_type) \
(rec_type == REC_TYPE_CONT || rec_type == REC_TYPE_NORM)
case REC_TYPE_END:
vstream_printf("*** MESSAGE FILE END %s ***\n", VSTREAM_PATH(fp));
break;
+ case REC_TYPE_ATTR:
+ error_text = split_nameval(STR(buffer), &attr_name, &attr_value);
+ if (error_text != 0) {
+ msg_warn("%s: malformed attribute: %s: %.100s",
+ VSTREAM_PATH(fp), error_text, STR(buffer));
+ break;
+ }
+ if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) {
+ time = atol(attr_value);
+ vstream_printf("%s: %s", MAIL_ATTR_CREATE_TIME,
+ asctime(localtime(&time)));
+ break;
+ }
+ /* FALLTHROUGH */
default:
vstream_printf("%s: %s\n", rec_type_name(rec_type), STR(buffer));
break;
postdrop.o: ../../include/attr.h
postdrop.o: ../../include/clean_env.h
postdrop.o: ../../include/cleanup_user.h
-postdrop.o: ../../include/dsn_attr_map.h
postdrop.o: ../../include/iostuff.h
postdrop.o: ../../include/mail_conf.h
postdrop.o: ../../include/mail_params.h
postdrop.o: ../../include/msg_syslog.h
postdrop.o: ../../include/msg_vstream.h
postdrop.o: ../../include/mymalloc.h
+postdrop.o: ../../include/rec_attr_map.h
postdrop.o: ../../include/rec_type.h
postdrop.o: ../../include/record.h
postdrop.o: ../../include/stringops.h
#include <record.h>
#include <rec_type.h>
#include <user_acl.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Application-specific. */
|| STREQ(attr_value, MAIL_ATTR_ENC_NONE)))
|| STREQ(attr_name, MAIL_ATTR_DSN_ENVID)
|| STREQ(attr_name, MAIL_ATTR_DSN_NOTIFY)
- || dsn_attr_map(attr_name)
+ || rec_attr_map(attr_name)
|| (STREQ(attr_name, MAIL_ATTR_RWR_CONTEXT)
&& (STREQ(attr_value, MAIL_ATTR_RWR_LOCAL)
|| STREQ(attr_value, MAIL_ATTR_RWR_REMOTE)))
qmgr_message.o: ../../include/deliver_request.h
qmgr_message.o: ../../include/dict.h
qmgr_message.o: ../../include/dsn.h
-qmgr_message.o: ../../include/dsn_attr_map.h
qmgr_message.o: ../../include/dsn_buf.h
qmgr_message.o: ../../include/dsn_mask.h
qmgr_message.o: ../../include/iostuff.h
qmgr_message.o: ../../include/mymalloc.h
qmgr_message.o: ../../include/opened.h
qmgr_message.o: ../../include/qmgr_user.h
+qmgr_message.o: ../../include/rec_attr_map.h
qmgr_message.o: ../../include/rec_type.h
qmgr_message.o: ../../include/recipient_list.h
qmgr_message.o: ../../include/record.h
VSTREAM *fp; /* open queue file or null */
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
- struct timeval arrival_time; /* time when queued */
+ struct timeval arrival_time; /* start of receive transaction */
+ time_t create_time; /* queue file create time */
struct timeval active_time; /* time of entry into active queue */
time_t queued_time; /* sanitized time when moved to the
* active queue */
* daemon waits for the qmgr to accept the "new mail" trigger.
*/
if (message->flags) {
- if (event_time() >= message->arrival_time.tv_sec +
+ if (event_time() >= message->create_time +
(*message->sender ? var_max_queue_time : var_dsn_queue_time)) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
* queue scans is finite.
*/
if (message->flags) {
- if (message->arrival_time.tv_sec > 0) {
- delay = event_time() - message->arrival_time.tv_sec;
+ if (message->create_time > 0) {
+ delay = event_time() - message->create_time;
if (delay > var_max_backoff_time)
delay = var_max_backoff_time;
if (delay < var_min_backoff_time)
#include <qmgr_user.h>
#include <split_addr.h>
#include <dsn_mask.h>
-#include <dsn_attr_map.h>
+#include <rec_attr_map.h>
/* Client stubs. */
message->refcount = 0;
message->single_rcpt = 0;
message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0;
+ message->create_time = 0;
GETTIMEOFDAY(&message->active_time);
message->queued_time = sane_time();
message->data_offset = 0;
rec_type = REC_TYPE_ERROR;
break;
}
- if ((n = dsn_attr_map(name)) != 0) {
+ if ((n = rec_attr_map(name)) != 0) {
start = value;
rec_type = n;
}
REC_TYPE_TIME_SCAN(start, message->arrival_time);
continue;
}
+ if (rec_type == REC_TYPE_CTIME) {
+ if (message->create_time == 0)
+ message->create_time = atol(start);
+ continue;
+ }
if (rec_type == REC_TYPE_FILT) {
if (message->filter_xport != 0)
myfree(message->filter_xport);
message->sasl_sender = mystrdup("");
if (message->rewrite_context == 0)
message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL);
+ /* Postfix < 2.3 compatibility. */
+ if (message->create_time == 0)
+ message->create_time = message->arrival_time.tv_sec;
/*
* Clean up.
* XXX We use REC_TYPE_ATTR for DSN-related recipient attributes even though
* 1) REC_TYPE_ATTR is not meant for multiple instances of the same named
* attribute, and 2) mixing REC_TYPE_ATTR with REC_TYPE_(not attr)
- * requires that we map attributes with dsn_attr_map() in order to
+ * requires that we map attributes with rec_attr_map() in order to
* simplify the recipient record processing loops in the cleanup and qmgr
* servers.
*