+2005-09-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * spam.el (spam-use-gmane, spam-report-gmane-register-routine)
+       (spam-report-gmane-unregister-routine): added support for gmane
+       unregistration
+
+       * spam-report.el (spam-report-gmane-unspam)
+       (spam-report-gmane-spam): new wrappers around spam-report-gmane
+       (spam-report-gmane): changed to take a single article and do
+       unspam registration
+
 2005-09-21  Katsumi Yamaoka  <yamaoka@jpl.org>
 
        * mm-view.el (mm-inline-text-html-render-with-w3m): Revert.
 
   "Report an article as ham by resending via email."
   (spam-report-resend articles t))
 
-(defun spam-report-gmane (&rest articles)
-  "Report an article as spam through Gmane."
+(defun spam-report-gmane-unspam (&rest articles)
+  "Report ARTICLES as not-spam (unregister) through Gmane."
   (interactive (gnus-summary-work-articles current-prefix-arg))
   (dolist (article articles)
-    (when (and gnus-newsgroup-name
-              (or (null spam-report-gmane-regex)
-                  (string-match spam-report-gmane-regex gnus-newsgroup-name)))
-      (gnus-message 6 "Reporting spam article %d to spam.gmane.org..." article)
-      (if spam-report-gmane-use-article-number
-         (spam-report-url-ping
-          "spam.gmane.org"
-          (format "/%s:%d"
-                  (gnus-group-real-name gnus-newsgroup-name)
-                  article))
-       (with-current-buffer nntp-server-buffer
-         (gnus-request-head article gnus-newsgroup-name)
-         (let ((case-fold-search t)
-               field host report url)
-           ;; First check for X-Report-Spam because it's more specific to
-           ;; spam reporting than Archived-At.  OTOH, all new articles on
-           ;; Gmane don't have X-Report-Spam anymore (unless Lars changes his
-           ;; mind :-)).
-           ;;
-           ;; There might be more than one Archived-At header so we need to
-           ;; find (and transform) the one related to Gmane.
-           (setq field (or (gnus-fetch-field "X-Report-Spam")
-                           (gnus-fetch-field "Archived-At")))
-           (setq host (progn
-                        (string-match
-                         (concat "http://\\([a-z]+\\.gmane\\.org\\)"
-                                 "\\(/[^:/]+[:/][0-9]+\\)")
-                         field)
-                        (match-string 1 field)))
-           (setq report (match-string 2 field))
-           (when (string-equal "permalink.gmane.org" host)
-             (setq host "spam.gmane.org")
-             (setq report (gnus-replace-in-string
-                           report "/\\([0-9]+\\)$" ":\\1")))
-           (setq url (format "http://%s%s" host report))
-           (if (not (and host report url))
-               (gnus-message
-                3 "Could not find a spam report header in article %d..."
-                article)
-             (gnus-message 7 "Reporting spam through URL %s..." url)
-             (spam-report-url-ping host report))))))))
+    (spam-report-gmane t article)))
 
