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