X-Git-Url: http://cgit.sxemacs.org/?p=gnus;a=blobdiff_plain;f=lisp%2Fnnml.el;h=42b532168758d52f132a187b2770a15ddabaf7ed;hp=61d1987eac25fab28578c5399559ab6bae1b3cf7;hb=06e3d74faa6b1196f0a7b877acc1bb6b6c1563a8;hpb=beea27f346deb91e5478dd18dd28e27cb1920dde diff --git a/lisp/nnml.el b/lisp/nnml.el index 61d1987ea..42b532168 100644 --- a/lisp/nnml.el +++ b/lisp/nnml.el @@ -1,7 +1,7 @@ ;;; nnml.el --- mail spool access for Gnus ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, -;; 2004, 2005, 2006 Free Software Foundation, Inc. +;; 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. ;; Authors: Didier Verna (adding compaction) ;; Simon Josefsson (adding MARKS) @@ -11,10 +11,10 @@ ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; 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 2, or (at your option) -;; any later version. +;; 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 @@ -22,9 +22,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -40,9 +38,9 @@ (require 'nnoo) (eval-when-compile (require 'cl)) -(eval-and-compile - (autoload 'gnus-article-unpropagatable-p "gnus-sum") - (autoload 'gnus-backlog-remove-article "gnus-bcklg")) +;; FIXME first is unused in this file. +(autoload 'gnus-article-unpropagatable-p "gnus-sum") +(autoload 'gnus-backlog-remove-article "gnus-bcklg") (nnoo-declare nnml) @@ -88,7 +86,7 @@ marks file will be regenerated properly by Gnus.") "If non-nil, allow using compressed message files. If it is a string, use it as the file extension which specifies -the comression program. You can set it to \".bz2\" if your Emacs +the compression program. You can set it to \".bz2\" if your Emacs supports auto-compression using the bzip2 program. A value of t is equivalent to \".gz\".") @@ -129,10 +127,40 @@ non-nil.") (nnoo-define-basics nnml) +(eval-when-compile + (defsubst nnml-group-name-charset (group server-or-method) + (gnus-group-name-charset + (if (stringp server-or-method) + (gnus-server-to-method + (if (string-match "\\+" server-or-method) + (concat (substring server-or-method 0 (match-beginning 0)) + ":" (substring server-or-method (match-end 0))) + (concat "nnml:" server-or-method))) + (or server-or-method gnus-command-method '(nnml ""))) + group))) + +(defun nnml-decoded-group-name (group &optional server-or-method) + "Return a decoded group name of GROUP on SERVER-OR-METHOD." + (if nnmail-group-names-not-encoded-p + group + (mm-decode-coding-string + group + (nnml-group-name-charset group server-or-method)))) + +(defun nnml-encoded-group-name (group &optional server-or-method) + "Return an encoded group name of GROUP on SERVER-OR-METHOD." + (mm-encode-coding-string + group + (nnml-group-name-charset group server-or-method))) + +(defun nnml-group-pathname (group &optional file server) + "Return an absolute file name of FILE for GROUP on SERVER." + (nnmail-group-pathname (inline (nnml-decoded-group-name group server)) + nnml-directory file)) + (deffoo nnml-retrieve-headers (sequence &optional group server fetch-old) (when (nnml-possibly-change-directory group server) - (save-excursion - (set-buffer nntp-server-buffer) + (with-current-buffer nntp-server-buffer (erase-buffer) (let* ((file nil) (number (length sequence)) @@ -201,14 +229,12 @@ non-nil.") (file-name-coding-system nnmail-pathname-coding-system) path gpath group-num) (if (stringp id) - (when (and (setq group-num (nnml-find-group-number id)) + (when (and (setq group-num (nnml-find-group-number id server)) (cdr (assq (cdr group-num) (nnheader-article-to-file-alist - (setq gpath - (nnmail-group-pathname - (car group-num) - nnml-directory)))))) + (setq gpath (nnml-group-pathname (car group-num) + nil server)))))) (setq path (concat gpath (int-to-string (cdr group-num))))) (setq path (nnml-article-to-file id))) (cond @@ -228,8 +254,9 @@ non-nil.") (cons (if group-num (car group-num) group) (string-to-number (file-name-nondirectory path))))))) -(deffoo nnml-request-group (group &optional server dont-check) - (let ((file-name-coding-system nnmail-pathname-coding-system)) +(deffoo nnml-request-group (group &optional server dont-check info) + (let ((file-name-coding-system nnmail-pathname-coding-system) + (decoded (nnml-decoded-group-name group server))) (cond ((not (nnml-possibly-change-directory group server)) (nnheader-report 'nnml "Invalid group (no such directory)")) @@ -239,15 +266,15 @@ non-nil.") ((not (file-directory-p nnml-current-directory)) (nnheader-report 'nnml "%s is not a directory" nnml-current-directory)) (dont-check - (nnheader-report 'nnml "Group %s selected" group) + (nnheader-report 'nnml "Group %s selected" decoded) t) (t (nnheader-re-read-dir nnml-current-directory) (nnmail-activate 'nnml) (let ((active (nth 1 (assoc group nnml-group-alist)))) (if (not active) - (nnheader-report 'nnml "No such group: %s" group) - (nnheader-report 'nnml "Selected group %s" group) + (nnheader-report 'nnml "No such group: %s" decoded) + (nnheader-report 'nnml "Selected group %s" decoded) (nnheader-insert "211 %d %d %d %s\n" (max (1+ (- (cdr active) (car active))) 0) (car active) (cdr active) group))))))) @@ -255,7 +282,7 @@ non-nil.") (deffoo nnml-request-scan (&optional group server) (setq nnml-article-file-alist nil) (nnml-possibly-change-directory group server) - (nnmail-get-new-mail 'nnml 'nnml-save-nov nnml-directory group)) + (nnmail-get-new-mail 'nnml 'nnml-save-incremental-nov nnml-directory group)) (deffoo nnml-close-group (group &optional server) (setq nnml-article-file-alist nil) @@ -265,19 +292,23 @@ non-nil.") (nnml-possibly-change-directory nil server) (nnmail-activate 'nnml) (cond + ((let ((file (directory-file-name (nnml-group-pathname group nil server))) + (file-name-coding-system nnmail-pathname-coding-system)) + (and (file-exists-p file) + (not (file-directory-p file)))) + (nnheader-report 'nnml "%s is a file" + (directory-file-name (nnml-group-pathname group + nil server)))) ((assoc group nnml-group-alist) t) - ((and (file-exists-p (nnmail-group-pathname group nnml-directory)) - (not (file-directory-p (nnmail-group-pathname group nnml-directory)))) - (nnheader-report 'nnml "%s is a file" - (nnmail-group-pathname group nnml-directory))) (t (let (active) (push (list group (setq active (cons 1 0))) nnml-group-alist) - (nnml-possibly-create-directory group) + (nnml-possibly-create-directory group server) (nnml-possibly-change-directory group server) - (let ((articles (nnml-directory-articles nnml-current-directory))) + (let* ((file-name-coding-system nnmail-pathname-coding-system) + (articles (nnml-directory-articles nnml-current-directory))) (when articles (setcar active (apply 'min articles)) (setcdr active (apply 'max articles)))) @@ -301,10 +332,12 @@ non-nil.") (deffoo nnml-request-expire-articles (articles group &optional server force) (nnml-possibly-change-directory group server) - (let ((active-articles - (nnml-directory-articles nnml-current-directory)) - (is-old t) - article rest mod-time number) + (let* ((file-name-coding-system nnmail-pathname-coding-system) + (active-articles + (nnml-directory-articles nnml-current-directory)) + (is-old t) + (decoded (nnml-decoded-group-name group server)) + article rest mod-time number target) (nnmail-activate 'nnml) (setq active-articles (sort active-articles '<)) @@ -321,23 +354,33 @@ non-nil.") nnml-inhibit-expiry))) (progn ;; Allow a special target group. - (unless (eq nnmail-expiry-target 'delete) + (setq target nnmail-expiry-target) + (unless (eq target 'delete) (with-temp-buffer (nnml-request-article number group server (current-buffer)) (let (nnml-current-directory nnml-current-group nnml-article-file-alist) - (nnmail-expiry-target-group nnmail-expiry-target group))) + (when (functionp target) + (setq target (funcall target group))) + (when (and target (not (eq target 'delete))) + (if (or (gnus-request-group target) + (gnus-request-create-group target)) + (nnmail-expiry-target-group target group) + (setq target nil))))) ;; Maybe directory is changed during nnmail-expiry-target-group. (nnml-possibly-change-directory group server)) - (nnheader-message 5 "Deleting article %s in %s" - number group) - (condition-case () - (funcall nnmail-delete-file-function article) - (file-error - (push number rest))) - (setq active-articles (delq number active-articles)) - (nnml-nov-delete-article group number)) + (if target + (progn + (nnheader-message 5 "Deleting article %s in %s" + number decoded) + (condition-case () + (funcall nnmail-delete-file-function article) + (file-error + (push number rest))) + (setq active-articles (delq number active-articles)) + (nnml-nov-delete-article group number)) + (push number rest))) (push number rest))) (let ((active (nth 1 (assoc group nnml-group-alist)))) (when active @@ -351,6 +394,7 @@ non-nil.") (deffoo nnml-request-move-article (article group server accept-form &optional last move-is-internal) (let ((buf (get-buffer-create " *nnml move*")) + (file-name-coding-system nnmail-pathname-coding-system) result) (nnml-possibly-change-directory group server) (nnml-update-file-alist) @@ -360,8 +404,7 @@ non-nil.") (let (nnml-current-directory nnml-current-group nnml-article-file-alist) - (save-excursion - (set-buffer buf) + (with-current-buffer buf (insert-buffer-substring nntp-server-buffer) (setq result (eval accept-form)) (kill-buffer (current-buffer)) @@ -391,16 +434,20 @@ non-nil.") (and (nnmail-activate 'nnml) (setq result (car (nnml-save-mail - (list (cons group (nnml-active-number group)))))) + (list (cons group (nnml-active-number group + server))) + server t))) (progn (nnmail-save-active nnml-group-alist nnml-active-file) (and last (nnml-save-nov)))) (and (nnmail-activate 'nnml) - (if (and (not (setq result (nnmail-article-group 'nnml-active-number))) + (if (and (not (setq result (nnmail-article-group + `(lambda (group) + (nnml-active-number group ,server))))) (yes-or-no-p "Moved to `junk' group; delete article? ")) (setq result 'junk) - (setq result (car (nnml-save-mail result)))) + (setq result (car (nnml-save-mail result server t)))) (when last (nnmail-save-active nnml-group-alist nnml-active-file) (when nnmail-cache-accepted-message-ids @@ -413,8 +460,7 @@ non-nil.") (deffoo nnml-request-replace-article (article group buffer) (nnml-possibly-change-directory group) - (save-excursion - (set-buffer buffer) + (with-current-buffer buffer (nnml-possibly-create-directory group) (let ((chars (nnmail-insert-lines)) (art (concat (int-to-string article) "\t")) @@ -429,8 +475,7 @@ non-nil.") t) (setq headers (nnml-parse-head chars article)) ;; Replace the NOV line in the NOV file. - (save-excursion - (set-buffer (nnml-open-nov group)) + (with-current-buffer (nnml-open-nov group) (goto-char (point-min)) (if (or (looking-at art) (search-forward (concat "\n" art) nil t)) @@ -452,33 +497,45 @@ non-nil.") (deffoo nnml-request-delete-group (group &optional force server) (nnml-possibly-change-directory group server) - (when force - ;; Delete all articles in GROUP. - (let ((articles - (directory-files - nnml-current-directory t - (concat nnheader-numerical-short-files - "\\|" (regexp-quote nnml-nov-file-name) "$" - "\\|" (regexp-quote nnml-marks-file-name) "$")))) - (dolist (article articles) - (when (file-writable-p article) - (nnheader-message 5 "Deleting article %s in %s..." article group) - (funcall nnmail-delete-file-function article)))) - ;; Try to delete the directory itself. - (ignore-errors (delete-directory nnml-current-directory))) - ;; Remove the group from all structures. - (setq nnml-group-alist - (delq (assoc group nnml-group-alist) nnml-group-alist) - nnml-current-group nil - nnml-current-directory nil) - ;; Save the active file. - (nnmail-save-active nnml-group-alist nnml-active-file) + (let ((file (directory-file-name nnml-current-directory)) + (file-name-coding-system nnmail-pathname-coding-system)) + (if (file-exists-p file) + (if (file-directory-p file) + (progn + (when force + ;; Delete all articles in GROUP. + (let ((articles + (directory-files + nnml-current-directory t + (concat + nnheader-numerical-short-files + "\\|" (regexp-quote nnml-nov-file-name) "$" + "\\|" (regexp-quote nnml-marks-file-name) "$"))) + (decoded (nnml-decoded-group-name group server))) + (dolist (article articles) + (when (file-writable-p article) + (nnheader-message 5 "Deleting article %s in %s..." + (file-name-nondirectory article) + decoded) + (funcall nnmail-delete-file-function article)))) + ;; Try to delete the directory itself. + (ignore-errors (delete-directory nnml-current-directory)))) + (nnheader-report 'nnml "%s is not a directory" file)) + (nnheader-report 'nnml "No such directory: %s/" file)) + ;; Remove the group from all structures. + (setq nnml-group-alist + (delq (assoc group nnml-group-alist) nnml-group-alist) + nnml-current-group nil + nnml-current-directory nil) + ;; Save the active file. + (nnmail-save-active nnml-group-alist nnml-active-file)) t) (deffoo nnml-request-rename-group (group new-name &optional server) (nnml-possibly-change-directory group server) - (let ((new-dir (nnmail-group-pathname new-name nnml-directory)) - (old-dir (nnmail-group-pathname group nnml-directory))) + (let ((new-dir (nnml-group-pathname new-name nil server)) + (old-dir (nnml-group-pathname group nil server)) + (file-name-coding-system nnmail-pathname-coding-system)) (when (ignore-errors (make-directory new-dir t) t) @@ -543,7 +600,8 @@ non-nil.") (defun nnml-deletable-article-p (group article) "Say whether ARTICLE in GROUP can be deleted." - (let (path) + (let ((file-name-coding-system nnmail-pathname-coding-system) + path) (when (setq path (nnml-article-to-file article)) (when (file-writable-p path) (or (not nnmail-keep-last-article) @@ -551,30 +609,28 @@ non-nil.") article))))))) ;; Find an article number in the current group given the Message-ID. -(defun nnml-find-group-number (id) - (save-excursion - (set-buffer (get-buffer-create " *nnml id*")) +(defun nnml-find-group-number (id server) + (with-current-buffer (get-buffer-create " *nnml id*") (let ((alist nnml-group-alist) number) ;; We want to look through all .overview files, but we want to ;; start with the one in the current directory. It seems most ;; likely that the article we are looking for is in that group. - (if (setq number (nnml-find-id nnml-current-group id)) + (if (setq number (nnml-find-id nnml-current-group id server)) (cons nnml-current-group number) ;; It wasn't there, so we look through the other groups as well. (while (and (not number) alist) (or (string= (caar alist) nnml-current-group) - (setq number (nnml-find-id (caar alist) id))) + (setq number (nnml-find-id (caar alist) id server))) (or number (setq alist (cdr alist)))) (and number (cons (caar alist) number)))))) -(defun nnml-find-id (group id) +(defun nnml-find-id (group id server) (erase-buffer) - (let ((nov (expand-file-name nnml-nov-file-name - (nnmail-group-pathname group nnml-directory))) + (let ((nov (nnml-group-pathname group nnml-nov-file-name server)) number found) (when (file-exists-p nov) (nnheader-insert-file-contents nov) @@ -596,8 +652,7 @@ non-nil.") nil (let ((nov (expand-file-name nnml-nov-file-name nnml-current-directory))) (when (file-exists-p nov) - (save-excursion - (set-buffer nntp-server-buffer) + (with-current-buffer nntp-server-buffer (erase-buffer) (nnheader-insert-file-contents nov) (if (and fetch-old @@ -615,7 +670,7 @@ non-nil.") (nnml-open-server server)) (if (not group) t - (let ((pathname (nnmail-group-pathname group nnml-directory)) + (let ((pathname (nnml-group-pathname group nil server)) (file-name-coding-system nnmail-pathname-coding-system)) (when (not (equal pathname nnml-current-directory)) (setq nnml-current-directory pathname @@ -623,22 +678,32 @@ non-nil.") nnml-article-file-alist nil)) (file-exists-p nnml-current-directory)))) -(defun nnml-possibly-create-directory (group) - (let ((dir (nnmail-group-pathname group nnml-directory))) +(defun nnml-possibly-create-directory (group &optional server) + (let ((dir (nnml-group-pathname group nil server)) + (file-name-coding-system nnmail-pathname-coding-system)) (unless (file-exists-p dir) (make-directory (directory-file-name dir) t) (nnheader-message 5 "Creating mail directory %s" dir)))) -(defun nnml-save-mail (group-art) - "Called narrowed to an article." - (let (chars headers extension) - (setq chars (nnmail-insert-lines)) - (setq extension - (and nnml-use-compressed-files - (> chars nnml-compressed-files-size-threshold) - (if (stringp nnml-use-compressed-files) - nnml-use-compressed-files - ".gz"))) +(defun nnml-save-mail (group-art &optional server full-nov) + "Save a mail into the groups GROUP-ART in the nnml server SERVER. +GROUP-ART is a list that each element is a cons of a group name and an +article number. This function is called narrowed to an article." + (let* ((chars (nnmail-insert-lines)) + (extension (and nnml-use-compressed-files + (> chars nnml-compressed-files-size-threshold) + (if (stringp nnml-use-compressed-files) + nnml-use-compressed-files + ".gz"))) + decoded dec file first headers) + (when nnmail-group-names-not-encoded-p + (dolist (ga (prog1 group-art (setq group-art nil))) + (setq group-art (nconc group-art + (list (cons (nnml-encoded-group-name (car ga) + server) + (cdr ga)))) + decoded (nconc decoded (list (car ga))))) + (setq dec decoded)) (nnmail-insert-xref group-art) (run-hooks 'nnmail-prepare-save-mail-hook) (run-hooks 'nnml-prepare-save-mail-hook) @@ -647,43 +712,52 @@ non-nil.") (replace-match "X-From-Line: ") (forward-line 1)) ;; We save the article in all the groups it belongs in. - (let ((ga group-art) - first) - (while ga - (nnml-possibly-create-directory (caar ga)) - (let ((file (concat (nnmail-group-pathname - (caar ga) nnml-directory) - (int-to-string (cdar ga)) - extension))) - (if first - ;; It was already saved, so we just make a hard link. - (funcall nnmail-crosspost-link-function first file t) - ;; Save the article. - (nnmail-write-region (point-min) (point-max) file nil - (if (nnheader-be-verbose 5) nil 'nomesg)) - (setq first file))) - (setq ga (cdr ga)))) + (dolist (ga group-art) + (if nnmail-group-names-not-encoded-p + (progn + (nnml-possibly-create-directory (car decoded) server) + (setq file (nnmail-group-pathname + (pop decoded) nnml-directory + (concat (number-to-string (cdr ga)) extension)))) + (nnml-possibly-create-directory (car ga) server) + (setq file (nnml-group-pathname + (car ga) (concat (number-to-string (cdr ga)) extension) + server))) + (if first + ;; It was already saved, so we just make a hard link. + (let ((file-name-coding-system nnmail-pathname-coding-system)) + (funcall nnmail-crosspost-link-function first file t)) + ;; Save the article. + (nnmail-write-region (point-min) (point-max) file nil + (if (nnheader-be-verbose 5) nil 'nomesg)) + (setq first file))) ;; Generate a nov line for this article. We generate the nov ;; line after saving, because nov generation destroys the ;; header. (setq headers (nnml-parse-head chars)) ;; Output the nov line to all nov databases that should have it. - (let ((ga group-art)) - (while ga - (nnml-add-nov (caar ga) (cdar ga) headers) - (setq ga (cdr ga)))) - group-art)) - -(defun nnml-active-number (group) - "Compute the next article number in GROUP." - (let ((active (cadr (assoc group nnml-group-alist)))) + (let ((func (if full-nov + 'nnml-add-nov + 'nnml-add-incremental-nov))) + (if nnmail-group-names-not-encoded-p + (dolist (ga group-art) + (funcall func (pop dec) (cdr ga) headers)) + (dolist (ga group-art) + (funcall func (car ga) (cdr ga) headers))))) + group-art) + +(defun nnml-active-number (group &optional server) + "Compute the next article number in GROUP on SERVER." + (let* ((encoded (if nnmail-group-names-not-encoded-p + (nnml-encoded-group-name group server))) + (active (cadr (assoc (or encoded group) nnml-group-alist)))) ;; The group wasn't known to nnml, so we just create an active ;; entry for it. (unless active ;; Perhaps the active file was corrupt? See whether ;; there are any articles in this group. - (nnml-possibly-create-directory group) - (nnml-possibly-change-directory group) + (nnml-possibly-create-directory group server) + (nnml-possibly-change-directory group server) (unless nnml-article-file-alist (setq nnml-article-file-alist (sort @@ -694,18 +768,44 @@ non-nil.") (cons (caar nnml-article-file-alist) (caar (last nnml-article-file-alist))) (cons 1 0))) - (push (list group active) nnml-group-alist)) + (push (list (or encoded group) active) nnml-group-alist)) (setcdr active (1+ (cdr active))) (while (file-exists-p - (expand-file-name (int-to-string (cdr active)) - (nnmail-group-pathname group nnml-directory))) + (nnml-group-pathname group (int-to-string (cdr active)) server)) (setcdr active (1+ (cdr active)))) (cdr active))) +(defvar nnml-incremental-nov-buffer-alist nil) + +(defun nnml-save-incremental-nov () + (save-excursion + (while nnml-incremental-nov-buffer-alist + (when (buffer-name (cdar nnml-incremental-nov-buffer-alist)) + (set-buffer (cdar nnml-incremental-nov-buffer-alist)) + (when (buffer-modified-p) + (nnmail-write-region (point-min) (point-max) + nnml-nov-buffer-file-name t 'nomesg)) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer))) + (setq nnml-incremental-nov-buffer-alist + (cdr nnml-incremental-nov-buffer-alist))))) + +(defun nnml-open-incremental-nov (group) + (or (cdr (assoc group nnml-incremental-nov-buffer-alist)) + (let ((buffer (nnml-get-nov-buffer group t))) + (push (cons group buffer) nnml-incremental-nov-buffer-alist) + buffer))) + +(defun nnml-add-incremental-nov (group article headers) + "Add a nov line for the GROUP nov headers, incrementally." + (with-current-buffer (nnml-open-incremental-nov group) + (goto-char (point-max)) + (mail-header-set-number headers article) + (nnheader-insert-nov headers))) + (defun nnml-add-nov (group article headers) "Add a nov line for the GROUP base." - (save-excursion - (set-buffer (nnml-open-nov group)) + (with-current-buffer (nnml-open-nov group) (goto-char (point-max)) (mail-header-set-number headers article) (nnheader-insert-nov headers))) @@ -728,16 +828,20 @@ non-nil.") (mail-header-set-number headers number) headers)))) -(defun nnml-get-nov-buffer (group) - (let ((buffer (get-buffer-create (format " *nnml overview %s*" group)))) - (save-excursion - (set-buffer buffer) +(defun nnml-get-nov-buffer (group &optional incrementalp) + (let* ((decoded (nnml-decoded-group-name group)) + (buffer (get-buffer-create (format " *nnml %soverview %s*" + (if incrementalp + "incremental " + "") + decoded))) + (file-name-coding-system nnmail-pathname-coding-system)) + (with-current-buffer buffer (set (make-local-variable 'nnml-nov-buffer-file-name) - (expand-file-name - nnml-nov-file-name - (nnmail-group-pathname group nnml-directory))) + (nnmail-group-pathname decoded nnml-directory nnml-nov-file-name)) (erase-buffer) - (when (file-exists-p nnml-nov-buffer-file-name) + (when (and (not incrementalp) + (file-exists-p nnml-nov-buffer-file-name)) (nnheader-insert-file-contents nnml-nov-buffer-file-name))) buffer)) @@ -774,47 +878,53 @@ non-nil.") ;; Save the active file. (nnmail-save-active nnml-group-alist nnml-active-file)) +(defvar nnml-files) (defun nnml-generate-nov-databases-directory (dir &optional seen no-active) "Regenerate the NOV database in DIR. Unless no-active is non-nil, update the active file too." - (interactive "DRegenerate NOV in: ") + (interactive (list (let ((file-name-coding-system + nnmail-pathname-coding-system)) + (read-directory-name "Regenerate NOV in: " + nnml-directory nil t)))) (setq dir (file-name-as-directory dir)) - ;; Only scan this sub-tree if we haven't been here yet. - (unless (member (file-truename dir) seen) - (push (file-truename dir) seen) - ;; We descend recursively - (dolist (dir (directory-files dir t nil t)) - (when (and (not (string-match "^\\." (file-name-nondirectory dir))) - (file-directory-p dir)) - (nnml-generate-nov-databases-directory dir seen))) - ;; Do this directory. - (let ((files (sort (nnheader-article-to-file-alist dir) - 'car-less-than-car))) - (if (not files) - (let* ((group (nnheader-file-to-group - (directory-file-name dir) nnml-directory)) - (info (cadr (assoc group nnml-group-alist)))) - (when info - (setcar info (1+ (cdr info))))) - (funcall nnml-generate-active-function dir) - ;; Generate the nov file. - (nnml-generate-nov-file dir files) - (unless no-active - (nnmail-save-active nnml-group-alist nnml-active-file)))))) - -(eval-when-compile (defvar files)) + (let ((file-name-coding-system nnmail-pathname-coding-system)) + ;; Only scan this sub-tree if we haven't been here yet. + (unless (member (file-truename dir) seen) + (push (file-truename dir) seen) + ;; We descend recursively + (dolist (dir (directory-files dir t nil t)) + (when (and (not (string-match "^\\." (file-name-nondirectory dir))) + (file-directory-p dir)) + (nnml-generate-nov-databases-directory dir seen))) + ;; Do this directory. + (let ((nnml-files (sort (nnheader-article-to-file-alist dir) + 'car-less-than-car))) + (if (not nnml-files) + (let* ((group (nnheader-file-to-group + (directory-file-name dir) nnml-directory)) + (info (cadr (assoc group nnml-group-alist)))) + (when info + (setcar info (1+ (cdr info))))) + (funcall nnml-generate-active-function dir) + ;; Generate the nov file. + (nnml-generate-nov-file dir nnml-files) + (unless no-active + (nnmail-save-active nnml-group-alist nnml-active-file))))))) + (defun nnml-generate-active-info (dir) ;; Update the active info for this group. - (let* ((group (nnheader-file-to-group - (directory-file-name dir) nnml-directory)) - (entry (assoc group nnml-group-alist)) - (last (or (caadr entry) 0))) - (setq nnml-group-alist (delq entry nnml-group-alist)) + (let ((group (directory-file-name dir)) + entry last) + (setq group (nnheader-file-to-group (nnml-encoded-group-name group) + nnml-directory) + entry (assoc group nnml-group-alist) + last (or (caadr entry) 0) + nnml-group-alist (delq entry nnml-group-alist)) (push (list group - (cons (or (caar files) (1+ last)) + (cons (or (caar nnml-files) (1+ last)) (max last - (or (caar (last files)) + (or (caar (last nnml-files)) 0)))) nnml-group-alist))) @@ -823,42 +933,38 @@ Unless no-active is non-nil, update the active file too." (nov (concat dir nnml-nov-file-name)) (nov-buffer (get-buffer-create " *nov*")) chars file headers) - (save-excursion + (with-current-buffer nov-buffer ;; Init the nov buffer. - (set-buffer nov-buffer) (buffer-disable-undo) (erase-buffer) (set-buffer nntp-server-buffer) ;; Delete the old NOV file. (when (file-exists-p nov) (funcall nnmail-delete-file-function nov)) - (while files - (unless (file-directory-p (setq file (concat dir (cdar files)))) - (erase-buffer) - (nnheader-insert-file-contents file) - (narrow-to-region - (goto-char (point-min)) - (progn - (re-search-forward "\n\r?\n" nil t) - (setq chars (- (point-max) (point))) - (max (point-min) (1- (point))))) - (unless (zerop (buffer-size)) - (goto-char (point-min)) - (setq headers (nnml-parse-head chars (caar files))) - (save-excursion - (set-buffer nov-buffer) - (goto-char (point-max)) - (nnheader-insert-nov headers))) - (widen)) - (setq files (cdr files))) - (save-excursion - (set-buffer nov-buffer) + (dolist (file files) + (let ((path (concat dir (cdr file)))) + (unless (file-directory-p path) + (erase-buffer) + (nnheader-insert-file-contents path) + (narrow-to-region + (goto-char (point-min)) + (progn + (re-search-forward "\n\r?\n" nil t) + (setq chars (- (point-max) (point))) + (max (point-min) (1- (point))))) + (unless (zerop (buffer-size)) + (goto-char (point-min)) + (setq headers (nnml-parse-head chars (car file))) + (with-current-buffer nov-buffer + (goto-char (point-max)) + (nnheader-insert-nov headers))) + (widen)))) + (with-current-buffer nov-buffer (nnmail-write-region (point-min) (point-max) nov nil 'nomesg) (kill-buffer (current-buffer)))))) (defun nnml-nov-delete-article (group article) - (save-excursion - (set-buffer (nnml-open-nov group)) + (with-current-buffer (nnml-open-nov group) (when (nnheader-find-nov-line article) (delete-region (point) (progn (forward-line 1) (point))) (when (bobp) @@ -889,11 +995,9 @@ Use the nov database for that directory if available." ;; build list from .overview if available ;; We would use nnml-open-nov, except that nnml-nov-buffer-alist is ;; defvoo'd, and we might get called when it hasn't been swapped in. - (save-excursion + (with-current-buffer (nnml-get-nov-buffer nnml-current-group) (let ((list nil) - art - (buffer (nnml-get-nov-buffer nnml-current-group))) - (set-buffer buffer) + art) (goto-char (point-min)) (while (not (eobp)) (setq art (read (current-buffer))) @@ -912,11 +1016,9 @@ Use the nov database for the current group if available." nnml-current-directory)))) (nnheader-article-to-file-alist nnml-current-directory) ;; build list from .overview if available - (save-excursion + (with-current-buffer (nnml-get-nov-buffer nnml-current-group) (let ((alist nil) - (buffer (nnml-get-nov-buffer nnml-current-group)) art) - (set-buffer buffer) (goto-char (point-min)) (while (not (eobp)) (setq art (read (current-buffer))) @@ -945,9 +1047,9 @@ Use the nov database for the current group if available." (nnml-save-marks group server)) nil) -(deffoo nnml-request-update-info (group info &optional server) +(deffoo nnml-request-marks (group info &optional server) (nnml-possibly-change-directory group server) - (when (and (not nnml-marks-is-evil) (nnml-marks-changed-p group)) + (when (and (not nnml-marks-is-evil) (nnml-marks-changed-p group server)) (nnheader-message 8 "Updating marks for %s..." group) (nnml-open-marks group server) ;; Update info using `nnml-marks'. @@ -970,9 +1072,8 @@ Use the nov database for the current group if available." (nnheader-message 8 "Updating marks for %s...done" group)) info) -(defun nnml-marks-changed-p (group) - (let ((file (expand-file-name nnml-marks-file-name - (nnmail-group-pathname group nnml-directory)))) +(defun nnml-marks-changed-p (group server) + (let ((file (nnml-group-pathname group nnml-marks-file-name server))) (if (null (gnus-gethash file nnml-marks-modtime)) t ;; never looked at marks file, assume it has changed (not (equal (gnus-gethash file nnml-marks-modtime) @@ -980,11 +1081,10 @@ Use the nov database for the current group if available." (defun nnml-save-marks (group server) (let ((file-name-coding-system nnmail-pathname-coding-system) - (file (expand-file-name nnml-marks-file-name - (nnmail-group-pathname group nnml-directory)))) + (file (nnml-group-pathname group nnml-marks-file-name server))) (condition-case err (progn - (nnml-possibly-create-directory group) + (nnml-possibly-create-directory group server) (with-temp-file file (erase-buffer) (gnus-prin1 nnml-marks) @@ -997,9 +1097,10 @@ Use the nov database for the current group if available." (error "Cannot write to %s (%s)" file err)))))) (defun nnml-open-marks (group server) - (let ((file (expand-file-name - nnml-marks-file-name - (nnmail-group-pathname group nnml-directory)))) + (let* ((decoded (nnml-decoded-group-name group server)) + (file (nnmail-group-pathname decoded nnml-directory + nnml-marks-file-name)) + (file-name-coding-system nnmail-pathname-coding-system)) (if (file-exists-p file) (condition-case err (with-temp-buffer @@ -1017,14 +1118,18 @@ Use the nov database for the current group if available." (let ((info (gnus-get-info (gnus-group-prefixed-name group - (gnus-server-to-method (format "nnml:%s" server)))))) - (nnheader-message 7 "Bootstrapping marks for %s..." group) + (gnus-server-to-method + (format "nnml:%s" (or server ""))))))) + (setq decoded (if (member server '(nil "")) + (concat "nnml:" decoded) + (format "nnml+%s:%s" server decoded))) + (nnheader-message 7 "Bootstrapping marks for %s..." decoded) (setq nnml-marks (gnus-info-marks info)) (push (cons 'read (gnus-info-read info)) nnml-marks) (dolist (el gnus-article-unpropagated-mark-lists) (setq nnml-marks (gnus-remassoc el nnml-marks))) (nnml-save-marks group server) - (nnheader-message 7 "Bootstrapping marks for %s...done" group))))) + (nnheader-message 7 "Bootstrapping marks for %s...done" decoded))))) ;;; @@ -1114,7 +1219,7 @@ Use the nov database for the current group if available." ;; #### already belongs to a range, whereas the corresponding ;; #### article doesn't exist (for example, if you delete an ;; #### article). For that reason, it is important to update - ;; #### the ranges (meaning remove inexistant articles) before + ;; #### the ranges (meaning remove inexistent articles) before ;; #### doing anything on them. ;; 2 a/ read articles: (let ((read (gnus-info-read info))) @@ -1138,8 +1243,7 @@ Use the nov database for the current group if available." (gnus-info-set-marks info newmarks)) ;; 3/ Update the NOV entry for this article: (unless nnml-nov-is-evil - (save-excursion - (set-buffer (nnml-open-nov group)) + (with-current-buffer (nnml-open-nov group) (when (nnheader-find-nov-line old-number) ;; Replace the article number: (looking-at old-number-string) @@ -1221,5 +1325,4 @@ Use the nov database for the current group if available." (provide 'nnml) -;;; arch-tag: 52c97dc3-9735-45de-b439-9e4d23b52004 ;;; nnml.el ends here