(with-syntax-table): Add some URLs WRT the XEmacs bug.
[gnus] / lisp / nnspool.el
1 ;;; nnspool.el --- spool access for GNU Emacs
2
3 ;; Copyright (C) 1988, 1989, 1990, 1993, 1994, 1995, 1996, 1997, 1998,
4 ;;   2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
5
6 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
7 ;;      Lars Magne Ingebrigtsen <larsi@gnus.org>
8 ;; Keywords: news
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;;; Code:
30
31 (require 'nnheader)
32 (require 'nntp)
33 (require 'nnoo)
34 (eval-when-compile (require 'cl))
35
36 (nnoo-declare nnspool)
37
38 (defvoo nnspool-inews-program news-inews-program
39   "Program to post news.
40 This is most commonly `inews' or `injnews'.")
41
42 (defvoo nnspool-inews-switches '("-h" "-S")
43   "Switches for nnspool-request-post to pass to `inews' for posting news.
44 If you are using Cnews, you probably should set this variable to nil.")
45
46 (defvoo nnspool-spool-directory
47     (file-name-as-directory (if (boundp 'news-directory)
48                                 (symbol-value 'news-directory)
49                               news-path))
50   "Local news spool directory.")
51
52 (defvoo nnspool-nov-directory (concat nnspool-spool-directory "over.view/")
53   "Local news nov directory.")
54
55 (defvoo nnspool-lib-dir
56     (if (file-exists-p "/usr/lib/news/active")
57         "/usr/lib/news/"
58       "/var/lib/news/")
59   "Where the local news library files are stored.")
60
61 (defvoo nnspool-active-file (concat nnspool-lib-dir "active")
62   "Local news active file.")
63
64 (defvoo nnspool-newsgroups-file (concat nnspool-lib-dir "newsgroups")
65   "Local news newsgroups file.")
66
67 (defvoo nnspool-distributions-file (concat nnspool-lib-dir "distribs.pat")
68   "Local news distributions file.")
69
70 (defvoo nnspool-history-file (concat nnspool-lib-dir "history")
71   "Local news history file.")
72
73 (defvoo nnspool-active-times-file (concat nnspool-lib-dir "active.times")
74   "Local news active date file.")
75
76 (defvoo nnspool-large-newsgroup 50
77   "The number of articles which indicates a large newsgroup.
78 If the number of articles is greater than the value, verbose
79 messages will be shown to indicate the current status.")
80
81 (defvoo nnspool-nov-is-evil nil
82   "Non-nil means that nnspool will never return NOV lines instead of headers.")
83
84 (defconst nnspool-sift-nov-with-sed nil
85   "If non-nil, use sed to get the relevant portion from the overview file.
86 If nil, nnspool will load the entire file into a buffer and process it
87 there.")
88
89 (defvoo nnspool-rejected-article-hook nil
90   "*A hook that will be run when an article has been rejected by the server.")
91
92 (defvoo nnspool-file-coding-system nnheader-file-coding-system
93   "Coding system for nnspool.")
94
95 \f
96
97 (defconst nnspool-version "nnspool 2.0"
98   "Version numbers of this version of NNSPOOL.")
99
100 (defvoo nnspool-current-directory nil
101   "Current news group directory.")
102
103 (defvoo nnspool-current-group nil)
104 (defvoo nnspool-status-string "")
105
106 \f
107 ;;; Interface functions.
108
109 (nnoo-define-basics nnspool)
110
111 (deffoo nnspool-retrieve-headers (articles &optional group server fetch-old)
112   "Retrieve the headers of ARTICLES."
113   (save-excursion
114     (set-buffer nntp-server-buffer)
115     (erase-buffer)
116     (when (nnspool-possibly-change-directory group)
117       (let* ((number (length articles))
118              (count 0)
119              (default-directory nnspool-current-directory)
120              (do-message (and (numberp nnspool-large-newsgroup)
121                               (> number nnspool-large-newsgroup)))
122              (nnheader-file-coding-system nnspool-file-coding-system)
123              file beg article ag)
124         (if (and (numberp (car articles))
125                  (nnspool-retrieve-headers-with-nov articles fetch-old))
126             ;; We successfully retrieved the NOV headers.
127             'nov
128           ;; No NOV headers here, so we do it the hard way.
129           (while (setq article (pop articles))
130             (if (stringp article)
131                 ;; This is a Message-ID.
132                 (setq ag (nnspool-find-id article)
133                       file (and ag (nnspool-article-pathname
134                                     (car ag) (cdr ag)))
135                       article (cdr ag))
136               ;; This is an article in the current group.
137               (setq file (int-to-string article)))
138             ;; Insert the head of the article.
139             (when (and file
140                        (file-exists-p file))
141               (insert "221 ")
142               (princ article (current-buffer))
143               (insert " Article retrieved.\n")
144               (setq beg (point))
145               (inline (nnheader-insert-head file))
146               (goto-char beg)
147               (if (search-forward "\n\n" nil t)
148                   (progn
149                     (forward-char -1)
150                     (insert ".\n"))
151                 (goto-char (point-max))
152                 (if (bolp)
153                     (insert ".\n")
154                   (insert "\n.\n")))
155               (delete-region (point) (point-max)))
156
157             (and do-message
158                  (zerop (% (incf count) 20))
159                  (nnheader-message 5 "nnspool: Receiving headers... %d%%"
160                                    (/ (* count 100) number))))
161
162           (when do-message
163             (nnheader-message 5 "nnspool: Receiving headers...done"))
164
165           ;; Fold continuation lines.
166           (nnheader-fold-continuation-lines)
167           'headers)))))
168
169 (deffoo nnspool-open-server (server &optional defs)
170   (nnoo-change-server 'nnspool server defs)
171   (cond
172    ((not (file-exists-p nnspool-spool-directory))
173     (nnspool-close-server)
174     (nnheader-report 'nnspool "Spool directory doesn't exist: %s"
175                      nnspool-spool-directory))
176    ((not (file-directory-p
177           (directory-file-name
178            (file-truename nnspool-spool-directory))))
179     (nnspool-close-server)
180     (nnheader-report 'nnspool "Not a directory: %s" nnspool-spool-directory))
181    ((not (file-exists-p nnspool-active-file))
182     (nnheader-report 'nnspool "The active file doesn't exist: %s"
183                      nnspool-active-file))
184    (t
185     (nnheader-report 'nnspool "Opened server %s using directory %s"
186                      server nnspool-spool-directory)
187     t)))
188
189 (deffoo nnspool-request-article (id &optional group server buffer)
190   "Select article by message ID (or number)."
191   (nnspool-possibly-change-directory group)
192   (let ((nntp-server-buffer (or buffer nntp-server-buffer))
193         file ag)
194     (if (stringp id)
195         ;; This is a Message-ID.
196         (when (setq ag (nnspool-find-id id))
197           (setq file (nnspool-article-pathname (car ag) (cdr ag))))
198       (setq file (nnspool-article-pathname nnspool-current-group id)))
199     (and file
200          (file-exists-p file)
201          (not (file-directory-p file))
202          (save-excursion (nnspool-find-file file))
203          ;; We return the article number and group name.
204          (if (numberp id)
205              (cons nnspool-current-group id)
206            ag))))
207
208 (deffoo nnspool-request-body (id &optional group server)
209   "Select article body by message ID (or number)."
210   (nnspool-possibly-change-directory group)
211   (let ((res (nnspool-request-article id)))
212     (when res
213       (save-excursion
214         (set-buffer nntp-server-buffer)
215         (goto-char (point-min))
216         (when (search-forward "\n\n" nil t)
217           (delete-region (point-min) (point)))
218         res))))
219
220 (deffoo nnspool-request-head (id &optional group server)
221   "Select article head by message ID (or number)."
222   (nnspool-possibly-change-directory group)
223   (let ((res (nnspool-request-article id)))
224     (when res
225       (save-excursion
226         (set-buffer nntp-server-buffer)
227         (goto-char (point-min))
228         (when (search-forward "\n\n" nil t)
229           (delete-region (1- (point)) (point-max)))
230         (nnheader-fold-continuation-lines)))
231     res))
232
233 (deffoo nnspool-request-group (group &optional server dont-check)
234   "Select news GROUP."
235   (let ((pathname (nnspool-article-pathname group))
236