*** empty log message ***
[gnus] / lisp / gnus-cache.el
index 74ad8de..bf7d72f 100644 (file)
 \f
 
 (defun gnus-cache-change-buffer (group)
-  (save-excursion
-    (cond ((null gnus-cache-buffer)
-          ;; No current cache, so we create and init the buffer.
-          (setq gnus-cache-buffer
-                (cons group (get-buffer-create " *gnus-cache-overview*")))
-          (set-buffer (cdr gnus-cache-buffer))
-          (buffer-disable-undo (current-buffer))
-          (erase-buffer)
-          (gnus-add-current-to-buffer-list)
-          (let ((file (gnus-cache-file-name group ".overview")))
-            (and (file-exists-p file)
-                 (insert-file-contents file))))
-         ((not (string= group (car gnus-cache-buffer)))
-          ;; If a different overview cache is the current, we
-          ;; (possibly) save it and change to this groups.
-          (set-buffer (cdr gnus-cache-buffer))
-          (and (buffer-modified-p)
-               (write-region (point-min) (point-max)
-                             (gnus-cache-file-name
-                              (car gnus-cache-buffer) ".overview")
-                             nil 'quiet))
-          (erase-buffer)
-          (setcar gnus-cache-buffer group)
-          (let ((file (gnus-cache-file-name group ".overview")))
-            (and (file-exists-p file)
-                 (insert-file-contents file)))))))
+  (and gnus-cache-buffer
+       ;; see if the current group's overview cache has been loaded 
+       (or (string= group (car gnus-cache-buffer))
+          ;; another overview cache is current, save it
+          (gnus-cache-save-buffers)))
+  ;; if gnus-cache buffer is nil, create it
+  (or gnus-cache-buffer
+      ;; create cache buffer
+      (save-excursion
+       (setq gnus-cache-buffer
+             (cons group
+                   (set-buffer (get-buffer-create " *gnus-cache-overview*"))))
+       (buffer-disable-undo (current-buffer))
+       ;; insert the contents of this groups cache overview
+       (erase-buffer)
+       (let ((file (gnus-cache-file-name group ".overview")))
+         (and (file-exists-p file)
+              (insert-file-contents file)))
+       ;; we have a fresh (empty/just loaded) buffer, 
+       ;; mark it as unmodified to save a redundant write later.
+       (set-buffer-modified-p nil))))
 
 
-;; Just save the overview buffer.
 (defun gnus-cache-save-buffers ()
-  (and gnus-cache-buffer
-       (save-excursion
-        (set-buffer (cdr gnus-cache-buffer))
-        (and (buffer-modified-p)
-             (write-region (point-min) (point-max)
-                           (gnus-cache-file-name (car gnus-cache-buffer)
-                                                 ".overview")
-                           nil 'quiet))))
-  (setq gnus-cache-buffer nil))
+  ;; save the overview buffer if it exists and has been modified
+  ;; delete empty cache subdirectories
+  (if (null gnus-cache-buffer)
+      ()
+    (let ((buffer (cdr gnus-cache-buffer))
+         (overview-file (gnus-cache-file-name
+                         (car gnus-cache-buffer) ".overview")))
+      ;; write the overview only if it was modified
+      (if (buffer-modified-p buffer)
+         (save-excursion
+           (set-buffer buffer)
+           (if (> (buffer-size) 0)
+               ;; non-empty overview, write it out
+               (gnus-make-directory (file-name-directory overview-file))
+               (write-region (point-min) (point-max)
+                             overview-file nil 'quietly)
+             ;; empty overview file, remove it
+             (and (file-exists-p overview-file)
+                  (delete-file overview-file))
+             ;; if possible, remove group's cache subdirectory
+             (condition-case nil
+                 ;; FIXME: we can detect the error type and warn the user
+                 ;; of any inconsistencies (articles w/o nov entries?).
+                 ;; for now, just be conservative...delete only if safe -- sj
+                 (delete-directory (file-name-directory overview-file))
+               (error nil)))))
+      ;; kill the buffer, it's either unmodified or saved
+      (gnus-kill-buffer buffer)
+      (setq gnus-cache-buffer nil))))
+
 
 ;; Return whether an article is a member of a class.
 (defun gnus-cache-member-of-class (class ticked dormant unread)
 (defun gnus-cache-file-name (group article)
   (concat (file-name-as-directory gnus-cache-directory)
          (if (gnus-use-long-file-name 'not-cache)
-             group (gnus-replace-chars-in-string group ?. ?/))
+             group 
+           (let ((group (concat group "")))
+             (if (string-match ":" group)
+                 (aset group (match-beginning 0) ?/))
+             (gnus-replace-chars-in-string group ?. ?/)))
          "/" (if (stringp article) article (int-to-string article))))
 
 (defun gnus-cache-possibly-enter-article 
   (group article headers ticked dormant unread)
   (let ((number (header-number headers))
        file dir)
-    (if (or (not (gnus-cache-member-of-class
+    (if (or (not (vectorp headers)) ; This might be a dummy article.
+           (not (gnus-cache-member-of-class
                  gnus-cache-enter-articles ticked dormant unread))
            (file-exists-p (setq file (gnus-cache-file-name group article))))
-       ()
-      (gnus-summary-select-article)
+       () ; Do nothing.
+      ;; Possibly create the cache directory.
       (or (file-exists-p (setq dir (file-name-directory file)))
          (gnus-make-directory dir))
+      ;; Save the article in the cache.
       (if (file-exists-p file)
-         t
+         t ; The article already is saved, so we end here.
+       (gnus-summary-select-article)
        (save-excursion
          (set-buffer gnus-article-buffer)
-         (write-region (point-min) (point-max) file nil 'quiet)
+         (save-restriction
+           (widen)
+           (write-region (point-min) (point-max) file nil 'quiet))
          (gnus-cache-change-buffer group)
          (set-buffer (cdr gnus-cache-buffer))
          (goto-char (point-max))
                        (forward-line 1)))
                (beginning-of-line))
            (forward-line 1))
+         (beginning-of-line)
          ;; [number subject from date id references chars lines xref]
-         (insert (format "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n"
+         (insert (format "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n"
                          (header-number headers)
                          (header-subject headers)
+                         (header-from headers)
                          (header-date headers)
                          (header-id headers)
                          (or (header-references headers) "")
                          (or (header-xref headers) ""))))
        t))))
 
-(defun gnus-cache-possibly-remove-article 
-  (group article ticked dormant unread)
-  (let ((file (gnus-cache-file-name group article)))
+(defun gnus-cache-enter-remove-article (article)
+  (setq gnus-cache-removeable-articles
+       (cons article gnus-cache-removeable-articles)))
+
+(defsubst gnus-cache-possibly-remove-article 
+  (article ticked dormant unread)
+  (let ((file (gnus-cache-file-name gnus-newsgroup-name article)))
     (if (or (not (file-exists-p file))
            (not (gnus-cache-member-of-class
                  gnus-cache-remove-articles ticked dormant unread)))
        nil
       (save-excursion
        (delete-file file)
-       (gnus-cache-change-buffer group)
        (set-buffer (cdr gnus-cache-buffer))
        (goto-char (point-min))
-       (if (or (looking-at (concat (string-to-int article) "\t"))
-               (search-forward (concat "\n" (string-to-int article) "\t")))
+       (if (or (looking-at (concat (int-to-string article) "\t"))
+               (search-forward (concat "\n" (int-to-string article) "\t")
+                               (point-max) t))
            (delete-region (progn (beginning-of-line) (point))
                           (progn (forward-line 1) (point))))))))
 
+(defun gnus-cache-possibly-remove-articles ()
+  (let ((articles gnus-cache-removeable-articles)
+       (cache-articles (gnus-cache-articles-in-group gnus-newsgroup-name))
+       article)
+    (gnus-cache-change-buffer gnus-newsgroup-name)
+    (while articles
+      (setq article (car articles)
+           articles (cdr articles))
+      (if (memq article cache-articles)
+         ;; The article was in the cache, so we see whether we are
+         ;; supposed to remove it from the cache.
+         (gnus-cache-possibly-remove-article
+          article (memq article gnus-newsgroup-marked)
+          (memq article gnus-newsgroup-dormant)
+          (or (memq article gnus-newsgroup-unreads)
+              (memq article gnus-newsgroup-unselected))))))
+  ;; the overview file might have been modified, save it
+  ;; safe because we're only called at group exit anyway
+  (gnus-cache-save-buffers))
+
+
 (defun gnus-cache-request-article (article group)
   (let ((file (gnus-cache-file-name group article)))
     (if (not (file-exists-p file))
     (kill-buffer cache-buf)))
 
 (defun gnus-cache-braid-heads (group cached)
-  (let ((cache-buf (get-buffer-create " *gnus-cache*"))
-       beg end)
+  (let ((cache-buf (get-buffer-create " *gnus-cache*")))
     (save-excursion
       (set-buffer cache-buf)
       (buffer-disable-undo (current-buffer))