diff -urN milter-greylist-ORIG/acl.c milter-greylist/acl.c
--- milter-greylist-ORIG/acl.c	2009-10-31 22:28:03.000000000 +0100
+++ milter-greylist/acl.c	2009-11-08 10:19:03.000000000 +0100
@@ -1845,6 +1845,14 @@
 	TAILQ_INSERT_TAIL(&acl_head, acl, a_list);
 	gacl = acl_init_entry();
 
+	if (acl_stage == AS_DATA && conf.c_first_dacl_line == INT_MAX) {
+		conf.c_first_dacl_line = conf_line - 1;
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"first dacl statement at line %d",
+			conf_line - 1);
+	}
+
 	if (conf.c_debug || conf.c_acldebug) {
 		switch(acl_type) {
 		case A_GREYLIST:
@@ -1920,6 +1928,20 @@
 		if (acl->a_stage != stage)
 			continue;
 
+		/*
+		 * Skip dacl processing for lines beyond matched
+		 * racl statement
+		 */
+		if (stage == AS_DATA &&
+		    acl->a_line > priv->priv_acl_line) {
+			if (conf.c_debug)
+				mg_log(LOG_DEBUG, 
+				"skipping dacl commands beyond matched racl line %d",
+				priv->priv_acl_line);
+			acl = NULL;
+			break;
+		}
+
 		retval = 0;
 		noretval = 0;
 		found = -1;
@@ -2004,7 +2026,7 @@
 			break;
 		}
 
-		priv->priv_sr.sr_acl_line = acl->a_line;
+		priv->priv_acl_line = acl->a_line;
 
 		priv->priv_sr.sr_delay =
 		    (ap.ap_delay != -1) ? ap.ap_delay : conf.c_delay;
@@ -2114,15 +2136,17 @@
 		if (testmode)
 			retval = EXF_WHITELIST;
 		else if (stage == AS_DATA)
-			retval = EXF_WHITELIST | EXF_NOLOG;
+			retval = EXF_WHITELIST;
 		else
-			retval = EXF_GREYLIST;
+			retval = EXF_WHITELIST;
 		retval |= EXF_DEFAULT;
 
 		priv->priv_sr.sr_delay = conf.c_delay;
 		priv->priv_sr.sr_autowhite = conf.c_autowhite_validity;
 		priv->priv_sr.sr_tarpit = conf.c_tarpit;
 		priv->priv_sr.sr_tarpit_scope = conf.c_tarpit_scope;
+
+		priv->priv_acl_line = INT_MAX;
 	}
 
 	if ((retval & EXF_NOLOG) == 0 && retval & EXF_WHITELIST) {
diff -urN milter-greylist-ORIG/conf.c milter-greylist/conf.c
--- milter-greylist-ORIG/conf.c	2009-09-09 14:19:17.000000000 +0200
+++ milter-greylist/conf.c	2009-11-08 10:19:03.000000000 +0100
@@ -447,6 +447,7 @@
 
 	c->c_forced = C_GLNONE;
 	c->c_debug = 0;
+	c->c_first_dacl_line = INT_MAX;
 	c->c_acldebug = 0;
 	c->c_quiet = 0;
 	c->c_noauth = 0;
diff -urN milter-greylist-ORIG/conf.h milter-greylist/conf.h
--- milter-greylist-ORIG/conf.h	2009-09-09 14:19:17.000000000 +0200
+++ milter-greylist/conf.h	2009-11-08 10:19:03.000000000 +0100
@@ -63,6 +63,7 @@
 
 	int c_forced;
 	int c_debug;
+	int c_first_dacl_line;
 	int c_acldebug;
 	int c_quiet;
 	int c_noauth;
diff -urN milter-greylist-ORIG/dkimcheck.c milter-greylist/dkimcheck.c
--- milter-greylist-ORIG/dkimcheck.c	2008-10-30 05:39:39.000000000 +0100
+++ milter-greylist/dkimcheck.c	2009-11-08 10:19:03.000000000 +0100
@@ -106,7 +106,7 @@
 		break;
 	}
 
