Mercurial > hg > xemacs-beta
comparison lisp/gnus/nnml.el @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | 8b8b7f3559a2 |
children | 0d2f883870bc |
comparison
equal
deleted
inserted
replaced
69:804d1389bcd6 | 70:131b0175ea99 |
---|---|
1 ;;; nnml.el --- mail spool access for Gnus | 1 ;;; nnml.el --- mail spool access for Gnus |
2 ;; Copyright (C) 1995,96,97 Free Software Foundation, Inc. | 2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc. |
3 | 3 |
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> | 4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> |
5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> | 5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> |
6 ;; Keywords: news, mail | 6 ;; Keywords: news, mail |
7 | 7 |
24 | 24 |
25 ;;; Commentary: | 25 ;;; Commentary: |
26 | 26 |
27 ;; Based on nnspool.el by Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>. | 27 ;; Based on nnspool.el by Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>. |
28 ;; For an overview of what the interface functions do, please see the | 28 ;; For an overview of what the interface functions do, please see the |
29 ;; Gnus sources. | 29 ;; Gnus sources. |
30 | 30 |
31 ;;; Code: | 31 ;;; Code: |
32 | 32 |
33 (require 'nnheader) | 33 (require 'nnheader) |
34 (require 'nnmail) | 34 (require 'nnmail) |
38 (nnoo-declare nnml) | 38 (nnoo-declare nnml) |
39 | 39 |
40 (defvoo nnml-directory message-directory | 40 (defvoo nnml-directory message-directory |
41 "Mail spool directory.") | 41 "Mail spool directory.") |
42 | 42 |
43 (defvoo nnml-active-file | 43 (defvoo nnml-active-file |
44 (concat (file-name-as-directory nnml-directory) "active") | 44 (concat (file-name-as-directory nnml-directory) "active") |
45 "Mail active file.") | 45 "Mail active file.") |
46 | 46 |
47 (defvoo nnml-newsgroups-file | 47 (defvoo nnml-newsgroups-file |
48 (concat (file-name-as-directory nnml-directory) "newsgroups") | 48 (concat (file-name-as-directory nnml-directory) "newsgroups") |
49 "Mail newsgroups description file.") | 49 "Mail newsgroups description file.") |
50 | 50 |
51 (defvoo nnml-get-new-mail t | 51 (defvoo nnml-get-new-mail t |
52 "If non-nil, nnml will check the incoming mail file and split the mail.") | 52 "If non-nil, nnml will check the incoming mail file and split the mail.") |
53 | 53 |
54 (defvoo nnml-nov-is-evil nil | 54 (defvoo nnml-nov-is-evil nil |
55 "If non-nil, Gnus will never generate and use nov databases for mail groups. | 55 "If non-nil, Gnus will never generate and use nov databases for mail groups. |
56 Using nov databases will speed up header fetching considerably. | 56 Using nov databases will speed up header fetching considerably. |
57 This variable shouldn't be flipped much. If you have, for some reason, | 57 This variable shouldn't be flipped much. If you have, for some reason, |
58 set this to t, and want to set it to nil again, you should always run | 58 set this to t, and want to set it to nil again, you should always run |
59 the `nnml-generate-nov-databases' command. The function will go | 59 the `nnml-generate-nov-databases' command. The function will go |
60 through all nnml directories and generate nov databases for them | 60 through all nnml directories and generate nov databases for them |
61 all. This may very well take some time.") | 61 all. This may very well take some time.") |
62 | 62 |
63 (defvoo nnml-prepare-save-mail-hook nil | 63 (defvoo nnml-prepare-save-mail-hook nil |
64 "Hook run narrowed to an article before saving.") | 64 "Hook run narrowed to an article before saving.") |
65 | 65 |
66 (defvoo nnml-inhibit-expiry nil | 66 (defvoo nnml-inhibit-expiry nil |
88 | 88 |
89 ;;; Interface functions. | 89 ;;; Interface functions. |
90 | 90 |
91 (nnoo-define-basics nnml) | 91 (nnoo-define-basics nnml) |
92 | 92 |
93 (deffoo nnml-retrieve-headers (sequence &optional group server fetch-old) | 93 (deffoo nnml-retrieve-headers (sequence &optional newsgroup server fetch-old) |
94 (when (nnml-possibly-change-directory group server) | 94 (save-excursion |
95 (save-excursion | 95 (set-buffer nntp-server-buffer) |
96 (set-buffer nntp-server-buffer) | 96 (erase-buffer) |
97 (erase-buffer) | 97 (let ((file nil) |
98 (let ((file nil) | 98 (number (length sequence)) |
99 (number (length sequence)) | 99 (count 0) |
100 (count 0) | 100 beg article) |
101 beg article) | 101 (if (stringp (car sequence)) |
102 (if (stringp (car sequence)) | 102 'headers |
103 'headers | 103 (nnml-possibly-change-directory newsgroup server) |
104 (if (nnml-retrieve-headers-with-nov sequence fetch-old) | 104 (unless nnml-article-file-alist |
105 'nov | 105 (setq nnml-article-file-alist |
106 (while sequence | 106 (nnheader-article-to-file-alist nnml-current-directory))) |
107 (setq article (car sequence)) | 107 (if (nnml-retrieve-headers-with-nov sequence fetch-old) |
108 (setq file (nnml-article-to-file article)) | 108 'nov |
109 (when (and file | 109 (while sequence |
110 (file-exists-p file) | 110 (setq article (car sequence)) |
111 (not (file-directory-p file))) | 111 (setq file |
112 (insert (format "221 %d Article retrieved.\n" article)) | 112 (concat nnml-current-directory |
113 (setq beg (point)) | 113 (or (cdr (assq article nnml-article-file-alist)) |
114 (nnheader-insert-head file) | 114 ""))) |
115 (goto-char beg) | 115 (if (and (file-exists-p file) |
116 (if (search-forward "\n\n" nil t) | 116 (not (file-directory-p file))) |
117 (forward-char -1) | 117 (progn |
118 (goto-char (point-max)) | 118 (insert (format "221 %d Article retrieved.\n" article)) |
119 (insert "\n\n")) | 119 (setq beg (point)) |
120 (insert ".\n") | 120 (nnheader-insert-head file) |
121 (delete-region (point) (point-max))) | 121 (goto-char beg) |
122 (setq sequence (cdr sequence)) | 122 (if (search-forward "\n\n" nil t) |
123 (setq count (1+ count)) | 123 (forward-char -1) |
124 (and (numberp nnmail-large-newsgroup) | 124 (goto-char (point-max)) |
125 (> number nnmail-large-newsgroup) | 125 (insert "\n\n")) |
126 (zerop (% count 20)) | 126 (insert ".\n") |
127 (nnheader-message 6 "nnml: Receiving headers... %d%%" | 127 (delete-region (point) (point-max)))) |
128 (/ (* count 100) number)))) | 128 (setq sequence (cdr sequence)) |
129 | 129 (setq count (1+ count)) |
130 (and (numberp nnmail-large-newsgroup) | 130 (and (numberp nnmail-large-newsgroup) |
131 (> number nnmail-large-newsgroup) | 131 (> number nnmail-large-newsgroup) |
132 (nnheader-message 6 "nnml: Receiving headers...done")) | 132 (zerop (% count 20)) |
133 | 133 (nnheader-message 6 "nnml: Receiving headers... %d%%" |
134 (nnheader-fold-continuation-lines) | 134 (/ (* count 100) number)))) |
135 'headers)))))) | 135 |
136 (and (numberp nnmail-large-newsgroup) | |
137 (> number nnmail-large-newsgroup) | |
138 (nnheader-message 6 "nnml: Receiving headers...done")) | |
139 | |
140 (nnheader-fold-continuation-lines) | |
141 'headers))))) | |
136 | 142 |
137 (deffoo nnml-open-server (server &optional defs) | 143 (deffoo nnml-open-server (server &optional defs) |
138 (nnoo-change-server 'nnml server defs) | 144 (nnoo-change-server 'nnml server defs) |
139 (when (not (file-exists-p nnml-directory)) | 145 (when (not (file-exists-p nnml-directory)) |
140 (condition-case () | 146 (condition-case () |
141 (make-directory nnml-directory t) | 147 (make-directory nnml-directory t) |
142 (error))) | 148 (error t))) |
143 (cond | 149 (cond |
144 ((not (file-exists-p nnml-directory)) | 150 ((not (file-exists-p nnml-directory)) |
145 (nnml-close-server) | 151 (nnml-close-server) |
146 (nnheader-report 'nnml "Couldn't create directory: %s" nnml-directory)) | 152 (nnheader-report 'nnml "Couldn't create directory: %s" nnml-directory)) |
147 ((not (file-directory-p (file-truename nnml-directory))) | 153 ((not (file-directory-p (file-truename nnml-directory))) |
148 (nnml-close-server) | 154 (nnml-close-server) |
150 (t | 156 (t |
151 (nnheader-report 'nnml "Opened server %s using directory %s" | 157 (nnheader-report 'nnml "Opened server %s using directory %s" |
152 server nnml-directory) | 158 server nnml-directory) |
153 t))) | 159 t))) |
154 | 160 |
155 (defun nnml-request-regenerate (server) | 161 (deffoo nnml-request-article (id &optional newsgroup server buffer) |
156 (nnml-possibly-change-directory nil server) | 162 (nnml-possibly-change-directory newsgroup server) |
157 (nnml-generate-nov-databases) | |
158 t) | |
159 | |
160 (deffoo nnml-request-article (id &optional group server buffer) | |
161 (nnml-possibly-change-directory group server) | |
162 (let* ((nntp-server-buffer (or buffer nntp-server-buffer)) | 163 (let* ((nntp-server-buffer (or buffer nntp-server-buffer)) |
163 path gpath group-num) | 164 file path gpath group-num) |
164 (if (stringp id) | 165 (if (stringp id) |
165 (when (and (setq group-num (nnml-find-group-number id)) | 166 (when (and (setq group-num (nnml-find-group-number id)) |
166 (cdr | 167 (setq file (cdr |
167 (assq (cdr group-num) | 168 (assq (cdr group-num) |
168 (nnheader-article-to-file-alist | 169 (nnheader-article-to-file-alist |
169 (setq gpath | 170 (setq gpath |
170 (nnmail-group-pathname | 171 (nnmail-group-pathname |
171 (car group-num) | 172 (car group-num) |
172 nnml-directory)))))) | 173 nnml-directory))))))) |
173 (setq path (concat gpath (int-to-string (cdr group-num))))) | 174 (setq path (concat gpath (int-to-string (cdr group-num))))) |
174 (setq path (nnml-article-to-file id))) | 175 (unless nnml-article-file-alist |
175 (cond | 176 (setq nnml-article-file-alist |
177 (nnheader-article-to-file-alist nnml-current-directory))) | |
178 (when (setq file (cdr (assq id nnml-article-file-alist))) | |
179 (setq path (concat nnml-current-directory file)))) | |
180 (cond | |
176 ((not path) | 181 ((not path) |
177 (nnheader-report 'nnml "No such article: %s" id)) | 182 (nnheader-report 'nnml "No such article: %s" id)) |
178 ((not (file-exists-p path)) | 183 ((not (file-exists-p path)) |
179 (nnheader-report 'nnml "No such file: %s" path)) | 184 (nnheader-report 'nnml "No such file: %s" path)) |
180 ((file-directory-p path) | 185 ((file-directory-p path) |
182 ((not (save-excursion (nnmail-find-file path))) | 187 ((not (save-excursion (nnmail-find-file path))) |
183 (nnheader-report 'nnml "Couldn't read file: %s" path)) | 188 (nnheader-report 'nnml "Couldn't read file: %s" path)) |
184 (t | 189 (t |
185 (nnheader-report 'nnml "Article %s retrieved" id) | 190 (nnheader-report 'nnml "Article %s retrieved" id) |
186 ;; We return the article number. | 191 ;; We return the article number. |
187 (cons (if group-num (car group-num) group) | 192 (cons newsgroup (string-to-int (file-name-nondirectory path))))))) |
188 (string-to-int (file-name-nondirectory path))))))) | |
189 | 193 |
190 (deffoo nnml-request-group (group &optional server dont-check) | 194 (deffoo nnml-request-group (group &optional server dont-check) |
191 (cond | 195 (cond |
192 ((not (nnml-possibly-change-directory group server)) | 196 ((not (nnml-possibly-change-directory group server)) |
193 (nnheader-report 'nnml "Invalid group (no such directory)")) | 197 (nnheader-report 'nnml "Invalid group (no such directory)")) |
194 ((not (file-exists-p nnml-current-directory)) | |
195 (nnheader-report 'nnml "Directory %s does not exist" | |
196 nnml-current-directory)) | |
197 ((not (file-directory-p nnml-current-directory)) | 198 ((not (file-directory-p nnml-current-directory)) |
198 (nnheader-report 'nnml "%s is not a directory" nnml-current-directory)) | 199 (nnheader-report 'nnml "%s is not a directory" nnml-current-directory)) |
199 (dont-check | 200 (dont-check |
200 (nnheader-report 'nnml "Group %s selected" group) | 201 (nnheader-report 'nnml "Group %s selected" group) |
201 t) | 202 t) |
202 (t | 203 (t |
203 (nnheader-re-read-dir nnml-current-directory) | |
204 (nnmail-activate 'nnml) | 204 (nnmail-activate 'nnml) |
205 (let ((active (nth 1 (assoc group nnml-group-alist)))) | 205 (let ((active (nth 1 (assoc group nnml-group-alist)))) |
206 (if (not active) | 206 (if (not active) |
207 (nnheader-report 'nnml "No such group: %s" group) | 207 (nnheader-report 'nnml "No such group: %s" group) |
208 (nnheader-report 'nnml "Selected group %s" group) | 208 (nnheader-report 'nnml "Selected group %s" group) |
209 (nnheader-insert "211 %d %d %d %s\n" | 209 (nnheader-insert "211 %d %d %d %s\n" |
210 (max (1+ (- (cdr active) (car active))) 0) | 210 (max (1+ (- (cdr active) (car active))) 0) |
211 (car active) (cdr active) group)))))) | 211 (car active) (cdr active) group)))))) |
212 | 212 |
213 (deffoo nnml-request-scan (&optional group server) | 213 (deffoo nnml-request-scan (&optional group server) |
214 (setq nnml-article-file-alist nil) | 214 (setq nnml-article-file-alist nil) |
215 (nnml-possibly-change-directory group server) | |
216 (nnmail-get-new-mail 'nnml 'nnml-save-nov nnml-directory group)) | 215 (nnmail-get-new-mail 'nnml 'nnml-save-nov nnml-directory group)) |
217 | 216 |
218 (deffoo nnml-close-group (group &optional server) | 217 (deffoo nnml-close-group (group &optional server) |
219 (setq nnml-article-file-alist nil) | 218 (setq nnml-article-file-alist nil) |
220 t) | 219 t) |
221 | 220 |
222 (deffoo nnml-request-create-group (group &optional server args) | 221 (deffoo nnml-request-create-group (group &optional server) |
223 (nnmail-activate 'nnml) | 222 (nnmail-activate 'nnml) |
224 (unless (assoc group nnml-group-alist) | 223 (or (assoc group nnml-group-alist) |
225 (let (active) | 224 (let (active) |
226 (push (list group (setq active (cons 1 0))) | 225 (setq nnml-group-alist (cons (list group (setq active (cons 1 0))) |
227 nnml-group-alist) | 226 nnml-group-alist)) |
228 (nnml-possibly-create-directory group) | 227 (nnml-possibly-create-directory group) |
229 (nnml-possibly-change-directory group server) | 228 (nnml-possibly-change-directory group server) |
230 (let ((articles (nnheader-directory-articles nnml-current-directory))) | 229 (let ((articles |
231 (when articles | 230 (nnheader-directory-articles nnml-current-directory ))) |
232 (setcar active (apply 'min articles)) | 231 (and articles |
233 (setcdr active (apply 'max articles)))) | 232 (progn |
234 (nnmail-save-active nnml-group-alist nnml-active-file))) | 233 (setcar active (apply 'min articles)) |
234 (setcdr active (apply 'max articles))))) | |
235 (nnmail-save-active nnml-group-alist nnml-active-file))) | |
235 t) | 236 t) |
236 | 237 |
237 (deffoo nnml-request-list (&optional server) | 238 (deffoo nnml-request-list (&optional server) |
238 (save-excursion | 239 (save-excursion |
239 (nnmail-find-file nnml-active-file) | 240 (nnmail-find-file nnml-active-file) |
240 (setq nnml-group-alist (nnmail-get-active)) | 241 (setq nnml-group-alist (nnmail-get-active)))) |
241 t)) | |
242 | 242 |
243 (deffoo nnml-request-newgroups (date &optional server) | 243 (deffoo nnml-request-newgroups (date &optional server) |
244 (nnml-request-list server)) | 244 (nnml-request-list server)) |
245 | 245 |
246 (deffoo nnml-request-list-newsgroups (&optional server) | 246 (deffoo nnml-request-list-newsgroups (&optional server) |
247 (save-excursion | 247 (save-excursion |
248 (nnmail-find-file nnml-newsgroups-file))) | 248 (nnmail-find-file nnml-newsgroups-file))) |
249 | 249 |
250 (deffoo nnml-request-expire-articles (articles group | 250 (deffoo nnml-request-expire-articles (articles newsgroup &optional server force) |
251 &optional server force) | 251 (nnml-possibly-change-directory newsgroup server) |
252 (nnml-possibly-change-directory group server) | 252 (let* ((active-articles |
253 (let* ((active-articles | |
254 (nnheader-directory-articles nnml-current-directory)) | 253 (nnheader-directory-articles nnml-current-directory)) |
255 (is-old t) | 254 (is-old t) |
256 article rest mod-time number) | 255 article rest mod-time number) |
257 (nnmail-activate 'nnml) | 256 (nnmail-activate 'nnml) |
258 | 257 |
258 (unless nnml-article-file-alist | |
259 (setq nnml-article-file-alist | |
260 (nnheader-article-to-file-alist nnml-current-directory))) | |
261 | |
259 (while (and articles is-old) | 262 (while (and articles is-old) |
260 (when (setq article (nnml-article-to-file (setq number (pop articles)))) | 263 (setq article (concat nnml-current-directory |
261 (when (setq mod-time (nth 5 (file-attributes article))) | 264 (int-to-string |
262 (if (and (nnml-deletable-article-p group number) | 265 (setq number (pop articles))))) |
263 (setq is-old | 266 (when (setq mod-time (nth 5 (file-attributes article))) |
264 (nnmail-expired-article-p group mod-time force | 267 (if (and (nnml-deletable-article-p newsgroup number) |
265 nnml-inhibit-expiry))) | 268 (setq is-old |
266 (progn | 269 (nnmail-expired-article-p newsgroup mod-time force |
267 (nnheader-message 5 "Deleting article %s in %s" | 270 nnml-inhibit-expiry))) |
268 article group) | 271 (progn |
269 (condition-case () | 272 (nnheader-message 5 "Deleting article %s in %s..." |
270 (funcall nnmail-delete-file-function article) | 273 article newsgroup) |
271 (file-error | 274 (condition-case () |
272 (push number rest))) | 275 (funcall nnmail-delete-file-function article) |
273 (setq active-articles (delq number active-articles)) | 276 (file-error |
274 (nnml-nov-delete-article group number)) | 277 (push number rest))) |
275 (push number rest))))) | 278 (setq active-articles (delq number active-articles)) |
276 (let ((active (nth 1 (assoc group nnml-group-alist)))) | 279 (nnml-nov-delete-article newsgroup number)) |
280 (push number rest)))) | |
281 (let ((active (nth 1 (assoc newsgroup nnml-group-alist)))) | |
277 (when active | 282 (when active |
278 (setcar active (or (and active-articles | 283 (setcar active (or (and active-articles |
279 (apply 'min active-articles)) | 284 (apply 'min active-articles)) |
280 (1+ (cdr active))))) | 285 (1+ (cdr active))))) |
281 (nnmail-save-active nnml-group-alist nnml-active-file)) | 286 (nnmail-save-active nnml-group-alist nnml-active-file)) |
282 (nnml-save-nov) | 287 (nnml-save-nov) |
288 (message "") | |
283 (nconc rest articles))) | 289 (nconc rest articles))) |
284 | 290 |
285 (deffoo nnml-request-move-article | 291 (deffoo nnml-request-move-article |
286 (article group server accept-form &optional last) | 292 (article group server accept-form &optional last) |
287 (let ((buf (get-buffer-create " *nnml move*")) | 293 (let ((buf (get-buffer-create " *nnml move*")) |
288 result) | 294 result) |
289 (nnml-possibly-change-directory group server) | 295 (nnml-possibly-change-directory group server) |
290 (nnml-update-file-alist) | 296 (unless nnml-article-file-alist |
291 (and | 297 (setq nnml-article-file-alist |
298 (nnheader-article-to-file-alist nnml-current-directory))) | |
299 (and | |
292 (nnml-deletable-article-p group article) | 300 (nnml-deletable-article-p group article) |
293 (nnml-request-article article group server) | 301 (nnml-request-article article group server) |
294 (save-excursion | 302 (save-excursion |
295 (set-buffer buf) | 303 (set-buffer buf) |
296 (insert-buffer-substring nntp-server-buffer) | 304 (insert-buffer-substring nntp-server-buffer) |
299 result) | 307 result) |
300 (progn | 308 (progn |
301 (nnml-possibly-change-directory group server) | 309 (nnml-possibly-change-directory group server) |
302 (condition-case () | 310 (condition-case () |
303 (funcall nnmail-delete-file-function | 311 (funcall nnmail-delete-file-function |
304 (nnml-article-to-file article)) | 312 (concat nnml-current-directory |
313 (int-to-string article))) | |
305 (file-error nil)) | 314 (file-error nil)) |
306 (nnml-nov-delete-article group article) | 315 (nnml-nov-delete-article group article) |
307 (when last | 316 (and last (nnml-save-nov)))) |
308 (nnml-save-nov) | |
309 (nnmail-save-active nnml-group-alist nnml-active-file)))) | |
310 result)) | 317 result)) |
311 | 318 |
312 (deffoo nnml-request-accept-article (group &optional server last) | 319 (deffoo nnml-request-accept-article (group &optional server last) |
313 (nnml-possibly-change-directory group server) | 320 (nnml-possibly-change-directory group server) |
314 (nnmail-check-syntax) | 321 (nnmail-check-syntax) |
315 (let (result) | 322 (let (result) |
316 (when nnmail-cache-accepted-message-ids | |
317 (nnmail-cache-insert (nnmail-fetch-field "message-id"))) | |
318 (if (stringp group) | 323 (if (stringp group) |
319 (and | 324 (and |
320 (nnmail-activate 'nnml) | 325 (nnmail-activate 'nnml) |
321 (setq result (car (nnml-save-mail | 326 ;; We trick the choosing function into believing that only one |
322 (list (cons group (nnml-active-number group)))))) | 327 ;; group is available. |
328 (let ((nnmail-split-methods (list (list group "")))) | |
329 (setq result (car (nnml-save-mail)))) | |
323 (progn | 330 (progn |
324 (nnmail-save-active nnml-group-alist nnml-active-file) | 331 (nnmail-save-active nnml-group-alist nnml-active-file) |
325 (and last (nnml-save-nov)))) | 332 (and last (nnml-save-nov)))) |
326 (and | 333 (and |
327 (nnmail-activate 'nnml) | 334 (nnmail-activate 'nnml) |
328 (if (not (setq result (nnmail-article-group 'nnml-active-number))) | 335 (setq result (car (nnml-save-mail))) |
329 (setq result 'junk) | 336 (progn |
330 (setq result (car (nnml-save-mail result)))) | |
331 (when last | |
332 (nnmail-save-active nnml-group-alist nnml-active-file) | 337 (nnmail-save-active nnml-group-alist nnml-active-file) |
333 (when nnmail-cache-accepted-message-ids | 338 (and last (nnml-save-nov))))) |
334 (nnmail-cache-close)) | |
335 (nnml-save-nov)))) | |
336 result)) | 339 result)) |
337 | 340 |
338 (deffoo nnml-request-replace-article (article group buffer) | 341 (deffoo nnml-request-replace-article (article group buffer) |
339 (nnml-possibly-change-directory group) | 342 (nnml-possibly-change-directory group) |
340 (save-excursion | 343 (save-excursion |
343 (let ((chars (nnmail-insert-lines)) | 346 (let ((chars (nnmail-insert-lines)) |
344 (art (concat (int-to-string article) "\t")) | 347 (art (concat (int-to-string article) "\t")) |
345 headers) | 348 headers) |
346 (when (condition-case () | 349 (when (condition-case () |
347 (progn | 350 (progn |
348 (nnmail-write-region | 351 (write-region |
349 (point-min) (point-max) | 352 (point-min) (point-max) |
350 (or (nnml-article-to-file article) | 353 (concat nnml-current-directory (int-to-string article)) |
351 (concat nnml-current-directory | |
352 (int-to-string article))) | |
353 nil (if (nnheader-be-verbose 5) nil 'nomesg)) | 354 nil (if (nnheader-be-verbose 5) nil 'nomesg)) |
354 t) | 355 t) |
355 (error nil)) | 356 (error nil)) |
356 (setq headers (nnml-parse-head chars article)) | 357 (setq headers (nnml-parse-head chars article)) |
357 ;; Replace the NOV line in the NOV file. | 358 ;; Replace the NOV line in the NOV file. |
358 (save-excursion | 359 (save-excursion |
359 (set-buffer (nnml-open-nov group)) | 360 (set-buffer (nnml-open-nov group)) |
360 (goto-char (point-min)) | 361 (goto-char (point-min)) |
361 (if (or (looking-at art) | 362 (if (or (looking-at art) |
362 (search-forward (concat "\n" art) nil t)) | 363 (search-forward (concat "\n" art) nil t)) |
363 ;; Delete the old NOV line. | 364 ;; Delete the old NOV line. |
364 (delete-region (progn (beginning-of-line) (point)) | 365 (delete-region (progn (beginning-of-line) (point)) |
365 (progn (forward-line 1) (point))) | 366 (progn (forward-line 1) (point))) |
366 ;; The line isn't here, so we have to find out where | 367 ;; The line isn't here, so we have to find out where |
367 ;; we should insert it. (This situation should never | 368 ;; we should insert it. (This situation should never |
368 ;; occur, but one likes to make sure...) | 369 ;; occur, but one likes to make sure...) |
369 (while (and (looking-at "[0-9]+\t") | 370 (while (and (looking-at "[0-9]+\t") |
370 (< (string-to-int | 371 (< (string-to-int |
371 (buffer-substring | 372 (buffer-substring |
372 (match-beginning 0) (match-end 0))) | 373 (match-beginning 0) (match-end 0))) |
373 article) | 374 article) |
374 (zerop (forward-line 1))))) | 375 (zerop (forward-line 1))))) |
375 (beginning-of-line) | 376 (beginning-of-line) |
376 (nnheader-insert-nov headers) | 377 (nnheader-insert-nov headers) |
379 | 380 |
380 (deffoo nnml-request-delete-group (group &optional force server) | 381 (deffoo nnml-request-delete-group (group &optional force server) |
381 (nnml-possibly-change-directory group server) | 382 (nnml-possibly-change-directory group server) |
382 (when force | 383 (when force |
383 ;; Delete all articles in GROUP. | 384 ;; Delete all articles in GROUP. |
384 (let ((articles | 385 (let ((articles |
385 (directory-files | 386 (directory-files |
386 nnml-current-directory t | 387 nnml-current-directory t |
387 (concat nnheader-numerical-short-files | 388 (concat nnheader-numerical-short-files |
388 "\\|" (regexp-quote nnml-nov-file-name) "$"))) | 389 "\\|" (regexp-quote nnml-nov-file-name) "$"))) |
389 article) | 390 article) |
390 (while articles | 391 (while articles |
391 (setq article (pop articles)) | 392 (setq article (pop articles)) |
392 (when (file-writable-p article) | 393 (when (file-writable-p article) |
393 (nnheader-message 5 "Deleting article %s in %s..." article group) | 394 (nnheader-message 5 "Deleting article %s in %s..." article group) |
394 (funcall nnmail-delete-file-function article)))) | 395 (funcall nnmail-delete-file-function article)))) |
395 ;; Try to delete the directory itself. | 396 ;; Try to delete the directory itself. |
396 (condition-case () | 397 (condition-case () |
397 (delete-directory nnml-current-directory) | 398 (delete-directory nnml-current-directory) |
398 (error nil))) | 399 (error nil))) |
399 ;; Remove the group from all structures. | 400 ;; Remove the group from all structures. |
400 (setq nnml-group-alist | 401 (setq nnml-group-alist |
401 (delq (assoc group nnml-group-alist) nnml-group-alist) | 402 (delq (assoc group nnml-group-alist) nnml-group-alist) |
402 nnml-current-group nil | 403 nnml-current-group nil |
403 nnml-current-directory nil) | 404 nnml-current-directory nil) |
404 ;; Save the active file. | 405 ;; Save the active file. |
405 (nnmail-save-active nnml-group-alist nnml-active-file) | 406 (nnmail-save-active nnml-group-alist nnml-active-file) |
406 t) | 407 t) |
407 | 408 |
408 (deffoo nnml-request-rename-group (group new-name &optional server) | 409 (deffoo nnml-request-rename-group (group new-name &optional server) |
409 (nnml-possibly-change-directory group server) | 410 (nnml-possibly-change-directory group server) |
410 (let ((new-dir (nnmail-group-pathname new-name nnml-directory)) | 411 ;; Rename directory. |
411 (old-dir (nnmail-group-pathname group nnml-directory))) | 412 (and (file-writable-p nnml-current-directory) |
412 (when (condition-case () | 413 (condition-case () |
413 (progn | 414 (let ((parent |
414 (make-directory new-dir t) | 415 (file-name-directory |
415 t) | 416 (directory-file-name |
416 (error nil)) | 417 (nnmail-group-pathname new-name nnml-directory))))) |
417 ;; We move the articles file by file instead of renaming | 418 (unless (file-exists-p parent) |
418 ;; the directory -- there may be subgroups in this group. | 419 (make-directory parent t)) |
419 ;; One might be more clever, I guess. | 420 (rename-file |
420 (let ((files (nnheader-article-to-file-alist old-dir))) | 421 (directory-file-name nnml-current-directory) |
421 (while files | 422 (directory-file-name |
422 (rename-file | 423 (nnmail-group-pathname new-name nnml-directory))) |
423 (concat old-dir (cdar files)) | 424 t) |
424 (concat new-dir (cdar files))) | 425 (error nil)) |
425 (pop files))) | 426 ;; That went ok, so we change the internal structures. |
426 ;; Move .overview file. | 427 (let ((entry (assoc group nnml-group-alist))) |
427 (let ((overview (concat old-dir nnml-nov-file-name))) | 428 (and entry (setcar entry new-name)) |
428 (when (file-exists-p overview) | 429 (setq nnml-current-directory nil |
429 (rename-file overview (concat new-dir nnml-nov-file-name)))) | 430 nnml-current-group nil) |
430 (when (<= (length (directory-files old-dir)) 2) | 431 ;; Save the new group alist. |
431 (condition-case () | 432 (nnmail-save-active nnml-group-alist nnml-active-file) |
432 (delete-directory old-dir) | 433 t))) |
433 (error nil))) | |
434 ;; That went ok, so we change the internal structures. | |
435 (let ((entry (assoc group nnml-group-alist))) | |
436 (when entry | |
437 (setcar entry new-name)) | |
438 (setq nnml-current-directory nil | |
439 nnml-current-group nil) | |
440 ;; Save the new group alist. | |
441 (nnmail-save-active nnml-group-alist nnml-active-file) | |
442 t)))) | |
443 | |
444 (deffoo nnml-set-status (article name value &optional group server) | |
445 (nnml-possibly-change-directory group server) | |
446 (let ((file (nnml-article-to-file article))) | |
447 (cond | |
448 ((not (file-exists-p file)) | |
449 (nnheader-report 'nnml "File %s does not exist" file)) | |
450 (t | |
451 (nnheader-temp-write file | |
452 (nnheader-insert-file-contents file) | |
453 (nnmail-replace-status name value)) | |
454 t)))) | |
455 | 434 |
456 | 435 |
457 ;;; Internal functions. | 436 ;;; Internal functions. |
458 | 437 |
459 (defun nnml-article-to-file (article) | |
460 (nnml-update-file-alist) | |
461 (let (file) | |
462 (when (setq file (cdr (assq article nnml-article-file-alist))) | |
463 (concat nnml-current-directory file)))) | |
464 | |
465 (defun nnml-deletable-article-p (group article) | 438 (defun nnml-deletable-article-p (group article) |
466 "Say whether ARTICLE in GROUP can be deleted." | 439 "Say whether ARTICLE in GROUP can be deleted." |
467 (let (path) | 440 (let (file path) |
468 (when (setq path (nnml-article-to-file article)) | 441 (when (setq file (cdr (assq article nnml-article-file-alist))) |
469 (when (file-writable-p path) | 442 (setq path (concat nnml-current-directory file)) |
470 (or (not nnmail-keep-last-article) | 443 (and (file-writable-p path) |
471 (not (eq (cdr (nth 1 (assoc group nnml-group-alist))) | 444 (or (not nnmail-keep-last-article) |
472 article))))))) | 445 (not (eq (cdr (nth 1 (assoc group nnml-group-alist))) |
473 | 446 article))))))) |
474 ;; Find an article number in the current group given the Message-ID. | 447 |
448 ;; Find an article number in the current group given the Message-ID. | |
475 (defun nnml-find-group-number (id) | 449 (defun nnml-find-group-number (id) |
476 (save-excursion | 450 (save-excursion |
477 (set-buffer (get-buffer-create " *nnml id*")) | 451 (set-buffer (get-buffer-create " *nnml id*")) |
478 (buffer-disable-undo (current-buffer)) | 452 (buffer-disable-undo (current-buffer)) |
479 (let ((alist nnml-group-alist) | 453 (let ((alist nnml-group-alist) |
480 number) | 454 number) |
481 ;; We want to look through all .overview files, but we want to | 455 ;; We want to look through all .overview files, but we want to |
482 ;; start with the one in the current directory. It seems most | 456 ;; start with the one in the current directory. It seems most |
483 ;; likely that the article we are looking for is in that group. | 457 ;; likely that the article we are looking for is in that group. |
484 (if (setq number (nnml-find-id nnml-current-group id)) | 458 (if (setq number (nnml-find-id nnml-current-group id)) |
485 (cons nnml-current-group number) | 459 (cons nnml-current-group number) |
486 ;; It wasn't there, so we look through the other groups as well. | 460 ;; It wasn't there, so we look through the other groups as well. |
487 (while (and (not number) | 461 (while (and (not number) |
488 alist) | 462 alist) |
497 (erase-buffer) | 471 (erase-buffer) |
498 (let ((nov (concat (nnmail-group-pathname group nnml-directory) | 472 (let ((nov (concat (nnmail-group-pathname group nnml-directory) |
499 nnml-nov-file-name)) | 473 nnml-nov-file-name)) |
500 number found) | 474 number found) |
501 (when (file-exists-p nov) | 475 (when (file-exists-p nov) |
502 (nnheader-insert-file-contents nov) | 476 (insert-file-contents nov) |
503 (while (and (not found) | 477 (while (and (not found) |
504 (search-forward id nil t)) ; We find the ID. | 478 (search-forward id nil t)) ; We find the ID. |
505 ;; And the id is in the fourth field. | 479 ;; And the id is in the fourth field. |
506 (if (not (and (search-backward "\t" nil t 4) | 480 (if (search-backward |
507 (not (search-backward"\t" (gnus-point-at-bol) t)))) | 481 "\t" (save-excursion (beginning-of-line) (point)) t 4) |
508 (forward-line 1) | 482 (progn |
509 (beginning-of-line) | 483 (beginning-of-line) |
510 (setq found t) | 484 (setq found t) |
511 ;; We return the article number. | 485 ;; We return the article number. |
512 (setq number | 486 (setq number |
513 (condition-case () | 487 (condition-case () |
514 (read (current-buffer)) | 488 (read (current-buffer)) |
515 (error nil))))) | 489 (error nil)))))) |
516 number))) | 490 number))) |
517 | 491 |
518 (defun nnml-retrieve-headers-with-nov (articles &optional fetch-old) | 492 (defun nnml-retrieve-headers-with-nov (articles &optional fetch-old) |
519 (if (or gnus-nov-is-evil nnml-nov-is-evil) | 493 (if (or gnus-nov-is-evil nnml-nov-is-evil) |
520 nil | 494 nil |
521 (let ((nov (concat nnml-current-directory nnml-nov-file-name))) | 495 (let ((first (car articles)) |
496 (last (progn (while (cdr articles) (setq articles (cdr articles))) | |
497 (car articles))) | |
498 (nov (concat nnml-current-directory nnml-nov-file-name))) | |
522 (when (file-exists-p nov) | 499 (when (file-exists-p nov) |
523 (save-excursion | 500 (save-excursion |
524 (set-buffer nntp-server-buffer) | 501 (set-buffer nntp-server-buffer) |
525 (erase-buffer) | 502 (erase-buffer) |
526 (nnheader-insert-file-contents nov) | 503 (insert-file-contents nov) |
527 (if (and fetch-old | 504 (if (and fetch-old |
528 (not (numberp fetch-old))) | 505 (not (numberp fetch-old))) |
529 t ; Don't remove anything. | 506 t ; Don't remove anything. |
530 (nnheader-nov-delete-outside-range | 507 (if fetch-old |
531 (if fetch-old (max 1 (- (car articles) fetch-old)) | 508 (setq first (max 1 (- first fetch-old)))) |
532 (car articles)) | 509 (goto-char (point-min)) |
533 (car (last articles))) | 510 (while (and (not (eobp)) (> first (read (current-buffer)))) |
511 (forward-line 1)) | |
512 (beginning-of-line) | |
513 (if (not (eobp)) (delete-region 1 (point))) | |
514 (while (and (not (eobp)) (>= last (read (current-buffer)))) | |
515 (forward-line 1)) | |
516 (beginning-of-line) | |
517 (if (not (eobp)) (delete-region (point) (point-max))) | |
534 t)))))) | 518 t)))))) |
535 | 519 |
536 (defun nnml-possibly-change-directory (group &optional server) | 520 (defun nnml-possibly-change-directory (group &optional server) |
537 (when (and server | 521 (when (and server |
538 (not (nnml-server-opened server))) | 522 (not (nnml-server-opened server))) |
539 (nnml-open-server server)) | 523 (nnml-open-server server)) |
540 (if (not group) | 524 (when group |
541 t | |
542 (let ((pathname (nnmail-group-pathname group nnml-directory))) | 525 (let ((pathname (nnmail-group-pathname group nnml-directory))) |
543 (when (not (equal pathname nnml-current-directory)) | 526 (when (not (equal pathname nnml-current-directory)) |
544 (setq nnml-current-directory pathname | 527 (setq nnml-current-directory pathname |
545 nnml-current-group group | 528 nnml-current-group group |
546 nnml-article-file-alist nil)) | 529 nnml-article-file-alist nil)))) |
547 (file-exists-p nnml-current-directory)))) | 530 t) |
548 | 531 |
549 (defun nnml-possibly-create-directory (group) | 532 (defun nnml-possibly-create-directory (group) |
550 (let (dir dirs) | 533 (let (dir dirs) |
551 (setq dir (nnmail-group-pathname group nnml-directory)) | 534 (setq dir (nnmail-group-pathname group nnml-directory)) |
552 (while (not (file-directory-p dir)) | 535 (while (not (file-directory-p dir)) |
553 (push dir dirs) | 536 (setq dirs (cons dir dirs)) |
554 (setq dir (file-name-directory (directory-file-name dir)))) | 537 (setq dir (file-name-directory (directory-file-name dir)))) |
555 (while dirs | 538 (while dirs |
556 (make-directory (directory-file-name (car dirs))) | 539 (make-directory (directory-file-name (car dirs))) |
557 (nnheader-message 5 "Creating mail directory %s" (car dirs)) | 540 (nnheader-message 5 "Creating mail directory %s" (car dirs)) |
558 (setq dirs (cdr dirs))))) | 541 (setq dirs (cdr dirs))))) |
559 | 542 |
560 (defun nnml-save-mail (group-art) | 543 (defun nnml-save-mail () |
561 "Called narrowed to an article." | 544 "Called narrowed to an article." |
562 (let (chars headers) | 545 (let ((group-art (nreverse (nnmail-article-group 'nnml-active-number))) |
546 chars headers) | |
563 (setq chars (nnmail-insert-lines)) | 547 (setq chars (nnmail-insert-lines)) |
564 (nnmail-insert-xref group-art) | 548 (nnmail-insert-xref group-art) |
565 (run-hooks 'nnmail-prepare-save-mail-hook) | 549 (run-hooks 'nnmail-prepare-save-mail-hook) |
566 (run-hooks 'nnml-prepare-save-mail-hook) | 550 (run-hooks 'nnml-prepare-save-mail-hook) |
567 (goto-char (point-min)) | 551 (goto-char (point-min)) |
568 (while (looking-at "From ") | 552 (while (looking-at "From ") |
569 (replace-match "X-From-Line: ") | 553 (replace-match "X-From-Line: ") |
570 (forward-line 1)) | 554 (forward-line 1)) |
571 ;; We save the article in all the groups it belongs in. | 555 ;; We save the article in all the newsgroups it belongs in. |
572 (let ((ga group-art) | 556 (let ((ga group-art) |
573 first) | 557 first) |
574 (while ga | 558 (while ga |
575 (nnml-possibly-create-directory (caar ga)) | 559 (nnml-possibly-create-directory (caar ga)) |
576 (let ((file (concat (nnmail-group-pathname | 560 (let ((file (concat (nnmail-group-pathname |
577 (caar ga) nnml-directory) | 561 (caar ga) nnml-directory) |
578 (int-to-string (cdar ga))))) | 562 (int-to-string (cdar ga))))) |
579 (if first | 563 (if first |
580 ;; It was already saved, so we just make a hard link. | 564 ;; It was already saved, so we just make a hard link. |
581 (funcall nnmail-crosspost-link-function first file t) | 565 (funcall nnmail-crosspost-link-function first file t) |
582 ;; Save the article. | 566 ;; Save the article. |
583 (nnmail-write-region (point-min) (point-max) file nil | 567 (write-region (point-min) (point-max) file nil |
584 (if (nnheader-be-verbose 5) nil 'nomesg)) | 568 (if (nnheader-be-verbose 5) nil 'nomesg)) |
585 (setq first file))) | 569 (setq first file))) |
586 (setq ga (cdr ga)))) | 570 (setq ga (cdr ga)))) |
587 ;; Generate a nov line for this article. We generate the nov | 571 ;; Generate a nov line for this article. We generate the nov |
588 ;; line after saving, because nov generation destroys the | 572 ;; line after saving, because nov generation destroys the |
589 ;; header. | 573 ;; header. |
590 (setq headers (nnml-parse-head chars)) | 574 (setq headers (nnml-parse-head chars)) |
591 ;; Output the nov line to all nov databases that should have it. | 575 ;; Output the nov line to all nov databases that should have it. |
592 (let ((ga group-art)) | 576 (let ((ga group-art)) |
593 (while ga | 577 (while ga |
594 (nnml-add-nov (caar ga) (cdar ga) headers) | 578 (nnml-add-nov (caar ga) (cdar ga) headers) |
597 | 581 |
598 (defun nnml-active-number (group) | 582 (defun nnml-active-number (group) |
599 "Compute the next article number in GROUP." | 583 "Compute the next article number in GROUP." |
600 (let ((active (cadr (assoc group nnml-group-alist)))) | 584 (let ((active (cadr (assoc group nnml-group-alist)))) |
601 ;; The group wasn't known to nnml, so we just create an active | 585 ;; The group wasn't known to nnml, so we just create an active |
602 ;; entry for it. | 586 ;; entry for it. |
603 (unless active | 587 (unless active |
604 ;; Perhaps the active file was corrupt? See whether | 588 ;; Perhaps the active file was corrupt? See whether |
605 ;; there are any articles in this group. | 589 ;; there are any articles in this group. |
606 (nnml-possibly-create-directory group) | 590 (nnml-possibly-create-directory group) |
607 (nnml-possibly-change-directory group) | 591 (nnml-possibly-change-directory group) |
613 (setq active | 597 (setq active |
614 (if nnml-article-file-alist | 598 (if nnml-article-file-alist |
615 (cons (caar nnml-article-file-alist) | 599 (cons (caar nnml-article-file-alist) |
616 (caar (last nnml-article-file-alist))) | 600 (caar (last nnml-article-file-alist))) |
617 (cons 1 0))) | 601 (cons 1 0))) |
618 (push (list group active) nnml-group-alist)) | 602 (setq nnml-group-alist (cons (list group active) nnml-group-alist))) |
619 (setcdr active (1+ (cdr active))) | 603 (setcdr active (1+ (cdr active))) |
620 (while (file-exists-p | 604 (while (file-exists-p |
621 (concat (nnmail-group-pathname group nnml-directory) | 605 (concat (nnmail-group-pathname group nnml-directory) |
622 (int-to-string (cdr active)))) | 606 (int-to-string (cdr active)))) |
623 (setcdr active (1+ (cdr active)))) | 607 (setcdr active (1+ (cdr active)))) |
624 (cdr active))) | 608 (cdr active))) |
625 | 609 |
626 (defun nnml-add-nov (group article headers) | 610 (defun nnml-add-nov (group article headers) |
627 "Add a nov line for the GROUP base." | 611 "Add a nov line for the GROUP base." |
628 (save-excursion | 612 (save-excursion |
629 (set-buffer (nnml-open-nov group)) | 613 (set-buffer (nnml-open-nov group)) |
630 (goto-char (point-max)) | 614 (goto-char (point-max)) |
631 (mail-header-set-number headers article) | 615 (mail-header-set-number headers article) |
632 (nnheader-insert-nov headers))) | 616 (nnheader-insert-nov headers))) |
633 | 617 |
637 (defun nnml-parse-head (chars &optional number) | 621 (defun nnml-parse-head (chars &optional number) |
638 "Parse the head of the current buffer." | 622 "Parse the head of the current buffer." |
639 (save-excursion | 623 (save-excursion |
640 (save-restriction | 624 (save-restriction |
641 (goto-char (point-min)) | 625 (goto-char (point-min)) |
642 (narrow-to-region | 626 (narrow-to-region |
643 (point) | 627 (point) |
644 (1- (or (search-forward "\n\n" nil t) (point-max)))) | 628 (1- (or (search-forward "\n\n" nil t) (point-max)))) |
645 ;; Fold continuation lines. | 629 ;; Fold continuation lines. |
646 (goto-char (point-min)) | 630 (goto-char (point-min)) |
647 (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t) | 631 (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t) |
653 (mail-header-set-number headers number) | 637 (mail-header-set-number headers number) |
654 headers)))) | 638 headers)))) |
655 | 639 |
656 (defun nnml-open-nov (group) | 640 (defun nnml-open-nov (group) |
657 (or (cdr (assoc group nnml-nov-buffer-alist)) | 641 (or (cdr (assoc group nnml-nov-buffer-alist)) |
658 (let ((buffer (nnheader-find-file-noselect | 642 (let ((buffer (find-file-noselect |
659 (concat (nnmail-group-pathname group nnml-directory) | 643 (concat (nnmail-group-pathname group nnml-directory) |
660 nnml-nov-file-name)))) | 644 nnml-nov-file-name)))) |
661 (save-excursion | 645 (save-excursion |
662 (set-buffer buffer) | 646 (set-buffer buffer) |
663 (buffer-disable-undo (current-buffer))) | 647 (buffer-disable-undo (current-buffer))) |
664 (push (cons group buffer) nnml-nov-buffer-alist) | 648 (setq nnml-nov-buffer-alist |
649 (cons (cons group buffer) nnml-nov-buffer-alist)) | |
665 buffer))) | 650 buffer))) |
666 | 651 |
667 (defun nnml-save-nov () | 652 (defun nnml-save-nov () |
668 (save-excursion | 653 (save-excursion |
669 (while nnml-nov-buffer-alist | 654 (while nnml-nov-buffer-alist |
670 (when (buffer-name (cdar nnml-nov-buffer-alist)) | 655 (when (buffer-name (cdar nnml-nov-buffer-alist)) |
671 (set-buffer (cdar nnml-nov-buffer-alist)) | 656 (set-buffer (cdar nnml-nov-buffer-alist)) |
672 (when (buffer-modified-p) | 657 (and (buffer-modified-p) |
673 (nnmail-write-region 1 (point-max) (buffer-file-name) nil 'nomesg)) | 658 (write-region |
659 1 (point-max) (buffer-file-name) nil 'nomesg)) | |
674 (set-buffer-modified-p nil) | 660 (set-buffer-modified-p nil) |
675 (kill-buffer (current-buffer))) | 661 (kill-buffer (current-buffer))) |
676 (setq nnml-nov-buffer-alist (cdr nnml-nov-buffer-alist))))) | 662 (setq nnml-nov-buffer-alist (cdr nnml-nov-buffer-alist))))) |
677 | 663 |
678 ;;;###autoload | 664 ;;;###autoload |
679 (defun nnml-generate-nov-databases () | 665 (defun nnml-generate-nov-databases () |
680 "Generate NOV databases in all nnml directories." | 666 "Generate nov databases in all nnml directories." |
681 (interactive) | 667 (interactive) |
682 ;; Read the active file to make sure we don't re-use articles | 668 ;; Read the active file to make sure we don't re-use articles |
683 ;; numbers in empty groups. | 669 ;; numbers in empty groups. |
684 (nnmail-activate 'nnml) | 670 (nnmail-activate 'nnml) |
685 (nnml-open-server (or (nnoo-current-server 'nnml) "")) | 671 (nnml-open-server (or (nnoo-current-server 'nnml) "")) |
686 (setq nnml-directory (expand-file-name nnml-directory)) | 672 (setq nnml-directory (expand-file-name nnml-directory)) |
687 ;; Recurse down the directories. | 673 ;; Recurse down the directories. |
688 (nnml-generate-nov-databases-1 nnml-directory nil t) | 674 (nnml-generate-nov-databases-1 nnml-directory) |
689 ;; Save the active file. | 675 ;; Save the active file. |
690 (nnmail-save-active nnml-group-alist nnml-active-file)) | 676 (nnmail-save-active nnml-group-alist nnml-active-file)) |
691 | 677 |
692 (defun nnml-generate-nov-databases-1 (dir &optional seen no-active) | 678 (defun nnml-generate-nov-databases-1 (dir) |
693 "Regenerate the NOV database in DIR." | |
694 (interactive "DRegenerate NOV in: ") | |
695 (setq dir (file-name-as-directory dir)) | 679 (setq dir (file-name-as-directory dir)) |
696 ;; Only scan this sub-tree if we haven't been here yet. | 680 ;; We descend recursively |
697 (unless (member (file-truename dir) seen) | 681 (let ((dirs (directory-files dir t nil t)) |
698 (push (file-truename dir) seen) | 682 dir) |
699 ;; We descend recursively | 683 (while dirs |
700 (let ((dirs (directory-files dir t nil t)) | 684 (setq dir (pop dirs)) |
701 dir) | 685 (when (and (not (member (file-name-nondirectory dir) '("." ".."))) |
702 (while (setq dir (pop dirs)) | 686 (file-directory-p dir)) |
703 (when (and (not (member (file-name-nondirectory dir) '("." ".."))) | 687 (nnml-generate-nov-databases-1 dir)))) |
704 (file-directory-p dir)) | 688 ;; Do this directory. |
705 (nnml-generate-nov-databases-1 dir seen)))) | 689 (let ((files (sort |
706 ;; Do this directory. | 690 (mapcar |
707 (let ((files (sort (nnheader-article-to-file-alist dir) | 691 (lambda (name) (string-to-int name)) |
708 (lambda (a b) (< (car a) (car b)))))) | 692 (directory-files dir nil "^[0-9]+$" t)) |
709 (when files | 693 '<))) |
710 (funcall nnml-generate-active-function dir) | 694 (when files |
711 ;; Generate the nov file. | 695 (funcall nnml-generate-active-function dir) |
712 (nnml-generate-nov-file dir files) | 696 ;; Generate the nov file. |
713 (unless no-active | 697 (nnml-generate-nov-file dir files)))) |
714 (nnmail-save-active nnml-group-alist nnml-active-file)))))) | |
715 | 698 |
716 (defvar files) | 699 (defvar files) |
717 (defun nnml-generate-active-info (dir) | 700 (defun nnml-generate-active-info (dir) |
718 ;; Update the active info for this group. | 701 ;; Update the active info for this group. |
719 (let ((group (nnheader-file-to-group | 702 (let ((group (nnheader-file-to-group |
720 (directory-file-name dir) nnml-directory))) | 703 (directory-file-name dir) nnml-directory))) |
721 (setq nnml-group-alist | 704 (setq nnml-group-alist |
722 (delq (assoc group nnml-group-alist) nnml-group-alist)) | 705 (delq (assoc group nnml-group-alist) nnml-group-alist)) |
723 (push (list group | 706 (push (list group |
724 (cons (caar files) | 707 (cons (car files) |
725 (let ((f files)) | 708 (let ((f files)) |
726 (while (cdr f) (setq f (cdr f))) | 709 (while (cdr f) (setq f (cdr f))) |
727 (caar f)))) | 710 (car f)))) |
728 nnml-group-alist))) | 711 nnml-group-alist))) |
729 | 712 |
730 (defun nnml-generate-nov-file (dir files) | 713 (defun nnml-generate-nov-file (dir files) |
731 (let* ((dir (file-name-as-directory dir)) | 714 (let* ((dir (file-name-as-directory dir)) |
732 (nov (concat dir nnml-nov-file-name)) | 715 (nov (concat dir nnml-nov-file-name)) |
733 (nov-buffer (get-buffer-create " *nov*")) | 716 (nov-buffer (get-buffer-create " *nov*")) |
734 chars file headers) | 717 nov-line chars file headers) |
735 (save-excursion | 718 (save-excursion |
736 ;; Init the nov buffer. | 719 ;; Init the nov buffer. |
737 (set-buffer nov-buffer) | 720 (set-buffer nov-buffer) |
738 (buffer-disable-undo (current-buffer)) | 721 (buffer-disable-undo (current-buffer)) |
739 (erase-buffer) | 722 (erase-buffer) |
740 (set-buffer nntp-server-buffer) | 723 (set-buffer nntp-server-buffer) |
741 ;; Delete the old NOV file. | 724 ;; Delete the old NOV file. |
742 (when (file-exists-p nov) | 725 (when (file-exists-p nov) |
743 (funcall nnmail-delete-file-function nov)) | 726 (funcall nnmail-delete-file-function nov)) |
744 (while files | 727 (while files |
745 (unless (file-directory-p (setq file (concat dir (cdar files)))) | 728 (unless (file-directory-p |
729 (setq file (concat dir (int-to-string (car files))))) | |
746 (erase-buffer) | 730 (erase-buffer) |
747 (nnheader-insert-file-contents file) | 731 (insert-file-contents file) |
748 (narrow-to-region | 732 (narrow-to-region |
749 (goto-char (point-min)) | 733 (goto-char (point-min)) |
750 (progn | 734 (progn |
751 (search-forward "\n\n" nil t) | 735 (search-forward "\n\n" nil t) |
752 (setq chars (- (point-max) (point))) | 736 (setq chars (- (point-max) (point))) |
753 (max 1 (1- (point))))) | 737 (max 1 (1- (point))))) |
754 (when (and (not (= 0 chars)) ; none of them empty files... | 738 (when (and (not (= 0 chars)) ; none of them empty files... |
755 (not (= (point-min) (point-max)))) | 739 (not (= (point-min) (point-max)))) |
756 (goto-char (point-min)) | 740 (goto-char (point-min)) |
757 (setq headers (nnml-parse-head chars (caar files))) | 741 (setq headers (nnml-parse-head chars (car files))) |
758 (save-excursion | 742 (save-excursion |
759 (set-buffer nov-buffer) | 743 (set-buffer nov-buffer) |
760 (goto-char (point-max)) | 744 (goto-char (point-max)) |
761 (nnheader-insert-nov headers))) | 745 (nnheader-insert-nov headers))) |
762 (widen)) | 746 (widen)) |
763 (setq files (cdr files))) | 747 (setq files (cdr files))) |
764 (save-excursion | 748 (save-excursion |
765 (set-buffer nov-buffer) | 749 (set-buffer nov-buffer) |
766 (nnmail-write-region 1 (point-max) nov nil 'nomesg) | 750 (write-region 1 (point-max) (expand-file-name nov) nil |
751 'nomesg) | |
767 (kill-buffer (current-buffer)))))) | 752 (kill-buffer (current-buffer)))))) |
768 | 753 |
769 (defun nnml-nov-delete-article (group article) | 754 (defun nnml-nov-delete-article (group article) |
770 (save-excursion | 755 (save-excursion |
771 (set-buffer (nnml-open-nov group)) | 756 (set-buffer (nnml-open-nov group)) |
772 (when (nnheader-find-nov-line article) | 757 (goto-char (point-min)) |
773 (delete-region (point) (progn (forward-line 1) (point))) | 758 (if (re-search-forward (concat "^" (int-to-string article) "\t") nil t) |
774 (when (bobp) | 759 (delete-region (match-beginning 0) (progn (forward-line 1) (point)))) |
775 (let ((active (cadr (assoc group nnml-group-alist))) | |
776 num) | |
777 (when active | |
778 (if (eobp) | |
779 (setf (car active) (1+ (cdr active))) | |
780 (when (and (setq num (ignore-errors (read (current-buffer)))) | |
781 (numberp num)) | |
782 (setf (car active) num))))))) | |
783 t)) | 760 t)) |
784 | 761 |
785 (defun nnml-update-file-alist () | |
786 (unless nnml-article-file-alist | |
787 (setq nnml-article-file-alist | |
788 (nnheader-article-to-file-alist nnml-current-directory)))) | |
789 | |
790 (provide 'nnml) | 762 (provide 'nnml) |
791 | 763 |
792 ;;; nnml.el ends here | 764 ;;; nnml.el ends here |