This fixes a problem in Simon's multiline-greeting patch. When smtpd_chat_reply() detects an I/O error, vstream_longjmp() is called, hence smtpd_chat_reply_multiline()'s context is destroyed but the local VSTRINGs are not. diff -ur postfix-2.0.16-20031026.orig/src/smtpd/smtpd.c postfix-2.0.16-20031026.patched/src/smtpd/smtpd.c --- postfix-2.0.16-20031026.orig/src/smtpd/smtpd.c Wed Oct 22 18:58:55 2003 +++ postfix-2.0.16-20031026.patched/src/smtpd/smtpd.c Wed Nov 12 16:47:46 2003 @@ -1808,7 +1808,7 @@ && (state->access_denied = smtpd_check_client(state)) != 0) { smtpd_chat_reply(state, "%s", state->access_denied); } else { - smtpd_chat_reply(state, "220 %s", var_smtpd_banner); + smtpd_chat_reply_multiline(state, 220, var_smtpd_banner); } for (;;) { diff -ur postfix-2.0.16-20031026.orig/src/smtpd/smtpd_chat.c postfix-2.0.16-20031026.patched/src/smtpd/smtpd_chat.c --- postfix-2.0.16-20031026.orig/src/smtpd/smtpd_chat.c Sat Jul 5 17:28:32 2003 +++ postfix-2.0.16-20031026.patched/src/smtpd/smtpd_chat.c Wed Nov 12 17:51:15 2003 @@ -14,6 +14,11 @@ /* SMTPD_STATE *state; /* char *format; /* +/* void smtpd_chat_reply_multiline(state, smtp_reply_code, format, ...) +/* SMTPD_STATE *state; +/* int smtp_reply_code; +/* char *format; +/* /* void smtpd_chat_notify(state) /* SMTPD_STATE *state; /* @@ -31,6 +36,11 @@ /* When soft_bounce is enabled, all 5xx (reject) reponses are /* replaced by 4xx (try again). /* +/* smtpd_chat_reply_multiline() formats a server reply, sends it to +/* the client, and appends a copy to the SMTP transaction log. +/* The reply can contain embedded "\n"s which will be treated as +/* separators in a multiline reply. +/* /* smtpd_chat_notify() sends a copy of the SMTP transaction log /* to the postmaster for review. The postmaster notice is sent only /* when delivery is possible immediately. It is an error to call @@ -61,6 +71,8 @@ #include #include /* 44BSD stdarg.h uses abort() */ #include +#include +#include /* Utility library. */ @@ -180,6 +192,61 @@ vstream_longjmp(state->client, SMTP_ERR_TIME); if (vstream_ferror(state->client)) vstream_longjmp(state->client, SMTP_ERR_EOF); +} + +/* trim_line - remove trailing whitespace and return a pointer to the first */ +/* non-space char in the string. Based on TRIM() in ../util/dict.c */ +/* WARNING: this function is DESTRUCTIVE. */ + +static char *trim_line( char *line ) { + char *p; + + for (p=line + strlen(line); p > line && ISSPACE(p[-1]); p--); + *p = 0; + + while ( ISSPACE(*line) ) + ++line; + + return ( line ); +} + +/* smtpd_chat_reply_multiline - convert multline string into seperate */ +/* lines, sending each one to smtpd_chat_reply() */ + +#define LINE_SEPARATOR "\n" + +void smtpd_chat_reply_multiline(SMTPD_STATE *state, int smtp_reply_code, char *format,...) +{ + va_list ap; + char *line, *line2; /* one line (of the multiline) reply */ + size_t size; /* size of a single line */ + static VSTRING *temp_line; /* SMTP reply before unescapeing */ + static VSTRING *multiline; /* SMTP reply after unescaping */ + + /* First-time intialization. */ + if (!temp_line) + temp_line = vstring_alloc(512); + if (!multiline) + multiline = vstring_alloc(512); + + va_start(ap, format); + vstring_vsprintf(temp_line, format, ap); + va_end(ap); + + /* unescape lines with "\\n", converting them to "\n" */ + unescape( multiline, STR(temp_line) ); + + line = STR(multiline); + while ( (size = strcspn(line, LINE_SEPARATOR)) < strlen(line) ) { + *(line + size) = 0; + + line2 = trim_line(line); + smtpd_chat_reply(state, "%03d-%s", smtp_reply_code, line2); + + line += size + 1; + } + line2 = trim_line(line); + smtpd_chat_reply(state, "%03d %s", smtp_reply_code, line2); } /* print_line - line_wrap callback */ diff -ur postfix-2.0.16-20031026.orig/src/smtpd/smtpd_chat.h postfix-2.0.16-20031026.patched/src/smtpd/smtpd_chat.h --- postfix-2.0.16-20031026.orig/src/smtpd/smtpd_chat.h Sat Nov 18 11:37:30 2000 +++ postfix-2.0.16-20031026.patched/src/smtpd/smtpd_chat.h Wed Nov 12 16:47:46 2003 @@ -15,6 +15,7 @@ extern void smtpd_chat_reset(SMTPD_STATE *); extern void smtpd_chat_query(SMTPD_STATE *); extern void PRINTFLIKE(2, 3) smtpd_chat_reply(SMTPD_STATE *, char *, ...); +extern void smtpd_chat_reply_multiline(SMTPD_STATE *, int, char *, ...); extern void smtpd_chat_notify(SMTPD_STATE *); /* LICENSE