-	if (priv->priv_dkim != DKIM_STAT_OK) {
+	if (priv->priv_dkimstat != DKIM_STAT_OK) {
 		(void)dkim_free(priv->priv_dkim);
 		priv->priv_dkim = NULL;
 	}
diff -urN milter-greylist-ORIG/milter-greylist.c milter-greylist/milter-greylist.c
--- milter-greylist-ORIG/milter-greylist.c	2009-11-06 04:52:25.000000000 +0100
+++ milter-greylist/milter-greylist.c	2009-11-08 10:19:03.000000000 +0100
@@ -483,6 +483,8 @@
 		free(priv->priv_buf);
 	priv->priv_msgcount = 0;
 
+	priv->priv_acl_line = INT_MAX;
+
 #ifdef USE_SPAMD
 	priv->priv_spamd_flags = 0;
 #endif
@@ -523,8 +525,10 @@
 	/*
 	 * Is the sender non-IP?
 	 */
-	if (priv->priv_sr.sr_whitelist & EXF_NONIP)
+	if (priv->priv_sr.sr_whitelist & EXF_NONIP) {
+		priv->priv_acl_line = 0;
 		return SMFIS_CONTINUE;
+	}
 
 	/*
 	 * Is the user authenticated?
@@ -537,6 +541,7 @@
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_AUTH;
 
+                priv->priv_acl_line = 0;
 		return SMFIS_CONTINUE;
 	} 
 
@@ -553,6 +558,7 @@
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_STARTTLS;
 
+                priv->priv_acl_line = 0;
 		return SMFIS_CONTINUE;
 	}
 
@@ -574,6 +580,7 @@
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_SPF;
 
+                priv->priv_acl_line = 0;
 		return SMFIS_CONTINUE;
 	}
 
@@ -622,10 +629,10 @@
 	 */
 	prop_clear(priv);
 #endif
-
-	if ((priv->priv_sr.sr_whitelist & EXF_WHITELIST) &&
-	    (priv->priv_sr.sr_whitelist &
-	     (EXF_NONIP | EXF_AUTH | EXF_STARTTLS | EXF_SPF)))
+	/*
+	 * Skip if whitelisted in envfrom stage
+	 */
+	if (!priv->priv_acl_line)
 		goto exit_accept;
 
 #ifdef USE_DRAC
@@ -636,6 +643,7 @@
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_DRAC;
 
+                priv->priv_acl_line = 0;
 		goto exit_accept;
 	}
 #endif
@@ -653,7 +661,8 @@
 		    "whitelisted by {greylist}");
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_ACCESSDB;
- 
+
+                priv->priv_acl_line = 0; 
 		goto exit_accept;
 	}
 
@@ -672,9 +681,23 @@
 		return SMFIS_TEMPFAIL;
 	}
 
+	/* 
+	 * Immediately continue to dacl processing if any dacl statements
+	 * occur before matching racl line
+	 */
+	if (conf.c_first_dacl_line < priv->priv_acl_line) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"dacl statement (line %d) before matched racl line %d; jump to dacl processing",
+			conf.c_first_dacl_line, priv->priv_acl_line);
+
+		goto exit_accept;
+	}
+
 	if (priv->priv_sr.sr_whitelist & EXF_WHITELIST &&
 	    priv->priv_sr.sr_tarpit <= 0) {
 		priv->priv_sr.sr_elapsed = 0;
+
 		goto exit_accept;
 	}
 
@@ -725,6 +748,7 @@
 	case T_AUTOWHITE:		/* autowhite listed */
 		priv->priv_sr.sr_elapsed = 0;
 		priv->priv_sr.sr_whitelist = EXF_WHITELIST | EXF_AUTO;
+		priv->priv_acl_line = 0; /* skip dacl */
 		goto exit_accept;
 		break;
 	case T_PENDING:			/* greylisted */
@@ -784,6 +808,7 @@
 	add_recipient(priv, rcpt);
 	if (priv->priv_sr.sr_whitelist & EXF_WHITELIST)
 		priv->priv_last_whitelist = priv->priv_sr.sr_whitelist;
+
 	return SMFIS_CONTINUE;
 }
 
@@ -821,7 +846,6 @@
 		exit(EX_OSERR);
 	}
 
-	len = strlen(name) + strlen(sep) + strlen(value) + strlen(crlf);
 	if ((h->h_line = malloc(len + 1)) == NULL) {
 		mg_log(LOG_ERR, "malloc() failed: %s", strerror(errno));
 		exit(EX_OSERR);
@@ -836,6 +860,18 @@
 
 	stat = SMFIS_CONTINUE;
 
+	/* 
+	 * No need to check headers for DKIM signature if there are
+	 * no dacl statements before matching racl line
+	 */
+	if (conf.c_first_dacl_line >= priv->priv_acl_line) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"no dacl statements before matched racl line %d; skipping header inspection",
+			priv->priv_acl_line);
+		return SMFIS_CONTINUE;
+	}
+
 #ifdef USE_DKIM
 	if ((stat = dkimcheck_header(name, value, priv)) != SMFIS_CONTINUE)
 		return stat;
