+--- src/smtpd/smtpd.h.org Wed Feb 9 03:00:14 2005
++++ src/smtpd/smtpd.h Mon Feb 7 20:06:58 2005
+@@ -111,6 +111,7 @@
+ int sender_rcptmap_checked; /* sender validated against maps */
+ int recipient_rcptmap_checked; /* recipient validated against maps */
+ int warn_if_reject; /* force reject into warning */
++ int header_if_reject; /* add header instead of rejecting */
+ SMTPD_DEFER defer_if_reject; /* force reject into deferral */
+ SMTPD_DEFER defer_if_permit; /* force permit into deferral */
+ int defer_if_permit_client; /* force permit into warning */
+--- src/global/mail_params.h.org Wed Feb 9 03:01:31 2005
++++ src/global/mail_params.h Wed Feb 9 02:01:01 2005
+@@ -1578,6 +1578,7 @@
+ #define CHECK_RECIP_NS_ACL "check_recipient_ns_access"
+
+ #define WARN_IF_REJECT "warn_if_reject"
++#define HEADER_IF_REJECT "header_if_reject"
+
+ #define REJECT_RBL "reject_rbl" /* LaMont compatibility */
+ #define REJECT_RBL_CLIENT "reject_rbl_client"
+--- src/smtpd/smtpd_check.c.org Sat Dec 27 03:54:03 2003
++++ src/smtpd/smtpd_check.c Wed Feb 9 06:04:25 2005
+@@ -351,29 +351,29 @@
+ * permit-style restriction fails. Otherwise, we could reject legitimate
+ * mail.
+ */
+-static void PRINTFLIKE(3, 4) defer_if(SMTPD_DEFER *, int, const char *,...);
++static void PRINTFLIKE(4, 5) defer_if(SMTPD_STATE *, SMTPD_DEFER *, int, const char *,...);
+
+ #define DEFER_IF_REJECT2(state, class, fmt, a1, a2) \
+- defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2))
++ defer_if((state), &(state)->defer_if_reject, (class), (fmt), (a1), (a2))
+ #define DEFER_IF_REJECT3(state, class, fmt, a1, a2, a3) \
+- defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3))
++ defer_if((state), &(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3))
+ #define DEFER_IF_REJECT4(state, class, fmt, a1, a2, a3, a4) \
+ defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3), (a4))
+ #define DEFER_IF_PERMIT2(state, class, fmt, a1, a2) do { \
+ if ((state)->warn_if_reject == 0) \
+- defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2)); \
++ defer_if((state), &(state)->defer_if_permit, (class), (fmt), (a1), (a2)); \
+ else \
+ (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2)); \
+ } while (0)
+ #define DEFER_IF_PERMIT3(state, class, fmt, a1, a2, a3) do { \
+ if ((state)->warn_if_reject == 0) \
+- defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3)); \
++ defer_if((state), &(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3)); \
+ else \
+ (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3)); \
+ } while (0)
+ #define DEFER_IF_PERMIT4(state, class, fmt, a1, a2, a3, a4) do { \
+ if ((state)->warn_if_reject == 0) \
+- defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3), (a4)); \
++ defer_if((state), &(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3), (a4)); \
+ else \
+ (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3), (a4)); \
+ } while (0)
+@@ -712,7 +712,18 @@
+ char *format,...)
+ {
+ va_list ap;
++
++ va_start(ap, format);
++ vstring_vsprintf(error_text, format, ap);
++ va_end(ap);
++
++ return(xsmtpd_check_reject(state, error_class, error_text));
++}
++static int xsmtpd_check_reject(SMTPD_STATE *state, int error_class,
++ VSTRING *error_text)
++{
+ int warn_if_reject;
++ int header_if_reject;
+ const char *whatsup;
+
+ /*
+@@ -726,15 +737,18 @@
+ warn_if_reject = 0;
+ whatsup = "reject";
+ }
++ if (state->header_if_reject && error_class != MAIL_ERROR_SOFTWARE) {
++ header_if_reject = 1;
++ whatsup = "header_warning";
++ } else {
++ header_if_reject = 0;
++ }
+
+ /*
+ * Update the error class mask, and format the response. XXX What about
+ * multi-line responses? For now we cheat and send whitespace.
+ */
+ state->error_mask |= error_class;
+- va_start(ap, format);
+- vstring_vsprintf(error_text, format, ap);
+- va_end(ap);
+
+ /*
+ * Ensure RFC compliance. We could do this inside smtpd_chat_reply() and
+@@ -796,15 +810,58 @@
+ */
+ log_whatsup(state, whatsup, STR(error_text));
+
+- return (warn_if_reject ? 0 : SMTPD_CHECK_REJECT);
++ if (state->header_if_reject) {
++ VSTRING *hbuf = vstring_alloc(100);
++ int elen = strlen(STR(error_text));
++
++ if (state->prepend == 0)
++ state->prepend = argv_alloc(1);
++ printable(STR(error_text), '?');
++
++#define PRETTY_HEADER
++#ifdef PRETTY_HEADER
++ if (elen > 65) {
++ int len = 0, n;
++ char *p;
++
++ vstring_sprintf(hbuf, "%s", "X-Reject: ");
++ while (len < elen-65 && (p = strchr(STR(error_text)+len+64, ' '))) {
++ *p = '\t';
++ n = p-(STR(error_text)+len);
++ vstring_sprintf_append(hbuf, "%.*s\n", n, STR(error_text)+len);
++ len+=n;
++ }
++ vstring_sprintf_append(hbuf, "%s", STR(error_text)+len);
++ }
++ else {
++ vstring_sprintf(hbuf, "X-Reject: %s", STR(error_text));
++ }
++#else
++ vstring_sprintf(hbuf, "X-Reject: %.*s", 999, STR(error_text));
++#endif
++ argv_add(state->prepend, STR(hbuf), ARGV_END);
++ vstring_free(hbuf);
++ }
++
++ return (warn_if_reject || header_if_reject ? 0 : SMTPD_CHECK_REJECT);
+ }
+
+ /* defer_if - prepare to change our mind */
+
+-static void defer_if(SMTPD_DEFER *defer, int error_class, const char *fmt,...)
++static void defer_if(SMTPD_STATE *state, SMTPD_DEFER *defer, int error_class, const char *fmt,...)
+ {
+ va_list ap;
+
++ if (state->header_if_reject) {
++ va_start(ap, fmt);
++ vstring_vsprintf(error_text, fmt, ap);
++ va_end(ap);
++ if (STR(error_text)[0] == '5') {
++ xsmtpd_check_reject(state, error_class, error_text);
++ return;
++ }
++ }
++
+ /*
+ * Keep the first reason for this type of deferral, to minimize
+ * confusion.
+@@ -3147,6 +3204,11 @@
+ state->warn_if_reject = state->recursion;
+ continue;
+ }
++ if (strcasecmp(name, HEADER_IF_REJECT) == 0) {
++ if (state->header_if_reject == 0)
++ state->header_if_reject = state->recursion;
++ continue;
++ }
+
+ /*
+ * Spoof the is_map_command() routine, so that we do not have to make
+@@ -3500,6 +3562,8 @@
+
+ if (state->warn_if_reject >= state->recursion)
+ state->warn_if_reject = 0;
++ if (state->header_if_reject >= state->recursion)
++ state->header_if_reject = 0;
+
+ if (status != 0)
+ break;
+@@ -3554,6 +3618,7 @@
+ #define SMTPD_CHECK_RESET() { \
+ state->recursion = 0; \
+ state->warn_if_reject = 0; \
++ state->header_if_reject = 0; \
+ state->defer_if_reject.active = 0; \
+ }
+