comparison lisp/gnus/nnmh.el @ 108:360340f9fd5f r20-1b6

Import from CVS: tag r20-1b6
author cvs
date Mon, 13 Aug 2007 09:18:39 +0200
parents cf808b4c4290
children fe104dbd9147
comparison
equal deleted inserted replaced
107:523141596bda 108:360340f9fd5f
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)
80 (nnmh-possibly-change-directory newsgroup server) 80 (nnmh-possibly-change-directory newsgroup server)
81 ;; We don't support fetching by Message-ID. 81 ;; We don't support fetching by Message-ID.
82 (if (stringp (car articles)) 82 (if (stringp (car articles))
83 'headers 83 'headers
84 (while articles 84 (while articles
85 (when (and (file-exists-p 85 (when (and (file-exists-p
86 (setq file (concat (file-name-as-directory 86 (setq file (concat (file-name-as-directory
87 nnmh-current-directory) 87 nnmh-current-directory)
88 (int-to-string 88 (int-to-string
89 (setq article (pop articles)))))) 89 (setq article (pop articles))))))
90 (not (file-directory-p file))) 90 (not (file-directory-p file)))
91 (insert (format "221 %d Article retrieved.\n" article)) 91 (insert (format "221 %d Article retrieved.\n" article))
115 (nnoo-change-server 'nnmh server defs) 115 (nnoo-change-server 'nnmh server defs)
116 (when (not (file-exists-p nnmh-directory)) 116 (when (not (file-exists-p nnmh-directory))
117 (condition-case () 117 (condition-case ()
118 (make-directory nnmh-directory t) 118 (make-directory nnmh-directory t)
119 (error t))) 119 (error t)))
120 (cond 120 (cond
121 ((not (file-exists-p nnmh-directory)) 121 ((not (file-exists-p nnmh-directory))
122 (nnmh-close-server) 122 (nnmh-close-server)
123 (nnheader-report 'nnmh "Couldn't create directory: %s" nnmh-directory)) 123 (nnheader-report 'nnmh "Couldn't create directory: %s" nnmh-directory))
124 ((not (file-directory-p (file-truename nnmh-directory))) 124 ((not (file-directory-p (file-truename nnmh-directory)))
125 (nnmh-close-server) 125 (nnmh-close-server)
142 (string-to-int (file-name-nondirectory file))))) 142 (string-to-int (file-name-nondirectory file)))))
143 143
144 (deffoo nnmh-request-group (group &optional server dont-check) 144 (deffoo nnmh-request-group (group &optional server dont-check)
145 (let ((pathname (nnmail-group-pathname group nnmh-directory)) 145 (let ((pathname (nnmail-group-pathname group nnmh-directory))
146 dir) 146 dir)
147 (cond 147 (cond
148 ((not (file-directory-p pathname)) 148 ((not (file-directory-p pathname))
149 (nnheader-report 149 (nnheader-report
150 'nnmh "Can't select group (no such directory): %s" group)) 150 'nnmh "Can't select group (no such directory): %s" group))
151 (t 151 (t
152 (setq nnmh-current-directory pathname) 152 (setq nnmh-current-directory pathname)
153 (and nnmh-get-new-mail 153 (and nnmh-get-new-mail
154 nnmh-be-safe 154 nnmh-be-safe
155 (nnmh-update-gnus-unreads group)) 155 (nnmh-update-gnus-unreads group))
156 (cond 156 (cond
157 (dont-check 157 (dont-check
158 (nnheader-report 'nnmh "Selected group %s" group) 158 (nnheader-report 'nnmh "Selected group %s" group)
159 t) 159 t)
160 (t 160 (t
161 ;; Re-scan the directory if it's on a foreign system. 161 ;; Re-scan the directory if it's on a foreign system.
162 (nnheader-re-read-dir pathname) 162 (nnheader-re-read-dir pathname)
163 (setq dir 163 (setq dir
164 (sort 164 (sort
165 (mapcar (lambda (name) (string-to-int name)) 165 (mapcar (lambda (name) (string-to-int name))
166 (directory-files pathname nil "^[0-9]+$" t)) 166 (directory-files pathname nil "^[0-9]+$" t))
167 '<)) 167 '<))
168 (cond 168 (cond
169 (dir 169 (dir
170 (nnheader-report 'nnmh "Selected group %s" group) 170 (nnheader-report 'nnmh "Selected group %s" group)
171 (nnheader-insert 171 (nnheader-insert
172 "211 %d %d %d %s\n" (length dir) (car dir) 172 "211 %d %d %d %s\n" (length dir) (car dir)
173 (progn (while (cdr dir) (setq dir (cdr dir))) (car dir)) 173 (progn (while (cdr dir) (setq dir (cdr dir))) (car dir))
208 (directory-files dir nil "^[0-9]+$" t)))) 208 (directory-files dir nil "^[0-9]+$" t))))
209 (when files 209 (when files
210 (save-excursion 210 (save-excursion
211 (set-buffer nntp-server-buffer) 211 (set-buffer nntp-server-buffer)
212 (goto-char (point-max)) 212 (goto-char (point-max))
213 (insert 213 (insert
214 (format 214 (format
215 "%s %d %d y\n" 215 "%s %d %d y\n"
216 (progn 216 (progn
217 (string-match 217 (string-match
218 (regexp-quote 218 (regexp-quote
219 (file-truename (file-name-as-directory 219 (file-truename (file-name-as-directory
220 (expand-file-name nnmh-toplev)))) 220 (expand-file-name nnmh-toplev))))
221 dir) 221 dir)
222 (nnheader-replace-chars-in-string 222 (nnheader-replace-chars-in-string
223 (substring dir (match-end 0)) ?/ ?.)) 223 (substring dir (match-end 0)) ?/ ?.))
224 (apply 'max files) 224 (apply 'max files)
229 (nnmh-request-list server)) 229 (nnmh-request-list server))
230 230
231 (deffoo nnmh-request-expire-articles (articles newsgroup 231 (deffoo nnmh-request-expire-articles (articles newsgroup
232 &optional server force) 232 &optional server force)
233 (nnmh-possibly-change-directory newsgroup server) 233 (nnmh-possibly-change-directory newsgroup server)
234 (let* ((active-articles 234 (let* ((active-articles
235 (mapcar 235 (mapcar
236 (function 236 (function
237 (lambda (name) 237 (lambda (name)
238 (string-to-int name))) 238 (string-to-int name)))
239 (directory-files nnmh-current-directory nil "^[0-9]+$" t))) 239 (directory-files nnmh-current-directory nil "^[0-9]+$" t)))
240 (is-old t) 240 (is-old t)
241 article rest mod-time) 241 article rest mod-time)
242 (nnmail-activate 'nnmh) 242 (nnmail-activate 'nnmh)
243 243
244 (while (and articles is-old) 244 (while (and articles is-old)
245 (setq article (concat nnmh-current-directory 245 (setq article (concat nnmh-current-directory
246 (int-to-string (car articles)))) 246 (int-to-string (car articles))))
247 (when (setq mod-time (nth 5 (file-attributes article))) 247 (when (setq mod-time (nth 5 (file-attributes article)))
248 (if (and (nnmh-deletable-article-p newsgroup (car articles)) 248 (if (and (nnmh-deletable-article-p newsgroup (car articles))
249 (setq is-old 249 (setq is-old
250 (nnmail-expired-article-p newsgroup mod-time force))) 250 (nnmail-expired-article-p newsgroup mod-time force)))
251 (progn 251 (progn
252 (nnheader-message 5 "Deleting article %s in %s..." 252 (nnheader-message 5 "Deleting article %s in %s..."
253 article newsgroup) 253 article newsgroup)
254 (condition-case () 254 (condition-case ()
255 (funcall nnmail-delete-file-function article) 255 (funcall nnmail-delete-file-function article)
256 (file-error 256 (file-error
257 (nnheader-message 1 "Couldn't delete article %s in %s" 257 (nnheader-message 1 "Couldn't delete article %s in %s"
263 (nconc rest articles))) 263 (nconc rest articles)))
264 264
265 (deffoo nnmh-close-group (group &optional server) 265 (deffoo nnmh-close-group (group &optional server)
266 t) 266 t)
267 267
268 (deffoo nnmh-request-move-article 268 (deffoo nnmh-request-move-article
269 (article group server accept-form &optional last) 269 (article group server accept-form &optional last)
270 (let ((buf (get-buffer-create " *nnmh move*")) 270 (let ((buf (get-buffer-create " *nnmh move*"))
271 result) 271 result)
272 (and 272 (and
273 (nnmh-deletable-article-p group article) 273 (nnmh-deletable-article-p group article)
274 (nnmh-request-article article group server) 274 (nnmh-request-article article group server)
275 (save-excursion 275 (save-excursion
276 (set-buffer buf) 276 (set-buffer buf)
277 (erase-buffer) 277 (erase-buffer)
288 result)) 288 result))
289 289
290 (deffoo nnmh-request-accept-article (group &optional server last noinsert) 290 (deffoo nnmh-request-accept-article (group &optional server last noinsert)
291 (nnmh-possibly-change-directory group server) 291 (nnmh-possibly-change-directory group server)
292 (nnmail-check-syntax) 292 (nnmail-check-syntax)
293 (nnmail-cache-insert (nnmail-fetch-field "message-id"))
293 (if (stringp group) 294 (if (stringp group)
294 (and 295 (and
295 (nnmail-activate 'nnmh) 296 (nnmail-activate 'nnmh)
296 (car (nnmh-save-mail 297 (car (nnmh-save-mail
297 (list (cons group (nnmh-active-number group))) 298 (list (cons group (nnmh-active-number group)))
298 noinsert))) 299 noinsert)))
299 (and 300 (and
300 (nnmail-activate 'nnmh) 301 (nnmail-activate 'nnmh)
301 (car (nnmh-save-mail (nnmail-article-group 'nnmh-active-number) 302 (car (nnmh-save-mail (nnmail-article-group 'nnmh-active-number)
302 noinsert))))) 303 noinsert))))
304 (when last
305 (nnmail-cache-close)))
303 306
304 (deffoo nnmh-request-replace-article (article group buffer) 307 (deffoo nnmh-request-replace-article (article group buffer)
305 (nnmh-possibly-change-directory group) 308 (nnmh-possibly-change-directory group)
306 (save-excursion 309 (save-excursion
307 (set-buffer buffer) 310 (set-buffer buffer)
308 (nnmh-possibly-create-directory group) 311 (nnmh-possibly-create-directory group)
309 (ignore-errors 312 (ignore-errors
310 (nnmail-write-region 313 (nnmail-write-region
311 (point-min) (point-max) 314 (point-min) (point-max)
312 (concat nnmh-current-directory (int-to-string article)) 315 (concat nnmh-current-directory (int-to-string article))
313 nil (if (nnheader-be-verbose 5) nil 'nomesg)) 316 nil (if (nnheader-be-verbose 5) nil 'nomesg))
314 t))) 317 t)))
315 318
322 (nnmh-possibly-create-directory group) 325 (nnmh-possibly-create-directory group)
323 (nnmh-possibly-change-directory group server) 326 (nnmh-possibly-change-directory group server)
324 (let ((articles (mapcar 327 (let ((articles (mapcar
325 (lambda (file) 328 (lambda (file)
326 (string-to-int file)) 329 (string-to-int file))
327 (directory-files 330 (directory-files
328 nnmh-current-directory nil "^[0-9]+$")))) 331 nnmh-current-directory nil "^[0-9]+$"))))
329 (when articles 332 (when articles
330 (setcar active (apply 'min articles)) 333 (setcar active (apply 'min articles))
331 (setcdr active (apply 'max articles)))))) 334 (setcdr active (apply 'max articles))))))
332 t) 335 t)
335 (nnmh-possibly-change-directory group server) 338 (nnmh-possibly-change-directory group server)
336 ;; Delete all articles in GROUP. 339 ;; Delete all articles in GROUP.
337 (if (not force) 340 (if (not force)
338 () ; Don't delete the articles. 341 () ; Don't delete the articles.
339 (let ((articles (directory-files nnmh-current-directory t "^[0-9]+$"))) 342 (let ((articles (directory-files nnmh-current-directory t "^[0-9]+$")))
340 (while articles 343 (while articles
341 (when (file-writable-p (car articles)) 344 (when (file-writable-p (car articles))
342 (nnheader-message 5 "Deleting article %s in %s..." 345 (nnheader-message 5 "Deleting article %s in %s..."
343 (car articles) group) 346 (car articles) group)
344 (funcall nnmail-delete-file-function (car articles))) 347 (funcall nnmail-delete-file-function (car articles)))
345 (setq articles (cdr articles)))) 348 (setq articles (cdr articles))))
346 ;; Try to delete the directory itself. 349 ;; Try to delete the directory itself.
347 (ignore-errors 350 (ignore-errors
348 (delete-directory nnmh-current-directory))) 351 (delete-directory nnmh-current-directory)))
349 ;; Remove the group from all structures. 352 ;; Remove the group from all structures.
350 (setq nnmh-group-alist 353 (setq nnmh-group-alist
351 (delq (assoc group nnmh-group-alist) nnmh-group-alist) 354 (delq (assoc group nnmh-group-alist) nnmh-group-alist)
352 nnmh-current-directory nil) 355 nnmh-current-directory nil)
353 t) 356 t)
354 357
355 (deffoo nnmh-request-rename-group (group new-name &optional server) 358 (deffoo nnmh-request-rename-group (group new-name &optional server)
362 ;; We move the articles file by file instead of renaming 365 ;; We move the articles file by file instead of renaming
363 ;; the directory -- there may be subgroups in this group. 366 ;; the directory -- there may be subgroups in this group.
364 ;; One might be more clever, I guess. 367 ;; One might be more clever, I guess.
365 (let ((files (nnheader-article-to-file-alist old-dir))) 368 (let ((files (nnheader-article-to-file-alist old-dir)))
366 (while files 369 (while files
367 (rename-file 370 (rename-file
368 (concat old-dir (cdar files)) 371 (concat old-dir (cdar files))
369 (concat new-dir (cdar files))) 372 (concat new-dir (cdar files)))
370 (pop files))) 373 (pop files)))
371 (when (<= (length (directory-files old-dir)) 2) 374 (when (<= (length (directory-files old-dir)) 2)
372 (ignore-errors 375 (ignore-errors
382 385
383 386
384 ;;; Internal functions. 387 ;;; Internal functions.
385 388
386 (defun nnmh-possibly-change-directory (newsgroup &optional server) 389 (defun nnmh-possibly-change-directory (newsgroup &optional server)
387 (when (and server 390 (when (and server
388 (not (nnmh-server-opened server))) 391 (not (nnmh-server-opened server)))
389 (nnmh-open-server server)) 392 (nnmh-open-server server))
390 (when newsgroup 393 (when newsgroup
391 (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory))) 394 (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory)))
392 (if (file-directory-p pathname) 395 (if (file-directory-p pathname)
402 (while dirs 405 (while dirs
403 (when (make-directory (directory-file-name (car dirs))) 406 (when (make-directory (directory-file-name (car dirs)))
404 (error "Could not create directory %s" (car dirs))) 407 (error "Could not create directory %s" (car dirs)))
405 (nnheader-message 5 "Creating mail directory %s" (car dirs)) 408 (nnheader-message 5 "Creating mail directory %s" (car dirs))
406 (setq dirs (cdr dirs))))) 409 (setq dirs (cdr dirs)))))
407 410
408 (defun nnmh-save-mail (group-art &optional noinsert) 411 (defun nnmh-save-mail (group-art &optional noinsert)
409 "Called narrowed to an article." 412 "Called narrowed to an article."
410 (unless noinsert 413 (unless noinsert
411 (nnmail-insert-lines) 414 (nnmail-insert-lines)
412 (nnmail-insert-xref group-art)) 415 (nnmail-insert-xref group-art))
419 ;; We save the article in all the newsgroups it belongs in. 422 ;; We save the article in all the newsgroups it belongs in.
420 (let ((ga group-art) 423 (let ((ga group-art)
421 first) 424 first)
422 (while ga 425 (while ga
423 (nnmh-possibly-create-directory (caar ga)) 426 (nnmh-possibly-create-directory (caar ga))
424 (let ((file (concat (nnmail-group-pathname 427 (let ((file (concat (nnmail-group-pathname
425 (caar ga) nnmh-directory) 428 (caar ga) nnmh-directory)
426 (int-to-string (cdar ga))))) 429 (int-to-string (cdar ga)))))
427 (if first 430 (if first
428 ;; It was already saved, so we just make a hard link. 431 ;; It was already saved, so we just make a hard link.
429 (funcall nnmail-crosspost-link-function first file t) 432 (funcall nnmail-crosspost-link-function first file t)
436 (defun nnmh-active-number (group) 439 (defun nnmh-active-number (group)
437 "Compute the next article number in GROUP." 440 "Compute the next article number in GROUP."
438 (let ((active (cadr (assoc group nnmh-group-alist)))) 441 (let ((active (cadr (assoc group nnmh-group-alist))))
439 (unless active 442 (unless active
440 ;; The group wasn't known to nnmh, so we just create an active 443 ;; The group wasn't known to nnmh, so we just create an active
441 ;; entry for it. 444 ;; entry for it.
442 (setq active (cons 1 0)) 445 (setq active (cons 1 0))
443 (push (list group active) nnmh-group-alist) 446 (push (list group active) nnmh-group-alist)
444 ;; Find the highest number in the group. 447 ;; Find the highest number in the group.
445 (let ((files (sort 448 (let ((files (sort
446 (mapcar 449 (mapcar
463 ;; Go through the .nnmh-articles file and compare with the actual 466 ;; Go through the .nnmh-articles file and compare with the actual
464 ;; articles in this folder. The articles that are "new" will be 467 ;; articles in this folder. The articles that are "new" will be
465 ;; marked as unread by Gnus. 468 ;; marked as unread by Gnus.
466 (let* ((dir nnmh-current-directory) 469 (let* ((dir nnmh-current-directory)
467 (files (sort (mapcar (function (lambda (name) (string-to-int name))) 470 (files (sort (mapcar (function (lambda (name) (string-to-int name)))
468 (directory-files nnmh-current-directory 471 (directory-files nnmh-current-directory
469 nil "^[0-9]+$" t)) 472 nil "^[0-9]+$" t))
470 '<)) 473 '<))
471 (nnmh-file (concat dir ".nnmh-articles")) 474 (nnmh-file (concat dir ".nnmh-articles"))
472 new articles) 475 new articles)
473 ;; Load the .nnmh-articles file. 476 ;; Load the .nnmh-articles file.
474 (when (file-exists-p nnmh-file) 477 (when (file-exists-p nnmh-file)
475 (setq articles 478 (setq articles
476 (let (nnmh-newsgroup-articles) 479 (let (nnmh-newsgroup-articles)
477 (ignore-errors (load nnmh-file nil t t)) 480 (ignore-errors (load nnmh-file nil t t))
478 nnmh-newsgroup-articles))) 481 nnmh-newsgroup-articles)))
479 ;; Add all new articles to the `new' list. 482 ;; Add all new articles to the `new' list.
480 (let ((art files)) 483 (let ((art files))
492 ;; they are by looking at the time-stamps. 495 ;; they are by looking at the time-stamps.
493 (let ((arts articles) 496 (let ((arts articles)
494 art) 497 art)
495 (while (setq art (pop arts)) 498 (while (setq art (pop arts))
496 (when (not (equal 499 (when (not (equal
497 (nth 5 (file-attributes 500 (nth 5 (file-attributes
498 (concat dir (int-to-string (car art))))) 501 (concat dir (int-to-string (car art)))))
499 (cdr art))) 502 (cdr art)))
500 (setq articles (delq art articles)) 503 (setq articles (delq art articles))
501 (push (car art) new)))) 504 (push (car art) new))))
502 ;; Go through all the new articles and add them, and their 505 ;; Go through all the new articles and add them, and their
509 (nth 5 (file-attributes 512 (nth 5 (file-attributes
510 (concat dir (int-to-string art)))))) 513 (concat dir (int-to-string art))))))
511 new))) 514 new)))
512 ;; Make Gnus mark all new articles as unread. 515 ;; Make Gnus mark all new articles as unread.
513 (when new 516 (when new
514 (gnus-make-articles-unread 517 (gnus-make-articles-unread
515 (gnus-group-prefixed-name group (list 'nnmh "")) 518 (gnus-group-prefixed-name group (list 'nnmh ""))
516 (setq new (sort new '<)))) 519 (setq new (sort new '<))))
517 ;; Sort the article list with highest numbers first. 520 ;; Sort the article list with highest numbers first.
518 (setq articles (sort articles (lambda (art1 art2) 521 (setq articles (sort articles (lambda (art1 art2)
519 (> (car art1) (car art2))))) 522 (> (car art1) (car art2)))))
526 529
527 (defun nnmh-deletable-article-p (group article) 530 (defun nnmh-deletable-article-p (group article)
528 "Say whether ARTICLE in GROUP can be deleted." 531 "Say whether ARTICLE in GROUP can be deleted."
529 (let ((path (concat nnmh-current-directory (int-to-string article)))) 532 (let ((path (concat nnmh-current-directory (int-to-string article))))
530 ;; Writable. 533 ;; Writable.
531 (and (file-writable-p path) 534 (and (file-writable-p path)
532 ;; We can never delete the last article in the group. 535 ;; We can never delete the last article in the group.
533 (not (eq (cdr (nth 1 (assoc group nnmh-group-alist))) 536 (not (eq (cdr (nth 1 (assoc group nnmh-group-alist)))
534 article))))) 537 article)))))
535 538
536 (provide 'nnmh) 539 (provide 'nnmh)