@@ -847,15 +883,28 @@
 real_eoh(ctx)
 	SMFICTX *ctx;
 {
-#ifdef USE_DKIM
 	struct mlfi_priv *priv;
-	sfsistat stat = SMFIS_CONTINUE;
 
 	if ((priv = (struct mlfi_priv *) smfi_getpriv(ctx)) == NULL) {
 		mg_log(LOG_ERR, "Internal error: smfi_getpriv() returns NULL");
 		return SMFIS_TEMPFAIL;
 	}
 
+	/* 
+	 * No need to check headers for DKIM signature if there are
+	 * no dacl statements before matching racl line
+	 */
+	if (conf.c_first_dacl_line >= priv->priv_acl_line) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"no dacl statements before matched racl line %d; skipping end-of-header",
+			priv->priv_acl_line);
+		return SMFIS_CONTINUE;
+	}
+
+#ifdef USE_DKIM
+	sfsistat stat = SMFIS_CONTINUE;
+
 	if ((stat = dkimcheck_eoh(priv)) != SMFIS_CONTINUE)
 		return stat;
 #endif /* USE_DKIM */
@@ -882,6 +931,18 @@
 
 	stat = SMFIS_CONTINUE;
 
+	/* 
+	 * No need to scan the body if there are no dacl statements
+	 * before matching racl line
+	 */
+	if (conf.c_first_dacl_line >= priv->priv_acl_line) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"no dacl statements before matched racl line %d; skipping body scan",
+			priv->priv_acl_line);
+		return SMFIS_CONTINUE;
+	}
+
 #ifdef USE_DKIM
 	if ((stat = dkimcheck_body(chunk, size, priv)) != SMFIS_CONTINUE)
 		return stat;
@@ -975,8 +1036,8 @@
 	struct smtp_reply rcpt_sr;
 	struct rcpt *rcpt;
 	time_t remaining;
-	int envrcpt_continue = 0;
 	int accept = 1;
+	int save_acl_line;
 	struct tuple_fields tuple;
 
 	if ((priv = (struct mlfi_priv *) smfi_getpriv(ctx)) == NULL) {
@@ -1010,24 +1071,34 @@
 
 	stat = SMFIS_CONTINUE;
 
-#ifdef USE_DKIM
-	if ((stat = dkimcheck_eom(priv)) != SMFIS_CONTINUE)
-		return stat;
-#endif
-
 	if (priv->priv_delayed_reject) {
 		LIST_FOREACH(rcpt, &priv->priv_rcpt, r_list) 
 			log_and_report_greylisting(ctx, priv, rcpt->r_addr);
 		return mg_stat(priv, SMFIS_TEMPFAIL);
 	}
 
-	if (priv->priv_sr.sr_whitelist & EXF_WHITELIST && 
-	    priv->priv_sr.sr_whitelist & EXF_DEFAULT)
-		envrcpt_continue = 1;
+	/* 
+	 * If there are no dacl statements before matching racl line,
+	 * the return code was handled in the rcpt stage; no need to
+	 * do it here. Jump to logging and reporting
+	 */
+	if (conf.c_first_dacl_line >= priv->priv_acl_line) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"no dacl statements before matched racl line %d; skip to logging",
+			priv->priv_acl_line);
+		goto passed;
+	}
+
+#ifdef USE_DKIM
+	if ((stat = dkimcheck_eom(priv)) != SMFIS_CONTINUE)
+		return stat;
+#endif
 
 	/* 
 	 * We save data obtained from RCPT and we will restore it afterward
 	 */
+	save_acl_line = priv->priv_acl_line;
 	memcpy(&rcpt_sr, &priv->priv_sr, sizeof(rcpt_sr));
 	smtp_reply_init(&priv->priv_sr);
 	priv->priv_sr.sr_elapsed = priv->priv_max_elapsed;
@@ -1036,6 +1107,31 @@
 		return SMFIS_TEMPFAIL;
 	}
 
+	/* 
+	 * Only dacl lines up to racl match are evaluated; no match means
+	 * we handle the racl result, followed by logging and reporting
+	 */
+	if (priv->priv_acl_line == INT_MAX) {
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, 
+			"no dacl match before matching racl line; restoring racl results");
+
+		/* Restore the info collected from RCPT stage */
+		smtp_reply_free(&priv->priv_sr);
+		memcpy(&priv->priv_sr, &rcpt_sr, sizeof(rcpt_sr));
+		priv->priv_acl_line = save_acl_line;
+	}
+
+	/*
+	 * Handle dacl or delayed racl processing
+	 */
+
+	if (priv->priv_sr.sr_whitelist & EXF_WHITELIST) {
+		priv->priv_sr.sr_elapsed = 0;
+
+		goto passed;
+	}
+
 	if (priv->priv_sr.sr_whitelist & EXF_BLACKLIST) {
 		char *aclstr;
 		char addrstr[IPADDRSTRLEN];
@@ -1063,7 +1159,7 @@
 		return mg_stat(priv, stat_from_code(priv->priv_sr.sr_code));
 	}
 
