*** empty log message ***
[gnus] / lisp / gnus-srvr.el
1 ;;; gnus-srvr.el --- virtual server support for Gnus
2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Keywords: news
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
23
24 ;;; Commentary:
25
26 ;;; Code:
27
28 (require 'gnus)
29 (eval-when-compile (require 'cl))
30
31 (defvar gnus-server-mode-hook nil
32   "Hook run in `gnus-server-mode' buffers.")
33
34 (defconst gnus-server-line-format "     {%(%h:%w%)} %s\n"
35   "Format of server lines.
36 It works along the same lines as a normal formatting string,
37 with some simple extensions.")
38
39 (defvar gnus-server-mode-line-format "Gnus  List of servers"
40   "The format specification for the server mode line.")
41
42 (defvar gnus-server-exit-hook nil
43   "*Hook run when exiting the server buffer.")
44
45 ;;; Internal variables.
46
47 (defvar gnus-inserted-opened-servers nil)
48
49 (defvar gnus-server-line-format-alist
50   `((?h how ?s)
51     (?n name ?s)
52     (?w where ?s)
53     (?s status ?s)))
54
55 (defvar gnus-server-mode-line-format-alist 
56   `((?S news-server ?s)
57     (?M news-method ?s)
58     (?u user-defined ?s)))
59
60 (defvar gnus-server-line-format-spec nil)
61 (defvar gnus-server-mode-line-format-spec nil)
62 (defvar gnus-server-killed-servers nil)
63
64 (defvar gnus-server-mode-map)
65
66 (defvar gnus-server-menu-hook nil
67   "*Hook run after the creation of the server mode menu.")
68
69 (defun gnus-server-make-menu-bar ()
70   (gnus-visual-turn-off-edit-menu 'server)
71   (or
72    (boundp 'gnus-server-menu)
73    (progn
74      (easy-menu-define
75       gnus-server-menu gnus-server-mode-map ""
76       '("Server"
77         ["Add" gnus-server-add-server t]
78         ["Browse" gnus-server-read-server t]
79         ["List" gnus-server-list-servers t]
80         ["Kill" gnus-server-kill-server t]
81         ["Yank" gnus-server-yank-server t]
82         ["Copy" gnus-server-copy-server t]
83         ["Edit" gnus-server-edit-server t]
84         ["Exit" gnus-server-exit t]
85         ))
86
87      (easy-menu-define
88       gnus-server-menu gnus-server-mode-map ""
89       '("Connections"
90         ["Open" gnus-server-open-server t]
91         ["Close" gnus-server-close-server t]
92         ["Deny" gnus-server-deny-servers t]
93         ["Reset" gnus-server-remove-denials t]
94         ))
95
96      (run-hooks 'gnus-server-menu-hook))))
97
98 (defvar gnus-server-mode-map nil)
99 (put 'gnus-server-mode 'mode-class 'special)
100
101 (unless gnus-server-mode-map
102   (setq gnus-server-mode-map (make-sparse-keymap))
103   (suppress-keymap gnus-server-mode-map)
104
105   (gnus-define-keys
106    gnus-server-mode-map
107    " " gnus-server-read-server
108    "\r" gnus-server-read-server
109    gnus-mouse-2 gnus-server-pick-server
110    "q" gnus-server-exit
111    "l" gnus-server-list-servers
112    "k" gnus-server-kill-server
113    "y" gnus-server-yank-server
114    "c" gnus-server-copy-server
115    "a" gnus-server-add-server
116    "e" gnus-server-edit-server
117
118    "O" gnus-server-open-server
119    "C" gnus-server-close-server
120    "D" gnus-server-deny-server
121    "R" gnus-server-remove-denials))
122
123 (defun gnus-server-mode ()
124   "Major mode for listing and editing servers.
125
126 All normal editing commands are switched off.
127 \\<gnus-server-mode-map>
128 For more in-depth information on this mode, read the manual 
129 (`\\[gnus-info-find-node]'). 
130
131 The following commands are available:
132
133 \\{gnus-server-mode-map}"
134   (interactive)
135   (when (and menu-bar-mode
136              (gnus-visual-p 'server-menu 'menu))
137     (gnus-server-make-menu-bar))
138   (kill-all-local-variables)
139   (gnus-simplify-mode-line)
140   (setq major-mode 'gnus-server-mode)
141   (setq mode-name "Server")
142                                         ;  (gnus-group-set-mode-line)
143   (setq mode-line-process nil)
144   (use-local-map gnus-server-mode-map)
145   (buffer-disable-undo (current-buffer))
146   (setq truncate-lines t)
147   (setq buffer-read-only t)
148   (run-hooks 'gnus-server-mode-hook))
149
150 (defun gnus-server-insert-server-line (name method)
151   (let* ((how (car method))
152          (where (nth 1 method))
153          (elem (assoc method gnus-opened-servers))
154          (status (cond ((eq (nth 1 elem) 'denied)
155                         "(denied)")
156                        ((or (gnus-server-opened method)
157                             (eq (nth 1 elem) 'ok))
158                         "(opened)")
159                        (t
160                         "(closed)"))))
161     (beginning-of-line)
162     (gnus-add-text-properties
163      (point)
164      (prog1 (1+ (point))
165        ;; Insert the text.
166        (eval gnus-server-line-format-spec))
167      (list 'gnus-server (intern name)))))
168
169 (defun gnus-enter-server-buffer ()
170   "Set up the server buffer."
171   (gnus-server-setup-buffer)
172   (gnus-configure-windows 'server)
173   (gnus-server-prepare))
174
175 (defun gnus-server-setup-buffer ()
176   "Initialize the server buffer."
177   (unless (get-buffer gnus-server-buffer)
178     (save-excursion
179       (set-buffer (get-buffer-create gnus-server-buffer))
180       (gnus-server-mode)
181       (when gnus-carpal 
182         (gnus-carpal-setup-buffer 'server)))))
183
184 (defun gnus-server-prepare ()
185   (setq gnus-server-mode-line-format-spec 
186         (gnus-parse-format gnus-server-mode-line-format 
187                            gnus-server-mode-line-format-alist))
188   (setq gnus-server-line-format-spec 
189         (gnus-parse-format gnus-server-line-format 
190                            gnus-server-line-format-alist t))
191   (let ((alist gnus-server-alist)
192         (buffer-read-only nil)
193         (opened gnus-opened-servers)
194         done server op-ser)
195     (erase-buffer)
196     (setq gnus-inserted-opened-servers nil)
197     ;; First we do the real list of servers.
198     (while alist
199       (push (cdr (setq server (pop alist))) done)
200       (when (and server (car server) (cdr server))
201         (gnus-server-insert-server-line (car server) (cdr server))))
202     ;; Then we insert the list of servers that have been opened in
203     ;; this session.
204     (while opened 
205       (unless (member (caar opened) done)
206         (gnus-server-insert-server-line 
207          (setq op-ser (format "%s:%s" (caaar opened) (nth 1 (caar opened))))
208          (caar opened))
209         (push (list op-ser (caar opened)) gnus-inserted-opened-servers))
210       (setq opened (cdr opened))))
211   (goto-char (point-min))
212   (gnus-server-position-point))
213
214 (defun gnus-server-server-name ()
215   (let ((server (get-text-property (gnus-point-at-bol) 'gnus-server)))
216     (and server (symbol-name server))))
217
218 (defalias 'gnus-server-position-point 'gnus-goto-colon)
219
220 (defconst gnus-server-edit-buffer "*Gnus edit server*")
221
222 (defun gnus-server-update-server (server)
223   (save-excursion
224     (set-buffer gnus-server-buffer)
225     (let* ((buffer-read-only nil)
226            (entry (assoc server gnus-server-alist)))
227       (when entry
228         (gnus-dribble-enter 
229          (concat "(gnus-server-set-info \"" server "\" '"
230                  (prin1-to-string (cdr entry)) ")"))
231         ;; Buffer may be narrowed.
232         (save-restriction
233           (widen)
234           (when (gnus-server-goto-server server)
235             (gnus-delete-line))
236           (gnus-server-insert-server-line (car entry) (cdr entry))
237           (gnus-server-position-point))))))
238
239 (defun gnus-server-set-info (server info)
240   ;; Enter a select method into the virtual server alist.
241   (when (and server info)
242     (gnus-dribble-enter 
243      (concat "(gnus-server-set-info \"" server "\" '"
244              (prin1-to-string info) ")"))
245     (let* ((server (nth 1 info))
246            (entry (assoc server gnus-server-alist)))
247       (if entry (setcdr entry info)
248         (setq gnus-server-alist
249               (nconc gnus-server-alist (list (cons server info))))))))
250
251 ;;; Interactive server functions.
252
253 (defun gnus-server-kill-server (server)
254   "Kill the server on the current line."
255   (interactive (list (gnus-server-server-name)))
256   (unless (gnus-server-goto-server server)
257     (if server (error "No such server: %s" server)
258       (error "No server on the current line")))
259   (unless (assoc server gnus-server-alist)
260     (error "Read-only server %s" server))
261   (gnus-dribble-enter "")
262   (let ((buffer-read-only nil))
263     (gnus-delete-line))
264   (setq gnus-server-killed-servers 
265         (cons (assoc server gnus-server-alist) gnus-server-killed-servers))
266   (setq gnus-server-alist (delq (car gnus-server-killed-servers)
267                                 gnus-server-alist))
268   (gnus-server-position-point))
269
270 (defun gnus-server-yank-server ()
271   "Yank the previously killed server."
272   (interactive)
273   (or gnus-server-killed-servers
274       (error "No killed servers to be yanked"))
275   (let ((alist gnus-server-alist)
276         (server (gnus-server-server-name))
277         (killed (car gnus-server-killed-servers)))
278     (if (not server) 
279         (setq gnus-server-alist (nconc gnus-server-alist (list killed)))
280       (if (string= server (caar gnus-server-alist))
281           (setq gnus-server-alist (cons killed gnus-server-alist))
282         (while (and (cdr alist)
283                     (not (string= server (caadr alist))))
284           (setq alist (cdr alist)))
285         (if alist
286             (setcdr alist (cons killed (cdr alist)))
287           (setq gnus-server-alist (list killed)))))
288     (gnus-server-update-server (car killed))
289     (setq gnus-server-killed-servers (cdr gnus-server-killed-servers))
290     (gnus-server-position-point)))
291
292 (defun gnus-server-exit ()
293   "Return to the group buffer."
294   (interactive)
295   (kill-buffer (current-buffer))
296   (switch-to-buffer gnus-group-buffer)
297   (run-hooks 'gnus-server-exit-hook))
298
299 (defun gnus-server-list-servers ()
300   "List all available servers."
301   (interactive)
302   (let ((cur (gnus-server-server-name)))
303     (gnus-server-prepare)
304     (if cur (gnus-server-goto-server cur)
305       (goto-char (point-max))
306       (forward-line -1))
307     (gnus-server-position-point)))
308
309 (defun gnus-opened-servers-remove (method)
310   "Remove METHOD from the list of opened servers."
311   (setq gnus-opened-servers (delq (assoc method gnus-opened-servers)
312                                   gnus-opened-servers)))
313
314 (defun gnus-server-open-server (server)
315   "Force an open of SERVER."
316   (interactive (list (gnus-server-server-name)))
317   (let ((method (gnus-server-to-method server)))
318     (or method (error "No such server: %s" server))
319     (gnus-opened-servers-remove method)
320     (prog1
321         (or (gnus-open-server method)
322             (progn (message "Couldn't open %s" server) nil))
323       (gnus-server-update-server server)
324       (gnus-server-position-point))))
325
326 (defun gnus-server-close-server (server)
327   "Close SERVER."
328   (interactive (list (gnus-server-server-name)))
329   (let ((method (gnus-server-to-method server)))
330     (or method (error "No such server: %s" server))
331     (gnus-opened-servers-remove method)
332     (prog1
333         (gnus-close-server method)
334       (gnus-server-update-server server)
335       (gnus-server-position-point))))
336
337 (defun gnus-server-deny-server (server)
338   "Make sure SERVER will never be attempted opened."
339   (interactive (list (gnus-server-server-name)))
340   (let ((method (gnus-server-to-method server)))
341     (or method (error "No such server: %s" server))
342     (gnus-opened-servers-remove method)
343     (setq gnus-opened-servers
344           (cons (list method 'denied) gnus-opened-servers)))
345   (gnus-server-update-server server)
346   (gnus-server-position-point))
347
348 (defun gnus-server-remove-denials ()
349   "Make all denied servers into closed servers."
350   (interactive)
351   (let ((servers gnus-opened-servers))
352     (while servers
353       (when (eq (nth 1 (car servers)) 'denied)
354         (setcar (nthcdr 1 (car servers)) 'closed))
355       (setq servers (cdr servers))))
356   (gnus-server-list-servers))
357
358 (defun gnus-server-copy-server (from to)
359   (interactive
360    (list
361     (or (gnus-server-server-name)
362         (error "No server on the current line"))
363     (read-string "Copy to: ")))
364   (or from (error "No server on current line"))
365   (or (and to (not (string= to ""))) (error "No name to copy to"))
366   (and (assoc to gnus-server-alist) (error "%s already exists" to))
367   (or (assoc from gnus-server-alist) 
368       (error "%s: no such server" from))
369   (let ((to-entry (gnus-copy-sequence (assoc from gnus-server-alist))))
370     (setcar to-entry to)
371     (setcar (nthcdr 2 to-entry) to)
372     (setq gnus-server-killed-servers 
373           (cons to-entry gnus-server-killed-servers))
374     (gnus-server-yank-server)))
375
376 (defun gnus-server-add-server (how where)
377   (interactive 
378    (list (intern (completing-read "Server method: "
379                                   gnus-valid-select-methods nil t))
380          (read-string "Server name: ")))
381   (setq gnus-server-killed-servers 
382         (cons (list where how where) gnus-server-killed-servers))
383   (gnus-server-yank-server))
384
385 (defun gnus-server-goto-server (server)
386   "Jump to a server line."
387   (interactive
388    (list (completing-read "Goto server: " gnus-server-alist nil t)))
389   (let ((to (text-property-any (point-min) (point-max) 
390                                'gnus-server (intern server))))
391     (and to
392          (progn
393            (goto-char to) 
394            (gnus-server-position-point)))))
395
396 (defun gnus-server-edit-server (server)
397   "Edit the server on the current line."
398   (interactive (list (gnus-server-server-name)))
399   (unless server
400     (error "No server on current line"))
401   (unless (assoc server gnus-server-alist)
402     (error "This server can't be edited"))
403   (let ((winconf (current-window-configuration))
404         (info (cdr (assoc server gnus-server-alist))))
405     (gnus-close-server info)
406     (get-buffer-create gnus-server-edit-buffer)
407     (gnus-configure-windows 'edit-server)
408     (gnus-add-current-to-buffer-list)
409     (emacs-lisp-mode)
410     (make-local-variable 'gnus-prev-winconf)
411     (setq gnus-prev-winconf winconf)
412     (use-local-map (copy-keymap (current-local-map)))
413     (let ((done-func '(lambda () 
414                         "Exit editing mode and update the information."
415                         (interactive)
416                         (gnus-server-edit-server-done 'group))))
417       (setcar (cdr (nth 4 done-func)) server)
418       (local-set-key "\C-c\C-c" done-func))
419     (erase-buffer)
420     (insert ";; Type `C-c C-c' after you have edited the server.\n\n")
421     (insert (pp-to-string info))))
422
423 (defun gnus-server-edit-server-done (server)
424   (interactive)
425   (set-buffer (get-buffer-create gnus-server-edit-buffer))
426   (goto-char (point-min))
427   (let ((form (read (current-buffer)))
428         (winconf gnus-prev-winconf))
429     (gnus-server-set-info server form)
430     (kill-buffer (current-buffer))
431     (and winconf (set-window-configuration winconf))
432     (set-buffer gnus-server-buffer)
433     (gnus-server-update-server server)
434     (gnus-server-list-servers)
435     (gnus-server-position-point)))
436
437 (defun gnus-server-read-server (server)
438   "Browse a server."
439   (interactive (list (gnus-server-server-name)))
440   (let ((buf (current-buffer)))
441     (prog1
442         (gnus-browse-foreign-server (gnus-server-to-method server) buf)
443       (save-excursion
444         (set-buffer buf)
445         (gnus-server-update-server (gnus-server-server-name))
446         (gnus-server-position-point)))))
447     
448 (defun gnus-server-pick-server (e)
449   (interactive "e")
450   (mouse-set-point e)
451   (gnus-server-read-server (gnus-server-server-name)))
452
453 \f
454 ;;;
455 ;;; Browse Server Mode
456 ;;;
457
458 (defvar gnus-browse-menu-hook nil
459   "*Hook run after the creation of the browse mode menu.")
460
461 (defvar gnus-browse-mode-hook nil)
462 (defvar gnus-browse-mode-map nil)
463 (put 'gnus-browse-mode 'mode-class 'special)
464
465 (unless gnus-browse-mode-map
466   (setq gnus-browse-mode-map (make-keymap))
467   (suppress-keymap gnus-browse-mode-map)
468
469   (gnus-define-keys
470    gnus-browse-mode-map
471    " " gnus-browse-read-group
472    "=" gnus-browse-select-group
473    "n" gnus-browse-next-group
474    "p" gnus-browse-prev-group
475    "\177" gnus-browse-prev-group
476    "N" gnus-browse-next-group
477    "P" gnus-browse-prev-group
478    "\M-n" gnus-browse-next-group
479    "\M-p" gnus-browse-prev-group
480    "\r" gnus-browse-select-group
481    "u" gnus-browse-unsubscribe-current-group
482    "l" gnus-browse-exit
483    "L" gnus-browse-exit
484    "q" gnus-browse-exit
485    "Q" gnus-browse-exit
486    "\C-c\C-c" gnus-browse-exit
487    "?" gnus-browse-describe-briefly
488    "\C-c\C-i" gnus-info-find-node))
489
490 (defun gnus-browse-make-menu-bar ()
491   (gnus-visual-turn-off-edit-menu 'browse)
492   (or
493    (boundp 'gnus-browse-menu)
494    (progn
495      (easy-menu-define
496       gnus-browse-menu gnus-browse-mode-map ""
497       '("Browse"
498         ["Subscribe" gnus-browse-unsubscribe-current-group t]
499         ["Read" gnus-browse-read-group t]
500         ["Select" gnus-browse-read-group t]
501         ["Next" gnus-browse-next-group t]
502         ["Prev" gnus-browse-next-group t]
503         ["Exit" gnus-browse-exit t]
504         ))
505       (run-hooks 'gnus-browse-menu-hook))))
506
507 (defvar gnus-browse-current-method nil)
508 (defvar gnus-browse-return-buffer nil)
509
510 (defvar gnus-browse-buffer "*Gnus Browse Server*")
511
512 (defun gnus-browse-foreign-server (method &optional return-buffer)
513   "Browse the server METHOD."
514   (setq gnus-browse-current-method method)
515   (setq gnus-browse-return-buffer return-buffer)
516   (let ((gnus-select-method method)
517         groups group)
518     (gnus-message 5 "Connecting to %s..." (nth 1 method))
519     (cond
520      ((not (gnus-check-server method))
521       (gnus-message
522        1 "Unable to contact server: %s" (gnus-status-message method))
523       nil)
524      ((not (gnus-request-list method))
525       (gnus-message
526        1 "Couldn't request list: %s" (gnus-status-message method))
527       nil)
528      (t
529       (get-buffer-create gnus-browse-buffer)
530       (gnus-add-current-to-buffer-list)
531       (and gnus-carpal (gnus-carpal-setup-buffer 'browse))
532       (gnus-configure-windows 'browse)
533       (buffer-disable-undo (current-buffer))
534       (let ((buffer-read-only nil))
535         (erase-buffer))
536       (gnus-browse-mode)
537       (setq mode-line-buffer-identification
538             (list
539              (format
540               "Gnus: %%b {%s:%s}" (car method) (cadr method))))
541       (save-excursion
542         (set-buffer nntp-server-buffer)
543         (let ((cur (current-buffer)))
544           (goto-char (point-min))
545           (or (string= gnus-ignored-newsgroups "")
546               (delete-matching-lines gnus-ignored-newsgroups))
547           (while (re-search-forward
548                   "\\(^[^ \t]+\\)[ \t]+[0-9]+[ \t]+[0-9]+" nil t)
549             (goto-char (match-end 1))
550             (setq groups (cons (cons (match-string 1)
551                                      (max 0 (- (1+ (read cur)) (read cur))))
552                                groups)))))
553       (setq groups (sort groups
554                          (lambda (l1 l2)
555                            (string< (car l1) (car l2)))))
556       (let ((buffer-read-only nil))
557         (while groups
558           (setq group (car groups))
559           (insert
560            (format "K%7d: %s\n" (cdr group) (car group)))
561           (setq groups (cdr groups))))
562       (switch-to-buffer (current-buffer))
563       (goto-char (point-min))
564       (gnus-group-position-point)
565       (gnus-message 5 "Connecting to %s...done" (nth 1 method))
566       t))))
567
568 (defun gnus-browse-mode ()
569   "Major mode for browsing a foreign server.
570
571 All normal editing commands are switched off.
572
573 \\<gnus-browse-mode-map>
574 The only things you can do in this buffer is
575
576 1) `\\[gnus-browse-unsubscribe-current-group]' to subscribe to a group.
577 The group will be inserted into the group buffer upon exit from this
578 buffer.
579
580 2) `\\[gnus-browse-read-group]' to read a group ephemerally.
581
582 3) `\\[gnus-browse-exit]' to return to the group buffer."
583   (interactive)
584   (kill-all-local-variables)
585   (when (and menu-bar-mode
586              (gnus-visual-p 'browse-menu 'menu))
587     (gnus-browse-make-menu-bar))
588   (gnus-simplify-mode-line)
589   (setq major-mode 'gnus-browse-mode)
590   (setq mode-name "Browse Server")
591   (setq mode-line-process nil)
592   (use-local-map gnus-browse-mode-map)
593   (buffer-disable-undo (current-buffer))
594   (setq truncate-lines t)
595   (setq buffer-read-only t)
596   (run-hooks 'gnus-browse-mode-hook))
597
598 (defun gnus-browse-read-group (&optional no-article)
599   "Enter the group at the current line."
600   (interactive)
601   (let ((group (gnus-browse-group-name)))
602     (or (gnus-group-read-ephemeral-group
603          group gnus-browse-current-method nil
604          (cons (current-buffer) 'browse))
605         (error "Couldn't enter %s" group))))
606
607 (defun gnus-browse-select-group ()
608   "Select the current group."
609   (interactive)
610   (gnus-browse-read-group 'no))
611
612 (defun gnus-browse-next-group (n)
613   "Go to the next group."
614   (interactive "p")
615   (prog1
616       (forward-line n)
617     (gnus-group-position-point)))
618
619 (defun gnus-browse-prev-group (n)
620   "Go to the next group."
621   (interactive "p")
622   (gnus-browse-next-group (- n)))
623
624 (defun gnus-browse-unsubscribe-current-group (arg)
625   "(Un)subscribe to the next ARG groups."
626   (interactive "p")
627   (when (eobp)
628     (error "No group at current line."))
629   (let ((ward (if (< arg 0) -1 1))
630         (arg (abs arg)))
631     (while (and (> arg 0)
632                 (not (eobp))
633                 (gnus-browse-unsubscribe-group)
634                 (zerop (gnus-browse-next-group ward)))
635       (decf arg))
636     (gnus-group-position-point)
637     (if (/= 0 arg) (gnus-message 7 "No more newsgroups"))
638     arg))
639
640 (defun gnus-browse-group-name ()
641   (save-excursion
642     (beginning-of-line)
643     (when (re-search-forward ": \\(.*\\)$" (gnus-point-at-eol) t)
644       (gnus-group-prefixed-name (match-string 1) gnus-browse-current-method))))
645
646 (defun gnus-browse-unsubscribe-group ()
647   "Toggle subscription of the current group in the browse buffer."
648   (let ((sub nil)
649         (buffer-read-only nil)
650         group)
651     (save-excursion
652       (beginning-of-line)
653       ;; If this group it killed, then we want to subscribe it.
654       (if (= (following-char) ?K) (setq sub t))
655       (setq group (gnus-browse-group-name))
656       (delete-char 1)
657       (if sub
658           (progn
659             (gnus-group-change-level
660              (list t group gnus-level-default-subscribed
661                    nil nil gnus-browse-current-method)
662              gnus-level-default-subscribed gnus-level-killed
663              (and (car (nth 1 gnus-newsrc-alist))
664                   (gnus-gethash (car (nth 1 gnus-newsrc-alist))
665                                 gnus-newsrc-hashtb))
666              t)
667             (insert ? ))
668         (gnus-group-change-level
669          group gnus-level-killed gnus-level-default-subscribed)
670         (insert ?K)))
671     t))
672
673 (defun gnus-browse-exit ()
674   "Quit browsing and return to the group buffer."
675   (interactive)
676   (when (eq major-mode 'gnus-browse-mode)
677     (kill-buffer (current-buffer)))
678   ;; Insert the newly subscribed groups in the group buffer.
679   (save-excursion
680     (set-buffer gnus-group-buffer)
681     (gnus-group-list-groups nil))
682   (if gnus-browse-return-buffer
683       (gnus-configure-windows 'server 'force)
684     (gnus-configure-windows 'group 'force)))
685
686 (defun gnus-browse-describe-briefly ()
687   "Give a one line description of the group mode commands."
688   (interactive)
689   (gnus-message 6
690                 (substitute-command-keys "\\<gnus-browse-mode-map>\\[gnus-group-next-group]:Forward  \\[gnus-group-prev-group]:Backward  \\[gnus-browse-exit]:Exit  \\[gnus-info-find-node]:Run Info  \\[gnus-browse-describe-briefly]:This help")))
691
692 (provide 'gnus-srvr)
693
694 ;;; gnus-srvr.el ends here.