(gnus-version-number): for version number for Open gnus.
[elisp/gnus.git-] / lisp / gnus.el
1 ;;; gnus.el --- a newsreader for GNU Emacs
2 ;; Copyright (C) 1987,88,89,90,93,94,95,96,97 Free Software Foundation, Inc.
3
4 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
5 ;;      Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
6 ;; Keywords: news, mail
7
8 ;; This file is part of GNU Emacs.
9
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)
13 ;; any later version.
14
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.
19
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 the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 (eval '(run-hooks 'gnus-load-hook))
30
31 (eval-when-compile (require 'cl))
32
33 (require 'custom)
34 (require 'gnus-load)
35 (require 'message)
36
37 (defgroup gnus nil
38   "The coffee-brewing, all singing, all dancing, kitchen sink newsreader."
39   :group 'news
40   :group 'mail)
41
42 (defgroup gnus-start nil
43   "Starting your favorite newsreader."
44   :group 'gnus)
45
46 (defgroup gnus-start-server nil
47   "Server options at startup."
48   :group 'gnus-start)
49
50 ;; These belong to gnus-group.el.
51 (defgroup gnus-group nil
52   "Group buffers."
53   :link '(custom-manual "(gnus)The Group Buffer")
54   :group 'gnus)
55
56 (defgroup gnus-group-foreign nil
57   "Foreign groups."
58   :link '(custom-manual "(gnus)Foreign Groups")
59   :group 'gnus-group)
60
61 (defgroup gnus-group-new nil
62   "Automatic subscription of new groups."
63   :group 'gnus-group)
64
65 (defgroup gnus-group-levels nil
66   "Group levels."
67   :link '(custom-manual "(gnus)Group Levels")
68   :group 'gnus-group)
69
70 (defgroup gnus-group-select nil
71   "Selecting a Group."
72   :link '(custom-manual "(gnus)Selecting a Group")
73   :group 'gnus-group)
74
75 (defgroup gnus-group-listing nil
76   "Showing slices of the group list."
77   :link '(custom-manual "(gnus)Listing Groups")
78   :group 'gnus-group)
79
80 (defgroup gnus-group-visual nil
81   "Sorting the group buffer."
82   :link '(custom-manual "(gnus)Group Buffer Format")
83   :group 'gnus-group
84   :group 'gnus-visual)
85
86 (defgroup gnus-group-various nil
87   "Various group options."
88   :link '(custom-manual "(gnus)Scanning New Messages")
89   :group 'gnus-group)
90
91 ;; These belong to gnus-sum.el.
92 (defgroup gnus-summary nil
93   "Summary buffers."
94   :link '(custom-manual "(gnus)The Summary Buffer")
95   :group 'gnus)
96
97 (defgroup gnus-summary-exit nil
98   "Leaving summary buffers."
99   :link '(custom-manual "(gnus)Exiting the Summary Buffer")
100   :group 'gnus-summary)
101
102 (defgroup gnus-summary-marks nil
103   "Marks used in summary buffers."
104   :link '(custom-manual "(gnus)Marking Articles")
105   :group 'gnus-summary)
106
107 (defgroup gnus-thread nil
108   "Ordering articles according to replies."
109   :link '(custom-manual "(gnus)Threading")
110   :group 'gnus-summary)
111
112 (defgroup gnus-summary-format nil
113   "Formatting of the summary buffer."
114   :link '(custom-manual "(gnus)Summary Buffer Format")
115   :group 'gnus-summary)
116
117 (defgroup gnus-summary-choose nil
118   "Choosing Articles."
119   :link '(custom-manual "(gnus)Choosing Articles")
120   :group 'gnus-summary)
121
122 (defgroup gnus-summary-maneuvering nil
123   "Summary movement commands."
124   :link '(custom-manual "(gnus)Summary Maneuvering")
125   :group 'gnus-summary)
126
127 (defgroup gnus-summary-mail nil
128   "Mail group commands."
129   :link '(custom-manual "(gnus)Mail Group Commands")
130   :group 'gnus-summary)
131
132 (defgroup gnus-summary-sort nil
133   "Sorting the summary buffer."
134   :link '(custom-manual "(gnus)Sorting")
135   :group 'gnus-summary)
136
137 (defgroup gnus-summary-visual nil
138   "Highlighting and menus in the summary buffer."
139   :link '(custom-manual "(gnus)Summary Highlighting")
140   :group 'gnus-visual
141   :group 'gnus-summary)
142
143 (defgroup gnus-summary-various nil
144   "Various summary buffer options."
145   :link '(custom-manual "(gnus)Various Summary Stuff")
146   :group 'gnus-summary)
147
148 (defgroup gnus-summary-pick nil
149   "Pick mode in the summary buffer."
150   :link '(custom-manual "(gnus)Pick and Read")
151   :prefix "gnus-pick-"
152   :group 'gnus-summary)
153
154 (defgroup gnus-summary-tree nil
155   "Tree display of threads in the summary buffer."
156   :link '(custom-manual "(gnus)Tree Display")
157   :prefix "gnus-tree-"
158   :group 'gnus-summary)
159
160 ;; Belongs to gnus-uu.el
161 (defgroup gnus-extract-view nil
162   "Viewing extracted files."
163   :link '(custom-manual "(gnus)Viewing Files")
164   :group 'gnus-extract)
165
166 ;; Belongs to gnus-score.el
167 (defgroup gnus-score nil
168   "Score and kill file handling."
169   :group 'gnus)
170
171 (defgroup gnus-score-kill nil
172   "Kill files."
173   :group 'gnus-score)
174
175 (defgroup gnus-score-adapt nil
176   "Adaptive score files."
177   :group 'gnus-score)
178
179 (defgroup gnus-score-default nil
180   "Default values for score files."
181   :group 'gnus-score)
182
183 (defgroup gnus-score-expire nil
184   "Expiring score rules."
185   :group 'gnus-score)
186
187 (defgroup gnus-score-decay nil
188   "Decaying score rules."
189   :group 'gnus-score)
190
191 (defgroup gnus-score-files nil
192   "Score and kill file names."
193   :group 'gnus-score
194   :group 'gnus-files)
195
196 (defgroup gnus-score-various nil
197   "Various scoring and killing options."
198   :group 'gnus-score)
199
200 ;; Other
201 (defgroup gnus-visual nil
202   "Options controling the visual fluff."
203   :group 'gnus
204   :group 'faces)
205
206 (defgroup gnus-agent nil
207   "Offline support for Gnus."
208   :group 'gnus)
209
210 (defgroup gnus-files nil
211   "Files used by Gnus."
212   :group 'gnus)
213
214 (defgroup gnus-dribble-file nil
215   "Auto save file."
216   :link '(custom-manual "(gnus)Auto Save")
217   :group 'gnus-files)
218
219 (defgroup gnus-newsrc nil
220   "Storing Gnus state."
221   :group 'gnus-files)
222
223 (defgroup gnus-server nil
224   "Options related to newsservers and other servers used by Gnus."
225   :group 'gnus)
226
227 (defgroup gnus-message '((message custom-group))
228   "Composing replies and followups in Gnus."
229   :group 'gnus)
230
231 (defgroup gnus-meta nil
232   "Meta variables controling major portions of Gnus.
233 In general, modifying these variables does not take affect until Gnus
234 is restarted, and sometimes reloaded."
235   :group 'gnus)
236
237 (defgroup gnus-various nil
238   "Other Gnus options."
239   :link '(custom-manual "(gnus)Various Various")
240   :group 'gnus)
241
242 (defgroup gnus-exit nil
243   "Exiting gnus."
244   :link '(custom-manual "(gnus)Exiting Gnus")
245   :group 'gnus)
246
247 (defconst gnus-version-number "6.0.0"
248   "Version number for this version of gnus.")
249
250 (defconst gnus-version
251   (format "Open gnus %s (based on Quassia v0.16)" gnus-version-number)
252   "Version string for this version of gnus.")
253
254 (defcustom gnus-inhibit-startup-message nil
255   "If non-nil, the startup message will not be displayed.
256 This variable is used before `.gnus.el' is loaded, so it should
257 be set in `.emacs' instead."
258   :group 'gnus-start
259   :type 'boolean)
260
261 (defcustom gnus-play-startup-jingle nil
262   "If non-nil, play the Gnus jingle at startup."
263   :group 'gnus-start
264   :type 'boolean)
265
266 ;;; Kludges to help the transition from the old `custom.el'.
267
268 (unless (featurep 'gnus-xmas)
269   (defalias 'gnus-make-overlay 'make-overlay)
270   (defalias 'gnus-delete-overlay 'delete-overlay)
271   (defalias 'gnus-overlay-put 'overlay-put)
272   (defalias 'gnus-move-overlay 'move-overlay)
273   (defalias 'gnus-overlay-end 'overlay-end)
274   (defalias 'gnus-extent-detached-p 'ignore)
275   (defalias 'gnus-extent-start-open 'ignore)
276   (defalias 'gnus-set-text-properties 'set-text-properties)
277   (defalias 'gnus-group-remove-excess-properties 'ignore)
278   (defalias 'gnus-appt-select-lowest-window 'appt-select-lowest-window)
279   (defalias 'gnus-mail-strip-quoted-names 'mail-strip-quoted-names)
280   (defalias 'gnus-character-to-event 'identity)
281   (defalias 'gnus-add-text-properties 'add-text-properties)
282   (defalias 'gnus-put-text-property 'put-text-property)
283   (defalias 'gnus-mode-line-buffer-identification 'identity)
284   (defalias 'gnus-characterp 'numberp)
285   (defalias 'gnus-deactivate-mark 'deactivate-mark)
286   (defalias 'gnus-window-edges 'window-edges)
287   (defalias 'gnus-key-press-event-p 'numberp))
288
289 ;; We define these group faces here to avoid the display
290 ;; update forced when creating new faces.
291
292 (defface gnus-group-news-1-face
293   '((((class color)
294       (background dark))
295      (:foreground "PaleTurquoise" :bold t))
296     (((class color)
297       (background light))
298      (:foreground "ForestGreen" :bold t))
299     (t
300      ()))
301   "Level 1 newsgroup face.")
302
303 (defface gnus-group-news-1-empty-face
304   '((((class color)
305       (background dark))
306      (:foreground "PaleTurquoise"))
307     (((class color)
308       (background light))
309      (:foreground "ForestGreen"))
310     (t
311      ()))
312   "Level 1 empty newsgroup face.")
313
314 (defface gnus-group-news-2-face
315   '((((class color)
316       (background dark))
317      (:foreground "turquoise" :bold t))
318     (((class color)
319       (background light))
320      (:foreground "CadetBlue4" :bold t))
321     (t
322      ()))
323   "Level 2 newsgroup face.")
324
325 (defface gnus-group-news-2-empty-face
326   '((((class color)
327       (background dark))
328      (:foreground "turquoise"))
329     (((class color)
330       (background light))
331      (:foreground "CadetBlue4"))
332     (t
333      ()))
334   "Level 2 empty newsgroup face.")
335
336 (defface gnus-group-news-3-face
337   '((((class color)
338       (background dark))
339      (:bold t))
340     (((class color)
341       (background light))
342      (:bold t))
343     (t
344      ()))
345   "Level 3 newsgroup face.")
346
347 (defface gnus-group-news-3-empty-face
348   '((((class color)
349       (background dark))
350      ())
351     (((class color)
352       (background light))
353      ())
354     (t
355      ()))
356   "Level 3 empty newsgroup face.")
357
358 (defface gnus-group-news-low-face
359   '((((class color)
360       (background dark))
361      (:foreground "DarkTurquoise" :bold t))
362     (((class color)
363       (background light))
364      (:foreground "DarkGreen" :bold t))
365     (t
366      ()))
367   "Low level newsgroup face.")
368
369 (defface gnus-group-news-low-empty-face
370   '((((class color)
371       (background dark))
372      (:foreground "DarkTurquoise"))
373     (((class color)
374       (background light))
375      (:foreground "DarkGreen"))
376     (t
377      ()))
378   "Low level empty newsgroup face.")
379
380 (defface gnus-group-mail-1-face
381   '((((class color)
382       (background dark))
383      (:foreground "aquamarine1" :bold t))
384     (((class color)
385       (background light))
386      (:foreground "DeepPink3" :bold t))
387     (t
388      (:bold t)))
389   "Level 1 mailgroup face.")
390
391 (defface gnus-group-mail-1-empty-face
392   '((((class color)
393       (background dark))
394      (:foreground "aquamarine1"))
395     (((class color)
396       (background light))
397      (:foreground "DeepPink3"))
398     (t
399      (:italic t :bold t)))
400   "Level 1 empty mailgroup face.")
401
402 (defface gnus-group-mail-2-face
403   '((((class color)
404       (background dark))
405      (:foreground "aquamarine2" :bold t))
406     (((class color)
407       (background light))
408      (:foreground "HotPink3" :bold t))
409     (t
410      (:bold t)))
411   "Level 2 mailgroup face.")
412
413 (defface gnus-group-mail-2-empty-face
414   '((((class color)
415       (background dark))
416      (:foreground "aquamarine2"))
417     (((class color)
418       (background light))
419      (:foreground "HotPink3"))
420     (t
421      (:bold t)))
422   "Level 2 empty mailgroup face.")
423
424 (defface gnus-group-mail-3-face
425   '((((class color)
426       (background dark))
427      (:foreground "aquamarine3" :bold t))
428     (((class color)
429       (background light))
430      (:foreground "magenta4" :bold t))
431     (t
432      (:bold t)))
433   "Level 3 mailgroup face.")
434
435 (defface gnus-group-mail-3-empty-face
436   '((((class color)
437       (background dark))
438      (:foreground "aquamarine3"))
439     (((class color)
440       (background light))
441      (:foreground "magenta4"))
442     (t
443      ()))
444   "Level 3 empty mailgroup face.")
445
446 (defface gnus-group-mail-low-face
447   '((((class color)
448       (background dark))
449      (:foreground "aquamarine4" :bold t))
450     (((class color)
451       (background light))
452      (:foreground "DeepPink4" :bold t))
453     (t
454      (:bold t)))
455   "Low level mailgroup face.")
456
457 (defface gnus-group-mail-low-empty-face
458   '((((class color)
459       (background dark))
460      (:foreground "aquamarine4"))
461     (((class color)
462       (background light))
463      (:foreground "DeepPink4"))
464     (t
465      (:bold t)))
466   "Low level empty mailgroup face.")
467
468 ;; Summary mode faces.
469
470 (defface gnus-summary-selected-face '((t
471                                        (:underline t)))
472   "Face used for selected articles.")
473
474 (defface gnus-summary-cancelled-face
475   '((((class color))
476      (:foreground "yellow" :background "black")))
477   "Face used for cancelled articles.")
478
479 (defface gnus-summary-high-ticked-face
480   '((((class color)
481       (background dark))
482      (:foreground "pink" :bold t))
483     (((class color)
484       (background light))
485      (:foreground "firebrick" :bold t))
486     (t
487      (:bold t)))
488   "Face used for high interest ticked articles.")
489
490 (defface gnus-summary-low-ticked-face
491   '((((class color)
492       (background dark))
493      (:foreground "pink" :italic t))
494     (((class color)
495       (background light))
496      (:foreground "firebrick" :italic t))
497     (t
498      (:italic t)))
499   "Face used for low interest ticked articles.")
500
501 (defface gnus-summary-normal-ticked-face
502   '((((class color)
503       (background dark))
504      (:foreground "pink"))
505     (((class color)
506       (background light))
507      (:foreground "firebrick"))
508     (t
509      ()))
510   "Face used for normal interest ticked articles.")
511
512 (defface gnus-summary-high-ancient-face
513   '((((class color)
514       (background dark))
515      (:foreground "SkyBlue" :bold t))
516     (((class color)
517       (background light))
518      (:foreground "RoyalBlue" :bold t))
519     (t
520      (:bold t)))
521   "Face used for high interest ancient articles.")
522
523 (defface gnus-summary-low-ancient-face
524   '((((class color)
525       (background dark))
526      (:foreground "SkyBlue" :italic t))
527     (((class color)
528       (background light))
529      (:foreground "RoyalBlue" :italic t))
530     (t
531      (:italic t)))
532   "Face used for low interest ancient articles.")
533
534 (defface gnus-summary-normal-ancient-face
535   '((((class color)
536       (background dark))
537      (:foreground "SkyBlue"))
538     (((class color)
539       (background light))
540      (:foreground "RoyalBlue"))
541     (t
542      ()))
543   "Face used for normal interest ancient articles.")
544
545 (defface gnus-summary-high-unread-face
546   '((t
547      (:bold t)))
548   "Face used for high interest unread articles.")
549
550 (defface gnus-summary-low-unread-face
551   '((t
552      (:italic t)))
553   "Face used for low interest unread articles.")
554
555 (defface gnus-summary-normal-unread-face
556   '((t
557      ()))
558   "Face used for normal interest unread articles.")
559
560 (defface gnus-summary-high-read-face
561   '((((class color)
562       (background dark))
563      (:foreground "PaleGreen"
564                   :bold t))
565     (((class color)
566       (background light))
567      (:foreground "DarkGreen"
568                   :bold t))
569     (t
570      (:bold t)))
571   "Face used for high interest read articles.")
572
573 (defface gnus-summary-low-read-face
574   '((((class color)
575       (background dark))
576      (:foreground "PaleGreen"
577                   :italic t))
578     (((class color)
579       (background light))
580      (:foreground "DarkGreen"
581                   :italic t))
582     (t
583      (:italic t)))
584   "Face used for low interest read articles.")
585
586 (defface gnus-summary-normal-read-face
587   '((((class color)
588       (background dark))
589      (:foreground "PaleGreen"))
590     (((class color)
591       (background light))
592      (:foreground "DarkGreen"))
593     (t
594      ()))
595   "Face used for normal interest read articles.")
596
597
598 ;;; Splash screen.
599
600 (defvar gnus-group-buffer "*Group*")
601
602 (eval-and-compile
603   (autoload 'gnus-play-jingle "gnus-audio"))
604
605 (defface gnus-splash-face
606   '((((class color)
607       (background dark))
608      (:foreground "ForestGreen"))
609     (((class color)
610       (background light))
611      (:foreground "ForestGreen"))
612     (t
613      ()))
614   "Level 1 newsgroup face.")
615
616 (defun gnus-splash ()
617   (save-excursion
618     (switch-to-buffer (get-buffer-create gnus-group-buffer))
619     (let ((buffer-read-only nil))
620       (erase-buffer)
621       (unless gnus-inhibit-startup-message
622         (gnus-group-startup-message)
623         (sit-for 0)
624         (when gnus-play-startup-jingle
625           (gnus-play-jingle))))))
626
627 (defun gnus-indent-rigidly (start end arg)
628   "Indent rigidly using only spaces and no tabs."
629   (save-excursion
630     (save-restriction
631       (narrow-to-region start end)
632       (let ((tab-width 8))
633         (indent-rigidly start end arg)
634         ;; We translate tabs into spaces -- not everybody uses
635         ;; an 8-character tab.
636         (goto-char (point-min))
637         (while (search-forward "\t" nil t)
638           (replace-match "        " t t))))))
639
640 (defvar gnus-simple-splash nil)
641
642 (defun gnus-group-startup-message (&optional x y)
643   "Insert startup message in current buffer."
644   ;; Insert the message.
645   (erase-buffer)
646   (insert
647    (format "              %s
648           _    ___ _             _
649           _ ___ __ ___  __    _ ___
650           __   _     ___    __  ___
651               _           ___     _
652              _  _ __             _
653              ___   __            _
654                    __           _
655                     _      _   _
656                    _      _    _
657                       _  _    _
658                   __  ___
659                  _   _ _     _
660                 _   _
661               _    _
662              _    _
663             _
664           __
665
666 "
667            ""))
668   ;; And then hack it.
669   (gnus-indent-rigidly (point-min) (point-max)
670                        (/ (max (- (window-width) (or x 46)) 0) 2))
671   (goto-char (point-min))
672   (forward-line 1)
673   (let* ((pheight (count-lines (point-min) (point-max)))
674          (wheight (window-height))
675          (rest (- wheight pheight)))
676     (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
677   ;; Fontify some.
678   (put-text-property (point-min) (point-max) 'face 'gnus-splash-face)
679   (goto-char (point-min))
680   (setq mode-line-buffer-identification (concat " " gnus-version))
681   (setq gnus-simple-splash t)
682   (set-buffer-modified-p t))
683
684 (eval-when (load)
685   (let ((command (format "%s" this-command)))
686     (when (and (string-match "gnus" command)
687                (not (string-match "gnus-other-frame" command)))
688       (gnus-splash))))
689
690 ;;; Do the rest.
691
692 (require 'custom)
693 (require 'gnus-util)
694 (require 'nnheader)
695
696 (defcustom gnus-home-directory "~/"
697   "Directory variable that specifies the \"home\" directory.
698 All other Gnus path variables are initialized from this variable."
699   :group 'gnus-files
700   :type 'directory)
701
702 (defcustom gnus-directory (or (getenv "SAVEDIR")
703                               (nnheader-concat gnus-home-directory "News/"))
704   "Directory variable from which all other Gnus file variables are derived."
705   :group 'gnus-files
706   :type 'directory)
707
708 (defcustom gnus-default-directory nil
709   "*Default directory for all Gnus buffers."
710   :group 'gnus-files
711   :type '(choice (const :tag "current" nil)
712                  directory))
713
714 ;; Site dependent variables.  These variables should be defined in
715 ;; paths.el.
716
717 (defvar gnus-default-nntp-server nil
718   "Specify a default NNTP server.
719 This variable should be defined in paths.el, and should never be set
720 by the user.
721 If you want to change servers, you should use `gnus-select-method'.
722 See the documentation to that variable.")
723
724 ;; Don't touch this variable.
725 (defvar gnus-nntp-service "nntp"
726   "NNTP service name (\"nntp\" or 119).
727 This is an obsolete variable, which is scarcely used.  If you use an
728 nntp server for your newsgroup and want to change the port number
729 used to 899, you would say something along these lines:
730
731  (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
732
733 (defcustom gnus-nntpserver-file "/etc/nntpserver"
734   "A file with only the name of the nntp server in it."
735   :group 'gnus-files
736   :group 'gnus-server
737   :type 'file)
738
739 ;; This function is used to check both the environment variable
740 ;; NNTPSERVER and the /etc/nntpserver file to see whether one can find
741 ;; an nntp server name default.
742 (defun gnus-getenv-nntpserver ()
743   (or (getenv "NNTPSERVER")
744       (and (file-readable-p gnus-nntpserver-file)
745            (save-excursion
746              (set-buffer (get-buffer-create " *gnus nntp*"))
747              (buffer-disable-undo (current-buffer))
748              (insert-file-contents gnus-nntpserver-file)
749              (let ((name (buffer-string)))
750                (prog1
751                    (if (string-match "^[ \t\n]*$" name)
752                        nil
753                      name)
754                  (kill-buffer (current-buffer))))))))
755
756 (defcustom gnus-select-method
757   (condition-case nil
758     (nconc
759      (list 'nntp (or (condition-case nil
760                          (gnus-getenv-nntpserver)
761                        (error nil))
762                      (when (and gnus-default-nntp-server
763                                 (not (string= gnus-default-nntp-server "")))
764                        gnus-default-nntp-server)
765                      "news"))
766      (if (or (null gnus-nntp-service)
767              (equal gnus-nntp-service "nntp"))
768          nil
769        (list gnus-nntp-service)))
770     (error nil))
771   "Default method for selecting a newsgroup.
772 This variable should be a list, where the first element is how the
773 news is to be fetched, the second is the address.
774
775 For instance, if you want to get your news via NNTP from
776 \"flab.flab.edu\", you could say:
777
778 \(setq gnus-select-method '(nntp \"flab.flab.edu\"))
779
780 If you want to use your local spool, say:
781
782 \(setq gnus-select-method (list 'nnspool (system-name)))
783
784 If you use this variable, you must set `gnus-nntp-server' to nil.
785
786 There is a lot more to know about select methods and virtual servers -
787 see the manual for details."
788   :group 'gnus-server
789   :type 'gnus-select-method)
790
791 (defcustom gnus-message-archive-method
792   `(nnfolder
793     "archive"
794     (nnfolder-directory ,(nnheader-concat message-directory "archive"))
795     (nnfolder-active-file
796      ,(nnheader-concat message-directory "archive/active"))
797     (nnfolder-get-new-mail nil)
798     (nnfolder-inhibit-expiry t))
799   "Method used for archiving messages you've sent.
800 This should be a mail method.
801
802 It's probably not a very effective to change this variable once you've
803 run Gnus once.  After doing that, you must edit this server from the
804 server buffer."
805   :group 'gnus-server
806   :group 'gnus-message
807   :type 'gnus-select-method)
808
809 (defcustom gnus-message-archive-group nil
810   "*Name of the group in which to save the messages you've written.
811 This can either be a string; a list of strings; or an alist
812 of regexps/functions/forms to be evaluated to return a string (or a list
813 of strings).  The functions are called with the name of the current
814 group (or nil) as a parameter.
815
816 If you want to save your mail in one group and the news articles you
817 write in another group, you could say something like:
818
819  \(setq gnus-message-archive-group
820         '((if (message-news-p)
821               \"misc-news\"
822             \"misc-mail\")))
823
824 Normally the group names returned by this variable should be
825 unprefixed -- which implicitly means \"store on the archive server\".
826 However, you may wish to store the message on some other server.  In
827 that case, just return a fully prefixed name of the group --
828 \"nnml+private:mail.misc\", for instance."
829   :group 'gnus-message
830   :type '(choice (const :tag "none" nil)
831                  string))
832
833 (defcustom gnus-secondary-servers nil
834   "List of NNTP servers that the user can choose between interactively.
835 To make Gnus query you for a server, you have to give `gnus' a
836 non-numeric prefix - `C-u M-x gnus', in short."
837   :group 'gnus-server
838   :type '(repeat string))
839
840 (defcustom gnus-nntp-server nil
841   "*The name of the host running the NNTP server.
842 This variable is semi-obsolete.  Use the `gnus-select-method'
843 variable instead."
844   :group 'gnus-server
845   :type '(choice (const :tag "disable" nil)
846                  string))
847
848 (defcustom gnus-secondary-select-methods nil
849   "A list of secondary methods that will be used for reading news.
850 This is a list where each element is a complete select method (see
851 `gnus-select-method').
852
853 If, for instance, you want to read your mail with the nnml backend,
854 you could set this variable:
855
856 \(setq gnus-secondary-select-methods '((nnml \"\")))"
857 :group 'gnus-server
858 :type '(repeat gnus-select-method))
859
860 (defvar gnus-backup-default-subscribed-newsgroups
861   '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
862   "Default default new newsgroups the first time Gnus is run.
863 Should be set in paths.el, and shouldn't be touched by the user.")
864
865 (defcustom gnus-local-domain nil
866   "Local domain name without a host name.
867 The DOMAINNAME environment variable is used instead if it is defined.
868 If the `system-name' function returns the full Internet name, there is
869 no need to set this variable."
870   :group 'gnus-message
871   :type '(choice (const :tag "default" nil)
872                  string))
873
874 (defvar gnus-local-organization nil
875   "String with a description of what organization (if any) the user belongs to.
876 Obsolete variable; use `message-user-organization' instead.")
877
878 ;; Customization variables
879
880 (defcustom gnus-refer-article-method nil
881   "Preferred method for fetching an article by Message-ID.
882 If you are reading news from the local spool (with nnspool), fetching
883 articles by Message-ID is painfully slow.  By setting this method to an
884 nntp method, you might get acceptable results.
885
886 The value of this variable must be a valid select method as discussed
887 in the documentation of `gnus-select-method'."
888   :group 'gnus-server
889   :type '(choice (const :tag "default" nil)
890                  gnus-select-method))
891
892 (defcustom gnus-group-faq-directory
893   '("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
894     "/ftp@sunsite.auc.dk:/pub/usenet/"
895     "/ftp@sunsite.doc.ic.ac.uk:/pub/usenet/news-faqs/"
896     "/ftp@src.doc.ic.ac.uk:/usenet/news-FAQS/"
897     "/ftp@ftp.seas.gwu.edu:/pub/rtfm/"
898     "/ftp@rtfm.mit.edu:/pub/usenet/"
899     "/ftp@ftp.uni-paderborn.de:/pub/FAQ/"
900     "/ftp@ftp.sunet.se:/pub/usenet/"
901     "/ftp@nctuccca.edu.tw:/USENET/FAQ/"
902     "/ftp@hwarang.postech.ac.kr:/pub/usenet/"
903     "/ftp@ftp.hk.super.net:/mirror/faqs/")
904   "Directory where the group FAQs are stored.
905 This will most commonly be on a remote machine, and the file will be
906 fetched by ange-ftp.
907
908 This variable can also be a list of directories.  In that case, the
909 first element in the list will be used by default.  The others can
910 be used when being prompted for a site.
911
912 Note that Gnus uses an aol machine as the default directory.  If this
913 feels fundamentally unclean, just think of it as a way to finally get
914 something of value back from them.
915
916 If the default site is too slow, try one of these:
917
918    North America: mirrors.aol.com                /pub/rtfm/usenet
919                   ftp.seas.gwu.edu               /pub/rtfm
920                   rtfm.mit.edu                   /pub/usenet
921    Europe:        ftp.uni-paderborn.de           /pub/FAQ
922                   src.doc.ic.ac.uk               /usenet/news-FAQS
923                   ftp.sunet.se                   /pub/usenet
924                   sunsite.auc.dk                 /pub/usenet
925    Asia:          nctuccca.edu.tw                /USENET/FAQ
926                   hwarang.postech.ac.kr          /pub/usenet
927                   ftp.hk.super.net               /mirror/faqs"
928   :group 'gnus-group-various
929   :type '(choice directory
930                  (repeat directory)))
931
932 (defcustom gnus-use-cross-reference t
933   "*Non-nil means that cross referenced articles will be marked as read.
934 If nil, ignore cross references.  If t, mark articles as read in
935 subscribed newsgroups.  If neither t nor nil, mark as read in all
936 newsgroups."
937   :group 'gnus-server
938   :type '(choice (const :tag "off" nil)
939                  (const :tag "subscribed" t)
940                  (sexp :format "all"
941                        :value always)))
942
943 (defcustom gnus-process-mark ?#
944   "*Process mark."
945   :group 'gnus-group-visual
946   :group 'gnus-summary-marks
947   :type 'character)
948
949 (defcustom gnus-asynchronous nil
950   "*If non-nil, Gnus will supply backends with data needed for async article fetching."
951   :group 'gnus-asynchronous
952   :type 'boolean)
953
954 (defcustom gnus-large-newsgroup 200
955   "*The number of articles which indicates a large newsgroup.
956 If the number of articles in a newsgroup is greater than this value,
957 confirmation is required for selecting the newsgroup."
958   :group 'gnus-group-select
959   :type 'integer)
960
961 (defcustom gnus-use-long-file-name (not (memq system-type '(usg-unix-v xenix)))
962   "*Non-nil means that the default name of a file to save articles in is the group name.
963 If it's nil, the directory form of the group name is used instead.
964
965 If this variable is a list, and the list contains the element
966 `not-score', long file names will not be used for score files; if it
967 contains the element `not-save', long file names will not be used for
968 saving; and if it contains the element `not-kill', long file names
969 will not be used for kill files.
970
971 Note that the default for this variable varies according to what system
972 type you're using.  On `usg-unix-v' and `xenix' this variable defaults
973 to nil while on all other systems it defaults to t."
974   :group 'gnus-start
975   :type 'boolean)
976
977 (defcustom gnus-kill-files-directory gnus-directory
978   "*Name of the directory where kill files will be stored (default \"~/News\")."
979   :group 'gnus-score-files
980   :group 'gnus-score-kill
981   :type 'directory)
982
983 (defcustom gnus-save-score nil
984   "*If non-nil, save group scoring info."
985   :group 'gnus-score-various
986   :group 'gnus-start
987   :type 'boolean)
988
989 (defcustom gnus-use-undo t
990   "*If non-nil, allow undoing in Gnus group mode buffers."
991   :group 'gnus-meta
992   :type 'boolean)
993
994 (defcustom gnus-use-adaptive-scoring nil
995   "*If non-nil, use some adaptive scoring scheme.
996 If a list, then the values `word' and `line' are meaningful.  The
997 former will perform adaption on individual words in the subject
998 header while `line' will perform adaption on several headers."
999   :group 'gnus-meta
1000   :group 'gnus-score-adapt
1001   :type '(set (const word) (const line)))
1002
1003 (defcustom gnus-use-cache 'passive
1004   "*If nil, Gnus will ignore the article cache.
1005 If `passive', it will allow entering (and reading) articles
1006 explicitly entered into the cache.  If anything else, use the
1007 cache to the full extent of the law."
1008   :group 'gnus-meta
1009   :group 'gnus-cache
1010   :type '(choice (const :tag "off" nil)
1011                  (const :tag "passive" passive)
1012                  (const :tag "active" t)))
1013
1014 (defcustom gnus-use-trees nil
1015   "*If non-nil, display a thread tree buffer."
1016   :group 'gnus-meta
1017   :type 'boolean)
1018
1019 (defcustom gnus-use-grouplens nil
1020   "*If non-nil, use GroupLens ratings."
1021   :group 'gnus-meta
1022   :type 'boolean)
1023
1024 (defcustom gnus-keep-backlog nil
1025   "*If non-nil, Gnus will keep read articles for later re-retrieval.
1026 If it is a number N, then Gnus will only keep the last N articles
1027 read.  If it is neither nil nor a number, Gnus will keep all read
1028 articles.  This is not a good idea."
1029   :group 'gnus-meta
1030   :type '(choice (const :tag "off" nil)
1031                  integer
1032                  (sexp :format "all"
1033                        :value t)))
1034
1035 (defcustom gnus-use-nocem nil
1036   "*If non-nil, Gnus will read NoCeM cancel messages."
1037   :group 'gnus-meta
1038   :type 'boolean)
1039
1040 (defcustom gnus-suppress-duplicates nil
1041   "*If non-nil, Gnus will mark duplicate copies of the same article as read."
1042   :group 'gnus-meta
1043   :type 'boolean)
1044
1045 (defcustom gnus-use-demon nil
1046   "If non-nil, Gnus might use some demons."
1047   :group 'gnus-meta
1048   :type 'boolean)
1049
1050 (defcustom gnus-use-scoring t
1051   "*If non-nil, enable scoring."
1052   :group 'gnus-meta
1053   :type 'boolean)
1054
1055 (defcustom gnus-use-picons nil
1056   "*If non-nil, display picons."
1057   :group 'gnus-meta
1058   :type 'boolean)
1059
1060 (defcustom gnus-summary-prepare-exit-hook
1061   '(gnus-summary-expire-articles)
1062   "A hook called when preparing to exit from the summary buffer.
1063 It calls `gnus-summary-expire-articles' by default."
1064   :group 'gnus-summary-exit
1065   :type 'hook)
1066
1067 (defcustom gnus-novice-user t
1068   "*Non-nil means that you are a usenet novice.
1069 If non-nil, verbose messages may be displayed and confirmations may be
1070 required."
1071   :group 'gnus-meta
1072   :type 'boolean)
1073
1074 (defcustom gnus-expert-user nil
1075   "*Non-nil means that you will never be asked for confirmation about anything.
1076 And that means *anything*."
1077   :group 'gnus-meta
1078   :type 'boolean)
1079
1080 (defcustom gnus-interactive-catchup t
1081   "*If non-nil, require your confirmation when catching up a group."
1082   :group 'gnus-group-select
1083   :type 'boolean)
1084
1085 (defcustom gnus-interactive-exit t
1086   "*If non-nil, require your confirmation when exiting Gnus."
1087   :group 'gnus-exit
1088   :type 'boolean)
1089
1090 (defcustom gnus-extract-address-components 'gnus-extract-address-components
1091   "*Function for extracting address components from a From header.
1092 Two pre-defined function exist: `gnus-extract-address-components',
1093 which is the default, quite fast, and too simplistic solution, and
1094 `mail-extract-address-components', which works much better, but is
1095 slower."
1096   :group 'gnus-summary-format
1097   :type '(radio (function-item gnus-extract-address-components)
1098                 (function-item mail-extract-address-components)
1099                 (function :tag "Other")))
1100
1101 (defcustom gnus-carpal nil
1102   "*If non-nil, display clickable icons."
1103   :group 'gnus-meta
1104   :type 'boolean)
1105
1106 (defcustom gnus-shell-command-separator ";"
1107   "String used to separate to shell commands."
1108   :group 'gnus-files
1109   :type 'string)
1110
1111 (defcustom gnus-valid-select-methods
1112   '(("nntp" post address prompt-address physical-address)
1113     ("nnspool" post address)
1114     ("nnvirtual" post-mail virtual prompt-address)
1115     ("nnmbox" mail respool address)
1116     ("nnml" mail respool address)
1117     ("nnmh" mail respool address)
1118     ("nndir" post-mail prompt-address physical-address)
1119     ("nneething" none address prompt-address physical-address)
1120     ("nndoc" none address prompt-address)
1121     ("nnbabyl" mail address respool)
1122     ("nnkiboze" post virtual)
1123     ("nnsoup" post-mail address)
1124     ("nndraft" post-mail)
1125     ("nnfolder" mail respool address)
1126     ("nngateway" none address prompt-address physical-address)
1127     ("nnweb" none)
1128     ("nnagent" post-mail))
1129   "An alist of valid select methods.
1130 The first element of each list lists should be a string with the name
1131 of the select method.  The other elements may be the category of
1132 this method (i. e., `post', `mail', `none' or whatever) or other
1133 properties that this method has (like being respoolable).
1134 If you implement a new select method, all you should have to change is
1135 this variable.  I think."
1136   :group 'gnus-server
1137   :type '(repeat (group (string :tag "Name")
1138                         (radio-button-choice (const :format "%v " post)
1139                                              (const :format "%v " mail)
1140                                              (const :format "%v " none)
1141                                              (const post-mail))
1142                         (checklist :inline t
1143                                    (const :format "%v " address)
1144                                    (const :format "%v " prompt-address)
1145                                    (const :format "%v " physical-address)
1146                                    (const :format "%v " virtual)
1147                                    (const respool)))))
1148
1149 (define-widget 'gnus-select-method 'list
1150   "Widget for entering a select method."
1151   :args `((choice :tag "Method"
1152                   ,@(mapcar (lambda (entry)
1153                               (list 'const :format "%v\n"
1154                                     (intern (car entry))))
1155                             gnus-valid-select-methods))
1156           (string :tag "Address")
1157           (editable-list  :inline t
1158                           (list :format "%v"
1159                                 variable
1160                                 (sexp :tag "Value")))))
1161
1162 (defcustom gnus-updated-mode-lines '(group article summary tree)
1163   "List of buffers that should update their mode lines.
1164 The list may contain the symbols `group', `article', `tree' and
1165 `summary'.  If the corresponding symbol is present, Gnus will keep
1166 that mode line updated with information that may be pertinent.
1167 If this variable is nil, screen refresh may be quicker."
1168   :group 'gnus-various
1169   :type '(set (const group)
1170               (const article)
1171               (const summary)
1172               (const tree)))
1173
1174 ;; Added by Keinonen Kari <kk85613@cs.tut.fi>.
1175 (defcustom gnus-mode-non-string-length nil
1176   "*Max length of mode-line non-string contents.
1177 If this is nil, Gnus will take space as is needed, leaving the rest
1178 of the modeline intact.  Note that the default of nil is unlikely
1179 to be desirable; see the manual for further details."
1180   :group 'gnus-various
1181   :type '(choice (const nil)
1182                  integer))
1183
1184 (defcustom gnus-auto-expirable-newsgroups nil
1185   "*Groups in which to automatically mark read articles as expirable.
1186 If non-nil, this should be a regexp that should match all groups in
1187 which to perform auto-expiry.  This only makes sense for mail groups."
1188   :group 'nnmail-expire
1189   :type '(choice (const nil)
1190                  regexp))
1191
1192 (defcustom gnus-total-expirable-newsgroups nil
1193   "*Groups in which to perform expiry of all read articles.
1194 Use with extreme caution.  All groups that match this regexp will be
1195 expiring - which means that all read articles will be deleted after
1196 \(say) one week.         (This only goes for mail groups and the like, of
1197 course.)"
1198   :group 'nnmail-expire
1199   :type '(choice (const nil)
1200                  regexp))
1201
1202 (defcustom gnus-group-uncollapsed-levels 1
1203   "Number of group name elements to leave alone when making a short group name."
1204   :group 'gnus-group-visual
1205   :type 'integer)
1206
1207 (defcustom gnus-group-use-permanent-levels nil
1208   "*If non-nil, once you set a level, Gnus will use this level."
1209   :group 'gnus-group-levels
1210   :type 'boolean)
1211
1212 ;; Hooks.
1213
1214 (defcustom gnus-load-hook nil
1215   "A hook run while Gnus is loaded."
1216   :group 'gnus-start
1217   :type 'hook)
1218
1219 (defcustom gnus-apply-kill-hook '(gnus-apply-kill-file)
1220   "A hook called to apply kill files to a group.
1221 This hook is intended to apply a kill file to the selected newsgroup.
1222 The function `gnus-apply-kill-file' is called by default.
1223
1224 Since a general kill file is too heavy to use only for a few
1225 newsgroups, I recommend you to use a lighter hook function.  For
1226 example, if you'd like to apply a kill file to articles which contains
1227 a string `rmgroup' in subject in newsgroup `control', you can use the
1228 following hook:
1229
1230  (setq gnus-apply-kill-hook
1231       (list
1232         (lambda ()
1233           (cond ((string-match \"control\" gnus-newsgroup-name)
1234                  (gnus-kill \"Subject\" \"rmgroup\")
1235                  (gnus-expunge \"X\"))))))"
1236   :group 'gnus-score-kill
1237   :options '(gnus-apply-kill-file)
1238   :type 'hook)
1239
1240 (defcustom gnus-group-change-level-function nil
1241   "Function run when a group level is changed.
1242 It is called with three parameters -- GROUP, LEVEL and OLDLEVEL."
1243   :group 'gnus-group-level
1244   :type 'function)
1245
1246 ;;; Face thingies.
1247
1248 (defcustom gnus-visual
1249   '(summary-highlight group-highlight article-highlight
1250                       mouse-face
1251                       summary-menu group-menu article-menu
1252                       tree-highlight menu highlight
1253                       browse-menu server-menu
1254                       page-marker tree-menu binary-menu pick-menu
1255                       grouplens-menu)
1256   "Enable visual features.
1257 If `visual' is disabled, there will be no menus and few faces.  Most of
1258 the visual customization options below will be ignored.  Gnus will use
1259 less space and be faster as a result.
1260
1261 This variable can also be a list of visual elements to switch on.  For
1262 instance, to switch off all visual things except menus, you can say:
1263
1264    (setq gnus-visual '(menu))
1265
1266 Valid elements include `summary-highlight', `group-highlight',
1267 `article-highlight', `mouse-face', `summary-menu', `group-menu',
1268 `article-menu', `tree-highlight', `menu', `highlight', `browse-menu',
1269 `server-menu', `page-marker', `tree-menu', `binary-menu', `pick-menu',
1270 and `grouplens-menu'."
1271   :group 'gnus-meta
1272   :group 'gnus-visual
1273   :type '(set (const summary-highlight)
1274               (const group-highlight)
1275               (const article-highlight)
1276               (const mouse-face)
1277               (const summary-menu)
1278               (const group-menu)
1279               (const article-menu)
1280               (const tree-highlight)
1281               (const menu)
1282               (const highlight)
1283               (const browse-menu)
1284               (const server-menu)
1285               (const page-marker)
1286               (const tree-menu)
1287               (const binary-menu)
1288               (const pick-menu)
1289               (const grouplens-menu)))
1290
1291 (defcustom gnus-mouse-face
1292   (condition-case ()
1293       (if (gnus-visual-p 'mouse-face 'highlight)
1294           (if (boundp 'gnus-mouse-face)
1295               (or gnus-mouse-face 'highlight)
1296             'highlight)
1297         'default)
1298     (error 'highlight))
1299   "Face used for group or summary buffer mouse highlighting.
1300 The line beneath the mouse pointer will be highlighted with this
1301 face."
1302   :group 'gnus-visual
1303   :type 'face)
1304
1305 (defcustom gnus-article-display-hook
1306   (if (and (string-match "XEmacs" emacs-version)
1307            (featurep 'xface))
1308       '(gnus-article-hide-headers-if-wanted
1309         gnus-article-hide-boring-headers
1310         gnus-article-treat-overstrike
1311         gnus-article-maybe-highlight
1312         gnus-article-display-x-face)
1313     '(gnus-article-hide-headers-if-wanted
1314       gnus-article-hide-boring-headers
1315       gnus-article-treat-overstrike
1316       gnus-article-maybe-highlight))
1317   "Controls how the article buffer will look.
1318
1319 If you leave the list empty, the article will appear exactly as it is
1320 stored on the disk.  The list entries will hide or highlight various
1321 parts of the article, making it easier to find the information you
1322 want."
1323   :group 'gnus-article-highlight
1324   :group 'gnus-visual
1325   :type 'hook
1326   :options '(gnus-article-add-buttons
1327              gnus-article-add-buttons-to-head
1328              gnus-article-emphasize
1329              gnus-article-fill-cited-article
1330              gnus-article-remove-cr
1331              gnus-article-de-quoted-unreadable
1332              gnus-summary-stop-page-breaking
1333              ;; gnus-summary-caesar-message
1334              ;; gnus-summary-verbose-headers
1335              gnus-summary-toggle-mime
1336              gnus-article-hide
1337              gnus-article-hide-headers
1338              gnus-article-hide-boring-headers
1339              gnus-article-hide-signature
1340              gnus-article-hide-citation
1341              gnus-article-hide-pgp
1342              gnus-article-hide-pem
1343              gnus-article-highlight
1344              gnus-article-highlight-headers
1345              gnus-article-highlight-citation
1346              gnus-article-highlight-signature
1347              gnus-article-date-ut
1348              gnus-article-date-local
1349              gnus-article-date-lapsed
1350              gnus-article-date-original
1351              gnus-article-remove-trailing-blank-lines
1352              gnus-article-strip-leading-blank-lines
1353              gnus-article-strip-multiple-blank-lines
1354              gnus-article-strip-blank-lines
1355              gnus-article-treat-overstrike
1356              gnus-article-display-x-face
1357              gnus-smiley-display))
1358
1359 (defcustom gnus-article-save-directory gnus-directory
1360   "*Name of the directory articles will be saved in (default \"~/News\")."
1361   :group 'gnus-article-saving
1362   :type 'directory)
1363
1364 (defvar gnus-plugged t
1365   "Whether Gnus is plugged or not.")
1366
1367 \f
1368 ;;; Internal variables
1369
1370 (defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
1371 (defvar gnus-original-article-buffer " *Original Article*")
1372 (defvar gnus-newsgroup-name nil)
1373
1374 (defvar gnus-agent nil
1375   "Whether we want to use the Gnus agent or not.")
1376
1377 (defvar gnus-command-method nil
1378   "Dynamically bound variable that says what the current backend is.")
1379
1380 (defvar gnus-current-select-method nil
1381   "The current method for selecting a newsgroup.")
1382
1383 (defvar gnus-tree-buffer "*Tree*"
1384   "Buffer where Gnus thread trees are displayed.")
1385
1386 ;; Dummy variable.
1387 (defvar gnus-use-generic-from nil)
1388
1389 ;; Variable holding the user answers to all method prompts.
1390 (defvar gnus-method-history nil)
1391 (defvar gnus-group-history nil)
1392
1393 ;; Variable holding the user answers to all mail method prompts.
1394 (defvar gnus-mail-method-history nil)
1395
1396 ;; Variable holding the user answers to all group prompts.
1397 (defvar gnus-group-history nil)
1398
1399 (defvar gnus-server-alist nil
1400   "List of available servers.")
1401
1402 (defvar gnus-predefined-server-alist
1403   `(("cache"
1404      (nnspool "cache"
1405               (nnspool-spool-directory "~/News/cache/")
1406               (nnspool-nov-directory "~/News/cache/")
1407               (nnspool-active-file "~/News/cache/active"))))
1408   "List of predefined (convenience) servers.")
1409
1410 (defvar gnus-topic-indentation "") ;; Obsolete variable.
1411
1412 (defconst gnus-article-mark-lists
1413   '((marked . tick) (replied . reply)
1414     (expirable . expire) (killed . killed)
1415     (bookmarks . bookmark) (dormant . dormant)
1416     (scored . score) (saved . save)
1417     (cached . cache) (downloadable . download)
1418     (unsendable . unsend)))
1419
1420 (defvar gnus-headers-retrieved-by nil)
1421 (defvar gnus-article-reply nil)
1422 (defvar gnus-override-method nil)
1423 (defvar gnus-article-check-size nil)
1424 (defvar gnus-opened-servers nil)
1425
1426 (defvar gnus-current-kill-article nil)
1427
1428 (defvar gnus-have-read-active-file nil)
1429
1430 (defconst gnus-maintainer
1431   "bugs@gnus.org (The Gnus Bugfixing Girls + Boys)"
1432   "The mail address of the Gnus maintainers.")
1433
1434 (defvar gnus-info-nodes
1435   '((gnus-group-mode "(gnus)The Group Buffer")
1436     (gnus-summary-mode "(gnus)The Summary Buffer")
1437     (gnus-article-mode "(gnus)The Article Buffer")
1438     (mime/viewer-mode "(gnus)The Article Buffer")
1439     (gnus-server-mode "(gnus)The Server Buffer")
1440     (gnus-browse-mode "(gnus)Browse Foreign Server")
1441     (gnus-tree-mode "(gnus)Tree Display"))
1442   "Alist of major modes and related Info nodes.")
1443
1444 (defvar gnus-group-buffer "*Group*")
1445 (defvar gnus-summary-buffer "*Summary*")
1446 (defvar gnus-article-buffer "*Article*")
1447 (defvar gnus-server-buffer "*Server*")
1448
1449 (defvar gnus-buffer-list nil
1450   "Gnus buffers that should be killed on exit.")
1451
1452 (defvar gnus-slave nil
1453   "Whether this Gnus is a slave or not.")
1454
1455 (defvar gnus-batch-mode nil
1456   "Whether this Gnus is running in batch mode or not.")
1457
1458 (defvar gnus-variable-list
1459   '(gnus-newsrc-options gnus-newsrc-options-n
1460     gnus-newsrc-last-checked-date
1461     gnus-newsrc-alist gnus-server-alist
1462     gnus-killed-list gnus-zombie-list
1463     gnus-topic-topology gnus-topic-alist
1464     gnus-format-specs)
1465   "Gnus variables saved in the quick startup file.")
1466
1467 (defvar gnus-newsrc-alist nil
1468   "Assoc list of read articles.
1469 gnus-newsrc-hashtb should be kept so that both hold the same information.")
1470
1471 (defvar gnus-newsrc-hashtb nil
1472   "Hashtable of gnus-newsrc-alist.")
1473
1474 (defvar gnus-killed-list nil
1475   "List of killed newsgroups.")
1476
1477 (defvar gnus-killed-hashtb nil
1478   "Hash table equivalent of gnus-killed-list.")
1479
1480 (defvar gnus-zombie-list nil
1481   "List of almost dead newsgroups.")
1482
1483 (defvar gnus-description-hashtb nil
1484   "Descriptions of newsgroups.")
1485
1486 (defvar gnus-list-of-killed-groups nil
1487   "List of newsgroups that have recently been killed by the user.")
1488
1489 (defvar gnus-active-hashtb nil
1490   "Hashtable of active articles.")
1491
1492 (defvar gnus-moderated-hashtb nil
1493   "Hashtable of moderated newsgroups.")
1494
1495 ;; Save window configuration.
1496 (defvar gnus-prev-winconf nil)
1497
1498 (defvar gnus-reffed-article-number nil)
1499
1500 ;;; Let the byte-compiler know that we know about this variable.
1501 (defvar rmail-default-rmail-file)
1502
1503 (defvar gnus-dead-summary nil)
1504
1505 ;;; End of variables.
1506
1507 ;; Define some autoload functions Gnus might use.
1508 (eval-and-compile
1509
1510   ;; This little mapcar goes through the list below and marks the
1511   ;; symbols in question as autoloaded functions.
1512   (mapcar
1513    (lambda (package)
1514      (let ((interactive (nth 1 (memq ':interactive package))))
1515        (mapcar
1516         (lambda (function)
1517           (let (keymap)
1518             (when (consp function)
1519               (setq keymap (car (memq 'keymap function)))
1520               (setq function (car function)))
1521             (autoload function (car package) nil interactive keymap)))
1522         (if (eq (nth 1 package) ':interactive)
1523             (cdddr package)
1524           (cdr package)))))
1525    '(("metamail" metamail-buffer)
1526      ("info" Info-goto-node)
1527      ("hexl" hexl-hex-string-to-integer)
1528      ("pp" pp pp-to-string pp-eval-expression)
1529      ("ps-print" ps-print-preprint)
1530      ("mail-extr" mail-extract-address-components)
1531      ("message" :interactive t
1532       message-send-and-exit message-yank-original)
1533      ("nnmail" nnmail-split-fancy nnmail-article-group nnmail-date-to-time)
1534      ("nnvirtual" nnvirtual-catchup-group nnvirtual-convert-headers)
1535      ("timezone" timezone-make-date-arpa-standard timezone-fix-time
1536       timezone-make-sortable-date timezone-make-time-string)
1537      ("rmailout" rmail-output)
1538      ("rmail" rmail-insert-rmail-file-header rmail-count-new-messages
1539       rmail-show-message)
1540      ("gnus-audio" :interactive t gnus-audio-play)
1541      ("gnus-xmas" gnus-xmas-splash)
1542      ("gnus-soup" :interactive t
1543       gnus-group-brew-soup gnus-brew-soup gnus-soup-add-article
1544       gnus-soup-send-replies gnus-soup-save-areas gnus-soup-pack-packet)
1545      ("nnsoup" nnsoup-pack-replies)
1546      ("score-mode" :interactive t gnus-score-mode)
1547      ("gnus-mh" gnus-summary-save-article-folder
1548       gnus-Folder-save-name gnus-folder-save-name)
1549      ("gnus-mh" :interactive t gnus-summary-save-in-folder)
1550      ("gnus-demon" gnus-demon-add-nocem gnus-demon-add-scanmail
1551       gnus-demon-add-rescan gnus-demon-add-scan-timestamps
1552       gnus-demon-add-disconnection gnus-demon-add-handler
1553       gnus-demon-remove-handler)
1554      ("gnus-demon" :interactive t
1555       gnus-demon-init gnus-demon-cancel)
1556      ("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
1557       gnus-tree-open gnus-tree-close gnus-carpal-setup-buffer)
1558      ("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
1559       gnus-nocem-unwanted-article-p)
1560      ("gnus-srvr" gnus-enter-server-buffer gnus-server-set-info
1561       gnus-server-server-name)
1562      ("gnus-srvr" gnus-browse-foreign-server)
1563      ("gnus-cite" :interactive t
1564       gnus-article-highlight-citation gnus-article-hide-citation-maybe
1565       gnus-article-hide-citation gnus-article-fill-cited-article
1566       gnus-article-hide-citation-in-followups)
1567      ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
1568       gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
1569       gnus-execute gnus-expunge)
1570      ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
1571       gnus-cache-possibly-remove-articles gnus-cache-request-article
1572       gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
1573       gnus-cache-enter-remove-article gnus-cached-article-p
1574       gnus-cache-open gnus-cache-close gnus-cache-update-article)
1575       ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
1576        gnus-cache-remove-article gnus-summary-insert-cached-articles)
1577       ("gnus-score" :interactive t
1578        gnus-summary-increase-score gnus-summary-set-score
1579        gnus-summary-raise-thread gnus-summary-raise-same-subject
1580        gnus-summary-raise-score gnus-summary-raise-same-subject-and-select
1581        gnus-summary-lower-thread gnus-summary-lower-same-subject
1582        gnus-summary-lower-score gnus-summary-lower-same-subject-and-select
1583        gnus-summary-current-score gnus-score-default
1584        gnus-score-flush-cache gnus-score-close
1585        gnus-possibly-score-headers gnus-score-followup-article
1586        gnus-score-followup-thread)
1587       ("gnus-score"
1588        (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
1589       gnus-current-score-file-nondirectory gnus-score-adaptive
1590       gnus-score-find-trace gnus-score-file-name)
1591      ("gnus-cus" :interactive t gnus-group-customize gnus-score-customize)
1592      ("gnus-topic" :interactive t gnus-topic-mode)
1593      ("gnus-topic" gnus-topic-remove-group gnus-topic-set-parameters)
1594      ("gnus-salt" :interactive t gnus-pick-mode gnus-binary-mode)
1595      ("gnus-uu" (gnus-uu-extract-map keymap) (gnus-uu-mark-map keymap))
1596      ("gnus-uu" :interactive t
1597       gnus-uu-digest-mail-forward gnus-uu-digest-post-forward
1598       gnus-uu-mark-series gnus-uu-mark-region gnus-uu-mark-buffer
1599       gnus-uu-mark-by-regexp gnus-uu-mark-all
1600       gnus-uu-mark-sparse gnus-uu-mark-thread gnus-uu-decode-uu
1601       gnus-uu-decode-uu-and-save gnus-uu-decode-unshar
1602       gnus-uu-decode-unshar-and-save gnus-uu-decode-save
1603       gnus-uu-decode-binhex gnus-uu-decode-uu-view
1604       gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
1605       gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
1606       gnus-uu-decode-binhex-view)
1607      ("gnus-uu" gnus-uu-delete-work-dir gnus-quote-arg-for-sh-or-csh)
1608      ("gnus-msg" (gnus-summary-send-map keymap)
1609       gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
1610      ("gnus-msg" :interactive t
1611       gnus-group-post-news gnus-group-mail gnus-summary-post-news
1612       gnus-summary-followup gnus-summary-followup-with-original
1613       gnus-summary-cancel-article gnus-summary-supersede-article
1614       gnus-post-news gnus-summary-reply gnus-summary-reply-with-original
1615       gnus-summary-mail-forward gnus-summary-mail-other-window
1616       gnus-summary-resend-message gnus-summary-resend-bounced-mail
1617       gnus-bug)
1618      ("gnus-picon" :interactive t gnus-article-display-picons
1619       gnus-group-display-picons gnus-picons-article-display-x-face
1620       gnus-picons-display-x-face)
1621      ("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p
1622       gnus-grouplens-mode)
1623      ("smiley" :interactive t gnus-smiley-display)
1624      ("gnus-win" gnus-configure-windows gnus-add-configuration)
1625      ("gnus-sum" gnus-summary-insert-line gnus-summary-read-group
1626       gnus-list-of-unread-articles gnus-list-of-read-articles
1627       gnus-offer-save-summaries gnus-make-thread-indent-array
1628       gnus-summary-exit gnus-update-read-articles)
1629      ("gnus-group" gnus-group-insert-group-line gnus-group-quit
1630       gnus-group-list-groups gnus-group-first-unread-group
1631       gnus-group-set-mode-line gnus-group-set-info gnus-group-save-newsrc
1632       gnus-group-setup-buffer gnus-group-get-new-news
1633       gnus-group-make-help-group gnus-group-update-group)
1634      ("gnus-bcklg" gnus-backlog-request-article gnus-backlog-enter-article
1635       gnus-backlog-remove-article)
1636      ("gnus-art" gnus-article-read-summary-keys gnus-article-save
1637       gnus-article-prepare gnus-article-set-window-start
1638       gnus-article-next-page gnus-article-prev-page
1639       gnus-request-article-this-buffer gnus-article-mode
1640       gnus-article-setup-buffer gnus-narrow-to-page
1641       gnus-article-delete-invisible-text gnus-hack-decode-rfc1522)
1642      ("gnus-art" :interactive t
1643       gnus-article-hide-headers gnus-article-hide-boring-headers
1644       gnus-article-treat-overstrike gnus-article-word-wrap
1645       gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
1646       gnus-article-display-x-face gnus-article-de-quoted-unreadable
1647       gnus-article-mime-decode-quoted-printable gnus-article-hide-pgp
1648       gnus-article-hide-pem gnus-article-hide-signature
1649       gnus-article-strip-leading-blank-lines gnus-article-date-local
1650       gnus-article-date-original gnus-article-date-lapsed
1651       gnus-article-show-all-headers
1652       gnus-article-edit-mode gnus-article-edit-article
1653       gnus-article-edit-done gnus-decode-rfc1522 article-decode-rfc1522
1654       gnus-start-date-timer gnus-stop-date-timer)
1655      ("gnus-int" gnus-request-type)
1656      ("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
1657       gnus-dribble-enter)
1658      ("gnus-dup" gnus-dup-suppress-articles gnus-dup-unsuppress-article
1659       gnus-dup-enter-articles)
1660      ("gnus-range" gnus-copy-sequence)
1661      ("gnus-eform" gnus-edit-form)
1662      ("gnus-move" :interactive t
1663       gnus-group-move-group-to-server gnus-change-server)
1664      ("gnus-logic" gnus-score-advanced)
1665      ("gnus-undo" gnus-undo-mode gnus-undo-register)
1666      ("gnus-async" gnus-async-request-fetched-article gnus-async-prefetch-next
1667       gnus-async-prefetch-article gnus-async-prefetch-remove-group
1668       gnus-async-halt-prefetch)
1669      ("gnus-agent" gnus-open-agent gnus-agent-get-function
1670       gnus-agent-save-groups gnus-agent-save-active gnus-agent-method-p
1671       gnus-agent-get-undownloaded-list)
1672      ("gnus-agent" :interactive t
1673       gnus-unplugged gnus-agentize)
1674      ("gnus-vm" :interactive t gnus-summary-save-in-vm
1675       gnus-summary-save-article-vm)
1676      ("gnus-draft" :interactive t gnus-draft-mode gnus-group-send-drafts))))
1677
1678 ;;; gnus-sum.el thingies
1679
1680
1681 (defcustom gnus-summary-line-format "%U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
1682   "*The format specification of the lines in the summary buffer.
1683
1684 It works along the same lines as a normal formatting string,
1685 with some simple extensions.
1686
1687 %N   Article number, left padded with spaces (string)
1688 %S   Subject (string)
1689 %s   Subject if it is at the root of a thread, and \"\" otherwise (string)
1690 %n   Name of the poster (string)
1691 %a   Extracted name of the poster (string)
1692 %A   Extracted address of the poster (string)
1693 %F   Contents of the From: header (string)
1694 %x   Contents of the Xref: header (string)
1695 %D   Date of the article (string)
1696 %d   Date of the article (string) in DD-MMM format
1697 %M   Message-id of the article (string)
1698 %r   References of the article (string)
1699 %c   Number of characters in the article (integer)
1700 %L   Number of lines in the article (integer)
1701 %I   Indentation based on thread level (a string of spaces)
1702 %T   A string with two possible values: 80 spaces if the article
1703      is on thread level two or larger and 0 spaces on level one
1704 %R   \"A\" if this article has been replied to, \" \" otherwise (character)
1705 %U   Status of this article (character, \"R\", \"K\", \"-\" or \" \")
1706 %[   Opening bracket (character, \"[\" or \"<\")
1707 %]   Closing bracket (character, \"]\" or \">\")
1708 %>   Spaces of length thread-level (string)
1709 %<   Spaces of length (- 20 thread-level) (string)
1710 %i   Article score (number)
1711 %z   Article zcore (character)
1712 %t   Number of articles under the current thread (number).
1713 %e   Whether the thread is empty or not (character).
1714 %l   GroupLens score (string).
1715 %V   Total thread score (number).
1716 %P   The line number (number).
1717 %O   Download mark (character).
1718 %u   User defined specifier.  The next character in the format string should
1719      be a letter.  Gnus will call the function gnus-user-format-function-X,
1720      where X is the letter following %u.  The function will be passed the
1721      current header as argument.  The function should return a string, which
1722      will be inserted into the summary just like information from any other
1723      summary specifier.
1724
1725 Text between %( and %) will be highlighted with `gnus-mouse-face'
1726 when the mouse point is placed inside the area.  There can only be one
1727 such area.
1728
1729 The %U (status), %R (replied) and %z (zcore) specs have to be handled
1730 with care.  For reasons of efficiency, Gnus will compute what column
1731 these characters will end up in, and \"hard-code\" that.  This means that
1732 it is illegal to have these specs after a variable-length spec.  Well,
1733 you might not be arrested, but your summary buffer will look strange,
1734 which is bad enough.
1735
1736 The smart choice is to have these specs as for to the left as
1737 possible.
1738
1739 This restriction may disappear in later versions of Gnus."
1740   :type 'string
1741   :group 'gnus-summary-format)
1742
1743 ;;;
1744 ;;; Skeleton keymaps
1745 ;;;
1746
1747 (defun gnus-suppress-keymap (keymap)
1748   (suppress-keymap keymap)
1749   (let ((keys `([delete] "\177" "\M-u"))) ;gnus-mouse-2
1750     (while keys
1751       (define-key keymap (pop keys) 'undefined))))
1752
1753 (defvar gnus-article-mode-map
1754   (let ((keymap (make-keymap)))
1755     (gnus-suppress-keymap keymap)
1756     keymap))
1757 (defvar gnus-summary-mode-map
1758   (let ((keymap (make-keymap)))
1759     (gnus-suppress-keymap keymap)
1760     keymap))
1761 (defvar gnus-group-mode-map
1762   (let ((keymap (make-keymap)))
1763     (gnus-suppress-keymap keymap)
1764     keymap))
1765
1766 \f
1767
1768 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
1769 ;; If you want the cursor to go somewhere else, set these two
1770 ;; functions in some startup hook to whatever you want.
1771 (defalias 'gnus-summary-position-point 'gnus-goto-colon)
1772 (defalias 'gnus-group-position-point 'gnus-goto-colon)
1773
1774 ;;; Various macros and substs.
1775
1776 (defun gnus-header-from (header)
1777   (mail-header-from header))
1778
1779 (defmacro gnus-gethash (string hashtable)
1780   "Get hash value of STRING in HASHTABLE."
1781   `(symbol-value (intern-soft ,string ,hashtable)))
1782
1783 (defmacro gnus-sethash (string value hashtable)
1784   "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
1785   `(set (intern ,string ,hashtable) ,value))
1786 (put 'gnus-sethash 'edebug-form-spec '(form form form))
1787
1788 (defmacro gnus-group-unread (group)
1789   "Get the currently computed number of unread articles in GROUP."
1790   `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
1791
1792 (defmacro gnus-group-entry (group)
1793   "Get the newsrc entry for GROUP."
1794   `(gnus-gethash ,group gnus-newsrc-hashtb))
1795
1796 (defmacro gnus-active (group)
1797   "Get active info on GROUP."
1798   `(gnus-gethash ,group gnus-active-hashtb))
1799
1800 (defmacro gnus-set-active (group active)
1801   "Set GROUP's active info."
1802   `(gnus-sethash ,group ,active gnus-active-hashtb))
1803
1804 (defun gnus-alive-p ()
1805   "Say whether Gnus is running or not."
1806   (and gnus-group-buffer
1807        (get-buffer gnus-group-buffer)
1808        (save-excursion
1809          (set-buffer gnus-group-buffer)
1810          (eq major-mode 'gnus-group-mode))))
1811
1812 ;; Info access macros.
1813
1814 (defmacro gnus-info-group (info)
1815   `(nth 0 ,info))
1816 (defmacro gnus-info-rank (info)
1817   `(nth 1 ,info))
1818 (defmacro gnus-info-read (info)
1819   `(nth 2 ,info))
1820 (defmacro gnus-info-marks (info)
1821   `(nth 3 ,info))
1822 (defmacro gnus-info-method (info)
1823   `(nth 4 ,info))
1824 (defmacro gnus-info-params (info)
1825   `(nth 5 ,info))
1826
1827 (defmacro gnus-info-level (info)
1828   `(let ((rank (gnus-info-rank ,info)))
1829      (if (consp rank)
1830          (car rank)
1831        rank)))
1832 (defmacro gnus-info-score (info)
1833   `(let ((rank (gnus-info-rank ,info)))
1834      (or (and (consp rank) (cdr rank)) 0)))
1835
1836 (defmacro gnus-info-set-group (info group)
1837   `(setcar ,info ,group))
1838 (defmacro gnus-info-set-rank (info rank)
1839   `(setcar (nthcdr 1 ,info) ,rank))
1840 (defmacro gnus-info-set-read (info read)
1841   `(setcar (nthcdr 2 ,info) ,read))
1842 (defmacro gnus-info-set-marks (info marks &optional extend)
1843   (if extend
1844       `(gnus-info-set-entry ,info ,marks 3)
1845     `(setcar (nthcdr 3 ,info) ,marks)))
1846 (defmacro gnus-info-set-method (info method &optional extend)
1847   (if extend
1848       `(gnus-info-set-entry ,info ,method 4)
1849     `(setcar (nthcdr 4 ,info) ,method)))
1850 (defmacro gnus-info-set-params (info params &optional extend)
1851   (if extend
1852       `(gnus-info-set-entry ,info ,params 5)
1853     `(setcar (nthcdr 5 ,info) ,params)))
1854
1855 (defun gnus-info-set-entry (info entry number)
1856   ;; Extend the info until we have enough elements.
1857   (while (<= (length info) number)
1858     (nconc info (list nil)))
1859   ;; Set the entry.
1860   (setcar (nthcdr number info) entry))
1861
1862 (defmacro gnus-info-set-level (info level)
1863   `(let ((rank (cdr ,info)))
1864      (if (consp (car rank))
1865          (setcar (car rank) ,level)
1866        (setcar rank ,level))))
1867 (defmacro gnus-info-set-score (info score)
1868   `(let ((rank (cdr ,info)))
1869      (if (consp (car rank))
1870          (setcdr (car rank) ,score)
1871        (setcar rank (cons (car rank) ,score)))))
1872
1873 (defmacro gnus-get-info (group)
1874   `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
1875
1876 ;; Byte-compiler warning.
1877 (defvar gnus-visual)
1878 ;; Find out whether the gnus-visual TYPE is wanted.
1879 (defun gnus-visual-p (&optional type class)
1880   (and gnus-visual                      ; Has to be non-nil, at least.
1881        (if (not type)                   ; We don't care about type.
1882            gnus-visual
1883          (if (listp gnus-visual)        ; It's a list, so we check it.
1884              (or (memq type gnus-visual)
1885                  (memq class gnus-visual))
1886            t))))
1887
1888 ;;; Load the compatability functions.
1889
1890 (require 'gnus-ems)
1891
1892 \f
1893 ;;;
1894 ;;; Shutdown
1895 ;;;
1896
1897 (defvar gnus-shutdown-alist nil)
1898
1899 (defun gnus-add-shutdown (function &rest symbols)
1900   "Run FUNCTION whenever one of SYMBOLS is shut down."
1901   (push (cons function symbols) gnus-shutdown-alist))
1902
1903 (defun gnus-shutdown (symbol)
1904   "Shut down everything that waits for SYMBOL."
1905   (let ((alist gnus-shutdown-alist)
1906         entry)
1907     (while (setq entry (pop alist))
1908       (when (memq symbol (cdr entry))
1909         (funcall (car entry))))))
1910
1911 \f
1912 ;;;
1913 ;;; Gnus Utility Functions
1914 ;;;
1915
1916 (defmacro gnus-string-or (&rest strings)
1917   "Return the first element of STRINGS that is a non-blank string.
1918 STRINGS will be evaluated in normal `or' order."
1919   `(gnus-string-or-1 ',strings))
1920
1921 (defun gnus-string-or-1 (strings)
1922   (let (string)
1923     (while strings
1924       (setq string (eval (pop strings)))
1925       (if (string-match "^[ \t]*$" string)
1926           (setq string nil)
1927         (setq strings nil)))
1928     string))
1929
1930 ;; Add the current buffer to the list of buffers to be killed on exit.
1931 (defun gnus-add-current-to-buffer-list ()
1932   (or (memq (current-buffer) gnus-buffer-list)
1933       (push (current-buffer) gnus-buffer-list)))
1934
1935 (defun gnus-version (&optional arg)
1936   "Version number of this version of Gnus.
1937 If ARG, insert string at point."
1938   (interactive "P")
1939   (let ((methods gnus-valid-select-methods)
1940         (mess gnus-version)
1941         meth)
1942     ;; Go through all the legal select methods and add their version
1943     ;; numbers to the total version string.  Only the backends that are
1944     ;; currently in use will have their message numbers taken into
1945     ;; consideration.
1946     (while methods
1947       (setq meth (intern (concat (caar methods) "-version")))
1948       (and (boundp meth)
1949            (stringp (symbol-value meth))
1950            (setq mess (concat mess "; " (symbol-value meth))))
1951       (setq methods (cdr methods)))
1952     (if arg
1953         (insert (message mess))
1954       (message mess))))
1955
1956 (defun gnus-continuum-version (version)
1957   "Return VERSION as a floating point number."
1958   (when (or (string-match "^\\([^ ]+\\)? ?Gnus v?\\([0-9.]+\\)$" version)
1959             (string-match "^\\(.?\\)gnus-\\([0-9.]+\\)$" version))
1960     (let* ((alpha (and (match-beginning 1) (match-string 1 version)))
1961            (number (match-string 2 version))
1962            major minor least)
1963       (string-match "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
1964       (setq major (string-to-number (match-string 1 number)))
1965       (setq minor (string-to-number (match-string 2 number)))
1966       (setq least (if (match-beginning 3)
1967                       (string-to-number (match-string 3 number))
1968                     0))
1969       (string-to-number
1970        (if (zerop major)
1971            (format "%s00%02d%02d"
1972                    (cond
1973                     ((member alpha '("(ding)" "d")) "4.99")
1974                     ((member alpha '("September" "s")) "5.01")
1975                     ((member alpha '("Red" "r")) "5.03"))
1976                    minor least)
1977          (format "%d.%02d%02d" major minor least))))))
1978
1979 (defun gnus-info-find-node ()
1980   "Find Info documentation of Gnus."
1981   (interactive)
1982   ;; Enlarge info window if needed.
1983   (let (gnus-info-buffer)
1984     (Info-goto-node (cadr (assq major-mode gnus-info-nodes)))
1985     (setq gnus-info-buffer (current-buffer))
1986     (gnus-configure-windows 'info)))
1987
1988 ;;;
1989 ;;; gnus-interactive
1990 ;;;
1991
1992 (defvar gnus-current-prefix-symbol nil
1993   "Current prefix symbol.")
1994
1995 (defvar gnus-current-prefix-symbols nil
1996   "List of current prefix symbols.")
1997
1998 (defun gnus-interactive (string &optional params)
1999   "Return a list that can be fed to `interactive'.
2000 See `interactive' for full documentation.
2001
2002 Adds the following specs:
2003
2004 y -- The current symbolic prefix.
2005 Y -- A list of the current symbolic prefix(es).
2006 A -- Article number.
2007 H -- Article header.
2008 g -- Group name."
2009   (let ((i 0)
2010         out c prompt)
2011     (while (< i (length string))
2012       (string-match ".\\([^\n]*\\)\n?" string i)
2013       (setq c (aref string i))
2014       (when (match-end 1)
2015         (setq prompt (match-string 1 string)))
2016       (setq i (match-end 0))
2017       ;; We basically emulate just about everything that
2018       ;; `interactive' does, but adds the "g" and "G" specs.
2019       (push
2020        (cond
2021         ((= c ?a)
2022          (completing-read prompt obarray 'fboundp t))
2023         ((= c ?b)
2024          (read-buffer prompt (current-buffer) t))
2025         ((= c ?B)
2026          (read-buffer prompt (other-buffer (current-buffer))))
2027         ((= c ?c)
2028          (read-char))
2029         ((= c ?C)
2030          (completing-read prompt obarray 'commandp t))
2031         ((= c ?d)
2032          (point))
2033         ((= c ?D)
2034          (read-file-name prompt nil default-directory 'lambda))
2035         ((= c ?f)
2036          (read-file-name prompt nil nil 'lambda))
2037         ((= c ?F)
2038          (read-file-name prompt))
2039         ((= c ?k)
2040          (read-key-sequence prompt))
2041         ((= c ?K)
2042          (error "Not implemented spec"))
2043         ((= c ?e)
2044          (error "Not implemented spec"))
2045         ((= c ?m)
2046          (mark))
2047         ((= c ?N)
2048          (error "Not implemented spec"))
2049         ((= c ?n)
2050          (string-to-number (read-from-minibuffer prompt)))
2051         ((= c ?p)
2052          (prefix-numeric-value current-prefix-arg))
2053         ((= c ?P)
2054          current-prefix-arg)
2055         ((= c ?r)
2056          'gnus-prefix-nil)
2057         ((= c ?s)
2058          (read-string prompt))
2059         ((= c ?S)
2060          (intern (read-string prompt)))
2061         ((= c ?v)
2062          (read-variable prompt))
2063         ((= c ?x)
2064          (read-minibuffer prompt))
2065         ((= c ?x)
2066          (eval-minibuffer prompt))
2067         ;; And here the new specs come.
2068         ((= c ?y)
2069          gnus-current-prefix-symbol)
2070         ((= c ?Y)
2071          gnus-current-prefix-symbols)
2072         ((= c ?g)
2073          (gnus-group-group-name))
2074         ((= c ?A)
2075          (gnus-summary-article-number))
2076         ((= c ?H)
2077          (gnus-summary-article-header))
2078         (t
2079          (error "Not implemented spec")))
2080        out)
2081       (cond
2082        ((= c ?r)
2083         (push (if (< (point) (mark) (point) (mark))) out)
2084         (push (if (> (point) (mark) (point) (mark))) out))))
2085     (setq out (delq 'gnus-prefix-nil out))
2086     (nreverse out)))
2087
2088 (defun gnus-symbolic-argument (&optional arg)
2089   "Read a symbolic argument and a command, and then execute command."
2090   (interactive "P")
2091   (let* ((in-command (this-command-keys))
2092          (command in-command)
2093          gnus-current-prefix-symbols
2094          gnus-current-prefix-symbol
2095          syms)
2096     (while (equal in-command command)
2097       (message "%s-" (key-description (this-command-keys)))
2098       (push (intern (char-to-string (read-char))) syms)
2099       (setq command (read-key-sequence nil t)))
2100     (setq gnus-current-prefix-symbols (nreverse syms)
2101           gnus-current-prefix-symbol (car gnus-current-prefix-symbols))
2102     (call-interactively (key-binding command t))))
2103
2104 ;;; More various functions.
2105
2106 (defsubst gnus-check-backend-function (func group)
2107   "Check whether GROUP supports function FUNC.
2108 GROUP can either be a string (a group name) or a select method."
2109   (ignore-errors
2110     (let ((method (if (stringp group)
2111                       (car (gnus-find-method-for-group group))
2112                     group)))
2113       (unless (featurep method)
2114         (require method))
2115       (fboundp (intern (format "%s-%s" method func))))))
2116
2117 (defun gnus-group-read-only-p (&optional group)
2118   "Check whether GROUP supports editing or not.
2119 If GROUP is nil, `gnus-newsgroup-name' will be checked instead.  Note
2120 that that variable is buffer-local to the summary buffers."
2121   (let ((group (or group gnus-newsgroup-name)))
2122     (not (gnus-check-backend-function 'request-replace-article group))))
2123
2124 (defun gnus-group-total-expirable-p (group)
2125   "Check whether GROUP is total-expirable or not."
2126   (let ((params (gnus-group-find-parameter group))
2127         val)
2128     (cond
2129      ((memq 'total-expire params)
2130       t)
2131      ((setq val (assq 'total-expire params)) ; (auto-expire . t)
2132       (cdr val))
2133      (gnus-total-expirable-newsgroups   ; Check var.
2134       (string-match gnus-total-expirable-newsgroups group)))))
2135
2136 (defun gnus-group-auto-expirable-p (group)
2137   "Check whether GROUP is auto-expirable or not."
2138   (let ((params (gnus-group-find-parameter group))
2139         val)
2140     (cond
2141      ((memq 'auto-expire params)
2142       t)
2143      ((setq val (assq 'auto-expire params)) ; (auto-expire . t)
2144       (cdr val))
2145      (gnus-auto-expirable-newsgroups    ; Check var.
2146       (string-match gnus-auto-expirable-newsgroups group)))))
2147
2148 (defun gnus-virtual-group-p (group)
2149   "Say whether GROUP is virtual or not."
2150   (memq 'virtual (assoc (symbol-name (car (gnus-find-method-for-group group)))
2151                         gnus-valid-select-methods)))
2152
2153 (defun gnus-news-group-p (group &optional article)
2154   "Return non-nil if GROUP (and ARTICLE) come from a news server."
2155   (or (gnus-member-of-valid 'post group) ; Ordinary news group.
2156       (and (gnus-member-of-valid 'post-mail group) ; Combined group.
2157            (eq (gnus-request-type group article) 'news))))
2158
2159 ;; Returns a list of writable groups.
2160 (defun gnus-writable-groups ()
2161   (let ((alist gnus-newsrc-alist)
2162         groups group)
2163     (while (setq group (car (pop alist)))
2164       (unless (gnus-group-read-only-p group)
2165         (push group groups)))
2166     (nreverse groups)))
2167
2168 ;; Check whether to use long file names.
2169 (defun gnus-use-long-file-name (symbol)
2170   ;; The variable has to be set...
2171   (and gnus-use-long-file-name
2172        ;; If it isn't a list, then we return t.
2173        (or (not (listp gnus-use-long-file-name))
2174            ;; If it is a list, and the list contains `symbol', we
2175            ;; return nil.
2176            (not (memq symbol gnus-use-long-file-name)))))
2177
2178 ;; Generate a unique new group name.
2179 (defun gnus-generate-new-group-name (leaf)
2180   (let ((name leaf)
2181         (num 0))
2182     (while (gnus-gethash name gnus-newsrc-hashtb)
2183       (setq name (concat leaf "<" (int-to-string (setq num (1+ num))) ">")))
2184     name))
2185
2186 (defun gnus-ephemeral-group-p (group)
2187   "Say whether GROUP is ephemeral or not."
2188   (gnus-group-get-parameter group 'quit-config))
2189
2190 (defun gnus-group-quit-config (group)
2191   "Return the quit-config of GROUP."
2192   (gnus-group-get-parameter group 'quit-config))
2193
2194 (defun gnus-kill-ephemeral-group (group)
2195   "Remove ephemeral GROUP from relevant structures."
2196   (gnus-sethash group nil gnus-newsrc-hashtb))
2197
2198 (defun gnus-simplify-mode-line ()
2199   "Make mode lines a bit simpler."
2200   (setq mode-line-modified (cdr gnus-mode-line-modified))
2201   (when (listp mode-line-format)
2202     (make-local-variable 'mode-line-format)
2203     (setq mode-line-format (copy-sequence mode-line-format))
2204     (when (equal (nth 3 mode-line-format) "   ")
2205       (setcar (nthcdr 3 mode-line-format) " "))))
2206
2207 ;;; Servers and groups.
2208
2209 (defsubst gnus-server-add-address (method)
2210   (let ((method-name (symbol-name (car method))))
2211     (if (and (memq 'address (assoc method-name gnus-valid-select-methods))
2212              (not (assq (intern (concat method-name "-address")) method))
2213              (memq 'physical-address (assq (car method)
2214                                            gnus-valid-select-methods)))
2215         (append method (list (list (intern (concat method-name "-address"))
2216                                    (nth 1 method))))
2217       method)))
2218
2219 (defsubst gnus-server-get-method (group method)
2220   ;; Input either a server name, and extended server name, or a
2221   ;; select method, and return a select method.
2222   (cond ((stringp method)
2223          (gnus-server-to-method method))
2224         ((equal method gnus-select-method)
2225          gnus-select-method)
2226         ((and (stringp (car method)) group)
2227          (gnus-server-extend-method group method))
2228         ((and method (not group)
2229               (equal (cadr method) ""))
2230          method)
2231         (t
2232          (gnus-server-add-address method))))
2233
2234 (defun gnus-server-to-method (server)
2235   "Map virtual server names to select methods."
2236   (or
2237    ;; Is this a method, perhaps?
2238    (and server (listp server) server)
2239    ;; Perhaps this is the native server?
2240    (and (equal server "native") gnus-select-method)
2241    ;; It should be in the server alist.
2242    (cdr (assoc server gnus-server-alist))
2243    ;; It could be in the predefined server alist.
2244    (cdr (assoc server gnus-predefined-server-alist))
2245    ;; If not, we look through all the opened server
2246    ;; to see whether we can find it there.
2247    (let ((opened gnus-opened-servers))
2248      (while (and opened
2249                  (not (equal server (format "%s:%s" (caaar opened)
2250                                             (cadaar opened)))))
2251        (pop opened))
2252      (caar opened))))
2253
2254 (defmacro gnus-method-equal (ss1 ss2)
2255   "Say whether two servers are equal."
2256   `(let ((s1 ,ss1)
2257          (s2 ,ss2))
2258      (or (equal s1 s2)
2259          (and (= (length s1) (length s2))
2260               (progn
2261                 (while (and s1 (member (car s1) s2))
2262                   (setq s1 (cdr s1)))
2263                 (null s1))))))
2264
2265 (defun gnus-server-equal (m1 m2)
2266   "Say whether two methods are equal."
2267   (let ((m1 (cond ((null m1) gnus-select-method)
2268                   ((stringp m1) (gnus-server-to-method m1))
2269                   (t m1)))
2270         (m2 (cond ((null m2) gnus-select-method)
2271                   ((stringp m2) (gnus-server-to-method m2))
2272                   (t m2))))
2273     (gnus-method-equal m1 m2)))
2274
2275 (defun gnus-servers-using-backend (backend)
2276   "Return a list of known servers using BACKEND."
2277   (let ((opened gnus-opened-servers)
2278         out)
2279     (while opened
2280       (when (eq backend (caaar opened))
2281         (push (caar opened) out))
2282       (pop opened))
2283     out))
2284
2285 (defun gnus-archive-server-wanted-p ()
2286   "Say whether the user wants to use the archive server."
2287   (cond
2288    ((or (not gnus-message-archive-method)
2289         (not gnus-message-archive-group))
2290     nil)
2291    ((and gnus-message-archive-method gnus-message-archive-group)
2292     t)
2293    (t
2294     (let ((active (cadr (assq 'nnfolder-active-file
2295                               gnus-message-archive-method))))
2296       (and active
2297            (file-exists-p active))))))
2298
2299 (defun gnus-group-prefixed-name (group method)
2300   "Return the whole name from GROUP and METHOD."
2301   (and (stringp method) (setq method (gnus-server-to-method method)))
2302   (if (or (not method)
2303           (gnus-server-equal method "native"))
2304       group
2305     (concat (format "%s" (car method))
2306             (when (and
2307                    (or (assoc (format "%s" (car method))
2308                               (gnus-methods-using 'address))
2309                        (gnus-server-equal method gnus-message-archive-method))
2310                    (nth 1 method)
2311                    (not (string= (nth 1 method) "")))
2312               (concat "+" (nth 1 method)))
2313             ":" group)))
2314
2315 (defun gnus-group-real-prefix (group)
2316   "Return the prefix of the current group name."
2317   (if (string-match "^[^:]+:" group)
2318       (substring group 0 (match-end 0))
2319     ""))
2320
2321 (defun gnus-group-method (group)
2322   "Return the server or method used for selecting GROUP.
2323 You should probably use `gnus-find-method-for-group' instead."
2324   (let ((prefix (gnus-group-real-prefix group)))
2325     (if (equal prefix "")
2326         gnus-select-method
2327       (let ((servers gnus-opened-servers)
2328             (server "")
2329             backend possible found)
2330         (if (string-match "^[^\\+]+\\+" prefix)
2331             (setq backend (intern (substring prefix 0 (1- (match-end 0))))
2332                   server (substring prefix (match-end 0) (1- (length prefix))))
2333           (setq backend (intern (substring prefix 0 (1- (length prefix))))))
2334         (while servers
2335           (when (eq (caaar servers) backend)
2336             (setq possible (caar servers))
2337             (when (equal (cadaar servers) server)
2338               (setq found (caar servers))))
2339           (pop servers))
2340         (or (car (rassoc found gnus-server-alist))
2341             found
2342             (car (rassoc possible gnus-server-alist))
2343             possible
2344             (list backend server))))))
2345
2346 (defsubst gnus-secondary-method-p (method)
2347   "Return whether METHOD is a secondary select method."
2348   (let ((methods gnus-secondary-select-methods)
2349         (gmethod (gnus-server-get-method nil method)))
2350     (while (and methods
2351                 (not (equal (gnus-server-get-method nil (car methods))
2352                             gmethod)))
2353       (setq methods (cdr methods)))
2354     methods))
2355
2356 (defun gnus-groups-from-server (server)
2357   "Return a list of all groups that are fetched from SERVER."
2358   (let ((alist (cdr gnus-newsrc-alist))
2359         info groups)
2360     (while (setq info (pop alist))
2361       (when (gnus-server-equal (gnus-info-method info) server)
2362         (push (gnus-info-group info) groups)))
2363     (sort groups 'string<)))
2364
2365 (defun gnus-group-foreign-p (group)
2366   "Say whether a group is foreign or not."
2367   (and (not (gnus-group-native-p group))
2368        (not (gnus-group-secondary-p group))))
2369
2370 (defun gnus-group-native-p (group)
2371   "Say whether the group is native or not."
2372   (not (string-match ":" group)))
2373
2374 (defun gnus-group-secondary-p (group)
2375   "Say whether the group is secondary or not."
2376   (gnus-secondary-method-p (gnus-find-method-for-group group)))
2377
2378 (defun gnus-group-find-parameter (group &optional symbol)
2379   "Return the group parameters for GROUP.
2380 If SYMBOL, return the value of that symbol in the group parameters."
2381   (save-excursion
2382     (set-buffer gnus-group-buffer)
2383     (let ((parameters (funcall gnus-group-get-parameter-function group)))
2384       (if symbol
2385           (gnus-group-parameter-value parameters symbol)
2386         parameters))))
2387
2388 (defun gnus-group-get-parameter (group &optional symbol)
2389   "Return the group parameters for GROUP.
2390 If SYMBOL, return the value of that symbol in the group parameters."
2391   (let ((params (gnus-info-params (gnus-get-info group))))
2392     (if symbol
2393         (gnus-group-parameter-value params symbol)
2394       params)))
2395
2396 (defun gnus-group-parameter-value (params symbol)
2397   "Return the value of SYMBOL in group PARAMS."
2398   (or (car (memq symbol params))        ; It's either a simple symbol
2399       (cdr (assq symbol params))))      ; or a cons.
2400
2401 (defun gnus-group-add-parameter (group param)
2402   "Add parameter PARAM to GROUP."
2403   (let ((info (gnus-get-info group)))
2404     (when info
2405       (gnus-group-remove-parameter group (if (consp param) (car param) param))
2406       ;; Cons the new param to the old one and update.
2407       (gnus-group-set-info (cons param (gnus-info-params info))
2408                            group 'params))))
2409
2410 (defun gnus-group-set-parameter (group name value)
2411   "Set parameter NAME to VALUE in GROUP."
2412   (let ((info (gnus-get-info group)))
2413     (when info
2414       (gnus-group-remove-parameter group name)
2415       (let ((old-params (gnus-info-params info))
2416             (new-params (list (cons name value))))
2417         (while old-params
2418           (when (or (not (listp (car old-params)))
2419                     (not (eq (caar old-params) name)))
2420             (setq new-params (append new-params (list (car old-params)))))
2421           (setq old-params (cdr old-params)))
2422         (gnus-group-set-info new-params group 'params)))))
2423
2424 (defun gnus-group-remove-parameter (group name)
2425   "Remove parameter NAME from GROUP."
2426   (let ((info (gnus-get-info group)))
2427     (when info
2428       (let ((params (gnus-info-params info)))
2429         (when params
2430           (setq params (delq name params))
2431           (while (assq name params)
2432             (setq params (delq (assq name params) params)))
2433           (gnus-info-set-params info params))))))
2434
2435 (defun gnus-group-add-score (group &optional score)
2436   "Add SCORE to the GROUP score.
2437 If SCORE is nil, add 1 to the score of GROUP."
2438   (let ((info (gnus-get-info group)))
2439     (when info
2440       (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
2441
2442 ;; Function written by Stainless Steel Rat <ratinox@peorth.gweep.net>
2443 (defun gnus-short-group-name (group &optional levels)
2444   "Collapse GROUP name LEVELS.
2445 Select methods are stripped and any remote host name is stripped down to
2446 just the host name."
2447   (let* ((name "") (foreign "") (depth -1) (skip 1)
2448          (levels (or levels
2449                      (progn
2450                        (while (string-match "\\." group skip)
2451                          (setq skip (match-end 0)
2452                                depth (+ depth 1)))
2453                        depth))))
2454     ;; separate foreign select method from group name and collapse.
2455     ;; if method contains a server, collapse to non-domain server name,
2456     ;; otherwise collapse to select method
2457     (when (string-match ":" group)
2458       (cond ((string-match "+" group)
2459              (let* ((plus (string-match "+" group))
2460                     (colon (string-match ":" group (or plus 0)))
2461                     (dot (string-match "\\." group)))
2462                (setq foreign (concat
2463                               (substring group (+ 1 plus)
2464                                          (cond ((null dot) colon)
2465                                                ((< colon dot) colon)
2466                                                ((< dot colon) dot)))
2467                               ":")
2468                      group (substring group (+ 1 colon)))))
2469             (t
2470              (let* ((colon (string-match ":" group)))
2471                (setq foreign (concat (substring group 0 (+ 1 colon)))
2472                      group (substring group (+ 1 colon)))))))
2473     ;; collapse group name leaving LEVELS uncollapsed elements
2474     (while group
2475       (if (and (string-match "\\." group) (> levels 0))
2476           (setq name (concat name (substring group 0 1))
2477                 group (substring group (match-end 0))
2478                 levels (- levels 1)
2479                 name (concat name "."))
2480         (setq name (concat foreign name group)
2481               group nil)))
2482     name))
2483
2484 (defun gnus-narrow-to-body ()
2485   "Narrow to the body of an article."
2486   (narrow-to-region
2487    (progn
2488      (goto-char (point-min))
2489      (or (search-forward "\n\n" nil t)
2490          (point-max)))
2491    (point-max)))
2492
2493 \f
2494 ;;;
2495 ;;; Kill file handling.
2496 ;;;
2497
2498 (defun gnus-apply-kill-file ()
2499   "Apply a kill file to the current newsgroup.
2500 Returns the number of articles marked as read."
2501   (if (or (file-exists-p (gnus-newsgroup-kill-file nil))
2502           (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
2503       (gnus-apply-kill-file-internal)
2504     0))
2505
2506 (defun gnus-kill-save-kill-buffer ()
2507   (let ((file (gnus-newsgroup-kill-file gnus-newsgroup-name)))
2508     (when (get-file-buffer file)
2509       (save-excursion
2510         (set-buffer (get-file-buffer file))
2511         (when (buffer-modified-p)
2512           (save-buffer))
2513         (kill-buffer (current-buffer))))))
2514
2515 (defcustom gnus-kill-file-name "KILL"
2516   "Suffix of the kill files."
2517   :group 'gnus-score-kill
2518   :group 'gnus-score-files
2519   :type 'string)
2520
2521 (defun gnus-newsgroup-kill-file (newsgroup)
2522   "Return the name of a kill file name for NEWSGROUP.
2523 If NEWSGROUP is nil, return the global kill file name instead."
2524   (cond
2525    ;; The global KILL file is placed at top of the directory.
2526    ((or (null newsgroup)
2527         (string-equal newsgroup ""))
2528     (expand-file-name gnus-kill-file-name
2529                       gnus-kill-files-directory))
2530    ;; Append ".KILL" to newsgroup name.
2531    ((gnus-use-long-file-name 'not-kill)
2532     (expand-file-name (concat (gnus-newsgroup-savable-name newsgroup)
2533                               "." gnus-kill-file-name)
2534                       gnus-kill-files-directory))
2535    ;; Place "KILL" under the hierarchical directory.
2536    (t
2537     (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
2538                               "/" gnus-kill-file-name)
2539                       gnus-kill-files-directory))))
2540
2541 ;;; Server things.
2542
2543 (defun gnus-member-of-valid (symbol group)
2544   "Find out if GROUP has SYMBOL as part of its \"valid\" spec."
2545   (memq symbol (assoc
2546                 (symbol-name (car (gnus-find-method-for-group group)))
2547                 gnus-valid-select-methods)))
2548
2549 (defun gnus-method-option-p (method option)
2550   "Return non-nil if select METHOD has OPTION as a parameter."
2551   (when (stringp method)
2552     (setq method (gnus-server-to-method method)))
2553   (memq option (assoc (format "%s" (car method))
2554                       gnus-valid-select-methods)))
2555
2556 (defun gnus-similar-server-opened (method)
2557   (let ((opened gnus-opened-servers))
2558     (while (and method opened)
2559       (when (and (equal (cadr method) (cadaar opened))
2560                  (not (equal method (caar opened))))
2561         (setq method nil))
2562       (pop opened))
2563     (not method)))
2564
2565 (defun gnus-server-extend-method (group method)
2566   ;; This function "extends" a virtual server.  If the server is
2567   ;; "hello", and the select method is ("hello" (my-var "something"))
2568   ;; in the group "alt.alt", this will result in a new virtual server
2569   ;; called "hello+alt.alt".
2570   (if (or (not (inline (gnus-similar-server-opened method)))
2571           (not (cddr method)))
2572       method
2573     `(,(car method) ,(concat (cadr method) "+" group)
2574       (,(intern (format "%s-address" (car method))) ,(cadr method))
2575       ,@(cddr method))))
2576
2577 (defun gnus-server-status (method)
2578   "Return the status of METHOD."
2579   (nth 1 (assoc method gnus-opened-servers)))
2580
2581 (defun gnus-group-name-to-method (group)
2582   "Guess a select method based on GROUP."
2583   (if (string-match ":" group)
2584       (let ((server (substring group 0 (match-beginning 0))))
2585         (if (string-match "\\+" server)
2586             (list (intern (substring server 0 (match-beginning 0)))
2587                   (substring server (match-end 0)))
2588           (list (intern server) "")))
2589     gnus-select-method))
2590
2591 (defun gnus-find-method-for-group (group &optional info)
2592   "Find the select method that GROUP uses."
2593   (or gnus-override-method
2594       (and (not group)
2595            gnus-select-method)
2596       (let ((info (or info (gnus-get-info group)))
2597             method)
2598         (if (or (not info)
2599                 (not (setq method (gnus-info-method info)))
2600                 (equal method "native"))
2601             gnus-select-method
2602           (setq method
2603                 (cond ((stringp method)
2604                        (inline (gnus-server-to-method method)))
2605                       ((stringp (cadr method))
2606                        (inline (gnus-server-extend-method group method)))
2607                       (t
2608                        method)))
2609           (cond ((equal (cadr method) "")
2610                  method)
2611                 ((null (cadr method))
2612                  (list (car method) ""))
2613                 (t
2614                  (gnus-server-add-address method)))))))
2615
2616 (defun gnus-methods-using (feature)
2617   "Find all methods that have FEATURE."
2618   (let ((valids gnus-valid-select-methods)
2619         outs)
2620     (while valids
2621       (when (memq feature (car valids))
2622         (push (car valids) outs))
2623       (setq valids (cdr valids)))
2624     outs))
2625
2626 (defun gnus-read-group (prompt &optional default)
2627   "Prompt the user for a group name.
2628 Disallow illegal group names."
2629   (let ((prefix "")
2630         group)
2631     (while (not group)
2632       (when (string-match
2633              "[: `'\"/]\\|^$"
2634              (setq group (read-string (concat prefix prompt)
2635                                       (cons (or default "") 0)
2636                                       'gnus-group-history)))
2637         (setq prefix (format "Illegal group name: \"%s\".  " group)
2638               group nil)))
2639     group))
2640
2641 (defun gnus-read-method (prompt)
2642   "Prompt the user for a method.
2643 Allow completion over sensible values."
2644   (let ((method
2645          (completing-read
2646           prompt (append gnus-valid-select-methods gnus-predefined-server-alist
2647                          gnus-server-alist)
2648           nil t nil 'gnus-method-history)))
2649     (cond
2650      ((equal method "")
2651       (setq method gnus-select-method))
2652      ((assoc method gnus-valid-select-methods)
2653       (list (intern method)
2654             (if (memq 'prompt-address
2655                       (assoc method gnus-valid-select-methods))
2656                 (read-string "Address: ")
2657               "")))
2658      ((assoc method gnus-server-alist)
2659       method)
2660      (t
2661       (list (intern method) "")))))
2662
2663 ;;; User-level commands.
2664
2665 ;;;###autoload
2666 (defun gnus-slave-no-server (&optional arg)
2667   "Read network news as a slave, without connecting to local server"
2668   (interactive "P")
2669   (gnus-no-server arg t))
2670
2671 ;;;###autoload
2672 (defun gnus-no-server (&optional arg slave)
2673   "Read network news.
2674 If ARG is a positive number, Gnus will use that as the
2675 startup level.  If ARG is nil, Gnus will be started at level 2.
2676 If ARG is non-nil and not a positive number, Gnus will
2677 prompt the user for the name of an NNTP server to use.
2678 As opposed to `gnus', this command will not connect to the local server."
2679   (interactive "P")
2680   (gnus-no-server-1 arg slave))
2681
2682 ;;;###autoload
2683 (defun gnus-slave (&optional arg)
2684   "Read news as a slave."
2685   (interactive "P")
2686   (gnus arg nil 'slave))
2687
2688 ;;;###autoload
2689 (defun gnus-other-frame (&optional arg)
2690   "Pop up a frame to read news."
2691   (interactive "P")
2692   (let ((window (get-buffer-window gnus-group-buffer)))
2693     (cond (window
2694            (select-frame (window-frame window)))
2695           ((= (length (frame-list)) 1)
2696            (select-frame (make-frame)))
2697           (t
2698            (other-frame 1))))
2699   (gnus arg))
2700
2701 ;;;###autoload
2702 (defun gnus (&optional arg dont-connect slave)
2703   "Read network news.
2704 If ARG is non-nil and a positive number, Gnus will use that as the
2705 startup level.  If ARG is non-nil and not a positive number, Gnus will
2706 prompt the user for the name of an NNTP server to use."
2707   (interactive "P")
2708   (gnus-1 arg dont-connect slave))
2709
2710 ;; Allow redefinition of Gnus functions.
2711
2712 (gnus-ems-redefine)
2713
2714 (provide 'gnus)
2715
2716 ;;; gnus.el ends here