+(defun spam-report-gmane-spam (&rest articles)
+  "Report ARTICLES as spam through Gmane."
+  (interactive (gnus-summary-work-articles current-prefix-arg))
+  (dolist (article articles)
+    (spam-report-gmane nil article)))
+
+(defun spam-report-gmane (unspam article)
+  "Report ARTICLE as spam or not-spam through Gmane, depending on UNSPAM."
+  (when (and gnus-newsgroup-name
+            (or (null spam-report-gmane-regex)
+                (string-match spam-report-gmane-regex gnus-newsgroup-name)))
+    (gnus-message 6 "Reporting spam article %d to spam.gmane.org..." article)
+    (if spam-report-gmane-use-article-number
+       (spam-report-url-ping
+        (if unspam "unspam.gmane.org" "spam.gmane.org")
+        (format "/%s:%d"
+                (gnus-group-real-name gnus-newsgroup-name)
+                article))
+      (with-current-buffer nntp-server-buffer
+       (gnus-request-head article gnus-newsgroup-name)
+       (let ((case-fold-search t)
+             field host report url)
+         ;; First check for X-Report-Spam because it's more specific to
+         ;; spam reporting than Archived-At.  OTOH, all new articles on
+         ;; Gmane don't have X-Report-Spam anymore (unless Lars changes his
+         ;; mind :-)).
+         ;;
+         ;; There might be more than one Archived-At header so we need to
+         ;; find (and transform) the one related to Gmane.
+         (setq field (or (gnus-fetch-field "X-Report-Spam")
+                         (gnus-fetch-field "Archived-At")))
+         (setq host (progn
+                      (string-match
+                       (concat "http://\\([a-z]+\\.gmane\\.org\\)"
+                               "\\(/[^:/]+[:/][0-9]+\\)")
+                       field)
+                      (match-string 1 field)))
+         (setq report (match-string 2 field))
+         (when (string-equal "permalink.gmane.org" host)
+           (setq host (if unspam "unspam.gmane.org" "spam.gmane.org"))
+           (setq report (gnus-replace-in-string
+                         report "/\\([0-9]+\\)$" ":\\1")))
+         (setq url (format "http://%s%s" host report))
+         (if (not (and host report url))
+             (gnus-message
+              3 "Could not find a spam report header in article %d..."
+              article)
+           (gnus-message 7 "Reporting %s through URL %s..." (if unspam "unspam" "spam") url)
+           (spam-report-url-ping host report)))))))
 
 (defun spam-report-url-ping (host report)
   "Ping a host through HTTP, addressing a specific GET resource using
 
                              nil)
 
 (spam-install-nocheck-backend 'spam-use-gmane
-                             nil
+                             'spam-report-gmane-unregister-routine
                              'spam-report-gmane-register-routine
-                             ;; does Gmane support unregistration?
-                             nil
-                             nil)
+                             'spam-report-gmane-register-routine
+                             'spam-report-gmane-unregister-routine)
 
 (spam-install-nocheck-backend 'spam-use-resend
                              'spam-report-resend-register-ham-routine
 ;;{{{ Spam-report glue (gmane and resend reporting)
 (defun spam-report-gmane-register-routine (articles)
   (when articles
-    (apply 'spam-report-gmane articles)))
+    (apply 'spam-report-gmane-spam articles)))
+
+(defun spam-report-gmane-unregister-routine (articles)
+  (when articles
+    (apply 'spam-report-gmane-unspam articles)))
 
 (defun spam-report-resend-register-ham-routine (articles)
   (spam-report-resend-register-routine articles t))
 
+2005-09-21  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus.texi (Blacklists and Whitelists)
+       (Blacklists and Whitelists, BBDB Whitelists)
+       (Gmane Spam Reporting, Bogofilter, spam-stat spam filtering)
+       (spam-stat spam filtering, SpamOracle)
+       (Extending the Spam ELisp package): removed extra quote symbol for clarity
+
 2005-09-20  Reiner Steib  <Reiner.Steib@gmx.de>
 
        * gnus.texi (MIME Commands): Add gnus-article-save-part-and-strip,
 
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-spam-exit-processor-blacklist} \e$B$NBe$o$j$K!"\e(B
-@code{'(spam spam-use-blacklist)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
+@code{(spam spam-use-blacklist)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
 \e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 
 @end defvar
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-ham-exit-processor-whitelist} \e$B$NBe$o$j$K!"\e(B
-@code{'(ham spam-use-whitelist)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
-\e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
+@code{(ham spam-use-whitelist)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n\e(B
+\e$B$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 
 @end defvar
 
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-ham-exit-processor-BBDB} \e$B$NBe$o$j$K!"\e(B
-@code{'(ham spam-use-BBDB)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9$k\e(B
+@code{(ham spam-use-BBDB)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9$k\e(B
 \e$B$3$H$OJ]>Z$5$l$^$9!#\e(B
 
 @end defvar
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-spam-exit-processor-report-gmane} \e$B$NBe$o$j$K!"\e(B
-@code{'(spam spam-use-gmane)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9\e(B
+@code{(spam spam-use-gmane)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9\e(B
 \e$B$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 
 @end defvar
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-spam-exit-processor-bogofilter} \e$B$NBe$o$j$K!"\e(B
-@code{'(spam spam-use-bogofilter)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$K\e(B
-\e$BF0:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
+@code{(spam spam-use-bogofilter)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
+\e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 @defvar gnus-group-ham-exit-processor-bogofilter
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-ham-exit-processor-bogofilter} \e$B$NBe$o$j$K!"\e(B
-@code{'(ham spam-use-bogofilter)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
+@code{(ham spam-use-bogofilter)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
 \e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-spam-exit-processor-stat} \e$B$NBe$o$j$K!"\e(B
-@code{'(spam spam-use-stat)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9\e(B
-\e$B$k$3$H$OJ]>Z$5$l$^$9!#\e(B
+@code{(spam spam-use-stat)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9$k\e(B
+\e$B$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 @defvar gnus-group-ham-exit-processor-stat
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-ham-exit-processor-stat} \e$B$NBe$o$j$K!"\e(B
-@code{'(ham spam-use-stat)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9$k\e(B
+@code{(ham spam-use-stat)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0:n$9$k\e(B
 \e$B$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-spam-exit-processor-spamoracle} \e$B$NBe$o$j$K!"\e(B
-@code{'(spam spam-use-spamoracle)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$K\e(B
-\e$BF0:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
+@code{(spam spam-use-spamoracle)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
+\e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 @defvar gnus-group-ham-exit-processor-spamoracle
 @emph{\e$B7Y9p\e(B}
 
 \e$BGQ$l$?\e(B @code{gnus-group-ham-exit-processor-spamoracle} \e$B$NBe$o$j$K!"\e(B
-@code{'(ham spam-use-spamoracle)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
+@code{(ham spam-use-spamoracle)} \e$B$r;H$&$3$H$r?d>)$7$^$9!#$9$Y$FF1Ey$KF0\e(B
 \e$B:n$9$k$3$H$OJ]>Z$5$l$^$9!#\e(B
 @end defvar
 
 \e$B$F2<$5$$!#\e(B
 
 \e$B$5$i$K\e(B ham \e$B$H\e(B spam \e$B$N%W%m%;%C%5!<$OC10l$NJQ?t$G$O$J$/$5$l$D$D$"$j!"Be$o\e(B
-\e$B$j$K\e(B @code{'(spam spam-use-blackbox)} \e$B$^$?\e(B
-\e$B$O\e(B @code{'(ham spam-use-blackbox)} \e$B$N7A<0$,?d>)$5$l$^$9!#:#$N$H$3\e(B
+\e$B$j$K\e(B @code{(spam spam-use-blackbox)} \e$B$^$?\e(B
+\e$B$O\e(B @code{(ham spam-use-blackbox)} \e$B$N7A<0$,?d>)$5$l$^$9!#:#$N$H$3\e(B
 \e$B$m\e(B spam/ham \e$B%W%m%;%C%5!<JQ?t$O$^$@$"$A$3$A$K$"$j$^$9$,!"D9$/$O$"$j$^$;$s!#\e(B
 
 @lisp
 
 
 Instead of the obsolete
 @code{gnus-group-spam-exit-processor-blacklist}, it is recommended
-that you use @code{'(spam spam-use-blacklist)}.  Everything will work
+that you use @code{(spam spam-use-blacklist)}.  Everything will work
 the same way, we promise.
 
 @end defvar
 
 Instead of the obsolete
 @code{gnus-group-ham-exit-processor-whitelist}, it is recommended
-that you use @code{'(ham spam-use-whitelist)}.  Everything will work
+that you use @code{(ham spam-use-whitelist)}.  Everything will work
 the same way, we promise.
 
 @end defvar
 
 Instead of the obsolete
 @code{gnus-group-ham-exit-processor-BBDB}, it is recommended
-that you use @code{'(ham spam-use-BBDB)}.  Everything will work
+that you use @code{(ham spam-use-BBDB)}.  Everything will work
 the same way, we promise.
 
 @end defvar
 
 Instead of the obsolete
 @code{gnus-group-spam-exit-processor-report-gmane}, it is recommended
-that you use @code{'(spam spam-use-gmane)}.  Everything will work the
+that you use @code{(spam spam-use-gmane)}.  Everything will work the
 same way, we promise.
 
 @end defvar
 
 Instead of the obsolete
 @code{gnus-group-spam-exit-processor-bogofilter}, it is recommended
-that you use @code{'(spam spam-use-bogofilter)}.  Everything will work
+that you use @code{(spam spam-use-bogofilter)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 
 Instead of the obsolete
 @code{gnus-group-ham-exit-processor-bogofilter}, it is recommended
-that you use @code{'(ham spam-use-bogofilter)}.  Everything will work
+that you use @code{(ham spam-use-bogofilter)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 
 Instead of the obsolete
 @code{gnus-group-spam-exit-processor-stat}, it is recommended
-that you use @code{'(spam spam-use-stat)}.  Everything will work
+that you use @code{(spam spam-use-stat)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 
 Instead of the obsolete
 @code{gnus-group-ham-exit-processor-stat}, it is recommended
-that you use @code{'(ham spam-use-stat)}.  Everything will work
+that you use @code{(ham spam-use-stat)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 
 Instead of the obsolete
 @code{gnus-group-spam-exit-processor-spamoracle}, it is recommended
-that you use @code{'(spam spam-use-spamoracle)}.  Everything will work
+that you use @code{(spam spam-use-spamoracle)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 
 Instead of the obsolete
 @code{gnus-group-ham-exit-processor-spamoracle}, it is recommended
-that you use @code{'(ham spam-use-spamoracle)}.  Everything will work
+that you use @code{(ham spam-use-spamoracle)}.  Everything will work
 the same way, we promise.
 @end defvar
 
 provide them if Blackbox supports spam or ham processing.
 
 Also, ham and spam processors are being phased out as single
-variables.  Instead the form @code{'(spam spam-use-blackbox)} or
-@code{'(ham spam-use-blackbox)} is favored.  For now, spam/ham
+variables.  Instead the form @code{(spam spam-use-blackbox)} or
+@code{(ham spam-use-blackbox)} is favored.  For now, spam/ham
 processor variables are still around but they won't be for long.
 
 @lisp