-	if (priv->priv_sr.sr_whitelist & EXF_GREYLIST && envrcpt_continue) {
+	if (priv->priv_sr.sr_whitelist & EXF_GREYLIST) {
 		/*
 		 * Multiple recipients for a single message. Here we check 
 		 * each recipient individually for greylisting and autowhite 
@@ -1072,6 +1168,10 @@
 		priv->priv_sr.sr_whitelist &= ~EXF_NONE;
 		LIST_FOREACH(rcpt, &priv->priv_rcpt, r_list) {
 
+		if (conf.c_debug)
+			mg_log(LOG_DEBUG, "data stage: evaluating greylist for recipient %s", 
+			    rcpt->r_addr);
+
 			tuple.sa = SA(&priv->priv_addr);
 			tuple.salen = priv->priv_addrlen;
 			tuple.from = priv->priv_from;
@@ -1111,6 +1211,9 @@
 	}
 
 passed:
+	if (priv->priv_sr.sr_whitelist & EXF_WHITELIST)
+		priv->priv_last_whitelist = priv->priv_sr.sr_whitelist;
+
 	/* Add custom header from DATA stage ACL */
 	if (priv->priv_sr.sr_addheader) {
 		char *hdrname;
@@ -1130,10 +1233,6 @@
 		free(hdrname);
 	}
 
-	/* Restore the info collected from RCPT stage */
-	smtp_reply_free(&priv->priv_sr);
-	memcpy(&priv->priv_sr, &rcpt_sr, sizeof(rcpt_sr));
-
 	if (priv->priv_max_elapsed == 0) {
 		/* All recipients are whitelisted */
 		char *hdrstr = NULL;
@@ -1205,10 +1304,19 @@
 				priv->priv_last_whitelist &= ~EXF_RCPT;
 			}
 			if (priv->priv_last_whitelist & EXF_AUTO) {
+				if (priv->priv_last_whitelist & EXF_DEFAULT) {
+				ADD_REASON(whystr, 
+				    "IP, sender and "
+				    "recipient auto-whitelisted (default action)");
+				priv->priv_last_whitelist &= ~EXF_AUTO;
+				priv->priv_last_whitelist &= ~EXF_DEFAULT;
+				}
+				else {
 				ADD_REASON(whystr, 
 				    "IP, sender and "
 				    "recipient auto-whitelisted");
 				priv->priv_last_whitelist &= ~EXF_AUTO;
+				}
 			}
 			if (priv->priv_last_whitelist & EXF_DNSRBL) {
 				ADD_REASON(whystr, 
@@ -3075,9 +3183,9 @@
 		case 'A': {	/* Line number for matching ACL */
 			char buf[16];
 
-			if (priv->priv_sr.sr_acl_line) {
+			if (priv->priv_acl_line) {
 				snprintf(buf, sizeof(buf), "%d", 
-				   priv->priv_sr.sr_acl_line); 
+				   priv->priv_acl_line); 
 				mystrncat(&outstr, buf, &outmaxlen);
 			} else {
 				mystrncat(&outstr, "(none)", &outmaxlen);
@@ -3091,9 +3199,9 @@
 				snprintf(buf, sizeof(buf), "%s", 
 				   priv->priv_sr.sr_acl_id); 
 				mystrncat(&outstr, buf, &outmaxlen);
-			} else if (priv->priv_sr.sr_acl_line) {
+			} else if (priv->priv_acl_line) {
 				snprintf(buf, sizeof(buf), "%d", 
-				   priv->priv_sr.sr_acl_line); 
+				   priv->priv_acl_line); 
 				mystrncat(&outstr, buf, &outmaxlen);
 				mystrncat(&outstr, "(none)", &outmaxlen);
 			}
diff -urN milter-greylist-ORIG/milter-greylist.h milter-greylist/milter-greylist.h
--- milter-greylist-ORIG/milter-greylist.h	2009-11-01 03:03:33.000000000 +0100
+++ milter-greylist/milter-greylist.h	2009-11-08 10:19:03.000000000 +0100
@@ -155,7 +155,6 @@
 	int sr_nowhitelist;
 	time_t sr_elapsed;
 	time_t sr_remaining;
-	int sr_acl_line;
 	char *sr_acl_id;
 	time_t sr_delay;
 	time_t sr_autowhite;
@@ -209,6 +208,7 @@
 	char *priv_queueid;
 	int priv_delayed_reject;
 	struct smtp_reply priv_sr;
+	int priv_acl_line;
 	time_t priv_max_elapsed;
 	long long priv_last_whitelist;
 #if defined(USE_CURL) || defined(USE_LDAP)
