src/cleanup/ Canonicalize and enqueue mail
src/discard/ Trivial discard mailer
src/error/ Trivial error mailer
- src/lmtp/ LMTP client
src/local/ Local delivery
src/master/ Postfix resident superserver
src/oqmgr/ Old queue manager
src/qmgr/ Queue manager
src/qmqpd/ QMQPD server
src/showq/ List Postfix queue status
- src/smtp/ SMTP client
+ src/smtp/ SMTP and LMTP client
src/smtpd/ SMTP server
src/spawn/ Run non-Postfix server
+ src/tlsmgr/ TLS session keys and random pool
src/trivial-rewrite/ Address rewriting and resolving
src/verify/ address verification service
src/virtual/ virtual mailbox-only delivery agent
Bugfix: null pointer bug when receiving a non-protocol
response on a cached SMTP/LMTP connection. Report by Brian
Kantor. Fix by Victor Duchovni. File: smtp/smtp_reuse.c.
+
+20061113
+
+ Bugfix: the Postfix install/upgrade procedure broke with
+ non-default config_directory. File: conf/post-install.
+
+20061115
+
+ Bugfix: null pointer bug in end-of-header Milter action
+ when the last header line is too large. Reported by Mark
+ Martinec. The root of the problem is that the MIME state
+ engine may execute up to three call-back functions when it
+ reaches the end of the headers, before it returns to the
+ caller; as long as call-backs return no result, each call-back
+ has to check for itself if a previous call-back ran into a
+ problem. File: milter/milter8.c.
+
+ Workaround: reduce effective header_size_limit to 60000
+ when Milter inspection is enabled, to avoid breaking the
+ Milter protocol request length limit. File:
+ cleanup/cleanup_message.c.
+
+20061123
+
+ Workaround: more agressive early refill of in-memory
+ recipients to prevent a worst-case scenario where the queue
+ manager became starved until after the last batch of slow
+ in-memory recipients of jumbo multi-recipient mail. Files:
+ qmgr/qmgr_job.c.
+
+ Safety: don't read more than 5000 recipients at a time, to
+ avoid spending too much time away from interrupts. File:
+ qmgr/qmgr_message.c.
+
+20061201
+
+ Workaround: don't complain with "Error 0" in the trivial-rewrite,
+ verify, proxymap or connection cache client when the server
+ exits after the client sends its request. We still complain,
+ however, when the problem persists. Files: global/rewrite_clnt.c,
+ global/resolve_clnt.c, global/verify_clnt.c, global/scache_clnt.c,
+ global/dict_proxy.c.
+
+
+ Safety: the header_size_limit is now enforced more strictly,
+ to avoid inter-operability problems with the Milter protocol.
+ Long headers are truncated at a line boundary if possible,
+ otherwise they are cut between line boundaries. File:
+ cleanup/cleanup_out.c.
+
+20061203
+
+ Bugfix (introduced with Postfix 2.2): with SMTP server
+ tarpit delays of smtp_rset_timeout or larger, the SMTP
+ client could get out of sync with the server while reusing
+ a connection. The symptoms were "recipient rejected .. in
+ reply to DATA". Fix by Victor Duchovni and Wietse. File:
+ smtp/smtp_proto.c.
Content-Description: Notification
Content-Type: text/plain
- This is the Postfix program at host spike.porcupine.org.
+ This is the mail system at host spike.porcupine.org.
Enclosed is the mail delivery report that you requested.
- The Postfix program
+ The mail system
<postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250
- Ok
+ 2.1.5 Ok
The second part of the report is in machine-readable form, and includes the
following information:
Reporting-MTA: dns; spike.porcupine.org
X-Postfix-Queue-ID: 84863BC0E5
X-Postfix-Sender: rfc822; wietse@porcupine.org
- Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+ Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Final-Recipient: rfc822; postfix-users@postfix.org
Action: deliverable
- Status: 2.0.0
+ Status: 2.1.5
Remote-MTA: dns; mail.cloud9.net
- Diagnostic-Code: smtp; 250 Ok
+ Diagnostic-Code: smtp; 250 2.1.5 Ok
The third part of the report contains the message that Postfix would have
delivered, including From: and To: message headers, so that you can see any
Content-Type: message/rfc822
Received: by spike.porcupine.org (Postfix, from userid 1001)
- id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+ id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Subject: probe
To: postfix-users@postfix.org
- Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org>
- Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+ Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org>
+ Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
From: wietse@porcupine.org (Wietse Venema)
# This safety net is also documented in LOCAL_RECIPIENT_README.
unknown_local=unknown_local_recipient_reject_code
- has_lrm=`$POSTCONF -n local_recipient_maps`
- has_lrjc=`$POSTCONF -n $unknown_local`
+ has_lrm=`$POSTCONF -c $config_directory -n local_recipient_maps`
+ has_lrjc=`$POSTCONF -c $config_directory -n $unknown_local`
if [ -z "$has_lrm" -a -z "$has_lrjc" ]
then
echo SAFETY: editing main.cf, setting $unknown_local=450.
echo See the LOCAL_RECIPIENT_README file for details.
- $POSTCONF -e "$unknown_local = 450" || exit 1
+ $POSTCONF -c $config_directory -e "$unknown_local = 450" || exit 1
fi
# Add missing proxymap service to master.cf.
test -n "$first_install_reminder" && {
- ALIASES=`$POSTCONF -h alias_database | sed 's/^[^:]*://'`
- NEWALIASES_PATH=`$POSTCONF -h newaliases_path`
+ ALIASES=`$POSTCONF -c $config_directory -h alias_database | sed 's/^[^:]*://'`
+ NEWALIASES_PATH=`$POSTCONF -c $config_directory -h newaliases_path`
cat <<EOF | ${FMT}
Warning: you still need to edit myorigin/mydestination/mynetworks
Content-Description: Notification
Content-Type: text/plain
-This is the Postfix program at host spike.porcupine.org.
+This is the mail system at host spike.porcupine.org.
Enclosed is the mail delivery report that you requested.
- The Postfix program
+ The mail system
-<postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 Ok
+<postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 2.1.5 Ok
</pre>
</blockquote>
Reporting-MTA: dns; spike.porcupine.org
X-Postfix-Queue-ID: 84863BC0E5
X-Postfix-Sender: rfc822; wietse@porcupine.org
-Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Final-Recipient: rfc822; postfix-users@postfix.org
Action: deliverable
-Status: 2.0.0
+Status: 2.1.5
Remote-MTA: dns; mail.cloud9.net
-Diagnostic-Code: smtp; 250 Ok
+Diagnostic-Code: smtp; 250 2.1.5 Ok
</pre>
</blockquote>
Content-Type: message/rfc822
Received: by spike.porcupine.org (Postfix, from userid 1001)
- id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+ id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Subject: probe
To: postfix-users@postfix.org
-Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org>
-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org>
+Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
From: wietse@porcupine.org (Wietse Venema)
</pre>
</blockquote>
Content-Description: Notification
Content-Type: text/plain
-This is the Postfix program at host spike.porcupine.org.
+This is the mail system at host spike.porcupine.org.
Enclosed is the mail delivery report that you requested.
- The Postfix program
+ The mail system
-<postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 Ok
+<postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 2.1.5 Ok
</pre>
</blockquote>
Reporting-MTA: dns; spike.porcupine.org
X-Postfix-Queue-ID: 84863BC0E5
X-Postfix-Sender: rfc822; wietse@porcupine.org
-Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Final-Recipient: rfc822; postfix-users@postfix.org
Action: deliverable
-Status: 2.0.0
+Status: 2.1.5
Remote-MTA: dns; mail.cloud9.net
-Diagnostic-Code: smtp; 250 Ok
+Diagnostic-Code: smtp; 250 2.1.5 Ok
</pre>
</blockquote>
Content-Type: message/rfc822
Received: by spike.porcupine.org (Postfix, from userid 1001)
- id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+ id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST)
Subject: probe
To: postfix-users@postfix.org
-Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org>
-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT)
+Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org>
+Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST)
From: wietse@porcupine.org (Wietse Venema)
</pre>
</blockquote>
TOK822 *token;
time_t tv;
+ /*
+ * XXX Workaround: when we reach the end of headers, mime_state_update()
+ * may execute up to three call-backs before returning to the caller:
+ * head_out(), head_end(), and body_out() or body_end(). As long as
+ * call-backs don't return a result, each call-back has to check for
+ * itself if the previous call-back experienced a problem.
+ */
+ if (CLEANUP_OUT_OK(state) == 0)
+ return;
+
/*
* Add a missing (Resent-)Message-Id: header. The message ID gives the
* time in GMT units, plus the local queue ID.
{
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
+ /*
+ * XXX Workaround: when we reach the end of headers, mime_state_update()
+ * may execute up to three call-backs before returning to the caller:
+ * head_out(), head_end(), and body_out() or body_end(). As long as
+ * call-backs don't return a result, each call-back has to check for
+ * itself if the previous call-back experienced a problem.
+ */
+ if (CLEANUP_OUT_OK(state) == 0)
+ return;
+
/*
* Crude message body content filter for emergencies. This code has
* several problems: it sees one line at a time; it looks at long lines
cleanup_mime_error_callback,
(void *) state);
+ /*
+ * XXX Workaround: truncate a long message header so that we don't exceed
+ * the Milter request size limit of 65535.
+ */
+#define KLUDGE_HEADER_LIMIT 60000
+ if ((cleanup_milters || state->milters)
+ && var_header_limit > KLUDGE_HEADER_LIMIT)
+ var_header_limit = KLUDGE_HEADER_LIMIT;
+
/*
* Pass control to the header processing routine.
*/
msg_warn(" del_rcpt addr");
}
+/* flatten_args - unparse partial command line */
+
static void flatten_args(VSTRING *buf, char **argv)
{
char **cpp;
VSTRING_TERMINATE(buf);
}
+/* open_queue_file - open an unedited queue file (all-zero dummy PTRs) */
+
static void open_queue_file(CLEANUP_STATE *state, const char *path)
{
VSTRING *buf = vstring_alloc(100);
long rcpt_count;
long qmgr_opts;
+ if (state->dst != 0) {
+ msg_warn("closing %s", cleanup_path);
+ vstream_fclose(state->dst);
+ state->dst = 0;
+ myfree(cleanup_path);
+ cleanup_path = 0;
+ }
if ((state->dst = vstream_fopen(path, O_RDWR, 0)) == 0) {
msg_warn("open %s: %m", path);
} else {
msg_vstream_init(argv[0], VSTREAM_ERR);
var_line_limit = DEF_LINE_LIMIT;
+ var_header_limit = DEF_HEADER_LIMIT;
for (;;) {
ARGV *argv;
* of such header lines. NB: This code destroys the header. We could try
* to avoid clobbering it, but we're not going to use the data any
* further.
+ *
+ * XXX We prefer to truncate a header at the last line boundary before the
+ * header size limit. If this would undershoot the limit by more than
+ * 10%, we truncate between line boundaries to avoid losing too much
+ * text. This "unkind cut" may result in syntax errors and may trigger
+ * warnings from down-stream MTAs.
*/
for (line = start; line; line = next_line) {
next_line = split_at(line, '\n');
+ if ((next_line ? next_line - 1 : line + strlen(line))
+ > start + var_header_limit) {
+ if (line - start > 0.9 * var_header_limit) /* nice cut */
+ break;
+ start[var_header_limit] = 0; /* unkind cut */
+ next_line = 0;
+ }
if (line == start || IS_SPACE_TAB(*line)) {
cleanup_out_string(state, REC_TYPE_NORM, line);
} else {
DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
VSTREAM *stream;
int status;
+ int count = 0;
/*
* The client and server live in separate processes that may start and
for (;;) {
stream = clnt_stream_access(proxy_stream);
errno = 0;
+ count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_LOOKUP,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, dict_proxy->result,
ATTR_TYPE_END) != 2) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
} else {
if (msg_verbose)
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20061101"
-#define MAIL_VERSION_NUMBER "2.3.4"
+#define MAIL_RELEASE_DATE "20061205"
+#define MAIL_VERSION_NUMBER "2.3.5-RC1"
#ifdef SNAPSHOT
# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
const char *myname = "resolve_clnt";
VSTREAM *stream;
int server_flags;
+ int count = 0;
/*
* One-entry cache.
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
errno = 0;
+ count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, class,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient,
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &reply->flags,
ATTR_TYPE_END) != 5) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
var_rewrite_service);
} else {
{
VSTREAM *stream;
int server_flags;
+ int count = 0;
/*
* One-entry cache.
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
errno = 0;
+ count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, REWRITE_ADDR,
ATTR_TYPE_STR, MAIL_ATTR_RULE, rule,
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, result,
ATTR_TYPE_END) != 2) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
var_rewrite_service);
} else {
VSTREAM *stream;
int status;
int tries;
+ int count = 0;
if (msg_verbose)
msg_info("%s: endp=%s prop=%s fd=%d",
for (tries = 0; sp->auto_clnt != 0; tries++) {
if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
errno = 0;
+ count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_ENDP,
ATTR_TYPE_INT, MAIL_ATTR_TTL, endp_ttl,
|| attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
VSTREAM_PATH(stream));
/* Give up or recover. */
myname, status);
break;
}
- }
+ }
/* Give up or recover. */
if (tries >= SCACHE_MAX_TRIES - 1) {
msg_warn("disabling connection caching");
{
VSTREAM *stream;
int request_status;
+ int count = 0;
/*
* Do client-server plumbing.
for (;;) {
stream = clnt_stream_access(vrfy_clnt);
errno = 0;
+ count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 3) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
var_verify_service);
} else {
int skip_reply,
ARGV *macros,...)
{
+ const char *myname = "milter8_event";
va_list ap;
ssize_t data_len;
int err;
#define DONT_SKIP_REPLY 0
+ /*
+ * Sanity check.
+ */
+ if (milter->fp == 0 || milter->def_reply != 0) {
+ msg_warn("%s: attempt to send event %s to milter %s after error",
+ myname,
+ (smfic_name = str_name_code(smfic_table, event)) != 0 ?
+ smfic_name : "(unknown MTA event)", milter->m.name);
+ return (milter->def_reply);
+ }
+
/*
* Skip this event if it doesn't exist in the protocol that I announced.
*/
(ssize_t) index,
STR(milter->buf));
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
#endif
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
/*
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
#endif
edit_resp = parent->add_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
/*
edit_resp = parent->del_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
/*
edit_resp = parent->repl_body(parent->chg_context,
milter->body);
if (edit_resp)
- return (milter8_def_reply(milter, edit_resp));
+ return (edit_resp);
continue;
#endif
}
char *cp;
int skip_reply;
+ /*
+ * XXX Workaround: mime_state_update() may invoke multiple call-backs
+ * before returning to the caller.
+ */
+#define MILTER8_MESSAGE_DONE(milter, msg_ctx) \
+ ((milter)->state != MILTER8_STAT_MESSAGE || (msg_ctx)->resp != 0)
+
+ if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
+ return;
+
/*
* XXX Sendmail compatibility. Don't expose our first (received) header
* to mail filter applications. See also cleanup_milter.c for code to
MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr;
MILTER8 *milter = msg_ctx->milter;
+ if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
+ return;
if (msg_verbose)
msg_info("%s: eoh milter %s", myname, milter->m.name);
msg_ctx->resp =
ssize_t space;
ssize_t count;
+ if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
+ return;
+
/*
* XXX Sendmail compatibility: don't expose our first body line.
*/
MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr;
MILTER8 *milter = msg_ctx->milter;
+ if (MILTER8_MESSAGE_DONE(milter, msg_ctx))
+ return;
if (msg_verbose)
msg_info("%s: eob milter %s", myname, milter->m.name);
msg_ctx->resp =
/*
* XXX When the message (not MIME body part) does not end in CRLF
- * (i.e. the last record was REC_TYPE_CONT), do we send CRLF
+ * (i.e. the last record was REC_TYPE_CONT), do we send a CRLF
* terminator before triggering the end-of-body condition?
*/
for (;;) {
msg_ctx.resp = "450 4.3.0 Queue file write error";
break;
}
- if (msg_ctx.resp != 0)
- break;
- if (milter->state != MILTER8_STAT_MESSAGE)
+ if (MILTER8_MESSAGE_DONE(milter, &msg_ctx))
break;
if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
break;
#define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0))
message->refcount--;
if (message->rcpt_offset > 0
- && qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit))
+ && qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit) - 100)
qmgr_message_realloc(message);
if (message->refcount == 0)
qmgr_active_done(message);
QMGR_PEER *peer;
QMGR_MESSAGE *message = job->message;
+ /*
+ * Workaround to prevent queue manager starvation until the last slow
+ * batch of multi-recipient mail is finished. Postfix 2.4 has a final
+ * solution, but that involves major changes.
+ */
+ if (message->rcpt_offset != 0
+ && message->rcpt_limit > message->rcpt_count + 100
+ && message->refcount > 0) {
+ qmgr_message_realloc(message);
+ }
if (HAS_ENTRIES(job) && (peer = qmgr_peer_select(job)) != 0)
return (peer);
if (recipient_limit < message->rcpt_limit)
recipient_limit = message->rcpt_limit;
}
+ /* Keep interrupt latency in check. */
+ if (recipient_limit > 5000)
+ recipient_limit = 5000;
if (recipient_limit <= 0)
msg_panic("%s: no recipient slots available", message->queue_id);
*/
session->error_mask |= MAIL_ERROR_PROTOCOL;
if (session->features & SMTP_FEATURE_PIPELINING) {
- msg_warn("non-%s response from %s: %.100s",
+ msg_warn("%s: non-%s response from %s: %.100s",
+ session->state->request->queue_id,
(session->state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) ?
"LMTP" : "ESMTP", session->namaddrport,
STR(session->buffer));
bad_session = THIS_SESSION_IS_BAD; /* smtp_quit() may fail */
if (THIS_SESSION_IS_EXPIRED)
smtp_quit(state); /* also disables caching */
- if (THIS_SESSION_IS_CACHED) {
+ if (THIS_SESSION_IS_CACHED
+ /* Redundant tests for safety... */
+ && vstream_ferror(session->stream) == 0
+ && vstream_ftimeout(session->stream) == 0
+ && vstream_feof(session->stream) == 0) {
smtp_save_session(state);
} else {
smtp_session_free(session);
&& smtp_helo(state) != 0) {
if (!THIS_SESSION_IS_DEAD
&& vstream_ferror(session->stream) == 0
+ && vstream_ftimeout(session->stream) == 0
&& vstream_feof(session->stream) == 0)
smtp_quit(state);
} else {
*/
if (!THIS_SESSION_IS_DEAD
&& vstream_ferror(session->stream) == 0
+ && vstream_ftimeout(session->stream) == 0
&& vstream_feof(session->stream) == 0)
smtp_quit(state);
} else {
} while (0)
#define RETURN(x) do { \
+ if (recv_state != SMTP_STATE_LAST) \
+ DONT_CACHE_THIS_SESSION; \
vstring_free(next_command); \
if (survivors) \
myfree((char *) survivors); \