*** empty log message ***
[gnus] / lisp / nnvirtual.el
index 974ad98..c221e92 100644 (file)
@@ -1,5 +1,5 @@
 ;;; nnvirtual.el --- virtual newsgroups access for Gnus
-;; Copyright (C) 1994,95,96 Free Software Foundation, Inc.
+;; Copyright (C) 1994,95,96,97 Free Software Foundation, Inc.
 
 ;; Author: David Moore <dmoore@ucsd.edu>
 ;;     Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
@@ -77,6 +77,9 @@ to virtual article number.")
 (defvoo nnvirtual-mapping-marks nil
   "Compressed marks alist for the virtual group as computed from the marks of individual component groups.")
 
+(defvoo nnvirtual-info-installed nil
+  "T if we have already installed the group info for this group, and shouldn't blast over it again.")
+
 (defvoo nnvirtual-status-string "")
 
 (eval-and-compile
@@ -181,26 +184,42 @@ to virtual article number.")
            (kill-buffer vbuf)))))))
 
 
+(defvoo nnvirtual-last-accessed-component-group nil)
 
 (deffoo nnvirtual-request-article (article &optional group server buffer)
-  (when (and (nnvirtual-possibly-change-server server)
-            (numberp article))
-    (let* ((amap (nnvirtual-map-article article))
-          (cgroup (car amap)))
-      (cond
-       ((not amap)
-       (nnheader-report 'nnvirtual "No such article: %s" article))
-       ((not (gnus-check-group cgroup))
-       (nnheader-report
-        'nnvirtual "Can't open server where %s exists" cgroup))
-       ((not (gnus-request-group cgroup t))
-       (nnheader-report 'nnvirtual "Can't open component group %s" cgroup))
-       (t
-       (if buffer 
-           (save-excursion
-             (set-buffer buffer)
-             (gnus-request-article-this-buffer (cdr amap) cgroup))
-         (gnus-request-article (cdr amap) cgroup)))))))
+  (when (nnvirtual-possibly-change-server server)
+    (if (stringp article)
+       ;; This is a fetch by Message-ID.
+       (cond
+        ((not nnvirtual-last-accessed-component-group)
+         (nnheader-report
+          'nnvirtual "Don't know what server to request from"))
+        (t
+         (save-excursion
+           (when buffer 
+             (set-buffer buffer))
+           (let ((method (gnus-find-method-for-group
+                          nnvirtual-last-accessed-component-group)))
+             (funcall (gnus-get-function method 'request-article)
+                      article nil (nth 1 method) buffer)))))
+      ;; This is a fetch by number.
+      (let* ((amap (nnvirtual-map-article article))
+            (cgroup (car amap)))
+       (cond
+        ((not amap)
+         (nnheader-report 'nnvirtual "No such article: %s" article))
+        ((not (gnus-check-group cgroup))
+         (nnheader-report
+          'nnvirtual "Can't open server where %s exists" cgroup))
+        ((not (gnus-request-group cgroup t))
+         (nnheader-report 'nnvirtual "Can't open component group %s" cgroup))
+        (t
+         (setq nnvirtual-last-accessed-component-group cgroup)
+         (if buffer 
+             (save-excursion
+               (set-buffer buffer)
+               (gnus-request-article-this-buffer (cdr amap) cgroup))
+           (gnus-request-article (cdr amap) cgroup))))))))
 
 
 (deffoo nnvirtual-open-server (server &optional defs)
@@ -214,7 +233,8 @@ to virtual article number.")
          nnvirtual-mapping-offsets nil
          nnvirtual-mapping-len 0
          nnvirtual-mapping-reads nil
-         nnvirtual-mapping-marks nil)
+         nnvirtual-mapping-marks nil
+         nnvirtual-info-installed nil)
     (when nnvirtual-component-regexp
       ;; Go through the newsrc alist and find all component groups.
       (let ((newsrc (cdr gnus-newsrc-alist))
@@ -268,9 +288,7 @@ to virtual article number.")
 (deffoo nnvirtual-close-group (group &optional server)
   (when (and (nnvirtual-possibly-change-server server)
             (not (gnus-ephemeral-group-p (nnvirtual-current-group))))
-    ;; Copy (un)read status and marks back to component groups.
-    (nnvirtual-update-reads)
-    (nnvirtual-update-marked t))
+    (nnvirtual-update-read-and-marked t t))
   t)
     
 
@@ -287,13 +305,17 @@ to virtual article number.")
 
 
 (deffoo nnvirtual-request-update-info (group info &optional server)
-  (when (nnvirtual-possibly-change-server server)
-    ;; Install the lists.
-    (setcar (cddr info) nnvirtual-mapping-reads)
-    (if (nthcdr 3 info)
-       (setcar (nthcdr 3 info) nnvirtual-mapping-marks)
-      (when nnvirtual-mapping-marks
-       (setcdr (nthcdr 2 info) (list nnvirtual-mapping-marks))))
+  (when (and (nnvirtual-possibly-change-server server)
+            (not nnvirtual-info-installed))
+    ;; Install the precomputed lists atomically, so the virtual group
+    ;; is not left in a half-way state in case of C-g.
+    (gnus-atomic-progn
+      (setcar (cddr info) nnvirtual-mapping-reads)
+      (if (nthcdr 3 info)
+         (setcar (nthcdr 3 info) nnvirtual-mapping-marks)
+       (when nnvirtual-mapping-marks
+         (setcdr (nthcdr 2 info) (list nnvirtual-mapping-marks))))
+      (setq nnvirtual-info-installed t))
     t))
       
 
@@ -301,7 +323,7 @@ to virtual article number.")
   (when (and (nnvirtual-possibly-change-server server)
             (not (gnus-ephemeral-group-p (nnvirtual-current-group))))
     ;; copy over existing marks first, in case they set anything
-    (nnvirtual-update-marked nil)
+    (nnvirtual-update-read-and-marked nil nil)
     ;; do a catchup on all component groups
     (let ((gnus-group-marked (copy-sequence nnvirtual-component-groups))
          (gnus-expert-user t))
@@ -381,49 +403,53 @@ to virtual article number.")
       (nnvirtual-open-server server)))
 
 
-(defun nnvirtual-update-reads ()
-  "Copy (un)read status from the virtual group to the component groups."
-  (let ((unreads (nnvirtual-partition-sequence (gnus-list-of-unread-articles
-                                               (nnvirtual-current-group))))
-       entry)
-    (while (setq entry (pop unreads))
-      (gnus-update-read-articles (car entry) (cdr entry)))))
-
-
-(defun nnvirtual-update-marked (update-p)
+(defun nnvirtual-update-read-and-marked (read-p update-p)
   "Copy marks from the virtual group to the component groups.
+If READ-P is not nil, update the (un)read status of the components.
 If UPDATE-P is not nil, call gnus-group-update-group on the components."
-  (let ((type-marks (mapcar (lambda (ml)
-                             (cons (car ml)
-                                   (nnvirtual-partition-sequence (cdr ml))))
-                           (gnus-info-marks (gnus-get-info
-                                             (nnvirtual-current-group)))))
-       mark type groups carticles info)
-
-    ;; clear all existing marks on the component groups, since
-    ;; we install new versions below.
-    (setq groups nnvirtual-component-groups)
-    (while groups
-      (when (and (setq info (gnus-get-info (pop groups)))
-                (gnus-info-marks info))
-       (gnus-info-set-marks info nil)))
-
-    ;; Ok, currently type-marks is an assq list with keys of a mark type,
-    ;; with data of an assq list with keys of component group names
-    ;; and the articles which correspond to that key/group pair.
-    (while (setq mark (pop type-marks))
-      (setq type (car mark))
-      (setq groups (cdr mark))
-      (while (setq carticles (pop groups))
-       (gnus-add-marked-articles (car carticles) type (cdr carticles) 
-                                 nil t)))
+  (when nnvirtual-current-group
+    (let ((unreads (and read-p
+                       (nnvirtual-partition-sequence 
+                        (gnus-list-of-unread-articles 
+                         (nnvirtual-current-group)))))
+         (type-marks (mapcar (lambda (ml)
+                               (cons (car ml)
+                                     (nnvirtual-partition-sequence (cdr ml))))
+                             (gnus-info-marks (gnus-get-info
+                                               (nnvirtual-current-group)))))
+         mark type groups carticles info entry)
+
+      ;; Ok, atomically move all of the (un)read info, clear any old
+      ;; marks, and move all of the current marks.  This way if someone
+      ;; hits C-g, you won't leave the component groups in a half-way state.
+      (gnus-atomic-progn
+       ;; move (un)read
+       (let ((gnus-newsgroup-active nil)) ;workaround guns-update-read-articles
+         (while (setq entry (pop unreads))
+           (gnus-update-read-articles (car entry) (cdr entry))))
+
+       ;; clear all existing marks on the component groups
+       (setq groups nnvirtual-component-groups)
+       (while groups
+         (when (and (setq info (gnus-get-info (pop groups)))
+                    (gnus-info-marks info))
+           (gnus-info-set-marks info nil)))
       
-    ;; possibly update the display, it is really slow
-    (when update-p
-      (setq groups nnvirtual-component-groups)
-      (while groups
-       (gnus-group-update-group (pop groups) t)))
-    ))
+       ;; Ok, currently type-marks is an assq list with keys of a mark type,
+       ;; with data of an assq list with keys of component group names
+       ;; and the articles which correspond to that key/group pair.
+       (while (setq mark (pop type-marks))
+         (setq type (car mark))
+         (setq groups (cdr mark))
+         (while (setq carticles (pop groups))
+           (gnus-add-marked-articles (car carticles) type (cdr carticles) 
+                                     nil t))))
+      
+      ;; possibly update the display, it is really slow
+      (when update-p
+       (setq groups nnvirtual-component-groups)
+       (while groups
+         (gnus-group-update-group (pop groups) t))))))
 
 
 (defun nnvirtual-current-group ()
@@ -730,6 +756,9 @@ based on the marks on the component groups."
 
     ;; Store the reads list for later use.
     (setq nnvirtual-mapping-reads (nreverse reads))
+
+    ;; Throw flag to show we changed the info.
+    (setq nnvirtual-info-installed nil)
     ))
 
 (provide 'nnvirtual)