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