1 ;;; nnvirtual.el --- virtual newsgroups access for Gnus
2 ;; Copyright (C) 1994,95,96 Free Software Foundation, Inc.
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 ;; The other access methods (nntp, nnspool, etc) are general news
27 ;; access methods. This module relies on Gnus and can not be used
36 (defvar nnvirtual-always-rescan nil
37 "*If non-nil, always scan groups for unread articles when entering a group.
38 If this variable is nil (which is the default) and you read articles
39 in a component group after the virtual group has been activated, the
40 read articles from the component group will show up when you enter the
45 (defconst nnvirtual-version "nnvirtual 1.0"
46 "Version number of this version of nnvirtual.")
48 (defvar nnvirtual-group-alist nil)
49 (defvar nnvirtual-current-group nil)
50 (defvar nnvirtual-component-groups nil)
51 (defvar nnvirtual-mapping nil)
53 (defvar nnvirtual-status-string "")
56 (autoload 'gnus-cache-articles-in-group "gnus-cache"))
60 ;;; Interface functions.
62 (defun nnvirtual-retrieve-headers (articles &optional newsgroup server fetch-old)
63 (when (nnvirtual-possibly-change-group newsgroup server t)
65 (if (stringp (car articles))
67 (let ((map nnvirtual-mapping)
68 (vbuf (nnheader-set-temp-buffer
69 (get-buffer-create " *virtual headers*")))
70 (unfetched (mapcar (lambda (g) (list g))
71 nnvirtual-component-groups))
72 beg cgroup active article result prefix)
74 (setq article (assq (pop articles) nnvirtual-mapping))
75 (setq cgroup (cadr article))
76 (gnus-request-group cgroup t)
77 (setq prefix (gnus-group-real-prefix cgroup))
78 (when (setq result (gnus-retrieve-headers
79 (list (caddr article)) cgroup))
80 (set-buffer nntp-server-buffer)
81 (if (zerop (buffer-size))
82 (nconc (assq cgroup unfetched) (caddr article))
83 ;; If we got HEAD headers, we convert them into NOV
84 ;; headers. This is slow, inefficient and, come to think
85 ;; of it, downright evil. So sue me. I couldn't be
86 ;; bothered to write a header parse routine that could
87 ;; parse a mixed HEAD/NOV buffer.
88 (when (eq result 'headers)
89 (nnvirtual-convert-headers))
90 (goto-char (point-min))
93 (point) (progn (read nntp-server-buffer) (point)))
94 (insert (int-to-string (car article)))
97 "[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t")
98 (goto-char (match-end 0))
100 "\t" (save-excursion (end-of-line) (point)) t)
102 (while (= (char-after (1- (point))) ? )
108 (or (= (char-after (1- (point))) ?\t)
110 (insert (format "Xref: %s %s:%d\t" (system-name)
111 cgroup (caddr article))))
112 (if (not (string= "" prefix))
113 (while (re-search-forward
115 (save-excursion (end-of-line) (point)) t)
117 (goto-char (match-beginning 0))
120 (or (= (char-after (1- (point))) ?\t)
124 (goto-char (point-max))
125 (insert-buffer-substring nntp-server-buffer))))
127 ;; In case some of the articles have expired or been
128 ;; cancelled, we have to mark them as read in the
131 (when (cdar unfetched)
132 (gnus-group-make-articles-read
133 (caar unfetched) (sort (cdar unfetched) '<)))
134 (setq unfetched (cdr unfetched)))
136 ;; The headers are ready for reading, so they are inserted into
137 ;; the nntp-server-buffer, which is where Gnus expects to find
141 (set-buffer nntp-server-buffer)
143 (insert-buffer-substring vbuf)
145 (kill-buffer vbuf)))))))
147 (defun nnvirtual-open-server (server &optional something)
148 (nnheader-init-server-buffer))
150 (defun nnvirtual-close-server (&rest dum)
153 (defun nnvirtual-request-close ()
154 (setq nnvirtual-current-group nil
155 nnvirtual-component-groups nil
156 nnvirtual-mapping nil
157 nnvirtual-group-alist nil)
160 (defun nnvirtual-server-opened (&optional server)
161 (and nntp-server-buffer
162 (get-buffer nntp-server-buffer)))
164 (defun nnvirtual-status-message (&optional server)
165 nnvirtual-status-string)
167 (defun nnvirtual-request-article (article &optional group server buffer)
168 (when (and (nnvirtual-possibly-change-group group server t)
170 (let* ((amap (assq article nnvirtual-mapping))
171 (cgroup (cadr amap)))
174 (nnheader-report 'nnvirtual "No such article: %s" article))
175 ((not (gnus-check-group cgroup))
177 'nnvirtual "Can't open server where %s exists" cgroup))
178 ((not (gnus-request-group cgroup t))
179 (nnheader-report 'nnvirtual "Can't open component group %s" cgroup))
184 (gnus-request-article-this-buffer (caddr amap) cgroup))
185 (gnus-request-article (caddr amap) cgroup)))))))
187 (defun nnvirtual-request-group (group &optional server dont-check)
189 ((null (nnvirtual-possibly-change-group
191 (if nnvirtual-always-rescan nil dont-check)))
192 (setq nnvirtual-current-group nil)
193 (nnheader-report 'nnvirtual "No component groups in %s" group))
195 (let ((len (length nnvirtual-mapping)))