*** 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.72"
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)
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)
652     ("nneething" none address prompt-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)
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-msg" (gnus-summary-send-map keymap)
1115       gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
1116      ("gnus-msg" :interactive t
1117       gnus-group-post-news gnus-group-mail gnus-summary-post-news
1118       gnus-summary-followup gnus-summary-followup-with-original
1119       gnus-summary-cancel-article gnus-summary-supersede-article
1120       gnus-post-news gnus-summary-reply gnus-summary-reply-with-original
1121       gnus-summary-mail-forward gnus-summary-mail-other-window
1122       gnus-summary-resend-message gnus-summary-resend-bounced-mail
1123       gnus-bug)
1124      ("gnus-picon" :interactive t gnus-article-display-picons
1125       gnus-group-display-picons gnus-picons-article-display-x-face
1126       gnus-picons-display-x-face)
1127      ("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p 
1128       gnus-grouplens-mode)
1129      ("smiley" :interactive t gnus-smiley-display)
1130      ("gnus-win" gnus-configure-windows)
1131      ("gnus-sum" gnus-summary-insert-line gnus-summary-read-group
1132       gnus-list-of-unread-articles gnus-list-of-read-articles
1133       gnus-offer-save-summaries gnus-make-thread-indent-array
1134       gnus-summary-exit gnus-update-read-articles)
1135      ("gnus-group" gnus-group-insert-group-line gnus-group-quit
1136       gnus-group-list-groups gnus-group-first-unread-group
1137       gnus-group-set-mode-line gnus-group-set-info gnus-group-save-newsrc
1138       gnus-group-setup-buffer gnus-group-get-new-news
1139       gnus-group-make-help-group gnus-group-update-group)
1140      ("gnus-bcklg" gnus-backlog-request-article gnus-backlog-enter-article
1141       gnus-backlog-remove-article)
1142      ("gnus-art" gnus-article-read-summary-keys gnus-article-save
1143       gnus-article-prepare gnus-article-set-window-start
1144       gnus-article-next-page gnus-article-prev-page
1145       gnus-request-article-this-buffer gnus-article-mode
1146       gnus-article-setup-buffer gnus-narrow-to-page)
1147      ("gnus-art" :interactive t
1148       gnus-article-hide-headers gnus-article-hide-boring-headers
1149       gnus-article-treat-overstrike gnus-article-word-wrap
1150       gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
1151       gnus-article-display-x-face gnus-article-de-quoted-unreadable
1152       gnus-article-mime-decode-quoted-printable gnus-article-hide-pgp
1153       gnus-article-hide-pem gnus-article-hide-signature
1154       gnus-article-strip-leading-blank-lines gnus-article-date-local
1155       gnus-article-date-original gnus-article-date-lapsed
1156       gnus-decode-rfc1522 gnus-article-show-all-headers
1157       gnus-article-edit-mode gnus-article-edit-article
1158       gnus-article-edit-done)
1159      ("gnus-int" gnus-request-type)
1160      ("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
1161       gnus-dribble-enter)
1162      ("gnus-dup" gnus-dup-suppress-articles gnus-dup-unsuppress-article
1163       gnus-dup-enter-articles)
1164      ("gnus-range" gnus-copy-sequence)
1165      ("gnus-eform" gnus-edit-form)
1166      ("gnus-move" :interactive t
1167       gnus-group-move-group-to-server gnus-change-server)
1168      ("gnus-logic" gnus-score-advanced)
1169      ("gnus-undo" gnus-undo-mode gnus-undo-register)
1170      ("gnus-async" gnus-async-request-fetched-article gnus-async-prefetch-next
1171       gnus-async-prefetch-article gnus-async-prefetch-remove-group
1172       gnus-async-halt-prefetch)
1173      ("article" article-decode-rfc1522)
1174      ("gnus-vm" :interactive t gnus-summary-save-in-vm
1175       gnus-summary-save-article-vm))))
1176
1177 ;;; gnus-sum.el thingies
1178
1179
1180 (defcustom gnus-summary-line-format "%U\%R\%z\%I\%(%[%4L: %-20,20n%]%) %s\n"
1181   "*The format specification of the lines in the summary buffer.
1182
1183 It works along the same lines as a normal formatting string,
1184 with some simple extensions.
1185
1186 %N   Article number, left padded with spaces (string)
1187 %S   Subject (string)
1188 %s   Subject if it is at the root of a thread, and \"\" otherwise (string)
1189 %n   Name of the poster (string)
1190 %a   Extracted name of the poster (string)
1191 %A   Extracted address of the poster (string)
1192 %F   Contents of the From: header (string)
1193 %x   Contents of the Xref: header (string)
1194 %D   Date of the article (string)
1195 %d   Date of the article (string) in DD-MMM format
1196 %M   Message-id of the article (string)
1197 %r   References of the article (string)
1198 %c   Number of characters in the article (integer)
1199 %L   Number of lines in the article (integer)
1200 %I   Indentation based on thread level (a string of spaces)
1201 %T   A string with two possible values: 80 spaces if the article
1202      is on thread level two or larger and 0 spaces on level one
1203 %R   \"A\" if this article has been replied to, \" \" otherwise (character)
1204 %U   Status of this article (character, \"R\", \"K\", \"-\" or \" \")
1205 %[   Opening bracket (character, \"[\" or \"<\")
1206 %]   Closing bracket (character, \"]\" or \">\")
1207 %>   Spaces of length thread-level (string)
1208 %<   Spaces of length (- 20 thread-level) (string)
1209 %i   Article score (number)
1210 %z   Article zcore (character)
1211 %t   Number of articles under the current thread (number).
1212 %e   Whether the thread is empty or not (character).
1213 %l   GroupLens score (string).
1214 %V   Total thread score (number).
1215 %P   The line number (number).
1216 %u   User defined specifier.  The next character in the format string should
1217      be a letter.  Gnus will call the function gnus-user-format-function-X,
1218      where X is the letter following %u.  The function will be passed the
1219      current header as argument.  The function should return a string, which
1220      will be inserted into the summary just like information from any other
1221      summary specifier.
1222
1223 Text between %( and %) will be highlighted with `gnus-mouse-face'
1224 when the mouse point is placed inside the area.  There can only be one
1225 such area.
1226
1227 The %U (status), %R (replied) and %z (zcore) specs have to be handled
1228 with care.  For reasons of efficiency, Gnus will compute what column
1229 these characters will end up in, and \"hard-code\" that.  This means that
1230 it is illegal to have these specs after a variable-length spec.  Well,
1231 you might not be arrested, but your summary buffer will look strange,
1232 which is bad enough.
1233
1234 The smart choice is to have these specs as for to the left as
1235 possible.
1236
1237 This restriction may disappear in later versions of Gnus."
1238   :type 'string
1239   :group 'gnus-summary)
1240
1241 ;;;
1242 ;;; Skeleton keymaps
1243 ;;;
1244
1245 (defun gnus-suppress-keymap (keymap)
1246   (suppress-keymap keymap)
1247   (let ((keys `([delete] "\177" "\M-u"))) ;gnus-mouse-2 
1248     (while keys
1249       (define-key keymap (pop keys) 'undefined))))
1250
1251 (defvar gnus-article-mode-map (make-keymap))
1252 (gnus-suppress-keymap gnus-article-mode-map)
1253 (defvar gnus-summary-mode-map (make-keymap))
1254 (gnus-suppress-keymap gnus-summary-mode-map)
1255 (defvar gnus-group-mode-map (make-keymap))
1256 (gnus-suppress-keymap gnus-group-mode-map)
1257
1258 \f
1259
1260 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
1261 ;; If you want the cursor to go somewhere else, set these two
1262 ;; functions in some startup hook to whatever you want.
1263 (defalias 'gnus-summary-position-point 'gnus-goto-colon)
1264 (defalias 'gnus-group-position-point 'gnus-goto-colon)
1265
1266 ;;; Various macros and substs.
1267
1268 (defun gnus-header-from (header)
1269   (mail-header-from header))
1270
1271 (defmacro gnus-gethash (string hashtable)
1272   "Get hash value of STRING in HASHTABLE."
1273   `(symbol-value (intern-soft ,string ,hashtable)))
1274
1275 (defmacro gnus-sethash (string value hashtable)
1276   "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
1277   `(set (intern ,string ,hashtable) ,value))
1278 (put 'gnus-sethash 'edebug-form-spec '(form form form))
1279
1280 (defmacro gnus-group-unread (group)
1281   "Get the currently computed number of unread articles in GROUP."
1282   `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
1283
1284 (defmacro gnus-group-entry (group)
1285   "Get the newsrc entry for GROUP."
1286   `(gnus-gethash ,group gnus-newsrc-hashtb))
1287
1288 (defmacro gnus-active (group)
1289   "Get active info on GROUP."
1290   `(gnus-gethash ,group gnus-active-hashtb))
1291
1292 (defmacro gnus-set-active (group active)
1293   "Set GROUP's active info."
1294   `(gnus-sethash ,group ,active gnus-active-hashtb))
1295
1296 (defun gnus-alive-p ()
1297   "Say whether Gnus is running or not."
1298   (and gnus-group-buffer
1299        (get-buffer gnus-group-buffer)
1300        (save-excursion
1301          (set-buffer gnus-group-buffer)
1302          (eq major-mode 'gnus-group-mode))))
1303
1304 ;; Info access macros.
1305
1306 (defmacro gnus-info-group (info)
1307   `(nth 0 ,info))
1308 (defmacro gnus-info-rank (info)
1309   `(nth 1 ,info))
1310 (defmacro gnus-info-read (info)
1311   `(nth 2 ,info))
1312 (defmacro gnus-info-marks (info)
1313   `(nth 3 ,info))
1314 (defmacro gnus-info-method (info)
1315   `(nth 4 ,info))
1316 (defmacro gnus-info-params (info)
1317   `(nth 5 ,info))
1318
1319 (defmacro gnus-info-level (info)
1320   `(let ((rank (gnus-info-rank ,info)))
1321      (if (consp rank)
1322          (car rank)
1323        rank)))
1324 (defmacro gnus-info-score (info)
1325   `(let ((rank (gnus-info-rank ,info)))
1326      (or (and (consp rank) (cdr rank)) 0)))
1327
1328 (defmacro gnus-info-set-group (info group)
1329   `(setcar ,info ,group))
1330 (defmacro gnus-info-set-rank (info rank)
1331   `(setcar (nthcdr 1 ,info) ,rank))
1332 (defmacro gnus-info-set-read (info read)
1333   `(setcar (nthcdr 2 ,info) ,read))
1334 (defmacro gnus-info-set-marks (info marks &optional extend)
1335   (if extend
1336       `(gnus-info-set-entry ,info ,marks 3)
1337     `(setcar (nthcdr 3 ,info) ,marks)))
1338 (defmacro gnus-info-set-method (info method &optional extend)
1339   (if extend
1340       `(gnus-info-set-entry ,info ,method 4)
1341     `(setcar (nthcdr 4 ,info) ,method)))
1342 (defmacro gnus-info-set-params (info params &optional extend)
1343   (if extend
1344       `(gnus-info-set-entry ,info ,params 5)
1345     `(setcar (nthcdr 5 ,info) ,params)))
1346
1347 (defun gnus-info-set-entry (info entry number)
1348   ;; Extend the info until we have enough elements.
1349   (while (<= (length info) number)
1350     (nconc info (list nil)))
1351   ;; Set the entry.
1352   (setcar (nthcdr number info) entry))
1353
1354 (defmacro gnus-info-set-level (info level)
1355   `(let ((rank (cdr ,info)))
1356      (if (consp (car rank))
1357          (setcar (car rank) ,level)
1358        (setcar rank ,level))))
1359 (defmacro gnus-info-set-score (info score)
1360   `(let ((rank (cdr ,info)))
1361      (if (consp (car rank))
1362          (setcdr (car rank) ,score)
1363        (setcar rank (cons (car rank) ,score)))))
1364
1365 (defmacro gnus-get-info (group)
1366   `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
1367
1368 ;; Byte-compiler warning.
1369 (defvar gnus-visual)
1370 ;; Find out whether the gnus-visual TYPE is wanted.
1371 (defun gnus-visual-p (&optional type class)
1372   (and gnus-visual                      ; Has to be non-nil, at least.
1373        (if (not type)                   ; We don't care about type.
1374            gnus-visual
1375          (if (listp gnus-visual)        ; It's a list, so we check it.
1376              (or (memq type gnus-visual)
1377                  (memq class gnus-visual))
1378            t))))
1379
1380 ;;; Load the compatability functions.
1381
1382 (require 'gnus-ems)
1383
1384 \f
1385 ;;;
1386 ;;; Shutdown
1387 ;;;
1388
1389 (defvar gnus-shutdown-alist nil)
1390
1391 (defun gnus-add-shutdown (function &rest symbols)
1392   "Run FUNCTION whenever one of SYMBOLS is shut down."
1393   (push (cons function symbols) gnus-shutdown-alist))
1394
1395 (defun gnus-shutdown (symbol)
1396   "Shut down everything that waits for SYMBOL."
1397   (let ((alist gnus-shutdown-alist)
1398         entry)
1399     (while (setq entry (pop alist))
1400       (when (memq symbol (cdr entry))
1401         (funcall (car entry))))))
1402
1403 \f
1404 ;;;
1405 ;;; Gnus Utility Functions
1406 ;;;
1407
1408 ;; Add the current buffer to the list of buffers to be killed on exit.
1409 (defun gnus-add-current-to-buffer-list ()
1410   (or (memq (current-buffer) gnus-buffer-list)
1411       (push (current-buffer) gnus-buffer-list)))
1412
1413 (defun gnus-version (&optional arg)
1414   "Version number of this version of Gnus.
1415 If ARG, insert string at point."
1416   (interactive "P")
1417   (let ((methods gnus-valid-select-methods)
1418         (mess gnus-version)
1419         meth)
1420     ;; Go through all the legal select methods and add their version
1421     ;; numbers to the total version string.  Only the backends that are
1422     ;; currently in use will have their message numbers taken into
1423     ;; consideration.
1424     (while methods
1425       (setq meth (intern (concat (caar methods) "-version")))
1426       (and (boundp meth)
1427            (stringp (symbol-value meth))
1428            (setq mess (concat mess "; " (symbol-value meth))))
1429       (setq methods (cdr methods)))
1430     (if arg
1431         (insert (message mess))
1432       (message mess))))
1433
1434 (defun gnus-continuum-version (version)
1435   "Return VERSION as a floating point number."
1436   (when (or (string-match "^\\([^ ]+\\)? ?Gnus v?\\([0-9.]+\\)$" version)
1437             (string-match "^\\(.?\\)gnus-\\([0-9.]+\\)$" version))
1438     (let* ((alpha (and (match-beginning 1) (match-string 1 version)))
1439            (number (match-string 2 version))
1440            major minor least)
1441       (string-match "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
1442       (setq major (string-to-number (match-string 1 number)))
1443       (setq minor (string-to-number (match-string 2 number)))
1444       (setq least (if (match-beginning 3)
1445                       (string-to-number (match-string 3 number))
1446                     0))
1447       (string-to-number
1448        (if (zerop major)
1449            (format "%s00%02d%02d"
1450                    (cond 
1451                     ((member alpha '("(ding)" "d")) "4.99")
1452                     ((member alpha '("September" "s")) "5.01")
1453                     ((member alpha '("Red" "r")) "5.03"))
1454                    minor least)
1455          (format "%d.%02d%02d" major minor least))))))
1456
1457 (defun gnus-info-find-node ()
1458   "Find Info documentation of Gnus."
1459   (interactive)
1460   ;; Enlarge info window if needed.
1461   (let (gnus-info-buffer)
1462     (Info-goto-node (cadr (assq major-mode gnus-info-nodes)))
1463     (setq gnus-info-buffer (current-buffer))
1464     (gnus-configure-windows 'info)))
1465
1466 ;;; More various functions.
1467
1468 (defun gnus-group-read-only-p (&optional group)
1469   "Check whether GROUP supports editing or not.
1470 If GROUP is nil, `gnus-newsgroup-name' will be checked instead.  Note
1471 that that variable is buffer-local to the summary buffers."
1472   (let ((group (or group gnus-newsgroup-name)))
1473     (not (gnus-check-backend-function 'request-replace-article group))))
1474
1475 (defun gnus-group-total-expirable-p (group)
1476   "Check whether GROUP is total-expirable or not."
1477   (let ((params (gnus-group-find-parameter group))
1478         val)
1479     (cond
1480      ((memq 'total-expire params)
1481       t)
1482      ((setq val (assq 'total-expire params)) ; (auto-expire . t)
1483       (cdr val))
1484      (gnus-total-expirable-newsgroups   ; Check var.
1485       (string-match gnus-total-expirable-newsgroups group)))))
1486
1487 (defun gnus-group-auto-expirable-p (group)
1488   "Check whether GROUP is total-expirable or not."
1489   (let ((params (gnus-group-find-parameter group))
1490         val)
1491     (cond
1492      ((memq 'auto-expire params)
1493       t)
1494      ((setq val (assq 'auto-expire params)) ; (auto-expire . t)
1495       (cdr val))
1496      (gnus-auto-expirable-newsgroups    ; Check var.
1497       (string-match gnus-auto-expirable-newsgroups group)))))
1498
1499 (defun gnus-virtual-group-p (group)
1500   "Say whether GROUP is virtual or not."
1501   (memq 'virtual (assoc (symbol-name (car (gnus-find-method-for-group group)))
1502                         gnus-valid-select-methods)))
1503
1504 (defun gnus-news-group-p (group &optional article)
1505   "Return non-nil if GROUP (and ARTICLE) come from a news server."
1506   (or (gnus-member-of-valid 'post group) ; Ordinary news group.
1507       (and (gnus-member-of-valid 'post-mail group) ; Combined group.
1508            (eq (gnus-request-type group article) 'news))))
1509
1510 ;; Returns a list of writable groups.
1511 (defun gnus-writable-groups ()
1512   (let ((alist gnus-newsrc-alist)
1513         groups group)
1514     (while (setq group (car (pop alist)))
1515       (unless (gnus-group-read-only-p group)
1516         (push group groups)))
1517     (nreverse groups)))
1518
1519 ;; Check whether to use long file names.
1520 (defun gnus-use-long-file-name (symbol)
1521   ;; The variable has to be set...
1522   (and gnus-use-long-file-name
1523        ;; If it isn't a list, then we return t.
1524        (or (not (listp gnus-use-long-file-name))
1525            ;; If it is a list, and the list contains `symbol', we
1526            ;; return nil.
1527            (not (memq symbol gnus-use-long-file-name)))))
1528
1529 ;; Generate a unique new group name.
1530 (defun gnus-generate-new-group-name (leaf)
1531   (let ((name leaf)
1532         (num 0))
1533     (while (gnus-gethash name gnus-newsrc-hashtb)
1534       (setq name (concat leaf "<" (int-to-string (setq num (1+ num))) ">")))
1535     name))
1536
1537 (defun gnus-ephemeral-group-p (group)
1538   "Say whether GROUP is ephemeral or not."
1539   (gnus-group-get-parameter group 'quit-config))
1540
1541 (defun gnus-group-quit-config (group)
1542   "Return the quit-config of GROUP."
1543   (gnus-group-get-parameter group 'quit-config))
1544
1545 (defun gnus-kill-ephemeral-group (group)
1546   "Remove ephemeral GROUP from relevant structures."
1547   (gnus-sethash group nil gnus-newsrc-hashtb))
1548
1549 (defun gnus-simplify-mode-line ()
1550   "Make mode lines a bit simpler."
1551   (setq mode-line-modified "-- ")
1552   (when (listp mode-line-format)
1553     (make-local-variable 'mode-line-format)
1554     (setq mode-line-format (copy-sequence mode-line-format))
1555     (when (equal (nth 3 mode-line-format) "   ")
1556       (setcar (nthcdr 3 mode-line-format) " "))))
1557
1558 ;;; Servers and groups.
1559
1560 (defsubst gnus-server-add-address (method)
1561   (let ((method-name (symbol-name (car method))))
1562     (if (and (memq 'address (assoc method-name gnus-valid-select-methods))
1563              (not (assq (intern (concat method-name "-address")) method)))
1564         (append method (list (list (intern (concat method-name "-address"))
1565                                    (nth 1 method))))
1566       method)))
1567
1568 (defsubst gnus-server-get-method (group method)
1569   ;; Input either a server name, and extended server name, or a
1570   ;; select method, and return a select method.
1571   (cond ((stringp method)
1572          (gnus-server-to-method method))
1573         ((equal method gnus-select-method)
1574          gnus-select-method)
1575         ((and (stringp (car method)) group)
1576          (gnus-server-extend-method group method))
1577         ((and method (not group)
1578               (equal (cadr method) ""))
1579          method)
1580         (t
1581          (gnus-server-add-address method))))
1582
1583 (defun gnus-server-to-method (server)
1584   "Map virtual server names to select methods."
1585   (or 
1586    ;; Is this a method, perhaps?
1587    (and server (listp server) server)
1588    ;; Perhaps this is the native server?
1589    (and (equal server "native") gnus-select-method)
1590    ;; It should be in the server alist.
1591    (cdr (assoc server gnus-server-alist))
1592    ;; It could be in the predefined server alist.
1593    (cdr (assoc server gnus-predefined-server-alist))
1594    ;; If not, we look through all the opened server
1595    ;; to see whether we can find it there.
1596    (let ((opened gnus-opened-servers))
1597      (while (and opened
1598                  (not (equal server (format "%s:%s" (caaar opened)
1599                                             (cadaar opened)))))
1600        (pop opened))
1601      (caar opened))))
1602
1603 (defmacro gnus-method-equal (ss1 ss2)
1604   "Say whether two servers are equal."
1605   `(let ((s1 ,ss1)
1606          (s2 ,ss2))
1607      (or (equal s1 s2)
1608          (and (= (length s1) (length s2))
1609               (progn
1610                 (while (and s1 (member (car s1) s2))
1611                   (setq s1 (cdr s1)))
1612                 (null s1))))))
1613
1614 (defun gnus-server-equal (m1 m2)
1615   "Say whether two methods are equal."
1616   (let ((m1 (cond ((null m1) gnus-select-method)
1617                   ((stringp m1) (gnus-server-to-method m1))
1618                   (t m1)))
1619         (m2 (cond ((null m2) gnus-select-method)
1620                   ((stringp m2) (gnus-server-to-method m2))
1621                   (t m2))))
1622     (gnus-method-equal m1 m2)))
1623
1624 (defun gnus-servers-using-backend (backend)
1625   "Return a list of known servers using BACKEND."
1626   (let ((opened gnus-opened-servers)
1627         out)
1628     (while opened
1629       (when (eq backend (caaar opened))
1630         (push (caar opened) out))
1631       (pop opened))
1632     out))
1633
1634 (defun gnus-archive-server-wanted-p ()
1635   "Say whether the user wants to use the archive server."
1636   (cond 
1637    ((or (not gnus-message-archive-method)
1638         (not gnus-message-archive-group))
1639     nil)
1640    ((and gnus-message-archive-method gnus-message-archive-group)
1641     t)
1642    (t
1643     (let ((active (cadr (assq 'nnfolder-active-file
1644                               gnus-message-archive-method))))
1645       (and active
1646            (file-exists-p active))))))
1647
1648 (defun gnus-group-prefixed-name (group method)
1649   "Return the whole name from GROUP and METHOD."
1650   (and (stringp method) (setq method (gnus-server-to-method method)))
1651   (if (not method)
1652       group
1653     (concat (format "%s" (car method))
1654             (when (and
1655                    (or (assoc (format "%s" (car method))
1656                               (gnus-methods-using 'address))
1657                        (gnus-server-equal method gnus-message-archive-method))
1658                    (nth 1 method)
1659                    (not (string= (nth 1 method) "")))
1660               (concat "+" (nth 1 method)))
1661             ":" group)))
1662
1663 (defun gnus-group-real-prefix (group)
1664   "Return the prefix of the current group name."
1665   (if (string-match "^[^:]+:" group)
1666       (substring group 0 (match-end 0))
1667     ""))
1668
1669 (defun gnus-group-method (group)
1670   "Return the server or method used for selecting GROUP."
1671   (let ((prefix (gnus-group-real-prefix group)))
1672     (if (equal prefix "")
1673         gnus-select-method
1674       (let ((servers gnus-opened-servers)
1675             (server "")
1676             backend possible found)
1677         (if (string-match "^[^\\+]+\\+" prefix)
1678             (setq backend (intern (substring prefix 0 (1- (match-end 0))))
1679                   server (substring prefix (match-end 0) (1- (length prefix))))
1680           (setq backend (intern (substring prefix 0 (1- (length prefix))))))
1681         (while servers
1682           (when (eq (caaar servers) backend)
1683             (setq possible (caar servers))
1684             (when (equal (cadaar servers) server)
1685               (setq found (caar servers))))
1686           (pop servers))
1687         (or (car (rassoc found gnus-server-alist))
1688             found
1689             (car (rassoc possible gnus-server-alist))
1690             possible
1691             (list backend server))))))
1692
1693 (defsubst gnus-secondary-method-p (method)
1694   "Return whether METHOD is a secondary select method."
1695   (let ((methods gnus-secondary-select-methods)
1696         (gmethod (gnus-server-get-method nil method)))
1697     (while (and methods
1698                 (not (equal (gnus-server-get-method nil (car methods))
1699                             gmethod)))
1700       (setq methods (cdr methods)))
1701     methods))
1702
1703 (defun gnus-group-foreign-p (group)
1704   "Say whether a group is foreign or not."
1705   (and (not (gnus-group-native-p group))
1706        (not (gnus-group-secondary-p group))))
1707
1708 (defun gnus-group-native-p (group)
1709   "Say whether the group is native or not."
1710   (not (string-match ":" group)))
1711
1712 (defun gnus-group-secondary-p (group)
1713   "Say whether the group is secondary or not."
1714   (gnus-secondary-method-p (gnus-find-method-for-group group)))
1715
1716 (defun gnus-group-find-parameter (group &optional symbol)
1717   "Return the group parameters for GROUP.
1718 If SYMBOL, return the value of that symbol in the group parameters."
1719   (save-excursion
1720     (set-buffer gnus-group-buffer)
1721     (let ((parameters (funcall gnus-group-get-parameter-function group)))
1722       (if symbol
1723           (gnus-group-parameter-value parameters symbol)
1724         parameters))))
1725
1726 (defun gnus-group-get-parameter (group &optional symbol)
1727   "Return the group parameters for GROUP.
1728 If SYMBOL, return the value of that symbol in the group parameters."
1729   (let ((params (gnus-info-params (gnus-get-info group))))
1730     (if symbol
1731         (gnus-group-parameter-value params symbol)
1732       params)))
1733
1734 (defun gnus-group-parameter-value (params symbol)
1735   "Return the value of SYMBOL in group PARAMS."
1736   (or (car (memq symbol params))        ; It's either a simple symbol
1737       (cdr (assq symbol params))))      ; or a cons.
1738
1739 (defun gnus-group-add-parameter (group param)
1740   "Add parameter PARAM to GROUP."
1741   (let ((info (gnus-get-info group)))
1742     (if (not info)
1743         ()                              ; This is a dead group.  We just ignore it.
1744       ;; Cons the new param to the old one and update.
1745       (gnus-group-set-info (cons param (gnus-info-params info))
1746                            group 'params))))
1747
1748 (defun gnus-group-set-parameter (group name value)
1749   "Set parameter NAME to VALUE in GROUP."
1750   (let ((info (gnus-get-info group)))
1751     (if (not info)
1752         ()                              ; This is a dead group.  We just ignore it.
1753       (let ((old-params (gnus-info-params info))
1754             (new-params (list (cons name value))))
1755         (while old-params
1756           (when (or (not (listp (car old-params)))
1757                     (not (eq (caar old-params) name)))
1758             (setq new-params (append new-params (list (car old-params)))))
1759           (setq old-params (cdr old-params)))
1760         (gnus-group-set-info new-params group 'params)))))
1761
1762 (defun gnus-group-add-score (group &optional score)
1763   "Add SCORE to the GROUP score.
1764 If SCORE is nil, add 1 to the score of GROUP."
1765   (let ((info (gnus-get-info group)))
1766     (when info
1767       (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
1768
1769 ;; Function written by Stainless Steel Rat <ratinox@peorth.gweep.net>
1770 (defun gnus-short-group-name (group &optional levels)
1771   "Collapse GROUP name LEVELS.
1772 Select methods are stripped and any remote host name is stripped down to
1773 just the host name."
1774   (let* ((name "") (foreign "") (depth -1) (skip 1)
1775          (levels (or levels
1776                      (progn
1777                        (while (string-match "\\." group skip)
1778                          (setq skip (match-end 0)
1779                                depth (+ depth 1)))
1780                        depth))))
1781     ;; separate foreign select method from group name and collapse.
1782     ;; if method contains a server, collapse to non-domain server name,
1783     ;; otherwise collapse to select method
1784     (when (string-match ":" group)
1785       (cond ((string-match "+" group)
1786              (let* ((plus (string-match "+" group))
1787                     (colon (string-match ":" group (or plus 0)))
1788                     (dot (string-match "\\." group)))
1789                (setq foreign (concat
1790                               (substring group (+ 1 plus)
1791                                          (cond ((null dot) colon)
1792                                                ((< colon dot) colon)
1793                                                ((< dot colon) dot)))
1794                               ":")
1795                      group (substring group (+ 1 colon)))))
1796             (t
1797              (let* ((colon (string-match ":" group)))
1798                (setq foreign (concat (substring group 0 (+ 1 colon)))
1799                      group (substring group (+ 1 colon)))))))
1800     ;; collapse group name leaving LEVELS uncollapsed elements
1801     (while group
1802       (if (and (string-match "\\." group) (> levels 0))
1803           (setq name (concat name (substring group 0 1))
1804                 group (substring group (match-end 0))
1805                 levels (- levels 1)
1806                 name (concat name "."))
1807         (setq name (concat foreign name group)
1808               group nil)))
1809     name))
1810
1811 \f
1812 ;;;
1813 ;;; Kill file handling.
1814 ;;;
1815
1816 (defun gnus-apply-kill-file ()
1817   "Apply a kill file to the current newsgroup.
1818 Returns the number of articles marked as read."
1819   (if (or (file-exists-p (gnus-newsgroup-kill-file nil))
1820           (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
1821       (gnus-apply-kill-file-internal)
1822     0))
1823
1824 (defun gnus-kill-save-kill-buffer ()
1825   (let ((file (gnus-newsgroup-kill-file gnus-newsgroup-name)))
1826     (when (get-file-buffer file)
1827       (save-excursion
1828         (set-buffer (get-file-buffer file))
1829         (when (buffer-modified-p)
1830           (save-buffer))
1831         (kill-buffer (current-buffer))))))
1832
1833 (defcustom gnus-kill-file-name "KILL"
1834   "Suffix of the kill files."
1835   :group 'gnus-score
1836   :type 'string)
1837
1838 (defun gnus-newsgroup-kill-file (newsgroup)
1839   "Return the name of a kill file name for NEWSGROUP.
1840 If NEWSGROUP is nil, return the global kill file name instead."
1841   (cond 
1842    ;; The global KILL file is placed at top of the directory.
1843    ((or (null newsgroup)
1844         (string-equal newsgroup ""))
1845     (expand-file-name gnus-kill-file-name
1846                       gnus-kill-files-directory))
1847    ;; Append ".KILL" to newsgroup name.
1848    ((gnus-use-long-file-name 'not-kill)
1849     (expand-file-name (concat (gnus-newsgroup-savable-name newsgroup)
1850                               "." gnus-kill-file-name)
1851                       gnus-kill-files-directory))
1852    ;; Place "KILL" under the hierarchical directory.
1853    (t
1854     (expand-file-name (concat (gnus-newsgroup-directory-form newsgroup)
1855                               "/" gnus-kill-file-name)
1856                       gnus-kill-files-directory))))
1857
1858 ;;; Server things.
1859
1860 (defun gnus-member-of-valid (symbol group)
1861   "Find out if GROUP has SYMBOL as part of its \"valid\" spec."
1862   (memq symbol (assoc
1863                 (symbol-name (car (gnus-find-method-for-group group)))
1864                 gnus-valid-select-methods)))
1865
1866 (defun gnus-method-option-p (method option)
1867   "Return non-nil if select METHOD has OPTION as a parameter."
1868   (when (stringp method)
1869     (setq method (gnus-server-to-method method)))
1870   (memq option (assoc (format "%s" (car method))
1871                       gnus-valid-select-methods)))
1872
1873 (defun gnus-server-extend-method (group method)
1874   ;; This function "extends" a virtual server.  If the server is
1875   ;; "hello", and the select method is ("hello" (my-var "something"))
1876   ;; in the group "alt.alt", this will result in a new virtual server
1877   ;; called "hello+alt.alt".
1878   (let ((entry
1879          (gnus-copy-sequence
1880           (if (gnus-server-equal method gnus-select-method) gnus-select-method
1881             (cdr (assoc (car method) gnus-server-alist))))))
1882     (if (not entry)
1883         method
1884       (setcar (cdr entry) (concat (nth 1 entry) "+" group))
1885       (nconc entry (cdr method)))))
1886
1887 (defun gnus-server-status (method)
1888   "Return the status of METHOD."
1889   (nth 1 (assoc method gnus-opened-servers)))
1890
1891 (defun gnus-group-name-to-method (group)
1892   "Return a select method suitable for GROUP."
1893   (if (string-match ":" group)
1894       (let ((server (substring group 0 (match-beginning 0))))
1895         (if (string-match "\\+" server)
1896             (list (intern (substring server 0 (match-beginning 0)))
1897                   (substring server (match-end 0)))
1898           (list (intern server) "")))
1899     gnus-select-method))
1900
1901 (defun gnus-find-method-for-group (group &optional info)
1902   "Find the select method that GROUP uses."
1903   (or gnus-override-method
1904       (and (not group)
1905            gnus-select-method)
1906       (let ((info (or info (gnus-get-info group)))
1907             method)
1908         (if (or (not info)
1909                 (not (setq method (gnus-info-method info)))
1910                 (equal method "native"))
1911             gnus-select-method
1912           (setq method
1913                 (cond ((stringp method)
1914                        (gnus-server-to-method method))
1915                       ((stringp (car method))
1916                        (gnus-server-extend-method group method))
1917                       (t
1918                        method)))
1919           (cond ((equal (cadr method) "")
1920                  method)
1921                 ((null (cadr method))
1922                  (list (car method) ""))
1923                 (t
1924                  (gnus-server-add-address method)))))))
1925
1926 (defun gnus-check-backend-function (func group)
1927   "Check whether GROUP supports function FUNC."
1928   (ignore-errors
1929     (let ((method (if (stringp group)
1930                       (car (gnus-find-method-for-group group))
1931                     group)))
1932       (unless (featurep method)
1933         (require method))
1934       (fboundp (intern (format "%s-%s" method func))))))
1935
1936 (defun gnus-methods-using (feature)
1937   "Find all methods that have FEATURE."
1938   (let ((valids gnus-valid-select-methods)
1939         outs)
1940     (while valids
1941       (when (memq feature (car valids))
1942         (push (car valids) outs))
1943       (setq valids (cdr valids)))
1944     outs))
1945
1946 (defun gnus-read-group (prompt)
1947   "Prompt the user for a group name.
1948 Disallow illegal group names."
1949   (let ((prefix "")
1950         group)
1951     (while (not group)
1952       (when (string-match
1953              "[: `'\"/]\\|^$"
1954              (setq group (read-string (concat prefix prompt)
1955                                       "" 'gnus-group-history)))
1956         (setq prefix (format "Illegal group name: \"%s\".  " group)
1957               group nil)))
1958     group))
1959
1960 (defun gnus-read-method (prompt)
1961   "Prompt the user for a method.
1962 Allow completion over sensible values."
1963   (let ((method
1964          (completing-read
1965           prompt (append gnus-valid-select-methods gnus-predefined-server-alist
1966                          gnus-server-alist)
1967           nil t nil 'gnus-method-history)))
1968     (cond 
1969      ((equal method "")
1970       (setq method gnus-select-method))
1971      ((assoc method gnus-valid-select-methods)
1972       (list (intern method)
1973             (if (memq 'prompt-address
1974                       (assoc method gnus-valid-select-methods))
1975                 (read-string "Address: ")
1976               "")))
1977      ((assoc method gnus-server-alist)
1978       method)
1979      (t
1980       (list (intern method) "")))))
1981
1982 ;;; User-level commands.
1983
1984 ;;;###autoload
1985 (defun gnus-slave-no-server (&optional arg)
1986   "Read network news as a slave, without connecting to local server"
1987   (interactive "P")
1988   (gnus-no-server arg t))
1989
1990 ;;;###autoload
1991 (defun gnus-no-server (&optional arg slave)
1992   "Read network news.
1993 If ARG is a positive number, Gnus will use that as the
1994 startup level.  If ARG is nil, Gnus will be started at level 2.
1995 If ARG is non-nil and not a positive number, Gnus will
1996 prompt the user for the name of an NNTP server to use.
1997 As opposed to `gnus', this command will not connect to the local server."
1998   (interactive "P")
1999   (gnus-no-server-1 arg slave))
2000
2001 ;;;###autoload
2002 (defun gnus-slave (&optional arg)
2003   "Read news as a slave."
2004   (interactive "P")
2005   (gnus arg nil 'slave))
2006
2007 ;;;###autoload
2008 (defun gnus-other-frame (&optional arg)
2009   "Pop up a frame to read news."
2010   (interactive "P")
2011   (let ((window (get-buffer-window gnus-group-buffer)))
2012     (cond (window
2013            (select-frame (window-frame window)))
2014           ((= (length (frame-list)) 1)
2015            (select-frame (make-frame)))
2016           (t
2017            (other-frame 1))))
2018   (gnus arg))
2019
2020 ;;;###autoload
2021 (defun gnus (&optional arg dont-connect slave)
2022   "Read network news.
2023 If ARG is non-nil and a positive number, Gnus will use that as the
2024 startup level.  If ARG is non-nil and not a positive number, Gnus will
2025 prompt the user for the name of an NNTP server to use."
2026   (interactive "P")
2027   (gnus-1 arg dont-connect slave))
2028
2029 ;; Allow redefinition of Gnus functions.
2030
2031 (gnus-ems-redefine)
2032
2033 (provide 'gnus)
2034
2035 ;;; gnus.el ends here