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