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