+++ /dev/null
-;;; gnus-nocem.el --- NoCeM pseudo-cancellation treatment
-
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-
-(require 'gnus)
-(require 'nnmail)
-(require 'gnus-art)
-(require 'gnus-sum)
-(require 'gnus-range)
-
-(defgroup gnus-nocem nil
- "NoCeM pseudo-cancellation treatment."
- :group 'gnus-score)
-
-(defcustom gnus-nocem-groups
- '("news.lists.filters" "alt.nocem.misc")
- "*List of groups that will be searched for NoCeM messages."
- :group 'gnus-nocem
- :version "23.1"
- :type '(repeat (string :tag "Group")))
-
-(defcustom gnus-nocem-issuers
- '("Adri Verhoef"
- "alba-nocem@albasani.net"
- "bleachbot@httrack.com"
- "news@arcor-online.net"
- "news@uni-berlin.de"
- "nocem@arcor.de"
- "pgpmoose@killfile.org"
- "xjsppl@gmx.de")
- "*List of NoCeM issuers to pay attention to.
-
-This can also be a list of `(ISSUER CONDITION ...)' elements.
-
-See <URL:http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html> for an
-issuer registry."
- :group 'gnus-nocem
- :link '(url-link "http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html")
- :version "23.1"
- :type '(repeat (cons :format "%v" (string :tag "Issuer")
- (repeat :tag "Condition"
- (group (checklist :inline t (const not))
- (regexp :tag "Type" :value ".*")))))
- :get (lambda (symbol)
- (mapcar (lambda (elem)
- (if (consp elem)
- (cons (car elem)
- (mapcar (lambda (elt)
- (if (consp elt) elt (list elt)))
- (cdr elem)))
- (list elem)))
- (default-value symbol)))
- :set (lambda (symbol value)
- (custom-set-default
- symbol
- (mapcar (lambda (elem)
- (if (consp elem)
- (if (cdr elem)
- (mapcar (lambda (elt)
- (if (consp elt)
- (if (cdr elt) elt (car elt))
- elt))
- elem)
- (car elem))
- elem))
- value))))
-
-(defcustom gnus-nocem-directory
- (nnheader-concat gnus-article-save-directory "NoCeM/")
- "*Directory where NoCeM files will be stored."
- :group 'gnus-nocem
- :type 'directory)
-
-(defcustom gnus-nocem-expiry-wait 15
- "*Number of days to keep NoCeM headers in the cache."
- :group 'gnus-nocem
- :type 'integer)
-
-(defcustom gnus-nocem-verifyer (if (locate-library "epg")
- 'gnus-nocem-epg-verify
- 'pgg-verify)
- "*Function called to verify that the NoCeM message is valid.
-If the function in this variable isn't bound, the message will be used
-unconditionally."
- :group 'gnus-nocem
- :version "23.1"
- :type '(radio (function-item gnus-nocem-epg-verify)
- (function-item pgg-verify)
- (function-item mc-verify)
- (function :tag "other"))
- :set (lambda (symbol value)
- (custom-set-default symbol
- (if (and (eq value 'gnus-nocem-epg-verify)
- (not (locate-library "epg")))
- 'pgg-verify
- value))))
-
-(defcustom gnus-nocem-liberal-fetch nil
- "*If t try to fetch all messages which have @@NCM in the subject.
-Otherwise don't fetch messages which have references or whose message-id
-matches a previously scanned and verified nocem message."
- :group 'gnus-nocem
- :type 'boolean)
-
-(defcustom gnus-nocem-check-article-limit 500
- "*If non-nil, the maximum number of articles to check in any NoCeM group."
- :group 'gnus-nocem
- :version "21.1"
- :type '(choice (const :tag "unlimited" nil)
- (integer 1000)))
-
-(defcustom gnus-nocem-check-from t
- "Non-nil means check for valid issuers in message bodies.
-Otherwise don't bother fetching articles unless their author matches a
-valid issuer, which is much faster if you are selective about the issuers."
- :group 'gnus-nocem
- :version "21.1"
- :type 'boolean)
-
-;;; Internal variables
-
-(defvar gnus-nocem-active nil)
-(defvar gnus-nocem-alist nil)
-(defvar gnus-nocem-touched-alist nil)
-(defvar gnus-nocem-hashtb nil)
-(defvar gnus-nocem-seen-message-ids nil)
-
-;;; Functions
-
-(defun gnus-nocem-active-file ()
- (concat (file-name-as-directory gnus-nocem-directory) "active"))
-
-(defun gnus-nocem-cache-file ()
- (concat (file-name-as-directory gnus-nocem-directory) "cache"))
-
-;;
-;; faster lookups for group names:
-;;
-
-(defvar gnus-nocem-real-group-hashtb nil
- "Real-name mappings of subscribed groups.")
-
-(defun gnus-fill-real-hashtb ()
- "Fill up a hash table with the real-name mappings from the user's active file."
- (if (hash-table-p gnus-nocem-real-group-hashtb)
- (clrhash gnus-nocem-real-group-hashtb)
- (setq gnus-nocem-real-group-hashtb (make-hash-table :test 'equal)))
- (mapcar (lambda (group)
- (setq group (gnus-group-real-name (car group)))
- (puthash group t gnus-nocem-real-group-hashtb))
- gnus-newsrc-alist))
-
-;;;###autoload
-(defun gnus-nocem-scan-groups ()
- "Scan all NoCeM groups for new NoCeM messages."
- (interactive)
- (let ((groups gnus-nocem-groups)
- (gnus-inhibit-demon t)
- group active gactive articles check-headers)
- (gnus-make-directory gnus-nocem-directory)
- ;; Load any previous NoCeM headers.
- (gnus-nocem-load-cache)
- ;; Get the group name mappings:
- (gnus-fill-real-hashtb)
- ;; Read the active file if it hasn't been read yet.
- (and (file-exists-p (gnus-nocem-active-file))
- (not gnus-nocem-active)
- (ignore-errors
- (load (gnus-nocem-active-file) t t t)))
- ;; Go through all groups and see whether new articles have
- ;; arrived.
- (while (setq group (pop groups))
- (if (not (setq gactive (gnus-activate-group group)))
- () ; This group doesn't exist.
- (setq active (nth 1 (assoc group gnus-nocem-active)))
- (when (and (not (< (cdr gactive) (car gactive))) ; Empty group.
- (or (not active)
- (< (cdr active) (cdr gactive))))
- ;; Ok, there are new articles in this group, se we fetch the
- ;; headers.
- (save-excursion
- (let ((dependencies (make-vector 10 nil))
- headers header)
- (with-temp-buffer
- (setq headers
- (if (eq 'nov
- (gnus-retrieve-headers
- (setq articles
- (gnus-uncompress-range
- (cons
- (if active (1+ (cdr active))
- (car gactive))
- (cdr gactive))))
- group))
- (gnus-get-newsgroup-headers-xover
- articles nil dependencies)
- (gnus-get-newsgroup-headers dependencies)))
- (while (setq header (pop headers))
- ;; We take a closer look on all articles that have
- ;; "@@NCM" in the subject. Unless we already read
- ;; this cross posted message. Nocem messages
- ;; are not allowed to have references, so we can
- ;; ignore scanning followups.
- (and (string-match "@@NCM" (mail-header-subject header))
- (and gnus-nocem-check-from
- (let ((case-fold-search t))
- (catch 'ok
- (mapc
- (lambda (author)
- (if (consp author)
- (setq author (car author)))
- (if (string-match
- author (mail-header-from header))
- (throw 'ok t)))
- gnus-nocem-issuers)
- nil)))
- (or gnus-nocem-liberal-fetch
- (and (or (string= "" (mail-header-references
- header))
- (null (mail-header-references header)))
- (not (member (mail-header-message-id header)
- gnus-nocem-seen-message-ids))))
- (push header check-headers)))
- (setq check-headers (last (nreverse check-headers)
- gnus-nocem-check-article-limit))
- (let ((i 0)
- (len (length check-headers)))
- (dolist (h check-headers)
- (gnus-message
- 7 "Checking article %d in %s for NoCeM (%d of %d)..."
- (mail-header-number h) group (incf i) len)
- (gnus-nocem-check-article group h)))))))
- (setq gnus-nocem-active
- (cons (list group gactive)
- (delq (assoc group gnus-nocem-active)
- gnus-nocem-active)))))
- ;; Save the results, if any.
- (gnus-nocem-save-cache)
- (gnus-nocem-save-active)))
-
-(defun gnus-nocem-check-article (group header)
- "Check whether the current article is an NCM article and that we want it."
- ;; Get the article.
- (let ((date (mail-header-date header))
- (gnus-newsgroup-name group)
- issuer b e type)
- (when (or (not date)
- (time-less-p
- (time-since (date-to-time date))
- (days-to-time gnus-nocem-expiry-wait)))
- (gnus-request-article-this-buffer (mail-header-number header) group)
- (goto-char (point-min))
- (when (re-search-forward
- "-----BEGIN PGP\\(?: SIGNED\\)? MESSAGE-----"
- nil t)
- (delete-region (point-min) (match-beginning 0)))
- (when (re-search-forward
- "-----END PGP \\(?:MESSAGE\\|SIGNATURE\\)-----\n?"
- nil t)
- (delete-region (match-end 0) (point-max)))
- (goto-char (point-min))
- ;; The article has to have proper NoCeM headers.
- (when (and (setq b (search-forward "\n@@BEGIN NCM HEADERS\n" nil t))
- (setq e (search-forward "\n@@BEGIN NCM BODY\n" nil t)))
- ;; We get the name of the issuer.
- (narrow-to-region b e)
- (setq issuer (mail-fetch-field "issuer")
- type (mail-fetch-field "type"))
- (widen)
- (if (not (gnus-nocem-message-wanted-p issuer type))
- (message "invalid NoCeM issuer: %s" issuer)
- (and (gnus-nocem-verify-issuer issuer) ; She is who she says she is.
- (gnus-nocem-enter-article) ; We gobble the message.
- (push (mail-header-message-id header) ; But don't come back for
- gnus-nocem-seen-message-ids))))))) ; second helpings.
-
-(defun gnus-nocem-message-wanted-p (issuer type)
- (let ((issuers gnus-nocem-issuers)
- wanted conditions condition)
- (cond
- ;; Do the quick check first.
- ((member issuer issuers)
- t)
- ((setq conditions (cdr (assoc issuer issuers)))
- ;; Check whether we want this type.
- (while (setq condition (pop conditions))
- (cond
- ((stringp condition)
- (when (string-match condition type)
- (setq wanted t)))
- ((and (consp condition)
- (eq (car condition) 'not)
- (stringp (cadr condition)))
- (when (string-match (cadr condition) type)
- (setq wanted nil)))
- (t
- (error "Invalid NoCeM condition: %S" condition))))
- wanted))))
-
-(defun gnus-nocem-verify-issuer (person)
- "Verify using PGP that the canceler is who she says she is."
- (if (functionp gnus-nocem-verifyer)
- (ignore-errors
- (funcall gnus-nocem-verifyer))
- ;; If we don't have Mailcrypt, then we use the message anyway.
- t))
-
-(defun gnus-nocem-enter-article ()
- "Enter the current article into the NoCeM cache."
- (goto-char (point-min))
- (let ((b (search-forward "\n@@BEGIN NCM BODY\n" nil t))
- (e (search-forward "\n@@END NCM BODY\n" nil t))
- (buf (current-buffer))
- ncm id group)
- (when (and b e)
- (narrow-to-region b (1+ (match-beginning 0)))
- (goto-char (point-min))
- (while (search-forward "\t" nil t)
- (cond
- ((not (ignore-errors
- (setq group (gnus-group-real-name (symbol-name (read buf))))
- (gethash group gnus-nocem-real-group-hashtb)))
- ;; An error.
- )
- (t
- ;; Valid group.
- (beginning-of-line)
- (while (eq (char-after) ?\t)
- (forward-line -1))
- (setq id (buffer-substring (point) (1- (search-forward "\t"))))
- (unless (if (hash-table-p gnus-nocem-hashtb)
- (gethash id gnus-nocem-hashtb)
- (setq gnus-nocem-hashtb (make-hash-table :test 'equal))
- nil)
- ;; only store if not already present
- (puthash id t gnus-nocem-hashtb)
- (push id ncm))
- (forward-line 1)
- (while (eq (char-after) ?\t)
- (forward-line 1)))))
- (when ncm
- (setq gnus-nocem-touched-alist t)
- (push (cons (let ((time (current-time))) (setcdr (cdr time) nil) time)
- ncm)
- gnus-nocem-alist))
- t)))
-
-;;;###autoload
-(defun gnus-nocem-load-cache ()
- "Load the NoCeM cache."
- (interactive)
- (unless gnus-nocem-alist
- ;; The buffer doesn't exist, so we create it and load the NoCeM
- ;; cache.
- (when (file-exists-p (gnus-nocem-cache-file))
- (load (gnus-nocem-cache-file) t t t)
- (gnus-nocem-alist-to-hashtb))))
-
-(defun gnus-nocem-save-cache ()
- "Save the NoCeM cache."
- (when (and gnus-nocem-alist
- gnus-nocem-touched-alist)
- (with-temp-file (gnus-nocem-cache-file)
- (gnus-prin1 `(setq gnus-nocem-alist ',gnus-nocem-alist)))
- (setq gnus-nocem-touched-alist nil)))
-
-(defun gnus-nocem-save-active ()
- "Save the NoCeM active file."
- (with-temp-file (gnus-nocem-active-file)
- (gnus-prin1 `(setq gnus-nocem-active ',gnus-nocem-active))))
-
-(defun gnus-nocem-alist-to-hashtb ()
- "Create a hashtable from the Message-IDs we have."
- (let* ((alist gnus-nocem-alist)
- (pprev (cons nil alist))
- (prev pprev)
- (expiry (days-to-time gnus-nocem-expiry-wait))
- entry)
- (if (hash-table-p gnus-nocem-hashtb)
- (clrhash gnus-nocem-hashtb)
- (setq gnus-nocem-hashtb (make-hash-table :test 'equal)))
- (while (setq entry (car alist))
- (if (not (time-less-p (time-since (car entry)) expiry))
- ;; This entry has expired, so we remove it.
- (setcdr prev (cdr alist))
- (setq prev alist)
- ;; This is ok, so we enter it into the hashtable.
- (setq entry (cdr entry))
- (while entry
- (puthash (car entry) t gnus-nocem-hashtb)
- (setq entry (cdr entry))))
- (setq alist (cdr alist)))))
-
-(gnus-add-shutdown 'gnus-nocem-close 'gnus)
-
-(defun gnus-nocem-close ()
- "Clear internal NoCeM variables."
- (setq gnus-nocem-alist nil
- gnus-nocem-hashtb nil
- gnus-nocem-active nil
- gnus-nocem-touched-alist nil
- gnus-nocem-seen-message-ids nil
- gnus-nocem-real-group-hashtb nil))
-
-(defun gnus-nocem-unwanted-article-p (id)
- "Say whether article ID in the current group is wanted."
- (and gnus-nocem-hashtb
- (gethash id gnus-nocem-hashtb)))
-
-(autoload 'epg-make-context "epg")
-(eval-when-compile
- (autoload 'epg-verify-string "epg")
- (autoload 'epg-context-result-for "epg")
- (autoload 'epg-signature-status "epg"))
-
-(defun gnus-nocem-epg-verify ()
- "Return t if EasyPG verifies a signed message in the current buffer."
- (let ((context (epg-make-context 'OpenPGP))
- result)
- (epg-verify-string context (buffer-string))
- (and (setq result (epg-context-result-for context 'verify))
- (not (cdr result))
- (eq (epg-signature-status (car result)) 'good))))
-
-(provide 'gnus-nocem)
-
-;;; gnus-nocem.el ends here
* Highlighting and Menus:: Making buffers look all nice and cozy.
* Buttons:: Get tendinitis in ten easy steps!
* Daemons:: Gnus can do things behind your back.
-* NoCeM:: How to avoid spam and other fatty foods.
* Undo:: Some actions can be undone.
* Predicate Specifiers:: Specifying predicates.
* Moderation:: What to do if you're a moderator.
posted it to several groups separately. Posting the same article to
several groups (not cross-posting) is called @dfn{spamming}, and you are
by law required to send nasty-grams to anyone who perpetrates such a
-heinous crime. You may want to try NoCeM handling to filter out spam
-(@pxref{NoCeM}).
+heinous crime.
Remember: Cross-posting is kinda ok, but posting the same article
separately to several groups is not. Massive cross-posting (aka.
* Highlighting and Menus:: Making buffers look all nice and cozy.
* Buttons:: Get tendinitis in ten easy steps!
* Daemons:: Gnus can do things behind your back.
-* NoCeM:: How to avoid spam and other fatty foods.
* Undo:: Some actions can be undone.
* Predicate Specifiers:: Specifying predicates.
* Moderation:: What to do if you're a moderator.
(gnus-demon-add-handler 'gnus-demon-close-connections 30 t)
@end lisp
-@findex gnus-demon-add-nocem
@findex gnus-demon-add-scanmail
@findex gnus-demon-add-rescan
@findex gnus-demon-add-scan-timestamps
@findex gnus-demon-add-disconnection
Some ready-made functions to do this have been created:
-@code{gnus-demon-add-nocem}, @code{gnus-demon-add-disconnection},
+@code{gnus-demon-add-disconnection},
@code{gnus-demon-add-nntp-close-connection},
@code{gnus-demon-add-scan-timestamps}, @code{gnus-demon-add-rescan}, and
@code{gnus-demon-add-scanmail}. Just put those functions in your
behave.
-@node NoCeM
-@section NoCeM
-@cindex nocem
-@cindex spam
-
-@dfn{Spamming} is posting the same article lots and lots of times.
-Spamming is bad. Spamming is evil.
-
-Spamming is usually canceled within a day or so by various anti-spamming
-agencies. These agencies usually also send out @dfn{NoCeM} messages.
-NoCeM is pronounced ``no see-'em'', and means what the name
-implies---these are messages that make the offending articles, like, go
-away.
-
-What use are these NoCeM messages if the articles are canceled anyway?
-Some sites do not honor cancel messages and some sites just honor cancels
-from a select few people. Then you may wish to make use of the NoCeM
-messages, which are distributed in the newsgroups
-@samp{news.lists.filters}, @samp{alt.nocem.misc}, etc.
-
-Gnus can read and parse the messages in this group automatically, and
-this will make spam disappear.
-
-There are some variables to customize, of course:
-
-@table @code
-@item gnus-use-nocem
-@vindex gnus-use-nocem
-Set this variable to @code{t} to set the ball rolling. It is @code{nil}
-by default.
-
-You can also set this variable to a positive number as a group level.
-In that case, Gnus scans NoCeM messages when checking new news if this
-value is not exceeding a group level that you specify as the prefix
-argument to some commands, e.g. @code{gnus},
-@code{gnus-group-get-new-news}, etc. Otherwise, Gnus does not scan
-NoCeM messages if you specify a group level that is smaller than this
-value to those commands. For example, if you use 1 or 2 on the mail
-groups and the levels on the news groups remain the default, 3 is the
-best choice.
-
-@item gnus-nocem-groups
-@vindex gnus-nocem-groups
-Gnus will look for NoCeM messages in the groups in this list. The
-default is
-@lisp
-("news.lists.filters" "alt.nocem.misc")
-@end lisp
-
-@item gnus-nocem-issuers
-@vindex gnus-nocem-issuers
-There are many people issuing NoCeM messages. This list says what
-people you want to listen to. The default is:
-
-@lisp
-("Adri Verhoef"
- "alba-nocem@@albasani.net"
- "bleachbot@@httrack.com"
- "news@@arcor-online.net"
- "news@@uni-berlin.de"
- "nocem@@arcor.de"
- "pgpmoose@@killfile.org"
- "xjsppl@@gmx.de")
-@end lisp
-
-Known despammers that you can put in this list are listed at@*
-@uref{http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html}.
-
-You do not have to heed NoCeM messages from all these people---just the
-ones you want to listen to. You also don't have to accept all NoCeM
-messages from the people you like. Each NoCeM message has a @dfn{type}
-header that gives the message a (more or less, usually less) rigorous
-definition. Common types are @samp{spam}, @samp{spew}, @samp{mmf},
-@samp{binary}, and @samp{troll}. To specify this, you have to use
-@code{(@var{issuer} @var{conditions} @dots{})} elements in the list.
-Each condition is either a string (which is a regexp that matches types
-you want to use) or a list on the form @code{(not @var{string})}, where
-@var{string} is a regexp that matches types you don't want to use.
-
-For instance, if you want all NoCeM messages from Chris Lewis except his
-@samp{troll} messages, you'd say:
-
-@lisp
-("clewis@@ferret.ocunix.on.ca" ".*" (not "troll"))
-@end lisp
-
-On the other hand, if you just want nothing but his @samp{spam} and
-@samp{spew} messages, you'd say:
-
-@lisp
-("clewis@@ferret.ocunix.on.ca" (not ".*") "spew" "spam")
-@end lisp
-
-The specs are applied left-to-right.
-
-
-@item gnus-nocem-verifyer
-@vindex gnus-nocem-verifyer
-@findex gnus-nocem-epg-verify
-@findex pgg-verify
-This should be a function for verifying that the NoCeM issuer is who she
-says she is. This variable defaults to @code{gnus-nocem-epg-verify} if
-EasyPG is available, otherwise defaults to @code{pgg-verify}. The
-function should return non-@code{nil} if the verification is successful,
-otherwise (including the case the NoCeM message was not signed) should
-return @code{nil}. If this is too slow and you don't care for
-verification (which may be dangerous), you can set this variable to
-@code{nil}.
-
-Formerly the default was @code{mc-verify}, which is a Mailcrypt
-function. While you can still use it, you can change it into
-@code{gnus-nocem-epg-verify} or @code{pgg-verify} running with GnuPG if
-you are willing to add the @acronym{PGP} public keys to GnuPG's keyring.
-
-@item gnus-nocem-directory
-@vindex gnus-nocem-directory
-This is where Gnus will store its NoCeM cache files. The default is@*
-@file{~/News/NoCeM/}.
-
-@item gnus-nocem-expiry-wait
-@vindex gnus-nocem-expiry-wait
-The number of days before removing old NoCeM entries from the cache.
-The default is 15. If you make it shorter Gnus will be faster, but you
-might then see old spam.
-
-@item gnus-nocem-check-from
-@vindex gnus-nocem-check-from
-Non-@code{nil} means check for valid issuers in message bodies.
-Otherwise don't bother fetching articles unless their author matches a
-valid issuer; that is much faster if you are selective about the
-issuers.
-
-@item gnus-nocem-check-article-limit
-@vindex gnus-nocem-check-article-limit
-If non-@code{nil}, the maximum number of articles to check in any NoCeM
-group. @code{nil} means no restriction. NoCeM groups can be huge and
-very slow to process.
-
-@end table
-
-Using NoCeM could potentially be a memory hog. If you have many living
-(i. e., subscribed or unsubscribed groups), your Emacs process will grow
-big. If this is a problem, you should kill off all (or most) of your
-unsubscribed groups (@pxref{Subscription Commands}).
-
-
@node Undo
@section Undo
@cindex undo
@end iflatex
@end iftex
-@item
-Gnus can make use of NoCeM files to weed out spam (@pxref{NoCeM}).
-
-@lisp
-(setq gnus-use-nocem t)
-@end lisp
-
@item
Groups can be made permanently visible (@pxref{Listing Groups}).