*** empty log message ***
[gnus] / lisp / gnus-nocem.el
1 ;;; gnus-nocem.el --- NoCeM pseudo-cancellation treatment
2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Keywords: news
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to
21 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27 (require 'gnus)
28 (eval-when-compile (require 'cl))
29
30 (defvar gnus-nocem-groups '("alt.nocem.misc" "news.admin.net-abuse.announce")
31   "*List of groups that will be searched for NoCeM messages.")
32
33 (defvar gnus-nocem-issuers '("Automoose-1" "clewis@ferret.ocunix.on.ca;")
34   "*List of NoCeM issuers to pay attention to.")
35
36 (defvar gnus-nocem-directory 
37   (concat (file-name-as-directory gnus-article-save-directory) "NoCeM/")
38   "*Directory where NoCeM files will be stored.")
39
40 (defvar gnus-nocem-expiry-wait 30
41   "*Number of days to keep NoCeM headers in the cache.")
42
43 ;;; Internal variables
44
45 (defvar gnus-nocem-active nil)
46 (defvar gnus-nocem-alist nil)
47 (defvar gnus-nocem-touched-alist nil)
48
49 ;;; Functions
50
51 (defun gnus-nocem-active-file ()
52   (concat (file-name-as-directory gnus-nocem-directory) "active"))
53
54 (defun gnus-nocem-cache-file ()
55   (concat (file-name-as-directory gnus-nocem-directory) "cache"))
56
57 (defun gnus-nocem-scan-groups ()
58   "Scan all NoCeM groups for new NoCeM messages."
59   (interactive)
60   (let ((groups gnus-nocem-groups)
61         group active gactive articles)
62     (or (file-exists-p gnus-nocem-directory)
63         (make-directory gnus-nocem-directory t))
64     ;; Load any previous NoCeM headers.
65     (gnus-nocem-load-cache)
66     ;; Read the active file if it hasn't been read yet.
67     (and (file-exists-p (gnus-nocem-active-file))
68          (not gnus-nocem-active)
69          (condition-case ()
70              (load (gnus-nocem-active-file) t t t)
71            (error nil)))
72     ;; Go through all groups and see whether new articles have
73     ;; arrived.  
74     (while groups
75       (setq group (pop groups))
76       (if (not (gnus-activate-group group))
77           () ; This group doesn't exist.
78         (setq active (nth 1 (assoc group gnus-nocem-active)))
79         (when (and (not (< (cdr gactive) (car gactive))) ; Empty group.
80                    (or (not active)
81                        (< (cdr active) 
82                           (cdr (setq gactive (gnus-gethash 
83                                               group gnus-newsrc-hashtb))))))
84           ;; Ok, there are new articles in this group, se we fetch the
85           ;; headers.
86           (let ((gnus-newsgroup-dependencies (make-vector 10))
87                 headers)
88             (setq headers
89                   (if (eq 'nov
90                           (gnus-retrieve-headers 
91                            (setq articles
92                                  (gnus-uncompress-range
93                                   (cons (1+ (cdr active)) (cdr gactive))))
94                            group))
95                       (gnus-get-newsgroup-headers-xover articles)
96                     (gnus-get-newsgroup-headers)))
97             (while headers
98               ;; We take a closer look on all articles that have
99               ;; "@@NCM" in the subject.  
100               (and (string-match "@@NCM" (mail-header-subject (car headers)))
101                    (gnus-nocem-check-article
102                     (mail-header-number (car headers)) group))
103               (setq headers (cdr headers)))))))
104     ;; Save the results, if any.
105     (gnus-nocem-save-cache)))
106
107 (defun gnus-nocem-check-article (number group)
108   "Check whether the current article is a NCM article and that we want it."
109   (save-excursion
110     (set-buffer nntp-server-buffer)
111     ;; Get the article.
112     (gnus-request-article-this-buffer number group)
113     (goto-char (point-min))
114     (let (issuer b)
115       ;; The article has to have proper NoCeM headers.
116       (when (and (setq b (search-forward "\n@@BEGIN NCM HEADERS\n" nil t))
117                  (search-forward "\n@@BEGIN NCM BODY\n" nil t))
118         ;; We get the name of the issuer.
119         (narrow-to-region b (match-beginning 0))
120         (setq issuer (mail-fetch-field "issuer"))
121         (and (member issuer gnus-nocem-issuers) ; We like her...
122              (gnus-nocem-verify-issuer issuer) ; She is who she says she is...
123              (gnus-nocem-enter-article)))) ; We gobble the message.
124     (widen)))
125
126 (defun gnus-nocem-verify-issuer (person)
127   "Verify using PGP that the canceler is who she says she is."
128   t)
129
130 (defun gnus-nocem-enter-article ()
131   "Enter the current article into the NoCeM cache."
132   (widen)
133   (goto-char (point-min))
134   (let ((b (search-forward "\n@@BEGIN NCM BODY\n" nil t))
135         (e (search-forward "\n@@END NCM BODY\n" nil t))
136         (buf (current-buffer))
137         ncm id)
138     (when (and b e)
139       (narrow-to-region b (1+ (match-beginning 0)))
140       (goto-char (point-min))
141       (while (search-forward "\t" nil t)
142         (when (boundp (let ((obarray gnus-newsrc-hashtb)) (read buf)))
143           (beginning-of-line)
144           (while (= (following-char) ?\t)
145             (forward-line -1))
146           (setq id (buffer-substring (point) (1- (search-forward "\t"))))
147           (push id ncm)
148           (gnus-sethash id t gnus-nocem-hashtb)
149           (forward-line 1)
150           (while (= (following-char) ?\t)
151             (forward-line 1))))
152       (when ncm
153         (setq gnus-nocem-touched-alist t)
154         (push (push (current-time-string) ncm) gnus-nocem-alist)))))
155
156 (defun gnus-nocem-load-cache ()
157   "Load the NoCeM cache."
158   (if gnus-nocem-alist
159       () ; Do nothing.
160     ;; The buffer doesn't exist, so we create it and load the NoCeM
161     ;; cache.  
162     (when (file-exists-p (gnus-nocem-cache-file))
163       (load (gnus-nocem-cache-file) t t t)
164       (gnus-nocem-alist-to-hashtb))))
165       
166 (defun gnus-nocem-save-cache ()
167   "Save the NoCeM cache."
168   (when (and gnus-nocem-alist
169              gnus-nocem-touched-alist)
170     (save-excursion
171       (nnheader-set-temp-buffer " *NoCeM*")
172       (insert (prin1-to-string
173                (list 'setq 'gnus-nocem-alist gnus-nocem-alist)))
174       (write-region (point-min) (point-max) 
175                     (gnus-nocem-cache-file) nil 'silent)
176       (kill-buffer (current-buffer))
177       (setq gnus-nocem-touched-alist nil))))
178
179 (defun gnus-nocem-alist-to-hashtb ()
180   "Create a hashtable from the Message-IDs we have."
181   (let ((alist gnus-nocem-alist)
182         (date (current-time-string))
183         entry)
184     (setq gnus-nocem-hashtb (* (length alist) 51))
185     (while alist
186       (setq entry (pop alist))
187       (if (> (gnus-days-between date (car entry)) gnus-nocem-expiry-wait)
188           ;; This entry has expired, so we remove it.
189           (setq gnus-nocem-alist (delq entry gnus-nocem-alist))
190         ;; This is ok, so we enter it into the hashtable.
191         (setq entry (cdr entry))
192         (while entry
193           (gnus-sethash (car entry) t gnus-nocem-hashtb)
194           (setq entry (cdr entry)))))))
195
196 (defun gnus-nocem-close ()
197   "Clear internal NoCeM variables."
198   (setq gnus-nocem-alist nil
199         gnus-nocem-hashtb nil
200         gnus-nocem-active nil
201         gnus-nocem-touched-alist nil))
202
203 ;;; gnus-nocem.el ends here