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