diff --git a/TODO b/TODO
index 1ec2363d145eaa610885aba72d09382a5e4f5e49..29e09b6853c04f8bcebb9d098da3eb5b3eb7ed09 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,13 @@
+Need to exclude robot users from autowhitelist.  Don't want to have to
+list all users, so implement something like !*-admin@bmsi.com,@bmsi.com.
 
-Feedback from user training is ignored because UMIS has already been
+Milter won't start when a whitelist/blacklist file is missing.
+
+Milter won't start when it can't change permissions on *.lock to match
+*.log.  Should maybe ignore that error - the effect will be to set
+the permissions to default.
+
+GOSSiP feedback from user training is ignored because UMIS has already been
 removed from queue.  Maybe keep UMIS in queue, and add method to 
 alter last feedback for ID.
 
@@ -145,6 +153,8 @@ Need a test module to feed sample messages to a milter though a live
 sendmail and SMTP.  The mockup currently used is probably not very accurate,
 and doesn't test the threading code.
 
+DONE Delayed failure detection should parse From header to find email address.
+
 DONE When bms.py can't find templates, it passes None to dsn.create_msg(),
 which uses local variable as backup, which no longer exist.  Do plain
 CBV in that case instead.
diff --git a/bms.py b/bms.py
index 152b75c07bf4d251b63fdbf13731b91688e4fcc5..e6e4f0ebdc7d4b4ed2b5bf7bbd9c2eb1fcfabf43 100644
--- a/bms.py
+++ b/bms.py
@@ -1,6 +1,10 @@
 #!/usr/bin/env python
 # A simple milter that has grown quite a bit.
 # $Log$
+# Revision 1.86  2007/01/16 05:17:29  customdesigned
+# REJECT after data for blacklisted emails - so in case of mistakes, a
+# legitimate sender will know what happened.
+#
 # Revision 1.85  2007/01/11 04:31:26  customdesigned
 # Negative feedback for bad headers.  Purge cache logs on startup.
 #
@@ -77,7 +81,7 @@ from Milter.config import MilterConfigParser
 
 from fnmatch import fnmatchcase
 from email.Header import decode_header
-from email.Utils import getaddresses
+from email.Utils import getaddresses,parseaddr
 
 # Import gossip if available
 try:
@@ -108,6 +112,7 @@ subjpats = (
  r'^undeliver',
  r'^delivery\b.*\bfail',
  r'^delivery problem',
+ r'\bnot\bbe\bdelivered',
  r'\buser unknown\b',
  r'^failed',
  r'^echec de distribution',
@@ -674,7 +679,7 @@ class bmsMilter(Milter.Milter):
     else:
       global gossip
       if gossip and domain and rc == Milter.CONTINUE \
-	  and not self.internal_connection:
+	  and not (self.internal_connection or self.trusted_relay):
 	if self.spf and self.spf.result == 'pass':
 	  qual = 'SPF'
 	elif res == 'pass':
@@ -682,6 +687,9 @@ class bmsMilter(Milter.Milter):
 	elif hres == 'pass':
 	  qual = 'HELO'
 	  domain = self.spf.h
+	elif self.missing_ptr and self.spf.result == 'none':
+	  qual = 'IP'
+	  domain = self.connectip
 	else:
 	  qual = self.connectip
 	try:
@@ -976,11 +984,13 @@ class bmsMilter(Milter.Milter):
 	  # if confirmed by finding our signed Message-ID, 
 	  # original sender (encoded in Message-ID) is blacklisted
 
-    elif lname == 'from' and val.lower().startswith('postmaster@'):
-      # Yes, if From header comes last, this might not help much.
-      # But this is a heuristic - if MTAs would send proper DSNs in
-      # the first place, none of this would be needed.
-      self.is_bounce = True
+    elif lname == 'from':
+      name,email = parseaddr(val)
+      if email.lower().startswith('postmaster@'):
+	# Yes, if From header comes last, this might not help much.
+	# But this is a heuristic - if MTAs would send proper DSNs in
+	# the first place, none of this would be needed.
+	self.is_bounce = True
       
     # check for invalid message id
     elif lname == 'message-id' and len(val) < 4:
diff --git a/doc/faq.ht b/doc/faq.ht
index 4d74ee78fd496386a62ae20717ab90f730e45f45..3e2e4416fae1f78d6bbc90f6e81f4b606dca45df 100644
--- a/doc/faq.ht
+++ b/doc/faq.ht
@@ -13,6 +13,13 @@ Title: Python Milter FAQ
 
 <h3> <a name="compiling">Compiling Python Milter </a> </h3>
 
+<li> Q. I have tried to download the current milter code and my virus scan
+traps several viruses in the download.
+<p>  A. The milter source includes a number of deactivated viruses in
+the test directory.  All but the first and last lines of the base64
+encoded virus data has been removed.  I suppose I should randomize
+the first and last lines as well, since pymilter just deletes executables,
+and doesn't look for signatures.
 <li> Q. I have installed sendmail from source, but Python milter won't
 compile.
 <p>  A. Even though libmilter is officially supported in sendmail-8.12, 
diff --git a/doc/links.h b/doc/links.h
index 0696c85549abe6e36f5cefbc55711bb63bf37555..92336fa0562997221a1cfe4816b669e7e711e61f 100644
--- a/doc/links.h
+++ b/doc/links.h
@@ -17,5 +17,6 @@
 <li><a href="http://www.openspf.org/">SPF</a>
 <li><a href="pysrs.html">pysrs</a>
 <li><a href="http://cheeseshop.python.org/pypi/pyspf">pyspf</a>
+<li><a href="http://bmsi.com/python/pygossip.html">pygossip</a>
 <li><a href="http://bmsi.com/python/dspam.html">pydspam</a>
 <li><a href="http://bmsi.com/libdspam/dspam.html">libdspam</a>