;;; 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>
(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
(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)
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))
(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)
(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))
(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))
(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 ()
;; 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)