02113fb26e9638b057891746449038be1d95768b
[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 'mail-utils)
32 (require 'timezone)
33 (require 'nnheader)
34 (require 'message)
35 (require 'nnmail)
36
37 (eval-when-compile (require 'cl))
38
39 (defvar gnus-directory (or (getenv "SAVEDIR") "~/News/")
40   "*Directory variable from which all other Gnus file variables are derived.")
41
42 ;; Site dependent variables.  These variables should be defined in
43 ;; paths.el.
44
45 (defvar gnus-default-nntp-server nil
46   "Specify a default NNTP server.
47 This variable should be defined in paths.el, and should never be set
48 by the user.
49 If you want to change servers, you should use `gnus-select-method'.
50 See the documentation to that variable.")
51
52 (defvar gnus-backup-default-subscribed-newsgroups
53   '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
54   "Default default new newsgroups the first time Gnus is run.
55 Should be set in paths.el, and shouldn't be touched by the user.")
56
57 (defvar gnus-local-domain nil
58   "Local domain name without a host name.
59 The DOMAINNAME environment variable is used instead if it is defined.
60 If the `system-name' function returns the full Internet name, there is
61 no need to set this variable.")
62
63 (defvar gnus-local-organization nil
64   "String with a description of what organization (if any) the user belongs to.
65 The ORGANIZATION environment variable is used instead if it is defined.
66 If this variable contains a function, this function will be called
67 with the current newsgroup name as the argument.  The function should
68 return a string.
69
70 In any case, if the string (either in the variable, in the environment
71 variable, or returned by the function) is a file name, the contents of
72 this file will be used as the organization.")
73
74 ;; Customization variables
75
76 ;; Don't touch this variable.
77 (defvar gnus-nntp-service "nntp"
78   "*NNTP service name (\"nntp\" or 119).
79 This is an obsolete variable, which is scarcely used.  If you use an
80 nntp server for your newsgroup and want to change the port number
81 used to 899, you would say something along these lines:
82
83  (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
84
85 (defvar gnus-nntpserver-file "/etc/nntpserver"
86   "*A file with only the name of the nntp server in it.")
87
88 ;; This function is used to check both the environment variable
89 ;; NNTPSERVER and the /etc/nntpserver file to see whether one can find
90 ;; an nntp server name default.
91 (defun gnus-getenv-nntpserver ()
92   (or (getenv "NNTPSERVER")
93       (and (file-readable-p gnus-nntpserver-file)
94            (save-excursion
95              (set-buffer (get-buffer-create " *gnus nntp*"))
96              (buffer-disable-undo (current-buffer))
97              (insert-file-contents gnus-nntpserver-file)
98              (let ((name (buffer-string)))
99                (prog1
100                    (if (string-match "^[ \t\n]*$" name)
101                        nil
102                      name)
103                  (kill-buffer (current-buffer))))))))
104
105 (defvar gnus-select-method
106   (nconc
107    (list 'nntp (or (condition-case ()
108                        (gnus-getenv-nntpserver)
109                      (error nil))
110                    (if (and gnus-default-nntp-server
111                             (not (string= gnus-default-nntp-server "")))
112                        gnus-default-nntp-server)
113                    (system-name)))
114    (if (or (null gnus-nntp-service)
115            (equal gnus-nntp-service "nntp"))
116        nil
117      (list gnus-nntp-service)))
118   "*Default method for selecting a newsgroup.
119 This variable should be a list, where the first element is how the
120 news is to be fetched, the second is the address.
121
122 For instance, if you want to get your news via NNTP from
123 \"flab.flab.edu\", you could say:
124
125 (setq gnus-select-method '(nntp \"flab.flab.edu\"))
126
127 If you want to use your local spool, say:
128
129 (setq gnus-select-method (list 'nnspool (system-name)))
130
131 If you use this variable, you must set `gnus-nntp-server' to nil.
132
133 There is a lot more to know about select methods and virtual servers -
134 see the manual for details.")
135
136 (defvar gnus-message-archive-method 
137   `(nnfolder
138     "archive"
139     (nnfolder-directory ,(nnheader-concat message-directory "archive"))
140     (nnfolder-active-file 
141      ,(nnheader-concat message-directory "archive/active"))
142     (nnfolder-get-new-mail nil)
143     (nnfolder-inhibit-expiry t))
144   "*Method used for archiving messages you've sent.
145 This should be a mail method.")
146
147 (defvar gnus-refer-article-method nil
148   "*Preferred method for fetching an article by Message-ID.
149 If you are reading news from the local spool (with nnspool), fetching
150 articles by Message-ID is painfully slow.  By setting this method to an
151 nntp method, you might get acceptable results.
152
153 The value of this variable must be a valid select method as discussed
154 in the documentation of `gnus-select-method'.")
155
156 (defvar gnus-secondary-select-methods nil
157   "*A list of secondary methods that will be used for reading news.
158 This is a list where each element is a complete select method (see
159 `gnus-select-method').
160
161 If, for instance, you want to read your mail with the nnml backend,
162 you could set this variable:
163
164 (setq gnus-secondary-select-methods '((nnml \"\")))")
165
166 (defvar gnus-secondary-servers nil
167   "*List of NNTP servers that the user can choose between interactively.
168 To make Gnus query you for a server, you have to give `gnus' a
169 non-numeric prefix - `C-u M-x gnus', in short.")
170
171 (defvar gnus-nntp-server nil
172   "*The name of the host running the NNTP server.
173 This variable is semi-obsolete.  Use the `gnus-select-method'
174 variable instead.")
175
176 (defvar gnus-startup-file "~/.newsrc"
177   "*Your `.newsrc' file.
178 `.newsrc-SERVER' will be used instead if that exists.")
179
180 (defvar gnus-init-file "~/.gnus"
181   "*Your Gnus elisp startup file.
182 If a file with the .el or .elc suffixes exist, it will be read
183 instead.")
184
185 (defvar gnus-group-faq-directory
186   '("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
187     "/ftp@sunsite.auc.dk:/pub/usenet/"
188     "/ftp@src.doc.ic.ac.uk:/usenet/news-FAQS/"
189     "/ftp@ftp.seas.gwu.edu:/pub/rtfm/"
190     "/ftp@rtfm.mit.edu:/pub/usenet/"
191     "/ftp@ftp.uni-paderborn.de:/pub/FAQ/"
192     "/ftp@ftp.sunet.se:/pub/usenet/"
193     "/ftp@nctuccca.edu.tw:/USENET/FAQ/"
194     "/ftp@hwarang.postech.ac.kr:/pub/usenet/"
195     "/ftp@ftp.hk.super.net:/mirror/faqs/")
196   "*Directory where the group FAQs are stored.
197 This will most commonly be on a remote machine, and the file will be
198 fetched by ange-ftp.
199
200 This variable can also be a list of directories.  In that case, the
201 first element in the list will be used by default, and the others will
202 be used as backup sites.
203
204 Note that Gnus uses an aol machine as the default directory.  If this
205 feels fundamentally unclean, just think of it as a way to finally get
206 something of value back from them.
207
208 If the default site is too slow, try one of these:
209
210    North America: mirrors.aol.com                /pub/rtfm/usenet
211                   ftp.seas.gwu.edu               /pub/rtfm
212                   rtfm.mit.edu                   /pub/usenet
213    Europe:        ftp.uni-paderborn.de           /pub/FAQ
214                   src.doc.ic.ac.uk               /usenet/news-FAQS
215                   ftp.sunet.se                   /pub/usenet
216                   sunsite.auc.dk                 /pub/usenet
217    Asia:          nctuccca.edu.tw                /USENET/FAQ
218                   hwarang.postech.ac.kr          /pub/usenet
219                   ftp.hk.super.net               /mirror/faqs")
220
221 (defvar gnus-group-archive-directory
222   "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
223   "*The address of the (ding) archives.")
224
225 (defvar gnus-group-recent-archive-directory
226   "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
227   "*The address of the most recent (ding) articles.")
228
229 (defvar gnus-default-subscribed-newsgroups nil
230   "*This variable lists what newsgroups should be subscribed the first time Gnus is used.
231 It should be a list of strings.
232 If it is `t', Gnus will not do anything special the first time it is
233 started; it'll just use the normal newsgroups subscription methods.")
234
235 (defvar gnus-use-cross-reference t
236   "*Non-nil means that cross referenced articles will be marked as read.
237 If nil, ignore cross references.  If t, mark articles as read in
238 subscribed newsgroups.  If neither t nor nil, mark as read in all
239 newsgroups.")
240
241 (defvar gnus-single-article-buffer t
242   "*If non-nil, display all articles in the same buffer.
243 If nil, each group will get its own article buffer.")
244
245 (defvar gnus-use-dribble-file t
246   "*Non-nil means that Gnus will use a dribble file to store user updates.
247 If Emacs should crash without saving the .newsrc files, complete
248 information can be restored from the dribble file.")
249
250 (defvar gnus-dribble-directory nil
251   "*The directory where dribble files will be saved.
252 If this variable is nil, the directory where the .newsrc files are
253 saved will be used.")
254
255 (defvar gnus-asynchronous nil
256   "*If non-nil, Gnus will supply backends with data needed for async article fetching.")
257
258 (defvar gnus-kill-summary-on-exit t
259   "*If non-nil, kill the summary buffer when you exit from it.
260 If nil, the summary will become a \"*Dead Summary*\" buffer, and
261 it will be killed sometime later.")
262
263 (defvar gnus-large-newsgroup 200
264   "*The number of articles which indicates a large newsgroup.
265 If the number of articles in a newsgroup is greater than this value,
266 confirmation is required for selecting the newsgroup.")
267
268 ;; Suggested by Andrew Eskilsson <pi92ae@lelle.pt.hk-r.se>.
269 (defvar gnus-no-groups-message "No news is horrible news"
270   "*Message displayed by Gnus when no groups are available.")
271
272 (defvar gnus-use-long-file-name (not (memq system-type '(usg-unix-v xenix)))
273   "*Non-nil means that the default name of a file to save articles in is the group name.
274 If it's nil, the directory form of the group name is used instead.
275
276 If this variable is a list, and the list contains the element
277 `not-score', long file names will not be used for score files; if it
278 contains the element `not-save', long file names will not be used for
279 saving; and if it contains the element `not-kill', long file names
280 will not be used for kill files.")
281
282 (defvar gnus-article-save-directory gnus-directory
283   "*Name of the directory articles will be saved in (default \"~/News\").")
284
285 (defvar gnus-kill-files-directory gnus-directory
286   "*Name of the directory where kill files will be stored (default \"~/News\").")
287
288 (defvar gnus-default-article-saver 'gnus-summary-save-in-rmail
289   "*A function to save articles in your favorite format.
290 The function must be interactively callable (in other words, it must
291 be an Emacs command).
292
293 Gnus provides the following functions:
294
295 * gnus-summary-save-in-rmail (Rmail format)
296 * gnus-summary-save-in-mail (Unix mail format)
297 * gnus-summary-save-in-folder (MH folder)
298 * gnus-summary-save-in-file (article format).
299 * gnus-summary-save-in-vm (use VM's folder format).")
300
301 (defvar gnus-prompt-before-saving 'always
302   "*This variable says how much prompting is to be done when saving articles.
303 If it is nil, no prompting will be done, and the articles will be
304 saved to the default files.  If this variable is `always', each and
305 every article that is saved will be preceded by a prompt, even when
306 saving large batches of articles.  If this variable is neither nil not
307 `always', there the user will be prompted once for a file name for
308 each invocation of the saving commands.")
309
310 (defvar gnus-rmail-save-name (function gnus-plain-save-name)
311   "*A function generating a file name to save articles in Rmail format.
312 The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
313
314 (defvar gnus-mail-save-name (function gnus-plain-save-name)
315   "*A function generating a file name to save articles in Unix mail format.
316 The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE.")
317
318 (defvar gnus-folder-save-name (function gnus-folder-save-name)
319   "*A function generating a file name to save articles in MH folder.
320 The function is called with NEWSGROUP, HEADERS, and optional LAST-FOLDER.")
321
322 (defvar gnus-file-save-name (function gnus-numeric-save-name)
323   "*A function generating a file name to save articles in article format.
324 The function is called with NEWSGROUP, HEADERS, and optional
325 LAST-FILE.")
326
327 (defvar gnus-split-methods
328   '((gnus-article-archive-name))
329   "*Variable used to suggest where articles are to be saved.
330 For instance, if you would like to save articles related to Gnus in
331 the file \"gnus-stuff\", and articles related to VM in \"vm-stuff\",
332 you could set this variable to something like:
333
334  '((\"^Subject:.*gnus\\|^Newsgroups:.*gnus\" \"gnus-stuff\")
335    (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))
336
337 This variable is an alist where the where the key is the match and the
338 value is a list of possible files to save in if the match is non-nil.
339
340 If the match is a string, it is used as a regexp match on the
341 article.  If the match is a symbol, that symbol will be funcalled
342 from the buffer of the article to be saved with the newsgroup as the
343 parameter.  If it is a list, it will be evaled in the same buffer.
344
345 If this form or function returns a string, this string will be used as
346 a possible file name; and if it returns a non-nil list, that list will
347 be used as possible file names.")
348
349 (defvar gnus-move-split-methods nil
350   "*Variable used to suggest where articles are to be moved to.
351 It uses the same syntax as the `gnus-split-methods' variable.")
352
353 (defvar gnus-save-score nil
354   "*If non-nil, save group scoring info.")
355
356 (defvar gnus-use-adaptive-scoring nil
357   "*If non-nil, use some adaptive scoring scheme.")
358
359 (defvar gnus-use-cache 'passive
360   "*If nil, Gnus will ignore the article cache.
361 If `passive', it will allow entering (and reading) articles
362 explicitly entered into the cache.  If anything else, use the
363 cache to the full extent of the law.")
364
365 (defvar gnus-use-trees nil
366   "*If non-nil, display a thread tree buffer.")
367
368 (defvar gnus-use-grouplens nil
369   "*If non-nil, use GroupLens ratings.")
370
371 (defvar gnus-keep-backlog nil
372   "*If non-nil, Gnus will keep read articles for later re-retrieval.
373 If it is a number N, then Gnus will only keep the last N articles
374 read.  If it is neither nil nor a number, Gnus will keep all read
375 articles.  This is not a good idea.")
376
377 (defvar gnus-use-nocem nil
378   "*If non-nil, Gnus will read NoCeM cancel messages.")
379
380 (defvar gnus-use-demon nil
381   "If non-nil, Gnus might use some demons.")
382
383 (defvar gnus-use-scoring t
384   "*If non-nil, enable scoring.")
385
386 (defvar gnus-use-picons nil
387   "*If non-nil, display picons.")
388
389 (defvar gnus-fetch-old-headers nil
390   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
391 If an unread article in the group refers to an older, already read (or
392 just marked as read) article, the old article will not normally be
393 displayed in the Summary buffer.  If this variable is non-nil, Gnus
394 will attempt to grab the headers to the old articles, and thereby
395 build complete threads.  If it has the value `some', only enough
396 headers to connect otherwise loose threads will be displayed.
397 This variable can also be a number.  In that case, no more than that
398 number of old headers will be fetched.
399
400 The server has to support NOV for any of this to work.")
401
402 ;see gnus-cus.el
403 ;(defvar gnus-visual t
404 ;  "*If non-nil, will do various highlighting.
405 ;If nil, no mouse highlights (or any other highlights) will be
406 ;performed.  This might speed up Gnus some when generating large group
407 ;and summary buffers.")
408
409 (defvar gnus-novice-user t
410   "*Non-nil means that you are a usenet novice.
411 If non-nil, verbose messages may be displayed and confirmations may be
412 required.")
413
414 (defvar gnus-expert-user nil
415   "*Non-nil means that you will never be asked for confirmation about anything.
416 And that means *anything*.")
417
418 (defvar gnus-verbose 7
419   "*Integer that says how verbose Gnus should be.
420 The higher the number, the more messages Gnus will flash to say what
421 it's doing.  At zero, Gnus will be totally mute; at five, Gnus will
422 display most important messages; and at ten, Gnus will keep on
423 jabbering all the time.")
424
425 (defvar gnus-keep-same-level nil
426   "*Non-nil means that the next newsgroup after the current will be on the same level.
427 When you type, for instance, `n' after reading the last article in the
428 current newsgroup, you will go to the next newsgroup.  If this variable
429 is nil, the next newsgroup will be the next from the group
430 buffer.
431 If this variable is non-nil, Gnus will either put you in the
432 next newsgroup with the same level, or, if no such newsgroup is
433 available, the next newsgroup with the lowest possible level higher
434 than the current level.
435 If this variable is `best', Gnus will make the next newsgroup the one
436 with the best level.")
437
438 (defvar gnus-summary-make-false-root 'adopt
439   "*nil means that Gnus won't gather loose threads.
440 If the root of a thread has expired or been read in a previous
441 session, the information necessary to build a complete thread has been
442 lost.  Instead of having many small sub-threads from this original thread
443 scattered all over the summary buffer, Gnus can gather them.
444
445 If non-nil, Gnus will try to gather all loose sub-threads from an
446 original thread into one large thread.
447
448 If this variable is non-nil, it should be one of `none', `adopt',
449 `dummy' or `empty'.
450
451 If this variable is `none', Gnus will not make a false root, but just
452 present the sub-threads after another.
453 If this variable is `dummy', Gnus will create a dummy root that will
454 have all the sub-threads as children.
455 If this variable is `adopt', Gnus will make one of the \"children\"
456 the parent and mark all the step-children as such.
457 If this variable is `empty', the \"children\" are printed with empty
458 subject fields.  (Or rather, they will be printed with a string
459 given by the `gnus-summary-same-subject' variable.)")
460
461 (defvar gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
462   "*A regexp to match subjects to be excluded from loose thread gathering.
463 As loose thread gathering is done on subjects only, that means that
464 there can be many false gatherings performed.  By rooting out certain
465 common subjects, gathering might become saner.")
466
467 (defvar gnus-summary-gather-subject-limit nil
468   "*Maximum length of subject comparisons when gathering loose threads.
469 Use nil to compare full subjects.  Setting this variable to a low
470 number will help gather threads that have been corrupted by
471 newsreaders chopping off subject lines, but it might also mean that
472 unrelated articles that have subject that happen to begin with the
473 same few characters will be incorrectly gathered.
474
475 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
476 comparing subjects.")
477
478 (defvar gnus-simplify-ignored-prefixes nil
479   "*Regexp, matches for which are removed from subject lines when simplifying.")
480
481 (defvar gnus-build-sparse-threads nil
482   "*If non-nil, fill in the gaps in threads.
483 If `some', only fill in the gaps that are needed to tie loose threads
484 together.  If `more', fill in all leaf nodes that Gnus can find.  If
485 non-nil and non-`some', fill in all gaps that Gnus manages to guess.")
486
487 (defvar gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject
488   "Function used for gathering loose threads.
489 There are two pre-defined functions: `gnus-gather-threads-by-subject',
490 which only takes Subjects into consideration; and
491 `gnus-gather-threads-by-references', which compared the References
492 headers of the articles to find matches.")
493
494 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
495 (defvar gnus-summary-same-subject ""
496   "*String indicating that the current article has the same subject as the previous.
497 This variable will only be used if the value of
498 `gnus-summary-make-false-root' is `empty'.")
499
500 (defvar gnus-summary-goto-unread t
501   "*If non-nil, marking commands will go to the next unread article.
502 If `never', \\<gnus-summary-mode-map>\\[gnus-summary-next-page] will go to the next article,
503 whether it is read or not.")
504
505 (defvar gnus-group-goto-unread t
506   "*If non-nil, movement commands will go to the next unread and subscribed group.")
507
508 (defvar gnus-goto-next-group-when-activating t
509   "*If non-nil, the \\<gnus-group-mode-map>\\[gnus-group-get-new-news-this-group] command will advance point to the next group.")
510
511 (defvar gnus-check-new-newsgroups t
512   "*Non-nil means that Gnus will add new newsgroups at startup.
513 If this variable is `ask-server', Gnus will ask the server for new
514 groups since the last time it checked.  This means that the killed list
515 is no longer necessary, so you could set `gnus-save-killed-list' to
516 nil.
517
518 A variant is to have this variable be a list of select methods.  Gnus
519 will then use the `ask-server' method on all these select methods to
520 query for new groups from all those servers.
521
522 Eg.
523   (setq gnus-check-new-newsgroups
524         '((nntp \"some.server\") (nntp \"other.server\")))
525
526 If this variable is nil, then you have to tell Gnus explicitly to
527 check for new newsgroups with \\<gnus-group-mode-map>\\[gnus-find-new-newsgroups].")
528
529 (defvar gnus-check-bogus-newsgroups nil
530   "*Non-nil means that Gnus will check and remove bogus newsgroup at startup.
531 If this variable is nil, then you have to tell Gnus explicitly to
532 check for bogus newsgroups with \\<gnus-group-mode-map>\\[gnus-group-check-bogus-groups].")
533
534 (defvar gnus-read-active-file t
535   "*Non-nil means that Gnus will read the entire active file at startup.
536 If this variable is nil, Gnus will only know about the groups in your
537 `.newsrc' file.
538
539 If this variable is `some', Gnus will try to only read the relevant
540 parts of the active file from the server.  Not all servers support
541 this, and it might be quite slow with other servers, but this should
542 generally be faster than both the t and nil value.
543
544 If you set this variable to nil or `some', you probably still want to
545 be told about new newsgroups that arrive.  To do that, set
546 `gnus-check-new-newsgroups' to `ask-server'.  This may not work
547 properly with all servers.")
548
549 (defvar gnus-level-subscribed 5
550   "*Groups with levels less than or equal to this variable are subscribed.")
551
552 (defvar gnus-level-unsubscribed 7
553   "*Groups with levels less than or equal to this variable are unsubscribed.
554 Groups with levels less than `gnus-level-subscribed', which should be
555 less than this variable, are subscribed.")
556
557 (defvar gnus-level-zombie 8
558   "*Groups with this level are zombie groups.")
559
560 (defvar gnus-level-killed 9
561   "*Groups with this level are killed.")
562
563 (defvar gnus-level-default-subscribed 3
564   "*New subscribed groups will be subscribed at this level.")
565
566 (defvar gnus-level-default-unsubscribed 6
567   "*New unsubscribed groups will be unsubscribed at this level.")
568
569 (defvar gnus-activate-level (1+ gnus-level-subscribed)
570   "*Groups higher than this level won't be activated on startup.
571 Setting this variable to something log might save lots of time when
572 you have many groups that you aren't interested in.")
573
574 (defvar gnus-activate-foreign-newsgroups 4
575   "*If nil, Gnus will not check foreign newsgroups at startup.
576 If it is non-nil, it should be a number between one and nine.  Foreign
577 newsgroups that have a level lower or equal to this number will be
578 activated on startup.  For instance, if you want to active all
579 subscribed newsgroups, but not the rest, you'd set this variable to
580 `gnus-level-subscribed'.
581
582 If you subscribe to lots of newsgroups from different servers, startup
583 might take a while.  By setting this variable to nil, you'll save time,
584 but you won't be told how many unread articles there are in the
585 groups.")
586
587 (defvar gnus-save-newsrc-file t
588   "*Non-nil means that Gnus will save the `.newsrc' file.
589 Gnus always saves its own startup file, which is called
590 \".newsrc.eld\".  The file called \".newsrc\" is in a format that can
591 be readily understood by other newsreaders.  If you don't plan on
592 using other newsreaders, set this variable to nil to save some time on
593 exit.")
594
595 (defvar gnus-save-killed-list t
596   "*If non-nil, save the list of killed groups to the startup file.
597 If you set this variable to nil, you'll save both time (when starting
598 and quitting) and space (both memory and disk), but it will also mean
599 that Gnus has no record of which groups are new and which are old, so
600 the automatic new newsgroups subscription methods become meaningless.
601
602 You should always set `gnus-check-new-newsgroups' to `ask-server' or
603 nil if you set this variable to nil.")
604
605 (defvar gnus-interactive-catchup t
606   "*If non-nil, require your confirmation when catching up a group.")
607
608 (defvar gnus-interactive-exit t
609   "*If non-nil, require your confirmation when exiting Gnus.")
610
611 (defvar gnus-kill-killed t
612   "*If non-nil, Gnus will apply kill files to already killed articles.
613 If it is nil, Gnus will never apply kill files to articles that have
614 already been through the scoring process, which might very well save lots
615 of time.")
616
617 (defvar gnus-extract-address-components 'gnus-extract-address-components
618   "*Function for extracting address components from a From header.
619 Two pre-defined function exist: `gnus-extract-address-components',
620 which is the default, quite fast, and too simplistic solution, and
621 `mail-extract-address-components', which works much better, but is
622 slower.")
623
624 (defvar gnus-summary-default-score 0
625   "*Default article score level.
626 If this variable is nil, scoring will be disabled.")
627
628 (defvar gnus-summary-zcore-fuzz 0
629   "*Fuzziness factor for the zcore in the summary buffer.
630 Articles with scores closer than this to `gnus-summary-default-score'
631 will not be marked.")
632
633 (defvar gnus-simplify-subject-fuzzy-regexp nil
634   "*Strings to be removed when doing fuzzy matches.
635 This can either be a regular expression or list of regular expressions
636 that will be removed from subject strings if fuzzy subject
637 simplification is selected.")
638
639 (defvar gnus-permanently-visible-groups nil
640   "*Regexp to match groups that should always be listed in the group buffer.
641 This means that they will still be listed when there are no unread
642 articles in the groups.")
643
644 (defvar gnus-list-groups-with-ticked-articles t
645   "*If non-nil, list groups that have only ticked articles.
646 If nil, only list groups that have unread articles.")
647
648 (defvar gnus-group-default-list-level gnus-level-subscribed
649   "*Default listing level.
650 Ignored if `gnus-group-use-permanent-levels' is non-nil.")
651
652 (defvar gnus-group-use-permanent-levels nil
653   "*If non-nil, once you set a level, Gnus will use this level.")
654
655 (defvar gnus-group-list-inactive-groups t
656   "*If non-nil, inactive groups will be listed.")
657
658 (defvar gnus-show-mime nil
659   "*If non-nil, do mime processing of articles.
660 The articles will simply be fed to the function given by
661 `gnus-show-mime-method'.")
662
663 (defvar gnus-strict-mime t
664   "*If nil, MIME-decode even if there is no Mime-Version header in the article.")
665
666 (defvar gnus-show-mime-method 'metamail-buffer
667   "*Function to process a MIME message.
668 The function is called from the article buffer.")
669
670 (defvar gnus-decode-encoded-word-method (lambda ())
671   "*Function to decode a MIME encoded-words.
672 The function is called from the article buffer.")
673
674 (defvar gnus-show-threads t
675   "*If non-nil, display threads in summary mode.")
676
677 (defvar gnus-thread-hide-subtree nil
678   "*If non-nil, hide all threads initially.
679 If threads are hidden, you have to run the command
680 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
681 to expose hidden threads.")
682
683 (defvar gnus-thread-hide-killed t
684   "*If non-nil, hide killed threads automatically.")
685
686 (defvar gnus-thread-ignore-subject nil
687   "*If non-nil, ignore subjects and do all threading based on the Reference header.
688 If nil, which is the default, articles that have different subjects
689 from their parents will start separate threads.")
690
691 (defvar gnus-thread-operation-ignore-subject t
692   "*If non-nil, subjects will be ignored when doing thread commands.
693 This affects commands like `gnus-summary-kill-thread' and
694 `gnus-summary-lower-thread'.
695
696 If this variable is nil, articles in the same thread with different
697 subjects will not be included in the operation in question.  If this
698 variable is `fuzzy', only articles that have subjects that are fuzzily
699 equal will be included.")
700
701 (defvar gnus-thread-indent-level 4
702   "*Number that says how much each sub-thread should be indented.")
703
704 (defvar gnus-ignored-newsgroups
705   (purecopy (mapconcat 'identity
706                        '("^to\\."       ; not "real" groups
707                          "^[0-9. \t]+ " ; all digits in name
708                          "[][\"#'()]"   ; bogus characters
709                          )
710                        "\\|"))
711   "*A regexp to match uninteresting newsgroups in the active file.
712 Any lines in the active file matching this regular expression are
713 removed from the newsgroup list before anything else is done to it,
714 thus making them effectively non-existent.")
715
716 (defvar gnus-ignored-headers
717   "^Path:\\|^Posting-Version:\\|^Article-I.D.:\\|^Expires:\\|^Date-Received:\\|^References:\\|^Control:\\|^Xref:\\|^Lines:\\|^Posted:\\|^Relay-Version:\\|^Message-ID:\\|^Nf-ID:\\|^Nf-From:\\|^Approved:\\|^Sender:\\|^Received:\\|^Mail-from:"
718   "*All headers that match this regexp will be hidden.
719 This variable can also be a list of regexps of headers to be ignored.
720 If `gnus-visible-headers' is non-nil, this variable will be ignored.")
721
722 (defvar gnus-visible-headers "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-"
723   "*All headers that do not match this regexp will be hidden.
724 This variable can also be a list of regexp of headers to remain visible.
725 If this variable is non-nil, `gnus-ignored-headers' will be ignored.")
726
727 (defvar gnus-sorted-header-list
728   '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:" "^To:"
729     "^Cc:" "^Date:" "^Organization:")
730   "*This variable is a list of regular expressions.
731 If it is non-nil, headers that match the regular expressions will
732 be placed first in the article buffer in the sequence specified by
733 this list.")
734
735 (defvar gnus-boring-article-headers
736   '(empty followup-to reply-to)
737   "*Headers that are only to be displayed if they have interesting data.
738 Possible values in this list are `empty', `newsgroups', `followup-to',
739 `reply-to', and `date'.")
740
741 (defvar gnus-show-all-headers nil
742   "*If non-nil, don't hide any headers.")
743
744 (defvar gnus-save-all-headers t
745   "*If non-nil, don't remove any headers before saving.")
746
747 (defvar gnus-saved-headers gnus-visible-headers
748   "*Headers to keep if `gnus-save-all-headers' is nil.
749 If `gnus-save-all-headers' is non-nil, this variable will be ignored.
750 If that variable is nil, however, all headers that match this regexp
751 will be kept while the rest will be deleted before saving.")
752
753 (defvar gnus-inhibit-startup-message nil
754   "*If non-nil, the startup message will not be displayed.")
755
756 (defvar gnus-signature-separator "^-- *$"
757   "Regexp matching signature separator.")
758
759 (defvar gnus-signature-limit nil
760   "Provide a limit to what is considered a signature.
761 If it is a number, no signature may not be longer (in characters) than
762 that number.  If it is a function, the function will be called without
763 any parameters, and if it returns nil, there is no signature in the
764 buffer.  If it is a string, it will be used as a regexp.  If it
765 matches, the text in question is not a signature.")
766
767 (defvar gnus-auto-extend-newsgroup t
768   "*If non-nil, extend newsgroup forward and backward when requested.")
769
770 (defvar gnus-auto-select-first t
771   "*If nil, don't select the first unread article when entering a group.
772 If this variable is `best', select the highest-scored unread article
773 in the group.  If neither nil nor `best', select the first unread
774 article.
775
776 If you want to prevent automatic selection of the first unread article
777 in some newsgroups, set the variable to nil in
778 `gnus-select-group-hook'.")
779
780 (defvar gnus-auto-select-next t
781   "*If non-nil, offer to go to the next group from the end of the previous.
782 If the value is t and the next newsgroup is empty, Gnus will exit
783 summary mode and go back to group mode.  If the value is neither nil
784 nor t, Gnus will select the following unread newsgroup.  In
785 particular, if the value is the symbol `quietly', the next unread
786 newsgroup will be selected without any confirmation, and if it is
787 `almost-quietly', the next group will be selected without any
788 confirmation if you are located on the last article in the group.
789 Finally, if this variable is `slightly-quietly', the `Z n' command
790 will go to the next group without confirmation.")
791
792 (defvar gnus-auto-select-same nil
793   "*If non-nil, select the next article with the same subject.")
794
795 (defvar gnus-summary-check-current nil
796   "*If non-nil, consider the current article when moving.
797 The \"unread\" movement commands will stay on the same line if the
798 current article is unread.")
799
800 (defvar gnus-auto-center-summary t
801   "*If non-nil, always center the current summary buffer.
802 In particular, if `vertical' do only vertical recentering.  If non-nil
803 and non-`vertical', do both horizontal and vertical recentering.")
804
805 (defvar gnus-break-pages t
806   "*If non-nil, do page breaking on articles.
807 The page delimiter is specified by the `gnus-page-delimiter'
808 variable.")
809
810 (defvar gnus-page-delimiter "^\^L"
811   "*Regexp describing what to use as article page delimiters.
812 The default value is \"^\^L\", which is a form linefeed at the
813 beginning of a line.")
814
815 (defvar gnus-use-full-window t
816   "*If non-nil, use the entire Emacs screen.")
817
818 (defvar gnus-window-configuration nil
819   "Obsolete variable.  See `gnus-buffer-configuration'.")
820
821 (defvar gnus-window-min-width 2
822   "*Minimum width of Gnus buffers.")
823
824 (defvar gnus-window-min-height 1
825   "*Minimum height of Gnus buffers.")
826
827 (defvar gnus-buffer-configuration
828   '((group
829      (vertical 1.0
830                (group 1.0 point)
831                (if gnus-carpal '(group-carpal 4))))
832     (summary
833      (vertical 1.0
834                (summary 1.0 point)
835                (if gnus-carpal '(summary-carpal 4))))
836     (article
837      (cond 
838       (gnus-use-picons
839        '(frame 1.0
840                (vertical 1.0
841                          (summary 0.25 point)
842                          (if gnus-carpal '(summary-carpal 4))
843                          (article 1.0))
844                (vertical ((height . 5) (width . 15)
845                           (user-position . t)
846                           (left . -1) (top . 1))
847                          (picons 1.0))))
848       (gnus-use-trees
849        '(vertical 1.0
850                   (summary 0.25 point)
851                   (tree 0.25)
852                   (article 1.0)))
853       (t
854        '(vertical 1.0
855                  (summary 0.25 point)
856                  (if gnus-carpal '(summary-carpal 4))
857                  (if gnus-use-trees '(tree 0.25))
858                  (article 1.0)))))
859     (server
860      (vertical 1.0
861                (server 1.0 point)
862                (if gnus-carpal '(server-carpal 2))))
863     (browse
864      (vertical 1.0
865                (browse 1.0 point)
866                (if gnus-carpal '(browse-carpal 2))))
867     (message
868      (vertical 1.0
869                (message 1.0 point)))
870     (pick
871      (vertical 1.0
872                (article 1.0 point)))
873     (info
874      (vertical 1.0
875                (info 1.0 point)))
876     (summary-faq
877      (vertical 1.0
878                (summary 0.25)
879                (faq 1.0 point)))
880     (edit-group
881      (vertical 1.0
882                (group 0.5)
883                (edit-group 1.0 point)))
884     (edit-server
885      (vertical 1.0
886                (server 0.5)
887                (edit-server 1.0 point)))
888     (edit-score
889      (vertical 1.0
890                (summary 0.25)
891                (edit-score 1.0 point)))
892     (post
893      (vertical 1.0
894                (post 1.0 point)))
895     (reply
896      (vertical 1.0
897                (article-copy 0.5)
898                (message 1.0 point)))
899     (forward
900      (vertical 1.0
901                (message 1.0 point)))
902     (reply-yank
903      (vertical 1.0
904                (message 1.0 point)))
905     (mail-bounce
906      (vertical 1.0
907                (article 0.5)
908                (message 1.0 point)))
909     (draft
910      (vertical 1.0
911                (draft 1.0 point)))
912     (pipe
913      (vertical 1.0
914                (summary 0.25 point)
915                (if gnus-carpal '(summary-carpal 4))
916                ("*Shell Command Output*" 1.0)))
917     (bug
918      (vertical 1.0
919                ("*Gnus Help Bug*" 0.5)
920                ("*Gnus Bug*" 1.0 point)))
921     (compose-bounce
922      (vertical 1.0
923                (article 0.5)
924                (message 1.0 point))))
925   "Window configuration for all possible Gnus buffers.
926 This variable is a list of lists.  Each of these lists has a NAME and
927 a RULE.  The NAMEs are commonsense names like `group', which names a
928 rule used when displaying the group buffer; `summary', which names a
929 rule for what happens when you enter a group and do not display an
930 article buffer; and so on.  See the value of this variable for a
931 complete list of NAMEs.
932
933 Each RULE is a list of vectors.  The first element in this vector is
934 the name of the buffer to be displayed; the second element is the
935 percentage of the screen this buffer is to occupy (a number in the
936 0.0-0.99 range); the optional third element is `point', which should
937 be present to denote which buffer point is to go to after making this
938 buffer configuration.")
939
940 (defvar gnus-window-to-buffer
941   '((group . gnus-group-buffer)
942     (summary . gnus-summary-buffer)
943     (article . gnus-article-buffer)
944     (server . gnus-server-buffer)
945     (browse . "*Gnus Browse Server*")
946     (edit-group . gnus-group-edit-buffer)
947     (edit-server . gnus-server-edit-buffer)
948     (group-carpal . gnus-carpal-group-buffer)
949     (summary-carpal . gnus-carpal-summary-buffer)
950     (server-carpal . gnus-carpal-server-buffer)
951     (browse-carpal . gnus-carpal-browse-buffer)
952     (edit-score . gnus-score-edit-buffer)
953     (message . gnus-message-buffer)
954     (mail . gnus-message-buffer)
955     (post-news . gnus-message-buffer)
956     (faq . gnus-faq-buffer)
957     (picons . "*Picons*")
958     (tree . gnus-tree-buffer)
959     (info . gnus-info-buffer)
960     (article-copy . gnus-article-copy)
961     (draft . gnus-draft-buffer))
962   "Mapping from short symbols to buffer names or buffer variables.")
963
964 (defvar gnus-carpal nil
965   "*If non-nil, display clickable icons.")
966
967 (defvar gnus-subscribe-newsgroup-method 'gnus-subscribe-zombies
968   "*Function called with a group name when new group is detected.
969 A few pre-made functions are supplied: `gnus-subscribe-randomly'
970 inserts new groups at the beginning of the list of groups;
971 `gnus-subscribe-alphabetically' inserts new groups in strict
972 alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
973 in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
974 for your decision; `gnus-subscribe-killed' kills all new groups;
975 `gnus-subscribe-zombies' will make all new groups into zombies.")
976
977 ;; Suggested by a bug report by Hallvard B Furuseth.
978 ;; <h.b.furuseth@usit.uio.no>.
979 (defvar gnus-subscribe-options-newsgroup-method
980   (function gnus-subscribe-alphabetically)
981   "*This function is called to subscribe newsgroups mentioned on \"options -n\" lines.
982 If, for instance, you want to subscribe to all newsgroups in the
983 \"no\" and \"alt\" hierarchies, you'd put the following in your
984 .newsrc file:
985
986 options -n no.all alt.all
987
988 Gnus will the subscribe all new newsgroups in these hierarchies with
989 the subscription method in this variable.")
990
991 (defvar gnus-subscribe-hierarchical-interactive nil
992   "*If non-nil, Gnus will offer to subscribe hierarchically.
993 When a new hierarchy appears, Gnus will ask the user:
994
995 'alt.binaries': Do you want to subscribe to this hierarchy? ([d]ys):
996
997 If the user pressed `d', Gnus will descend the hierarchy, `y' will
998 subscribe to all newsgroups in the hierarchy and `s' will skip this
999 hierarchy in its entirety.")
1000
1001 (defvar gnus-group-sort-function 'gnus-group-sort-by-alphabet
1002   "*Function used for sorting the group buffer.
1003 This function will be called with group info entries as the arguments
1004 for the groups to be sorted.  Pre-made functions include
1005 `gnus-group-sort-by-alphabet', `gnus-group-sort-by-unread',
1006 `gnus-group-sort-by-level', `gnus-group-sort-by-score', and
1007 `gnus-group-sort-by-rank'.
1008
1009 This variable can also be a list of sorting functions.  In that case,
1010 the most significant sort function should be the last function in the
1011 list.")
1012
1013 ;; Mark variables suggested by Thomas Michanek
1014 ;; <Thomas.Michanek@telelogic.se>.
1015 (defvar gnus-unread-mark ? 
1016   "*Mark used for unread articles.")
1017 (defvar gnus-ticked-mark ?!
1018   "*Mark used for ticked articles.")
1019 (defvar gnus-dormant-mark ??
1020   "*Mark used for dormant articles.")
1021 (defvar gnus-del-mark ?r
1022   "*Mark used for del'd articles.")
1023 (defvar gnus-read-mark ?R
1024   "*Mark used for read articles.")
1025 (defvar gnus-expirable-mark ?E
1026   "*Mark used for expirable articles.")
1027 (defvar gnus-killed-mark ?K
1028   "*Mark used for killed articles.")
1029 (defvar gnus-souped-mark ?F
1030   "*Mark used for killed articles.")
1031 (defvar gnus-kill-file-mark ?X
1032   "*Mark used for articles killed by kill files.")
1033 (defvar gnus-low-score-mark ?Y
1034   "*Mark used for articles with a low score.")
1035 (defvar gnus-catchup-mark ?C
1036   "*Mark used for articles that are caught up.")
1037 (defvar gnus-replied-mark ?A
1038   "*Mark used for articles that have been replied to.")
1039 (defvar gnus-cached-mark ?*
1040   "*Mark used for articles that are in the cache.")
1041 (defvar gnus-saved-mark ?S
1042   "*Mark used for articles that have been saved to.")
1043 (defvar gnus-process-mark ?#
1044   "*Process mark.")
1045 (defvar gnus-ancient-mark ?O
1046   "*Mark used for ancient articles.")
1047 (defvar gnus-sparse-mark ?Q
1048   "*Mark used for sparsely reffed articles.")
1049 (defvar gnus-canceled-mark ?G
1050   "*Mark used for canceled articles.")
1051 (defvar gnus-score-over-mark ?+
1052   "*Score mark used for articles with high scores.")
1053 (defvar gnus-score-below-mark ?-
1054   "*Score mark used for articles with low scores.")
1055 (defvar gnus-empty-thread-mark ? 
1056   "*There is no thread under the article.")
1057 (defvar gnus-not-empty-thread-mark ?=
1058   "*There is a thread under the article.")
1059
1060 (defvar gnus-view-pseudo-asynchronously nil
1061   "*If non-nil, Gnus will view pseudo-articles asynchronously.")
1062
1063 (defvar gnus-view-pseudos nil
1064   "*If `automatic', pseudo-articles will be viewed automatically.
1065 If `not-confirm', pseudos will be viewed automatically, and the user
1066 will not be asked to confirm the command.")
1067
1068 (defvar gnus-view-pseudos-separately t
1069   "*If non-nil, one pseudo-article will be created for each file to be viewed.
1070 If nil, all files that use the same viewing command will be given as a
1071 list of parameters to that command.")
1072
1073 (defvar gnus-insert-pseudo-articles t
1074   "*If non-nil, insert pseudo-articles when decoding articles.")
1075
1076 (defvar gnus-group-line-format "%M%S%p%P%5y: %(%g%)%l\n"
1077   "*Format of group lines.
1078 It works along the same lines as a normal formatting string,
1079 with some simple extensions.
1080
1081 %M    Only marked articles (character, \"*\" or \" \")
1082 %S    Whether the group is subscribed (character, \"U\", \"K\", \"Z\" or \" \")
1083 %L    Level of subscribedness (integer)
1084 %N    Number of unread articles (integer)
1085 %I    Number of dormant articles (integer)
1086 %i    Number of ticked and dormant (integer)
1087 %T    Number of ticked articles (integer)
1088 %R    Number of read articles (integer)
1089 %t    Total number of articles (integer)
1090 %y    Number of unread, unticked articles (integer)
1091 %G    Group name (string)
1092 %g    Qualified group name (string)
1093 %D    Group description (string)
1094 %s    Select method (string)
1095 %o    Moderated group (char, \"m\")
1096 %p    Process mark (char)
1097 %O    Moderated group (string, \"(m)\" or \"\")
1098 %P    Topic indentation (string)
1099 %l    Whether there are GroupLens predictions for this group (string)
1100 %n    Select from where (string)
1101 %z    A string that look like `<%s:%n>' if a foreign select method is used
1102 %u    User defined specifier.  The next character in the format string should
1103       be a letter.  Gnus will call the function gnus-user-format-function-X,
1104       where X is the letter following %u.  The function will be passed the
1105       current header as argument.  The function should return a string, which
1106       will be inserted into the buffer just like information from any other
1107       group specifier.
1108
1109 Text between %( and %) will be highlighted with `gnus-mouse-face' when
1110 the mouse point move inside the area.  There can only be one such area.
1111
1112 Note that this format specification is not always respected.  For
1113 reasons of efficiency, when listing killed groups, this specification
1114 is ignored altogether.  If the spec is changed considerably, your
1115 output may end up looking strange when listing both alive and killed
1116 groups.
1117
1118 If you use %o or %O, reading the active file will be slower and quite
1119 a bit of extra memory will be used. %D will also worsen performance.
1120 Also note that if you change the format specification to include any
1121 of these specs, you must probably re-start Gnus to see them go into
1122 effect.")
1123
1124 (defvar gnus-summary-line-format "%U%R%z%I%(%[%4L: %-20,20n%]%) %s\n"
1125   "*The format specification of the lines in the summary buffer.
1126
1127 It works along the same lines as a normal formatting string,
1128 with some simple extensions.
1129
1130 %N   Article number, left padded with spaces (string)
1131 %S   Subject (string)
1132 %s   Subject if it is at the root of a thread, and \"\" otherwise (string)
1133 %n   Name of the poster (string)
1134 %a   Extracted name of the poster (string)
1135 %A   Extracted address of the poster (string)
1136 %F   Contents of the From: header (string)
1137 %x   Contents of the Xref: header (string)
1138 %D   Date of the article (string)
1139 %d   Date of the article (string) in DD-MMM format
1140 %M   Message-id of the article (string)
1141 %r   References of the article (string)
1142 %c   Number of characters in the article (integer)
1143 %L   Number of lines in the article (integer)
1144 %I   Indentation based on thread level (a string of spaces)
1145 %T   A string with two possible values: 80 spaces if the article
1146      is on thread level two or larger and 0 spaces on level one
1147 %R   \"A\" if this article has been replied to, \" \" otherwise (character)
1148 %U   Status of this article (character, \"R\", \"K\", \"-\" or \" \")
1149 %[   Opening bracket (character, \"[\" or \"<\")
1150 %]   Closing bracket (character, \"]\" or \">\")
1151 %>   Spaces of length thread-level (string)
1152 %<   Spaces of length (- 20 thread-level) (string)
1153 %i   Article score (number)
1154 %z   Article zcore (character)
1155 %t   Number of articles under the current thread (number).
1156 %e   Whether the thread is empty or not (character).
1157 %l   GroupLens score (string).
1158 %u   User defined specifier.  The next character in the format string should
1159      be a letter.  Gnus will call the function gnus-user-format-function-X,
1160      where X is the letter following %u.  The function will be passed the
1161      current header as argument.  The function should return a string, which
1162      will be inserted into the summary just like information from any other
1163      summary specifier.
1164
1165 Text between %( and %) will be highlighted with `gnus-mouse-face'
1166 when the mouse point is placed inside the area.  There can only be one
1167 such area.
1168
1169 The %U (status), %R (replied) and %z (zcore) specs have to be handled
1170 with care.  For reasons of efficiency, Gnus will compute what column
1171 these characters will end up in, and \"hard-code\" that.  This means that
1172 it is illegal to have these specs after a variable-length spec.  Well,
1173 you might not be arrested, but your summary buffer will look strange,
1174 which is bad enough.
1175
1176 The smart choice is to have these specs as for to the left as
1177 possible.
1178
1179 This restriction may disappear in later versions of Gnus.")
1180
1181 (defvar gnus-summary-dummy-line-format
1182   "*  %(:                          :%) %S\n"
1183   "*The format specification for the dummy roots in the summary buffer.
1184 It works along the same lines as a normal formatting string,
1185 with some simple extensions.
1186
1187 %S  The subject")
1188
1189 (defvar gnus-summary-mode-line-format "Gnus: %%b [%A] %Z"
1190   "*The format specification for the summary mode line.
1191 It works along the same lines as a normal formatting string,
1192 with some simple extensions:
1193
1194 %G  Group name
1195 %p  Unprefixed group name
1196 %A  Current article number
1197 %V  Gnus version
1198 %U  Number of unread articles in the group
1199 %e  Number of unselected articles in the group
1200 %Z  A string with unread/unselected article counts
1201 %g  Shortish group name
1202 %S  Subject of the current article
1203 %u  User-defined spec
1204 %s  Current score file name
1205 %d  Number of dormant articles
1206 %r  Number of articles that have been marked as read in this session
1207 %E  Number of articles expunged by the score files")
1208
1209 (defvar gnus-article-mode-line-format "Gnus: %%b %S"
1210   "*The format specification for the article mode line.
1211 See `gnus-summary-mode-line-format' for a closer description.")
1212
1213 (defvar gnus-group-mode-line-format "Gnus: %%b {%M%:%S}"
1214   "*The format specification for the group mode line.
1215 It works along the same lines as a normal formatting string,
1216 with some simple extensions:
1217
1218 %S   The native news server.
1219 %M   The native select method.
1220 %:   \":\" if %S isn't \"\".")
1221
1222 (defvar gnus-valid-select-methods
1223   '(("nntp" post address prompt-address)
1224     ("nnspool" post address)
1225     ("nnvirtual" post-mail virtual prompt-address)
1226     ("nnmbox" mail respool address)
1227     ("nnml" mail respool address)
1228     ("nnmh" mail respool address)
1229     ("nndir" post-mail prompt-address address)
1230     ("nneething" none address prompt-address)
1231     ("nndoc" none address prompt-address)
1232     ("nnbabyl" mail address respool)
1233     ("nnkiboze" post address virtual)
1234     ("nnsoup" post-mail address)
1235     ("nndraft" post-mail)
1236     ("nnfolder" mail respool address))
1237   "An alist of valid select methods.
1238 The first element of each list lists should be a string with the name
1239 of the select method.  The other elements may be be the category of
1240 this method (ie. `post', `mail', `none' or whatever) or other
1241 properties that this method has (like being respoolable).
1242 If you implement a new select method, all you should have to change is
1243 this variable.  I think.")
1244
1245 (defvar gnus-updated-mode-lines '(group article summary tree)
1246   "*List of buffers that should update their mode lines.
1247 The list may contain the symbols `group', `article' and `summary'.  If
1248 the corresponding symbol is present, Gnus will keep that mode line
1249 updated with information that may be pertinent.
1250 If this variable is nil, screen refresh may be quicker.")
1251
1252 ;; Added by Keinonen Kari <kk85613@cs.tut.fi>.
1253 (defvar gnus-mode-non-string-length nil
1254   "*Max length of mode-line non-string contents.
1255 If this is nil, Gnus will take space as is needed, leaving the rest
1256 of the modeline intact.")
1257
1258 ;see gnus-cus.el
1259 ;(defvar gnus-mouse-face 'highlight
1260 ;  "*Face used for mouse highlighting in Gnus.
1261 ;No mouse highlights will be done if `gnus-visual' is nil.")
1262
1263 (defvar gnus-summary-mark-below 0
1264   "*Mark all articles with a score below this variable as read.
1265 This variable is local to each summary buffer and usually set by the
1266 score file.")
1267
1268 (defvar gnus-article-sort-functions '(gnus-article-sort-by-number)
1269   "*List of functions used for sorting articles in the summary buffer.
1270 This variable is only used when not using a threaded display.")
1271
1272 (defvar gnus-thread-sort-functions '(gnus-thread-sort-by-number)
1273   "*List of functions used for sorting threads in the summary buffer.
1274 By default, threads are sorted by article number.
1275
1276 Each function takes two threads and return non-nil if the first thread
1277 should be sorted before the other.  If you use more than one function,
1278 the primary sort function should be the last.  You should probably
1279 always include `gnus-thread-sort-by-number' in the list of sorting
1280 functions -- preferably first.
1281
1282 Ready-mady functions include `gnus-thread-sort-by-number',
1283 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
1284 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score' and
1285 `gnus-thread-sort-by-total-score' (see `gnus-thread-score-function').")
1286
1287 (defvar gnus-thread-score-function '+
1288   "*Function used for calculating the total score of a thread.
1289
1290 The function is called with the scores of the article and each
1291 subthread and should then return the score of the thread.
1292
1293 Some functions you can use are `+', `max', or `min'.")
1294
1295 (defvar gnus-summary-expunge-below nil
1296   "All articles that have a score less than this variable will be expunged.")
1297
1298 (defvar gnus-thread-expunge-below nil
1299   "All threads that have a total score less than this variable will be expunged.
1300 See `gnus-thread-score-function' for en explanation of what a
1301 \"thread score\" is.")
1302
1303 (defvar gnus-auto-subscribed-groups
1304   "^nnml\\|^nnfolder\\|^nnmbox\\|^nnmh\\|^nnbabyl"
1305   "*All new groups that match this regexp will be subscribed automatically.
1306 Note that this variable only deals with new groups.  It has no effect
1307 whatsoever on old groups.")
1308
1309 (defvar gnus-options-subscribe nil
1310   "*All new groups matching this regexp will be subscribed unconditionally.
1311 Note that this variable deals only with new newsgroups.  This variable
1312 does not affect old newsgroups.")
1313
1314 (defvar gnus-options-not-subscribe nil
1315   "*All new groups matching this regexp will be ignored.
1316 Note that this variable deals only with new newsgroups.  This variable
1317 does not affect old (already subscribed) newsgroups.")
1318
1319 (defvar gnus-auto-expirable-newsgroups nil
1320   "*Groups in which to automatically mark read articles as expirable.
1321 If non-nil, this should be a regexp that should match all groups in
1322 which to perform auto-expiry.  This only makes sense for mail groups.")
1323
1324 (defvar gnus-total-expirable-newsgroups nil
1325   "*Groups in which to perform expiry of all read articles.
1326 Use with extreme caution.  All groups that match this regexp will be
1327 expiring - which means that all read articles will be deleted after
1328 (say) one week.  (This only goes for mail groups and the like, of
1329 course.)")
1330
1331 (defvar gnus-group-uncollapsed-levels 1
1332   "Number of group name elements to leave alone when making a short group name.")
1333
1334 (defvar gnus-hidden-properties '(invisible t intangible t)
1335   "Property list to use for hiding text.")
1336
1337 (defvar gnus-modtime-botch nil
1338   "*Non-nil means .newsrc should be deleted prior to save.  
1339 Its use is due to the bogus appearance that .newsrc was modified on
1340 disc.")
1341
1342 ;; Hooks.
1343
1344 (defvar gnus-group-mode-hook nil
1345   "*A hook for Gnus group mode.")
1346
1347 (defvar gnus-summary-mode-hook nil
1348   "*A hook for Gnus summary mode.
1349 This hook is run before any variables are set in the summary buffer.")
1350
1351 (defvar gnus-article-mode-hook nil
1352   "*A hook for Gnus article mode.")
1353
1354 (defvar gnus-summary-prepare-exit-hook nil
1355   "*A hook called when preparing to exit from the summary buffer.
1356 It calls `gnus-summary-expire-articles' by default.")
1357 (add-hook 'gnus-summary-prepare-exit-hook 'gnus-summary-expire-articles)
1358
1359 (defvar gnus-summary-exit-hook nil
1360   "*A hook called on exit from the summary buffer.")
1361
1362 (defvar gnus-group-catchup-group-hook nil
1363   "*A hook run when catching up a group from the group buffer.")
1364
1365 (defvar gnus-open-server-hook nil
1366   "*A hook called just before opening connection to the news server.")
1367
1368 (defvar gnus-load-hook nil
1369   "*A hook run while Gnus is loaded.")
1370
1371 (defvar gnus-startup-hook nil
1372   "*A hook called at startup.
1373 This hook is called after Gnus is connected to the NNTP server.")
1374
1375 (defvar gnus-get-new-news-hook nil
1376   "*A hook run just before Gnus checks for new news.")
1377
1378 (defvar gnus-after-getting-new-news-hook nil
1379   "*A hook run after Gnus checks for new news.")
1380
1381 (defvar gnus-group-prepare-function 'gnus-group-prepare-flat
1382   "*A function that is called to generate the group buffer.
1383 The function is called with three arguments: The first is a number;
1384 all group with a level less or equal to that number should be listed,
1385 if the second is non-nil, empty groups should also be displayed.  If
1386 the third is non-nil, it is a number.  No groups with a level lower
1387 than this number should be displayed.
1388
1389 The only current function implemented is `gnus-group-prepare-flat'.")
1390
1391 (defvar gnus-group-prepare-hook nil
1392   "*A hook called after the group buffer has been generated.
1393 If you want to modify the group buffer, you can use this hook.")
1394
1395 (defvar gnus-summary-prepare-hook nil
1396   "*A hook called after the summary buffer has been generated.
1397 If you want to modify the summary buffer, you can use this hook.")
1398
1399 (defvar gnus-summary-generate-hook nil
1400   "*A hook run just before generating the summary buffer.
1401 This hook is commonly used to customize threading variables and the
1402 like.")
1403
1404 (defvar gnus-article-prepare-hook nil
1405   "*A hook called after an article has been prepared in the article buffer.
1406 If you want to run a special decoding program like nkf, use this hook.")
1407
1408 ;(defvar gnus-article-display-hook nil
1409 ;  "*A hook called after the article is displayed in the article buffer.
1410 ;The hook is designed to change the contents of the article
1411 ;buffer.  Typical functions that this hook may contain are
1412 ;`gnus-article-hide-headers' (hide selected headers),
1413 ;`gnus-article-maybe-highlight' (perform fancy article highlighting),
1414 ;`gnus-article-hide-signature' (hide signature) and
1415 ;`gnus-article-treat-overstrike' (turn \"^H_\" into bold characters).")
1416 ;(add-hook 'gnus-article-display-hook 'gnus-article-hide-headers-if-wanted)
1417 ;(add-hook 'gnus-article-display-hook 'gnus-article-treat-overstrike)
1418 ;(add-hook 'gnus-article-display-hook 'gnus-article-maybe-highlight)
1419
1420 (defvar gnus-article-x-face-command
1421   "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | xv -quit -"
1422   "String or function to be executed to display an X-Face header.
1423 If it is a string, the command will be executed in a sub-shell
1424 asynchronously.  The compressed face will be piped to this command.")
1425
1426 (defvar gnus-article-x-face-too-ugly nil
1427   "Regexp matching posters whose face shouldn't be shown automatically.")
1428
1429 (defvar gnus-select-group-hook nil
1430   "*A hook called when a newsgroup is selected.
1431
1432 If you'd like to simplify subjects like the
1433 `gnus-summary-next-same-subject' command does, you can use the
1434 following hook:
1435
1436  (setq gnus-select-group-hook
1437       (list
1438         (lambda ()
1439           (mapcar (lambda (header)
1440                      (mail-header-set-subject
1441                       header
1442                       (gnus-simplify-subject
1443                        (mail-header-subject header) 're-only)))
1444                   gnus-newsgroup-headers))))")
1445
1446 (defvar gnus-select-article-hook nil
1447   "*A hook called when an article is selected.")
1448
1449 (defvar gnus-apply-kill-hook '(gnus-apply-kill-file)
1450   "*A hook called to apply kill files to a group.
1451 This hook is intended to apply a kill file to the selected newsgroup.
1452 The function `gnus-apply-kill-file' is called by default.
1453
1454 Since a general kill file is too heavy to use only for a few
1455 newsgroups, I recommend you to use a lighter hook function.  For
1456 example, if you'd like to apply a kill file to articles which contains
1457 a string `rmgroup' in subject in newsgroup `control', you can use the
1458 following hook:
1459
1460  (setq gnus-apply-kill-hook
1461       (list
1462         (lambda ()
1463           (cond ((string-match \"control\" gnus-newsgroup-name)
1464                  (gnus-kill \"Subject\" \"rmgroup\")
1465                  (gnus-expunge \"X\"))))))")
1466
1467 (defvar gnus-visual-mark-article-hook
1468   (list 'gnus-highlight-selected-summary)
1469   "*Hook run after selecting an article in the summary buffer.
1470 It is meant to be used for highlighting the article in some way.  It
1471 is not run if `gnus-visual' is nil.")
1472
1473 (defvar gnus-parse-headers-hook nil
1474   "*A hook called before parsing the headers.")
1475 (add-hook 'gnus-parse-headers-hook 'gnus-decode-rfc1522)
1476
1477 (defvar gnus-exit-group-hook nil
1478   "*A hook called when exiting (not quitting) summary mode.")
1479
1480 (defvar gnus-suspend-gnus-hook nil
1481   "*A hook called when suspending (not exiting) Gnus.")
1482
1483 (defvar gnus-exit-gnus-hook nil
1484   "*A hook called when exiting Gnus.")
1485
1486 (defvar gnus-after-exiting-gnus-hook nil
1487   "*A hook called after exiting Gnus.")
1488
1489 (defvar gnus-save-newsrc-hook nil
1490   "*A hook called before saving any of the newsrc files.")
1491
1492 (defvar gnus-save-quick-newsrc-hook nil
1493   "*A hook called just before saving the quick newsrc file.
1494 Can be used to turn version control on or off.")
1495
1496 (defvar gnus-save-standard-newsrc-hook nil
1497   "*A hook called just before saving the standard newsrc file.
1498 Can be used to turn version control on or off.")
1499
1500 (defvar gnus-summary-update-hook
1501   (list 'gnus-summary-highlight-line)
1502   "*A hook called when a summary line is changed.
1503 The hook will not be called if `gnus-visual' is nil.
1504
1505 The default function `gnus-summary-highlight-line' will
1506 highlight the line according to the `gnus-summary-highlight'
1507 variable.")
1508
1509 (defvar gnus-group-update-hook '(gnus-group-highlight-line)
1510   "*A hook called when a group line is changed.
1511 The hook will not be called if `gnus-visual' is nil.
1512
1513 The default function `gnus-group-highlight-line' will
1514 highlight the line according to the `gnus-group-highlight'
1515 variable.")
1516
1517 (defvar gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
1518   "*A hook called when an article is selected for the first time.
1519 The hook is intended to mark an article as read (or unread)
1520 automatically when it is selected.")
1521
1522 (defvar gnus-group-change-level-function nil
1523   "Function run when a group level is changed.
1524 It is called with three parameters -- GROUP, LEVEL and OLDLEVEL.")
1525
1526 ;; Remove any hilit infestation.
1527 (add-hook 'gnus-startup-hook
1528           (lambda ()
1529             (remove-hook 'gnus-summary-prepare-hook
1530                          'hilit-rehighlight-buffer-quietly)
1531             (remove-hook 'gnus-summary-prepare-hook 'hilit-install-line-hooks)
1532             (setq gnus-mark-article-hook
1533                   '(gnus-summary-mark-read-and-unread-as-read))
1534             (remove-hook 'gnus-article-prepare-hook
1535                          'hilit-rehighlight-buffer-quietly)))
1536
1537 \f
1538 ;; Internal variables
1539
1540 (defvar gnus-tree-buffer "*Tree*"
1541   "Buffer where Gnus thread trees are displayed.")
1542
1543 ;; Dummy variable.
1544 (defvar gnus-use-generic-from nil)
1545
1546 (defvar gnus-thread-indent-array nil)
1547 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
1548
1549 (defvar gnus-newsrc-file-version nil)
1550
1551 (defvar gnus-method-history nil)
1552 ;; Variable holding the user answers to all method prompts.
1553
1554 (defvar gnus-group-history nil)
1555 ;; Variable holding the user answers to all group prompts.
1556
1557 (defvar gnus-server-alist nil
1558   "List of available servers.")
1559
1560 (defvar gnus-group-indentation-function nil)
1561
1562 (defvar gnus-topic-indentation "") ;; Obsolete variable.
1563
1564 (defvar gnus-goto-missing-group-function nil)
1565
1566 (defvar gnus-override-subscribe-method nil)
1567
1568 (defvar gnus-group-goto-next-group-function nil
1569   "Function to override finding the next group after listing groups.")
1570
1571 (defconst gnus-article-mark-lists
1572   '((marked . tick) (replied . reply)
1573     (expirable . expire) (killed . killed)
1574     (bookmarks . bookmark) (dormant . dormant)
1575     (scored . score) (saved . save)
1576     (cached . cache)
1577     ))
1578
1579 ;; Avoid highlighting in kill files.
1580 (defvar gnus-summary-inhibit-highlight nil)
1581 (defvar gnus-newsgroup-selected-overlay nil)
1582
1583 (defvar gnus-inhibit-hiding nil)
1584 (defvar gnus-group-indentation "")
1585 (defvar gnus-inhibit-limiting nil)
1586 (defvar gnus-created-frames nil)
1587
1588 (defvar gnus-article-mode-map nil)
1589 (defvar gnus-dribble-buffer nil)
1590 (defvar gnus-headers-retrieved-by nil)
1591 (defvar gnus-article-reply nil)
1592 (defvar gnus-override-method nil)
1593 (defvar gnus-article-check-size nil)
1594
1595 (defvar gnus-current-score-file nil)
1596 (defvar gnus-newsgroup-adaptive-score-file nil)
1597 (defvar gnus-scores-exclude-files nil)
1598
1599 (defvar gnus-opened-servers nil)
1600
1601 (defvar gnus-current-move-group nil)
1602 (defvar gnus-current-copy-group nil)
1603 (defvar gnus-current-crosspost-group nil)
1604
1605 (defvar gnus-newsgroup-dependencies nil)
1606 (defvar gnus-newsgroup-async nil)
1607 (defconst gnus-group-edit-buffer "*Gnus edit newsgroup*")
1608
1609 (defvar gnus-newsgroup-adaptive nil)
1610
1611 (defvar gnus-summary-display-table nil)
1612 (defvar gnus-summary-display-article-function nil)
1613
1614 (defvar gnus-summary-highlight-line-function nil
1615   "Function called after highlighting a summary line.")
1616
1617 (defvar gnus-group-line-format-alist
1618   `((?M gnus-tmp-marked-mark ?c)
1619     (?S gnus-tmp-subscribed ?c)
1620     (?L gnus-tmp-level ?d)
1621     (?N (cond ((eq number t) "*" )
1622               ((numberp number) 
1623                (int-to-string
1624                 (+ number
1625                    (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
1626                    (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))))
1627               (t number)) ?s)
1628     (?R gnus-tmp-number-of-read ?s)
1629     (?t gnus-tmp-number-total ?d)
1630     (?y gnus-tmp-number-of-unread ?s)
1631     (?I (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
1632     (?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
1633     (?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
1634            (gnus-range-length (cdr (assq 'tick gnus-tmp-marked)))) ?d)
1635     (?g gnus-tmp-group ?s)
1636     (?G gnus-tmp-qualified-group ?s)
1637     (?c (gnus-short-group-name gnus-tmp-group) ?s)
1638     (?D gnus-tmp-newsgroup-description ?s)
1639     (?o gnus-tmp-moderated ?c)
1640     (?O gnus-tmp-moderated-string ?s)
1641     (?p gnus-tmp-process-marked ?c)
1642     (?s gnus-tmp-news-server ?s)
1643     (?n gnus-tmp-news-method ?s)
1644     (?P gnus-group-indentation ?s)
1645     (?l gnus-tmp-grouplens ?s)
1646     (?z gnus-tmp-news-method-string ?s)
1647     (?u gnus-tmp-user-defined ?s)))
1648
1649 (defvar gnus-summary-line-format-alist
1650   `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
1651     (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
1652     (?s gnus-tmp-subject-or-nil ?s)
1653     (?n gnus-tmp-name ?s)
1654     (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
1655         ?s)
1656     (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
1657             gnus-tmp-from) ?s)
1658     (?F gnus-tmp-from ?s)
1659     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
1660     (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
1661     (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
1662     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
1663     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
1664     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
1665     (?L gnus-tmp-lines ?d)
1666     (?I gnus-tmp-indentation ?s)
1667     (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
1668     (?R gnus-tmp-replied ?c)
1669     (?\[ gnus-tmp-opening-bracket ?c)
1670     (?\] gnus-tmp-closing-bracket ?c)
1671     (?\> (make-string gnus-tmp-level ? ) ?s)
1672     (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
1673     (?i gnus-tmp-score ?d)
1674     (?z gnus-tmp-score-char ?c)
1675     (?l (bbb-grouplens-score gnus-tmp-header) ?s)
1676     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
1677     (?U gnus-tmp-unread ?c)
1678     (?t (gnus-summary-number-of-articles-in-thread
1679          (and (boundp 'thread) (car thread)) gnus-tmp-level)
1680         ?d)
1681     (?e (gnus-summary-number-of-articles-in-thread
1682          (and (boundp 'thread) (car thread)) gnus-tmp-level t)
1683         ?c)
1684     (?u gnus-tmp-user-defined ?s))
1685   "An alist of format specifications that can appear in summary lines,
1686 and what variables they correspond with, along with the type of the
1687 variable (string, integer, character, etc).")
1688
1689 (defvar gnus-summary-dummy-line-format-alist
1690   `((?S gnus-tmp-subject ?s)
1691     (?N gnus-tmp-number ?d)
1692     (?u gnus-tmp-user-defined ?s)))
1693
1694 (defvar gnus-summary-mode-line-format-alist
1695   `((?G gnus-tmp-group-name ?s)
1696     (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
1697     (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
1698     (?A gnus-tmp-article-number ?d)
1699     (?Z gnus-tmp-unread-and-unselected ?s)
1700     (?V gnus-version ?s)
1701     (?U gnus-tmp-unread ?d)
1702     (?S gnus-tmp-subject ?s)
1703     (?e gnus-tmp-unselected ?d)
1704     (?u gnus-tmp-user-defined ?s)
1705     (?d (length gnus-newsgroup-dormant) ?d)
1706     (?t (length gnus-newsgroup-marked) ?d)
1707     (?r (length gnus-newsgroup-reads) ?d)
1708     (?E gnus-newsgroup-expunged-tally ?d)
1709     (?s (gnus-current-score-file-nondirectory) ?s)))
1710
1711 (defvar gnus-article-mode-line-format-alist
1712   gnus-summary-mode-line-format-alist)
1713
1714 (defvar gnus-group-mode-line-format-alist
1715   `((?S gnus-tmp-news-server ?s)
1716     (?M gnus-tmp-news-method ?s)
1717     (?u gnus-tmp-user-defined ?s)
1718     (?: gnus-tmp-colon ?s)))
1719
1720 (defvar gnus-have-read-active-file nil)
1721
1722 (defconst gnus-maintainer
1723   "gnus-bug@ifi.uio.no (The Gnus Bugfixing Girls + Boys)"
1724   "The mail address of the Gnus maintainers.")
1725
1726 (defconst gnus-version-number "5.2.2"
1727   "Version number for this version of Gnus.")
1728
1729 (defconst gnus-version (format "Gnus v%s" gnus-version-number)
1730   "Version string for this version of Gnus.")
1731
1732 (defvar gnus-info-nodes
1733   '((gnus-group-mode "(gnus)The Group Buffer")
1734     (gnus-summary-mode "(gnus)The Summary Buffer")
1735     (gnus-article-mode "(gnus)The Article Buffer"))
1736   "Assoc list of major modes and related Info nodes.")
1737
1738 (defvar gnus-group-buffer "*Group*")
1739 (defvar gnus-summary-buffer "*Summary*")
1740 (defvar gnus-article-buffer "*Article*")
1741 (defvar gnus-server-buffer "*Server*")
1742
1743 (defvar gnus-work-buffer " *gnus work*")
1744
1745 (defvar gnus-original-article-buffer " *Original Article*")
1746 (defvar gnus-original-article nil)
1747
1748 (defvar gnus-buffer-list nil
1749   "Gnus buffers that should be killed on exit.")
1750
1751 (defvar gnus-slave nil
1752   "Whether this Gnus is a slave or not.")
1753
1754 (defvar gnus-variable-list
1755   '(gnus-newsrc-options gnus-newsrc-options-n
1756     gnus-newsrc-last-checked-date
1757     gnus-newsrc-alist gnus-server-alist
1758     gnus-killed-list gnus-zombie-list
1759     gnus-topic-topology gnus-topic-alist
1760     gnus-format-specs)
1761   "Gnus variables saved in the quick startup file.")
1762
1763 (defvar gnus-newsrc-options nil
1764   "Options line in the .newsrc file.")
1765
1766 (defvar gnus-newsrc-options-n nil
1767   "List of regexps representing groups to be subscribed/ignored unconditionally.")
1768
1769 (defvar gnus-newsrc-last-checked-date nil
1770   "Date Gnus last asked server for new newsgroups.")
1771
1772 (defvar gnus-topic-topology nil
1773   "The complete topic hierarchy.")
1774
1775 (defvar gnus-topic-alist nil
1776   "The complete topic-group alist.")
1777
1778 (defvar gnus-newsrc-alist nil
1779   "Assoc list of read articles.
1780 gnus-newsrc-hashtb should be kept so that both hold the same information.")
1781
1782 (defvar gnus-newsrc-hashtb nil
1783   "Hashtable of gnus-newsrc-alist.")
1784
1785 (defvar gnus-killed-list nil
1786   "List of killed newsgroups.")
1787
1788 (defvar gnus-killed-hashtb nil
1789   "Hash table equivalent of gnus-killed-list.")
1790
1791 (defvar gnus-zombie-list nil
1792   "List of almost dead newsgroups.")
1793
1794 (defvar gnus-description-hashtb nil
1795   "Descriptions of newsgroups.")
1796
1797 (defvar gnus-list-of-killed-groups nil
1798   "List of newsgroups that have recently been killed by the user.")
1799
1800 (defvar gnus-active-hashtb nil
1801   "Hashtable of active articles.")
1802
1803 (defvar gnus-moderated-list nil
1804   "List of moderated newsgroups.")
1805
1806 (defvar gnus-group-marked nil)
1807
1808 (defvar gnus-current-startup-file nil
1809   "Startup file for the current host.")
1810
1811 (defvar gnus-last-search-regexp nil
1812   "Default regexp for article search command.")
1813
1814 (defvar gnus-last-shell-command nil
1815   "Default shell command on article.")
1816
1817 (defvar gnus-current-select-method nil
1818   "The current method for selecting a newsgroup.")
1819
1820 (defvar gnus-group-list-mode nil)
1821
1822 (defvar gnus-article-internal-prepare-hook nil)
1823
1824 (defvar gnus-newsgroup-name nil)
1825 (defvar gnus-newsgroup-begin nil)
1826 (defvar gnus-newsgroup-end nil)
1827 (defvar gnus-newsgroup-last-rmail nil)
1828 (defvar gnus-newsgroup-last-mail nil)
1829 (defvar gnus-newsgroup-last-folder nil)
1830 (defvar gnus-newsgroup-last-file nil)
1831 (defvar gnus-newsgroup-auto-expire nil)
1832 (defvar gnus-newsgroup-active nil)
1833
1834 (defvar gnus-newsgroup-data nil)
1835 (defvar gnus-newsgroup-data-reverse nil)
1836 (defvar gnus-newsgroup-limit nil)
1837 (defvar gnus-newsgroup-limits nil)
1838
1839 (defvar gnus-newsgroup-unreads nil
1840   "List of unread articles in the current newsgroup.")
1841
1842 (defvar gnus-newsgroup-unselected nil
1843   "List of unselected unread articles in the current newsgroup.")
1844
1845 (defvar gnus-newsgroup-reads nil
1846   "Alist of read articles and article marks in the current newsgroup.")
1847
1848 (defvar gnus-newsgroup-expunged-tally nil)
1849
1850 (defvar gnus-newsgroup-marked nil
1851   "List of ticked articles in the current newsgroup (a subset of unread art).")
1852
1853 (defvar gnus-newsgroup-killed nil
1854   "List of ranges of articles that have been through the scoring process.")
1855
1856 (defvar gnus-newsgroup-cached nil
1857   "List of articles that come from the article cache.")
1858
1859 (defvar gnus-newsgroup-saved nil
1860   "List of articles that have been saved.")
1861
1862 (defvar gnus-newsgroup-kill-headers nil)
1863
1864 (defvar gnus-newsgroup-replied nil
1865   "List of articles that have been replied to in the current newsgroup.")
1866
1867 (defvar gnus-newsgroup-expirable nil
1868   "List of articles in the current newsgroup that can be expired.")
1869
1870 (defvar gnus-newsgroup-processable nil
1871   "List of articles in the current newsgroup that can be processed.")
1872
1873 (defvar gnus-newsgroup-bookmarks nil
1874   "List of articles in the current newsgroup that have bookmarks.")
1875
1876 (defvar gnus-newsgroup-dormant nil
1877   "List of dormant articles in the current newsgroup.")
1878
1879 (defvar gnus-newsgroup-scored nil
1880   "List of scored articles in the current newsgroup.")
1881
1882 (defvar gnus-newsgroup-headers nil
1883   "List of article headers in the current newsgroup.")
1884
1885 (defvar gnus-newsgroup-threads nil)
1886
1887 (defvar gnus-newsgroup-prepared nil
1888   "Whether the current group has been prepared properly.")
1889
1890 (defvar gnus-newsgroup-ancient nil
1891   "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
1892
1893 (defvar gnus-newsgroup-sparse nil)
1894
1895 (defvar gnus-current-article nil)
1896 (defvar gnus-article-current nil)
1897 (defvar gnus-current-headers nil)
1898 (defvar gnus-have-all-headers nil)
1899 (defvar gnus-last-article nil)
1900 (defvar gnus-newsgroup-history nil)
1901 (defvar gnus-current-kill-article nil)
1902
1903 ;; Save window configuration.
1904 (defvar gnus-prev-winconf nil)
1905
1906 (defvar gnus-summary-mark-positions nil)
1907 (defvar gnus-group-mark-positions nil)
1908
1909 (defvar gnus-reffed-article-number nil)
1910
1911 ;;; Let the byte-compiler know that we know about this variable.
1912 (defvar rmail-default-rmail-file)
1913
1914 (defvar gnus-cache-removable-articles nil)
1915
1916 (defvar gnus-dead-summary nil)
1917
1918 (defconst gnus-summary-local-variables
1919   '(gnus-newsgroup-name
1920     gnus-newsgroup-begin gnus-newsgroup-end
1921     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
1922     gnus-newsgroup-last-folder gnus-newsgroup-last-file
1923     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
1924     gnus-newsgroup-unselected gnus-newsgroup-marked
1925     gnus-newsgroup-reads gnus-newsgroup-saved
1926     gnus-newsgroup-replied gnus-newsgroup-expirable
1927     gnus-newsgroup-processable gnus-newsgroup-killed
1928     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
1929     gnus-newsgroup-headers gnus-newsgroup-threads
1930     gnus-newsgroup-prepared gnus-summary-highlight-line-function
1931     gnus-current-article gnus-current-headers gnus-have-all-headers
1932     gnus-last-article gnus-article-internal-prepare-hook
1933     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1934     gnus-newsgroup-scored gnus-newsgroup-kill-headers
1935     gnus-newsgroup-async gnus-thread-expunge-below
1936     gnus-score-alist gnus-current-score-file gnus-summary-expunge-below
1937     (gnus-summary-mark-below . 0)
1938     gnus-newsgroup-active gnus-scores-exclude-files
1939     gnus-newsgroup-history gnus-newsgroup-ancient
1940     gnus-newsgroup-sparse
1941     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
1942     gnus-newsgroup-adaptive-score-file
1943     (gnus-newsgroup-expunged-tally . 0)
1944     gnus-cache-removable-articles gnus-newsgroup-cached
1945     gnus-newsgroup-data gnus-newsgroup-data-reverse
1946     gnus-newsgroup-limit gnus-newsgroup-limits)
1947   "Variables that are buffer-local to the summary buffers.")
1948
1949 (defconst gnus-bug-message
1950   "Sending a bug report to the Gnus Towers.
1951 ========================================
1952
1953 The buffer below is a mail buffer.  When you press `C-c C-c', it will
1954 be sent to the Gnus Bug Exterminators.
1955
1956 At the bottom of the buffer you'll see lots of variable settings.
1957 Please do not delete those.  They will tell the Bug People what your
1958 environment is, so that it will be easier to locate the bugs.
1959
1960 If you have found a bug that makes Emacs go \"beep\", set
1961 debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET')
1962 and include the backtrace in your bug report.
1963
1964 Please describe the bug in annoying, painstaking detail.
1965
1966 Thank you for your help in stamping out bugs.
1967 ")
1968
1969 ;;; End of variables.
1970
1971 ;; Define some autoload functions Gnus might use.
1972 (eval-and-compile
1973
1974   ;; This little mapcar goes through the list below and marks the
1975   ;; symbols in question as autoloaded functions.
1976   (mapcar
1977    (lambda (package)
1978      (let ((interactive (nth 1 (memq ':interactive package))))
1979        (mapcar
1980         (lambda (function)
1981           (let (keymap)
1982             (when (consp function)
1983               (setq keymap (car (memq 'keymap function)))
1984               (setq function (car function)))
1985             (autoload function (car package) nil interactive keymap)))
1986         (if (eq (nth 1 package) ':interactive)
1987             (cdddr package)
1988           (cdr package)))))
1989    '(("metamail" metamail-buffer)
1990      ("info" Info-goto-node)
1991      ("hexl" hexl-hex-string-to-integer)
1992      ("pp" pp pp-to-string pp-eval-expression)
1993      ("mail-extr" mail-extract-address-components)
1994      ("nnmail" nnmail-split-fancy nnmail-article-group)
1995      ("nnvirtual" nnvirtual-catchup-group)
1996      ("timezone" timezone-make-date-arpa-standard timezone-fix-time
1997       timezone-make-sortable-date timezone-make-time-string)
1998      ("sendmail" mail-position-on-field mail-setup)
1999      ("rmailout" rmail-output)
2000      ("rnewspost" news-mail-other-window news-reply-yank-original
2001       news-caesar-buffer-body)
2002      ("rmail" rmail-insert-rmail-file-header rmail-count-new-messages
2003       rmail-show-message)
2004      ("gnus-soup" :interactive t
2005       gnus-group-brew-soup gnus-brew-soup gnus-soup-add-article
2006       gnus-soup-send-replies gnus-soup-save-areas gnus-soup-pack-packet)
2007      ("nnsoup" nnsoup-pack-replies)
2008      ("gnus-scomo" :interactive t gnus-score-mode)
2009      ("gnus-mh" gnus-mh-mail-setup gnus-summary-save-article-folder
2010       gnus-Folder-save-name gnus-folder-save-name)
2011      ("gnus-mh" :interactive t gnus-summary-save-in-folder)
2012      ("gnus-vis" gnus-group-make-menu-bar gnus-summary-make-menu-bar
2013       gnus-server-make-menu-bar gnus-article-make-menu-bar
2014       gnus-browse-make-menu-bar gnus-highlight-selected-summary
2015       gnus-summary-highlight-line gnus-carpal-setup-buffer
2016       gnus-group-highlight-line
2017       gnus-article-add-button gnus-insert-next-page-button
2018       gnus-insert-prev-page-button gnus-visual-turn-off-edit-menu)
2019      ("gnus-vis" :interactive t
2020       gnus-article-push-button gnus-article-press-button
2021       gnus-article-highlight gnus-article-highlight-some
2022       gnus-article-highlight-headers gnus-article-highlight-signature
2023       gnus-article-add-buttons gnus-article-add-buttons-to-head
2024       gnus-article-next-button gnus-article-prev-button)
2025      ("gnus-demon" gnus-demon-add-nocem gnus-demon-add-scanmail
2026       gnus-demon-add-disconnection gnus-demon-add-handler
2027       gnus-demon-remove-handler)
2028      ("gnus-demon" :interactive t
2029       gnus-demon-init gnus-demon-cancel)
2030      ("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
2031       gnus-tree-open gnus-tree-close)
2032      ("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
2033       gnus-nocem-unwanted-article-p)
2034      ("gnus-srvr" gnus-enter-server-buffer gnus-server-set-info)
2035      ("gnus-srvr" gnus-browse-foreign-server)
2036      ("gnus-cite" :interactive t
2037       gnus-article-highlight-citation gnus-article-hide-citation-maybe
2038       gnus-article-hide-citation gnus-article-fill-cited-article
2039       gnus-article-hide-citation-in-followups)
2040      ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
2041       gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
2042       gnus-execute gnus-expunge)
2043      ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
2044       gnus-cache-possibly-remove-articles gnus-cache-request-article
2045       gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
2046       gnus-cache-enter-remove-article gnus-cached-article-p
2047       gnus-cache-open gnus-cache-close gnus-cache-update-article)
2048      ("gnus-cache" :interactive t gnus-jog-cache gnus-cache-enter-article
2049       gnus-cache-remove-article)
2050      ("gnus-score" :interactive t
2051       gnus-summary-increase-score gnus-summary-lower-score
2052       gnus-score-flush-cache gnus-score-close
2053       gnus-score-raise-same-subject-and-select
2054       gnus-score-raise-same-subject gnus-score-default
2055       gnus-score-raise-thread gnus-score-lower-same-subject-and-select
2056       gnus-score-lower-same-subject gnus-score-lower-thread
2057       gnus-possibly-score-headers gnus-summary-raise-score 
2058       gnus-summary-set-score gnus-summary-current-score)
2059      ("gnus-score"
2060       (gnus-summary-score-map keymap) gnus-score-save gnus-score-headers
2061       gnus-current-score-file-nondirectory gnus-score-adaptive
2062       gnus-score-find-trace gnus-score-file-name)
2063      ("gnus-edit" :interactive t gnus-score-customize)
2064      ("gnus-topic" :interactive t gnus-topic-mode)
2065      ("gnus-topic" gnus-topic-remove-group)
2066      ("gnus-salt" :interactive t gnus-pick-mode gnus-binary-mode)
2067      ("gnus-uu" (gnus-uu-extract-map keymap) (gnus-uu-mark-map keymap))
2068      ("gnus-uu" :interactive t
2069       gnus-uu-digest-mail-forward gnus-uu-digest-post-forward
2070       gnus-uu-mark-series gnus-uu-mark-region gnus-uu-mark-buffer
2071       gnus-uu-mark-by-regexp gnus-uu-mark-all
2072       gnus-uu-mark-sparse gnus-uu-mark-thread gnus-uu-decode-uu
2073       gnus-uu-decode-uu-and-save gnus-uu-decode-unshar
2074       gnus-uu-decode-unshar-and-save gnus-uu-decode-save
2075       gnus-uu-decode-binhex gnus-uu-decode-uu-view
2076       gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
2077       gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
2078       gnus-uu-decode-binhex-view)
2079      ("gnus-msg" (gnus-summary-send-map keymap)
2080       gnus-mail-yank-original gnus-mail-send-and-exit
2081       gnus-sendmail-setup-mail gnus-article-mail
2082       gnus-inews-message-id gnus-new-mail gnus-mail-reply)
2083      ("gnus-msg" :interactive t
2084       gnus-group-post-news gnus-group-mail gnus-summary-post-news
2085       gnus-summary-followup gnus-summary-followup-with-original
2086       gnus-summary-followup-and-reply
2087       gnus-summary-followup-and-reply-with-original
2088       gnus-summary-cancel-article gnus-summary-supersede-article
2089       gnus-post-news gnus-inews-news gnus-cancel-news
2090       gnus-summary-reply gnus-summary-reply-with-original
2091       gnus-summary-mail-forward gnus-summary-mail-other-window
2092       gnus-bug)
2093      ("gnus-picon" :interactive t gnus-article-display-picons
2094       gnus-group-display-picons gnus-picons-article-display-x-face)
2095      ("gnus-gl" bbb-login bbb-logout bbb-grouplens-group-p 
2096       gnus-grouplens-mode)
2097      ("gnus-vm" gnus-vm-mail-setup)
2098      ("gnus-vm" :interactive t gnus-summary-save-in-vm
2099       gnus-summary-save-article-vm gnus-yank-article))))
2100
2101 \f
2102
2103 ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
2104 ;; If you want the cursor to go somewhere else, set these two
2105 ;; functions in some startup hook to whatever you want.
2106 (defalias 'gnus-summary-position-point 'gnus-goto-colon)
2107 (defalias 'gnus-group-position-point 'gnus-goto-colon)
2108
2109 ;;; Various macros and substs.
2110
2111 (defun gnus-header-from (header)
2112   (mail-header-from header))
2113
2114 (defmacro gnus-eval-in-buffer-window (buffer &rest forms)
2115   "Pop to BUFFER, evaluate FORMS, and then return to the original window."
2116   (let ((tempvar (make-symbol "GnusStartBufferWindow"))
2117         (w (make-symbol "w"))
2118         (buf (make-symbol "buf")))
2119     `(let* ((,tempvar (selected-window))
2120             (,buf ,buffer)
2121             (,w (get-buffer-window ,buf 'visible)))
2122        (unwind-protect
2123            (progn
2124              (if ,w
2125                  (select-window ,w)
2126                (pop-to-buffer ,buf))
2127              ,@forms)
2128          (select-window ,tempvar)))))
2129
2130 (defmacro gnus-gethash (string hashtable)
2131   "Get hash value of STRING in HASHTABLE."
2132   `(symbol-value (intern-soft ,string ,hashtable)))
2133
2134 (defmacro gnus-sethash (string value hashtable)
2135   "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
2136   `(set (intern ,string ,hashtable) ,value))
2137
2138 (defmacro gnus-intern-safe (string hashtable)
2139   "Set hash value.  Arguments are STRING, VALUE, and HASHTABLE."
2140   `(let ((symbol (intern ,string ,hashtable)))
2141      (or (boundp symbol)
2142          (set symbol nil))
2143      symbol))
2144
2145 (defmacro gnus-group-unread (group)
2146   "Get the currently computed number of unread articles in GROUP."
2147   `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
2148
2149 (defmacro gnus-group-entry (group)
2150   "Get the newsrc entry for GROUP."
2151   `(gnus-gethash ,group gnus-newsrc-hashtb))
2152
2153 (defmacro gnus-active (group)
2154   "Get active info on GROUP."
2155   `(gnus-gethash ,group gnus-active-hashtb))
2156
2157 (defmacro gnus-set-active (group active)
2158   "Set GROUP's active info."
2159   `(gnus-sethash ,group ,active gnus-active-hashtb))
2160
2161 ;; modified by MORIOKA Tomohiko <morioka@jaist.ac.jp>
2162 ;;   function `substring' might cut on a middle of multi-octet
2163 ;;   character.
2164 (defun gnus-truncate-string (str width)
2165   (substring str 0 width))
2166
2167 ;; Added by Geoffrey T. Dairiki <dairiki@u.washington.edu>.  A safe way
2168 ;; to limit the length of a string.  This function is necessary since
2169 ;; `(substr "abc" 0 30)' pukes with "Args out of range".
2170 (defsubst gnus-limit-string (str width)
2171   (if (> (length str) width)
2172       (substring str 0 width)
2173     str))
2174
2175 (defsubst gnus-simplify-subject-re (subject)
2176   "Remove \"Re:\" from subject lines."
2177   (if (string-match "^[Rr][Ee]: *" subject)
2178       (substring subject (match-end 0))
2179     subject))
2180
2181 (defsubst gnus-functionp (form)
2182   "Return non-nil if FORM is funcallable."
2183   (or (and (symbolp form) (fboundp form))
2184       (and (listp form) (eq (car form) 'lambda))))
2185
2186 (defsubst gnus-goto-char (point)
2187   (and point (goto-char point)))
2188
2189 (defmacro gnus-buffer-exists-p (buffer)
2190   `(let ((buffer ,buffer))
2191      (and buffer
2192           (funcall (if (stringp buffer) 'get-buffer 'buffer-name)
2193                    buffer))))
2194
2195 (defmacro gnus-kill-buffer (buffer)
2196   `(let ((buf ,buffer))
2197      (if (gnus-buffer-exists-p buf)
2198          (kill-buffer buf))))
2199
2200 (defsubst gnus-point-at-bol ()
2201   "Return point at the beginning of the line."
2202   (let ((p (point)))
2203     (beginning-of-line)
2204     (prog1
2205         (point)
2206       (goto-char p))))
2207
2208 (defsubst gnus-point-at-eol ()
2209   "Return point at the end of the line."
2210   (let ((p (point)))
2211     (end-of-line)
2212     (prog1
2213         (point)
2214       (goto-char p))))
2215
2216 (defun gnus-alive-p ()
2217   "Say whether Gnus is running or not."
2218   (and gnus-group-buffer
2219        (get-buffer gnus-group-buffer)))
2220
2221 ;; Delete the current line (and the next N lines.);
2222 (defmacro gnus-delete-line (&optional n)
2223   `(delete-region (progn (beginning-of-line) (point))
2224                   (progn (forward-line ,(or n 1)) (point))))
2225
2226 ;; Suggested by Brian Edmonds <edmonds@cs.ubc.ca>.
2227 (defvar gnus-init-inhibit nil)
2228 (defun gnus-read-init-file (&optional inhibit-next)
2229   (if gnus-init-inhibit
2230       (setq gnus-init-inhibit nil)
2231     (setq gnus-init-inhibit inhibit-next)
2232     (and gnus-init-file
2233          (or (and (file-exists-p gnus-init-file)
2234                   ;; Don't try to load a directory.
2235                   (not (file-directory-p gnus-init-file)))
2236              (file-exists-p (concat gnus-init-file ".el"))
2237              (file-exists-p (concat gnus-init-file ".elc")))
2238          (condition-case var
2239              (load gnus-init-file nil t)
2240            (error
2241             (error "Error in %s: %s" gnus-init-file var))))))
2242
2243 ;; Info access macros.
2244
2245 (defmacro gnus-info-group (info)
2246   `(nth 0 ,info))
2247 (defmacro gnus-info-rank (info)
2248   `(nth 1 ,info))
2249 (defmacro gnus-info-read (info)
2250   `(nth 2 ,info))
2251 (defmacro gnus-info-marks (info)
2252   `(nth 3 ,info))
2253 (defmacro gnus-info-method (info)
2254   `(nth 4 ,info))
2255 (defmacro gnus-info-params (info)
2256   `(nth 5 ,info))
2257
2258 (defmacro gnus-info-level (info)
2259   `(let ((rank (gnus-info-rank ,info)))
2260      (if (consp rank)
2261          (car rank)
2262        rank)))
2263 (defmacro gnus-info-score (info)
2264   `(let ((rank (gnus-info-rank ,info)))
2265      (or (and (consp rank) (cdr rank)) 0)))
2266
2267 (defmacro gnus-info-set-group (info group)
2268   `(setcar ,info ,group))
2269 (defmacro gnus-info-set-rank (info rank)
2270   `(setcar (nthcdr 1 ,info) ,rank))
2271 (defmacro gnus-info-set-read (info read)
2272   `(setcar (nthcdr 2 ,info) ,read))
2273 (defmacro gnus-info-set-marks (info marks)
2274   `(setcar (nthcdr 3 ,info) ,marks))
2275 (defmacro gnus-info-set-method (info method)
2276   `(setcar (nthcdr 4 ,info) ,method))
2277 (defmacro gnus-info-set-params (info params)
2278   `(setcar (nthcdr 5 ,info) ,params))
2279
2280 (defmacro gnus-info-set-level (info level)
2281   `(let ((rank (cdr ,info)))
2282      (if (consp (car rank))
2283          (setcar (car rank) ,level)
2284        (setcar rank ,level))))
2285 (defmacro gnus-info-set-score (info score)
2286   `(let ((rank (cdr ,info)))
2287      (if (consp (car rank))
2288          (setcdr (car rank) ,score)
2289        (setcar rank (cons (car rank) ,score)))))
2290
2291 (defmacro gnus-get-info (group)
2292   `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
2293
2294 (defun gnus-byte-code (func)
2295   "Return a form that can be `eval'ed based on FUNC."
2296   (let ((fval (symbol-function func)))
2297     (if (byte-code-function-p fval)
2298         (let ((flist (append fval nil)))
2299           (setcar flist 'byte-code)
2300           flist)
2301       (cons 'progn (cddr fval)))))
2302
2303 ;;; Load the compatability functions.
2304
2305 (require 'gnus-cus)
2306 (require 'gnus-ems)
2307
2308 \f
2309 ;;;
2310 ;;; Shutdown
2311 ;;;
2312
2313 (defvar gnus-shutdown-alist nil)
2314
2315 (defun gnus-add-shutdown (function &rest symbols)
2316   "Run FUNCTION whenever one of SYMBOLS is shut down."
2317   (push (cons function symbols) gnus-shutdown-alist))
2318
2319 (defun gnus-shutdown (symbol)
2320   "Shut down everything that waits for SYMBOL."
2321   (let ((alist gnus-shutdown-alist)
2322         entry)
2323     (while (setq entry (pop alist))
2324       (when (memq symbol (cdr entry))
2325         (funcall (car entry))))))
2326
2327 \f
2328
2329 ;; Format specs.  The chunks below are the machine-generated forms
2330 ;; that are to be evaled as the result of the default format strings.
2331 ;; We write them in here to get them byte-compiled.  That way the
2332 ;; default actions will be quite fast, while still retaining the full
2333 ;; flexibility of the user-defined format specs.
2334
2335 ;; First we have lots of dummy defvars to let the compiler know these
2336 ;; are really dynamic variables.
2337
2338 (defvar gnus-tmp-unread)
2339 (defvar gnus-tmp-replied)
2340 (defvar gnus-tmp-score-char)
2341 (defvar gnus-tmp-indentation)
2342 (defvar gnus-tmp-opening-bracket)
2343 (defvar gnus-tmp-lines)
2344 (defvar gnus-tmp-name)
2345 (defvar gnus-tmp-closing-bracket)
2346 (defvar gnus-tmp-subject-or-nil)
2347 (defvar gnus-tmp-subject)
2348 (defvar gnus-tmp-marked)
2349 (defvar gnus-tmp-marked-mark)
2350 (defvar gnus-tmp-subscribed)
2351 (defvar gnus-tmp-process-marked)
2352 (defvar gnus-tmp-number-of-unread)
2353 (defvar gnus-tmp-group-name)
2354 (defvar gnus-tmp-group)
2355 (defvar gnus-tmp-article-number)
2356 (defvar gnus-tmp-unread-and-unselected)
2357 (defvar gnus-tmp-news-method)
2358 (defvar gnus-tmp-news-server)
2359 (defvar gnus-tmp-article-number)
2360 (defvar gnus-mouse-face)
2361 (defvar gnus-mouse-face-prop)
2362
2363 (defun gnus-summary-line-format-spec ()
2364   (insert gnus-tmp-unread gnus-tmp-replied
2365           gnus-tmp-score-char gnus-tmp-indentation)
2366   (gnus-put-text-property
2367    (point)
2368    (progn
2369      (insert
2370       gnus-tmp-opening-bracket
2371       (format "%4d: %-20s"
2372               gnus-tmp-lines
2373               (if (> (length gnus-tmp-name) 20)
2374                   (substring gnus-tmp-name 0 20)
2375                 gnus-tmp-name))
2376       gnus-tmp-closing-bracket)
2377      (point))
2378    gnus-mouse-face-prop gnus-mouse-face)
2379   (insert " " gnus-tmp-subject-or-nil "\n"))
2380
2381 (defvar gnus-summary-line-format-spec
2382   (gnus-byte-code 'gnus-summary-line-format-spec))
2383
2384 (defun gnus-summary-dummy-line-format-spec ()
2385   (insert "*  ")
2386   (gnus-put-text-property
2387    (point)
2388    (progn
2389      (insert ":                          :")
2390      (point))
2391    gnus-mouse-face-prop gnus-mouse-face)
2392   (insert " " gnus-tmp-subject "\n"))
2393
2394 (defvar gnus-summary-dummy-line-format-spec
2395   (gnus-byte-code 'gnus-summary-dummy-line-format-spec))
2396
2397 (defun gnus-group-line-format-spec ()
2398   (insert gnus-tmp-marked-mark gnus-tmp-subscribed
2399           gnus-tmp-process-marked
2400           gnus-group-indentation
2401           (format "%5s: " gnus-tmp-number-of-unread))
2402   (gnus-put-text-property
2403    (point)
2404    (progn
2405      (insert gnus-tmp-group "\n")
2406      (1- (point)))
2407    gnus-mouse-face-prop gnus-mouse-face))
2408 (defvar gnus-group-line-format-spec
2409   (gnus-byte-code 'gnus-group-line-format-spec))
2410
2411 (defvar gnus-format-specs
2412   `((version . ,emacs-version)
2413     (group ,gnus-group-line-format ,gnus-group-line-format-spec)
2414     (summary-dummy ,gnus-summary-dummy-line-format
2415                    ,gnus-summary-dummy-line-format-spec)
2416     (summary ,gnus-summary-line-format ,gnus-summary-line-format-spec)))
2417
2418 (defvar gnus-article-mode-line-format-spec nil)
2419 (defvar gnus-summary-mode-line-format-spec nil)
2420 (defvar gnus-group-mode-line-format-spec nil)
2421
2422 ;;; Phew.  All that gruft is over, fortunately.
2423
2424 \f
2425 ;;;
2426 ;;; Gnus Utility Functions
2427 ;;;
2428
2429 (defun gnus-extract-address-components (from)
2430   (let (name address)
2431     ;; First find the address - the thing with the @ in it.  This may
2432     ;; not be accurate in mail addresses, but does the trick most of
2433     ;; the time in news messages.
2434     (if (string-match "\\b[^@ \t<>]+[!@][^@ \t<>]+\\b" from)
2435         (setq address (substring from (match-beginning 0) (match-end 0))))
2436     ;; Then we check whether the "name <address>" format is used.
2437     (and address
2438          ;; Fix by MORIOKA Tomohiko <morioka@jaist.ac.jp>
2439          ;; Linear white space is not required.
2440          (string-match (concat "[ \t]*<" (regexp-quote address) ">") from)
2441          (and (setq name (substring from 0 (match-beginning 0)))
2442               ;; Strip any quotes from the name.
2443               (string-match "\".*\"" name)
2444               (setq name (substring name 1 (1- (match-end 0))))))
2445     ;; If not, then "address (name)" is used.
2446     (or name
2447         (and (string-match "(.+)" from)
2448              (setq name (substring from (1+ (match-beginning 0))
2449                                    (1- (match-end 0)))))
2450         (and (string-match "()" from)
2451              (setq name address))
2452         ;; Fix by MORIOKA Tomohiko <morioka@jaist.ac.jp>.
2453         ;; XOVER might not support folded From headers.
2454         (and (string-match "(.*" from)
2455              (setq name (substring from (1+ (match-beginning 0))
2456                                    (match-end 0)))))
2457     ;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
2458     (list (or name from) (or address from))))
2459
2460 (defun gnus-fetch-field (field)
2461   "Return the value of the header FIELD of current article."
2462   (save-excursion
2463     (save-restriction
2464       (let ((case-fold-search t)
2465             (inhibit-point-motion-hooks t))
2466         (nnheader-narrow-to-headers)
2467         (message-fetch-field field)))))
2468
2469 (defun gnus-goto-colon ()
2470   (beginning-of-line)
2471   (search-forward ":" (gnus-point-at-eol) t))
2472
2473 ;;;###autoload
2474 (defun gnus-update-format (var)
2475   "Update the format specification near point."
2476   (interactive
2477    (list
2478     (save-excursion
2479       (eval-defun nil)
2480       ;; Find the end of the current word.
2481       (re-search-forward "[ \t\n]" nil t)
2482       ;; Search backward.
2483       (when (re-search-backward "\\(gnus-[-a-z]+-line-format\\)" nil t)
2484         (match-string 1)))))
2485   (let* ((type (intern (progn (string-match "gnus-\\([-a-z]+\\)-line" var)
2486                               (match-string 1 var))))
2487          (entry (assq type gnus-format-specs))
2488          value spec)
2489     (when entry
2490       (setq gnus-format-specs (delq entry gnus-format-specs)))
2491     (set
2492      (intern (format "%s-spec" var))
2493      (gnus-parse-format (setq value (symbol-value (intern var)))
2494                         (symbol-value (intern (format "%s-alist" var)))
2495                         (not (string-match "mode" var))))
2496     (setq spec (symbol-value (intern (format "%s-spec" var))))
2497     (push (list type value spec) gnus-format-specs)
2498
2499     (pop-to-buffer "*Gnus Format*")
2500     (erase-buffer)
2501     (lisp-interaction-mode)
2502     (insert (pp-to-string spec))))
2503
2504 (defun gnus-update-format-specifications (&optional force)
2505   "Update all (necessary) format specifications."
2506   ;; Make the indentation array.
2507   (gnus-make-thread-indent-array)
2508
2509   ;; See whether all the stored info needs to be flushed.
2510   (when (or force
2511             (not (equal emacs-version
2512                         (cdr (assq 'version gnus-format-specs)))))
2513     (setq gnus-format-specs nil))
2514
2515   ;; Go through all the formats and see whether they need updating.
2516   (let ((types '(summary summary-dummy group
2517                          summary-mode group-mode article-mode))
2518         new-format entry type val)
2519     (while (setq type (pop types))
2520       ;; Jump to the proper buffer to find out the value of
2521       ;; the variable, if possible.  (It may be buffer-local.)
2522       (save-excursion
2523         (let ((buffer (intern (format "gnus-%s-buffer" type)))
2524               val)
2525           (when (and (boundp buffer)
2526                      (setq val (symbol-value buffer))
2527                      (get-buffer val)
2528                      (buffer-name (get-buffer val)))
2529             (set-buffer (get-buffer val)))
2530           (setq new-format (symbol-value
2531                             (intern (format "gnus-%s-line-format" type))))))
2532       (setq entry (cdr (assq type gnus-format-specs)))
2533       (if (and entry
2534                (equal (car entry) new-format))
2535           ;; Use the old format.
2536           (set (intern (format "gnus-%s-line-format-spec" type))
2537                (cadr entry))
2538         ;; This is a new format.
2539         (setq val
2540               (if (not (stringp new-format))
2541                   ;; This is a function call or something.
2542                   new-format
2543                 ;; This is a "real" format.
2544                 (gnus-parse-format
2545                  new-format
2546                  (symbol-value
2547                   (intern (format "gnus-%s-line-format-alist"
2548                                   (if (eq type 'article-mode)
2549                                       'summary-mode type))))
2550                  (not (string-match "mode$" (symbol-name type))))))
2551         ;; Enter the new format spec into the list.
2552         (if entry
2553             (progn
2554               (setcar (cdr entry) val)
2555               (setcar entry new-format))
2556           (push (list type new-format val) gnus-format-specs))
2557         (set (intern (format "gnus-%s-line-format-spec" type)) val))))
2558
2559   (unless (assq 'version gnus-format-specs)
2560     (push (cons 'version emacs-version) gnus-format-specs))
2561
2562   (gnus-update-group-mark-positions)
2563   (gnus-update-summary-mark-positions))
2564
2565 (defun gnus-update-summary-mark-positions ()
2566   "Compute where the summary marks are to go."
2567   (save-excursion
2568     (when (and gnus-summary-buffer
2569                (get-buffer gnus-summary-buffer)
2570                (buffer-name (get-buffer gnus-summary-buffer)))
2571       (set-buffer gnus-summary-buffer))
2572     (let ((gnus-replied-mark 129)
2573           (gnus-score-below-mark 130)
2574           (gnus-score-over-mark 130)
2575           (thread nil)
2576           (gnus-visual nil)
2577           (spec gnus-summary-line-format-spec)
2578           pos)
2579       (save-excursion
2580         (gnus-set-work-buffer)
2581         (let ((gnus-summary-line-format-spec spec))
2582           (gnus-summary-insert-line
2583            [0 "" "" "" "" "" 0 0 ""]  0 nil 128 t nil "" nil 1)
2584           (goto-char (point-min))
2585           (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
2586                                              (- (point) 2)))))
2587           (goto-char (point-min))
2588           (push (cons 'replied (and (search-forward "\201" nil t) 
2589                                     (- (point) 2)))
2590                 pos)
2591           (goto-char (point-min))
2592           (push (cons 'score (and (search-forward "\202" nil t) (- (point) 2)))
2593                 pos)))
2594       (setq gnus-summary-mark-positions pos))))
2595
2596 (defun gnus-update-group-mark-positions ()
2597   (save-excursion
2598     (let ((gnus-process-mark 128)
2599           (gnus-group-marked '("dummy.group"))
2600           (gnus-active-hashtb (make-vector 10 0)))
2601       (gnus-set-active "dummy.group" '(0 . 0))
2602       (gnus-set-work-buffer)
2603       (gnus-group-insert-group-line "dummy.group" 0 nil 0 nil)
2604       (goto-char (point-min))
2605       (setq gnus-group-mark-positions
2606             (list (cons 'process (and (search-forward "\200" nil t)
2607                                       (- (point) 2))))))))
2608
2609 (defvar gnus-mouse-face-0 'highlight)
2610 (defvar gnus-mouse-face-1 'highlight)
2611 (defvar gnus-mouse-face-2 'highlight)
2612 (defvar gnus-mouse-face-3 'highlight)
2613 (defvar gnus-mouse-face-4 'highlight)
2614
2615 (defun gnus-mouse-face-function (form type)
2616   `(gnus-put-text-property
2617     (point) (progn ,@form (point))
2618     gnus-mouse-face-prop
2619     ,(if (equal type 0)
2620          'gnus-mouse-face
2621        `(quote ,(symbol-value (intern (format "gnus-mouse-face-%d" type)))))))
2622
2623 (defvar gnus-face-0 'bold)
2624 (defvar gnus-face-1 'italic)
2625 (defvar gnus-face-2 'bold-italic)
2626 (defvar gnus-face-3 'bold)
2627 (defvar gnus-face-4 'bold)
2628
2629 (defun gnus-face-face-function (form type)
2630   `(gnus-put-text-property
2631     (point) (progn ,@form (point))
2632     'face ',(symbol-value (intern (format "gnus-face-%d" type)))))
2633
2634 (defun gnus-max-width-function (el max-width)
2635   (or (numberp max-width) (signal 'wrong-type-argument '(numberp max-width)))
2636   (if (symbolp el)
2637       `(if (> (length ,el) ,max-width)
2638            (substring ,el 0 ,max-width)
2639          ,el)
2640     `(let ((val (eval ,el)))
2641        (if (numberp val)
2642            (setq val (int-to-string val)))
2643        (if (> (length val) ,max-width)
2644            (substring val 0 ,max-width)
2645          val))))
2646
2647 (defun gnus-parse-format (format spec-alist &optional insert)
2648   ;; This function parses the FORMAT string with the help of the
2649   ;; SPEC-ALIST and returns a list that can be eval'ed to return the
2650   ;; string.  If the FORMAT string contains the specifiers %( and %)
2651   ;; the text between them will have the mouse-face text property.
2652   (if (string-match
2653        "\\`\\(.*\\)%[0-9]?[{(]\\(.*\\)%[0-9]?[})]\\(.*\n?\\)\\'"
2654        format)
2655       (gnus-parse-complex-format format spec-alist)
2656     ;; This is a simple format.
2657     (gnus-parse-simple-format format spec-alist insert)))
2658
2659 (defun gnus-parse-complex-format (format spec-alist)
2660   (save-excursion
2661     (gnus-set-work-buffer)
2662     (insert format)
2663     (goto-char (point-min))
2664     (while (re-search-forward "\"" nil t)
2665       (replace-match "\\\"" nil t))
2666     (goto-char (point-min))
2667     (insert "(\"")
2668     (while (re-search-forward "%\\([0-9]+\\)?\\([{}()]\\)" nil t)
2669       (let ((number (if (match-beginning 1)
2670                         (match-string 1) "0"))
2671             (delim (aref (match-string 2) 0)))
2672         (if (or (= delim ?\() (= delim ?\{))
2673             (replace-match (concat "\"(" (if (= delim ?\() "mouse" "face")
2674                                    " " number " \""))
2675           (replace-match "\")\""))))
2676     (goto-char (point-max))
2677     (insert "\")")
2678     (goto-char (point-min))
2679     (let ((form (read (current-buffer))))
2680       (cons 'progn (gnus-complex-form-to-spec form spec-alist)))))
2681
2682 (defun gnus-complex-form-to-spec (form spec-alist)
2683   (delq nil
2684         (mapcar
2685          (lambda (sform)
2686            (if (stringp sform)
2687                (gnus-parse-simple-format sform spec-alist t)
2688              (funcall (intern (format "gnus-%s-face-function" (car sform)))
2689                       (gnus-complex-form-to-spec (cddr sform) spec-alist)
2690                       (nth 1 sform))))
2691          form)))
2692
2693 (defun gnus-parse-simple-format (format spec-alist &optional insert)
2694   ;; This function parses the FORMAT string with the help of the
2695   ;; SPEC-ALIST and returns a list that can be eval'ed to return a
2696   ;; string.
2697   (let ((max-width 0)
2698         spec flist fstring newspec elem beg result dontinsert)
2699     (save-excursion
2700       (gnus-set-work-buffer)
2701       (insert format)
2702       (goto-char (point-min))
2703       (while (re-search-forward "%[-0-9]*\\(,[0-9]+\\)?\\([^0-9]\\)\\(.\\)?"
2704                                 nil t)
2705         (if (= (setq spec (string-to-char (match-string 2))) ?%)
2706               (setq newspec "%"
2707                     beg (1+ (match-beginning 0)))
2708           ;; First check if there are any specs that look anything like
2709           ;; "%12,12A", ie. with a "max width specification".  These have
2710           ;; to be treated specially.
2711           (if (setq beg (match-beginning 1))
2712               (setq max-width
2713                     (string-to-int
2714                      (buffer-substring
2715                       (1+ (match-beginning 1)) (match-end 1))))
2716             (setq max-width 0)
2717             (setq beg (match-beginning 2)))
2718           ;; Find the specification from `spec-alist'.
2719           (unless (setq elem (cdr (assq spec spec-alist)))
2720             (setq elem '("*" ?s)))
2721           ;; Treat user defined format specifiers specially.
2722           (when (eq (car elem) 'gnus-tmp-user-defined)
2723             (setq elem
2724                   (list
2725                    (list (intern (concat "gnus-user-format-function-"
2726                                          (match-string 3)))
2727                          'gnus-tmp-header) ?s))
2728             (delete-region (match-beginning 3) (match-end 3)))
2729           (if (not (zerop max-width))
2730               (let ((el (car elem)))
2731                 (cond ((= (cadr elem) ?c)
2732                        (setq el (list 'char-to-string el)))
2733                       ((= (cadr elem) ?d)
2734                        (setq el (list 'int-to-string el))))
2735                 (setq flist (cons (gnus-max-width-function el max-width)
2736                                   flist))
2737                 (setq newspec ?s))
2738             (progn
2739               (setq flist (cons (car elem) flist))
2740               (setq newspec (cadr elem)))))
2741         ;; Remove the old specification (and possibly a ",12" string).
2742         (delete-region beg (match-end 2))
2743         ;; Insert the new specification.
2744         (goto-char beg)
2745         (insert newspec))
2746       (setq fstring (buffer-substring 1 (point-max))))
2747     ;; Do some postprocessing to increase efficiency.
2748     (setq
2749      result
2750      (cond
2751       ;; Emptyness.
2752       ((string= fstring "")
2753        nil)
2754       ;; Not a format string.
2755       ((not (string-match "%" fstring))
2756        (list fstring))
2757       ;; A format string with just a single string spec.
2758       ((string= fstring "%s")
2759        (list (car flist)))
2760       ;; A single character.
2761       ((string= fstring "%c")
2762        (list (car flist)))
2763       ;; A single number.
2764       ((string= fstring "%d")
2765        (setq dontinsert)
2766        (if insert
2767            (list `(princ ,(car flist)))
2768          (list `(int-to-string ,(car flist)))))
2769       ;; Just lots of chars and strings.
2770       ((string-match "\\`\\(%[cs]\\)+\\'" fstring)
2771        (nreverse flist))
2772       ;; A single string spec at the beginning of the spec.
2773       ((string-match "\\`%[sc][^%]+\\'" fstring)
2774        (list (car flist) (substring fstring 2)))
2775       ;; A single string spec in the middle of the spec.
2776       ((string-match "\\`\\([^%]+\\)%[sc]\\([^%]+\\)\\'" fstring)
2777        (list (match-string 1 fstring) (car flist) (match-string 2 fstring)))
2778       ;; A single string spec in the end of the spec.
2779       ((string-match "\\`\\([^%]+\\)%[sc]\\'" fstring)
2780        (list (match-string 1 fstring) (car flist)))
2781       ;; A more complex spec.
2782       (t
2783        (list (cons 'format (cons fstring (nreverse flist)))))))
2784
2785     (if insert
2786         (when result
2787           (if dontinsert
2788               result
2789             (cons 'insert result)))
2790       (cond ((stringp result)
2791              result)
2792             ((consp result)
2793              (cons 'concat result))
2794             (t "")))))
2795
2796 (defun gnus-eval-format (format &optional alist props)
2797   "Eval the format variable FORMAT, using ALIST.
2798 If PROPS, insert the result."
2799   (let ((form (gnus-parse-format format alist props)))
2800     (if props
2801         (gnus-add-text-properties (point) (progn (eval form) (point)) props)
2802       (eval form))))
2803
2804 (defun gnus-remove-text-with-property (prop)
2805   "Delete all text in the current buffer with text property PROP."
2806   (save-excursion
2807     (goto-char (point-min))
2808     (while (not (eobp))
2809       (while (get-text-property (point) prop)
2810         (delete-char 1))
2811       (goto-char (next-single-property-change (point) prop nil (point-max))))))
2812
2813 (defun gnus-set-work-buffer ()
2814   (if (get-buffer gnus-work-buffer)
2815       (progn
2816         (set-buffer gnus-work-buffer)
2817         (erase-buffer))
2818     (set-buffer (get-buffer-create gnus-work-buffer))
2819     (kill-all-local-variables)
2820     (buffer-disable-undo (current-buffer))
2821     (gnus-add-current-to-buffer-list)))
2822
2823 ;; Article file names when saving.
2824
2825 (defun gnus-Numeric-save-name (newsgroup headers &optional last-file)
2826   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
2827 If variable `gnus-use-long-file-name' is nil, it is ~/News/News.group/num.
2828 Otherwise, it is like ~/News/news/group/num."
2829   (let ((default
2830           (expand-file-name
2831            (concat (if (gnus-use-long-file-name 'not-save)
2832                        (gnus-capitalize-newsgroup newsgroup)
2833                      (gnus-newsgroup-directory-form newsgroup))
2834                    "/" (int-to-string (mail-header-number headers)))
2835            gnus-article-save-directory)))
2836     (if (and last-file
2837              (string-equal (file-name-directory default)
2838                            (file-name-directory last-file))
2839              (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
2840         default
2841       (or last-file default))))
2842
2843 (defun gnus-numeric-save-name (newsgroup headers &optional last-file)
2844   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
2845 If variable `gnus-use-long-file-name' is non-nil, it is
2846 ~/News/news.group/num.  Otherwise, it is like ~/News/news/group/num."
2847   (let ((default
2848           (expand-file-name
2849            (concat (if (gnus-use-long-file-name 'not-save)
2850                        newsgroup
2851                      (gnus-newsgroup-directory-form newsgroup))
2852                    "/" (int-to-string (mail-header-number headers)))
2853            gnus-article-save-directory)))
2854     (if (and last-file
2855              (string-equal (file-name-directory default)
2856                            (file-name-directory last-file))
2857              (string-match "^[0-9]+$" (file-name-nondirectory last-file)))
2858         default
2859       (or last-file default))))
2860
2861 (defun gnus-Plain-save-name (newsgroup headers &optional last-file)
2862   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
2863 If variable `gnus-use-long-file-name' is non-nil, it is
2864 ~/News/News.group.  Otherwise, it is like ~/News/news/group/news."
2865   (or last-file
2866       (expand-file-name
2867        (if (gnus-use-long-file-name 'not-save)
2868            (gnus-capitalize-newsgroup newsgroup)
2869          (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
2870        gnus-article-save-directory)))
2871
2872 (defun gnus-plain-save-name (newsgroup headers &optional last-file)
2873   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
2874 If variable `gnus-use-long-file-name' is non-nil, it is
2875 ~/News/news.group.  Otherwise, it is like ~/News/news/group/news."
2876   (or last-file
2877       (expand-file-name
2878        (if (gnus-use-long-file-name 'not-save)
2879            newsgroup
2880          (concat (gnus-newsgroup-directory-form newsgroup) "/news"))
2881        gnus-article-save-directory)))
2882
2883 ;; For subscribing new newsgroup
2884
2885 (defun gnus-subscribe-hierarchical-interactive (groups)
2886   (let ((groups (sort groups 'string<))
2887         prefixes prefix start ans group starts)
2888     (while groups
2889       (setq prefixes (list "^"))
2890       (while (and groups prefixes)
2891         (while (not (string-match (car prefixes) (car groups)))
2892           (setq prefixes (cdr prefixes)))
2893         (setq prefix (car prefixes))
2894         (setq start (1- (length prefix)))
2895         (if (and (string-match "[^\\.]\\." (car groups) start)
2896                  (cdr groups)
2897                  (setq prefix
2898                        (concat "^" (substring (car groups) 0 (match-end 0))))
2899                  (string-match prefix (cadr groups)))
2900             (progn
2901               (setq prefixes (cons prefix prefixes))
2902               (message "Descend hierarchy %s? ([y]nsq): "
2903                        (substring prefix 1 (1- (length prefix))))
2904               (setq ans (read-char))
2905               (cond ((= ans ?n)
2906                      (while (and groups
2907                                  (string-match prefix
2908                                                (setq group (car groups))))
2909                        (setq gnus-killed-list
2910                              (cons group gnus-killed-list))
2911                        (gnus-sethash group group gnus-killed-hashtb)
2912                        (setq groups (cdr groups)))
2913                      (setq starts (cdr starts)))
2914                     ((= ans ?s)
2915                      (while (and groups
2916                                  (string-match prefix
2917                                                (setq group (car groups))))
2918                        (gnus-sethash group group gnus-killed-hashtb)
2919                        (gnus-subscribe-alphabetically (car groups))
2920                        (setq groups (cdr groups)))
2921                      (setq starts (cdr starts)))
2922                     ((= ans ?q)
2923                      (while groups
2924                        (setq group (car groups))
2925                        (setq gnus-killed-list (cons group gnus-killed-list))
2926                        (gnus-sethash group group gnus-killed-hashtb)
2927                        (setq groups (cdr groups))))
2928                     (t nil)))
2929           (message "Subscribe %s? ([n]yq)" (car groups))
2930           (setq ans (read-char))
2931           (setq group (car groups))
2932           (cond ((= ans ?y)
2933                  (gnus-subscribe-alphabetically (car groups))
2934                  (gnus-sethash group group gnus-killed-hashtb))
2935                 ((= ans ?q)
2936                  (while groups
2937                    (setq group (car groups))
2938                    (setq gnus-killed-list (cons group gnus-killed-list))
2939                    (gnus-sethash group group gnus-killed-hashtb)
2940                    (setq groups (cdr groups))))
2941                 (t
2942                  (setq gnus-killed-list (cons group gnus-killed-list))
2943                  (gnus-sethash group group gnus-killed-hashtb)))
2944           (setq groups (cdr groups)))))))
2945
2946 (defun gnus-subscribe-randomly (newsgroup)
2947   "Subscribe new NEWSGROUP by making it the first newsgroup."
2948   (gnus-subscribe-newsgroup newsgroup))
2949
2950 (defun gnus-subscribe-alphabetically (newgroup)
2951   "Subscribe new NEWSGROUP and insert it in alphabetical order."
2952   (let ((groups (cdr gnus-newsrc-alist))
2953         before)
2954     (while (and (not before) groups)
2955       (if (string< newgroup (caar groups))
2956           (setq before (caar groups))
2957         (setq groups (cdr groups))))
2958     (gnus-subscribe-newsgroup newgroup before)))
2959
2960 (defun gnus-subscribe-hierarchically (newgroup)
2961   "Subscribe new NEWSGROUP and insert it in hierarchical newsgroup order."
2962   ;; Basic ideas by mike-w@cs.aukuni.ac.nz (Mike Williams)
2963   (save-excursion
2964     (set-buffer (find-file-noselect gnus-current-startup-file))
2965     (let ((groupkey newgroup)
2966           before)
2967       (while (and (not before) groupkey)
2968         (goto-char (point-min))
2969         (let ((groupkey-re
2970                (concat "^\\(" (regexp-quote groupkey) ".*\\)[!:]")))
2971           (while (and (re-search-forward groupkey-re nil t)
2972                       (progn
2973                         (setq before (match-string 1))
2974                         (string< before newgroup)))))
2975         ;; Remove tail of newsgroup name (eg. a.b.c -> a.b)
2976         (setq groupkey
2977               (if (string-match "^\\(.*\\)\\.[^.]+$" groupkey)
2978                   (substring groupkey (match-beginning 1) (match-end 1)))))
2979       (gnus-subscribe-newsgroup newgroup before))))
2980
2981 (defun gnus-subscribe-interactively (group)
2982   "Subscribe the new GROUP interactively.
2983 It is inserted in hierarchical newsgroup order if subscribed.  If not,
2984 it is killed."
2985   (if (gnus-y-or-n-p (format "Subscribe new newsgroup: %s " group))
2986       (gnus-subscribe-hierarchically group)
2987     (push group gnus-killed-list)))
2988
2989 (defun gnus-subscribe-zombies (group)
2990   "Make the new GROUP into a zombie group."
2991   (push group gnus-zombie-list))
2992
2993 (defun gnus-subscribe-killed (group)
2994   "Make the new GROUP a killed group."
2995   (push group gnus-killed-list))
2996
2997 (defun gnus-subscribe-newsgroup (newsgroup &optional next)
2998   "Subscribe new NEWSGROUP.
2999 If NEXT is non-nil, it is inserted before NEXT.  Otherwise it is made
3000 the first newsgroup."
3001   ;; We subscribe the group by changing its level to `subscribed'.
3002   (gnus-group-change-level
3003    newsgroup gnus-level-default-subscribed
3004    gnus-level-killed (gnus-gethash (or next "dummy.group") gnus-newsrc-hashtb))
3005   (gnus-message 5 "Subscribe newsgroup: %s" newsgroup))
3006
3007 ;; For directories
3008
3009 (defun gnus-newsgroup-directory-form (newsgroup)
3010   "Make hierarchical directory name from NEWSGROUP name."
3011   (let ((newsgroup (gnus-newsgroup-savable-name newsgroup))
3012         (len (length newsgroup))
3013         idx)
3014     ;; If this is a foreign group, we don't want to translate the
3015     ;; entire name.
3016     (if (setq idx (string-match ":" newsgroup))
3017         (aset newsgroup idx ?/)
3018       (setq idx 0))
3019     ;; Replace all occurrences of `.' with `/'.
3020     (while (< idx len)
3021       (if (= (aref newsgroup idx) ?.)
3022           (aset newsgroup idx ?/))
3023       (setq idx (1+ idx)))
3024     newsgroup))
3025
3026 (defun gnus-newsgroup-savable-name (group)
3027   ;; Replace any slashes in a group name (eg. an ange-ftp nndoc group)
3028   ;; with dots.
3029   (nnheader-replace-chars-in-string group ?/ ?.))
3030
3031 (defun gnus-make-directory (dir)
3032   "Make DIRECTORY recursively."
3033   ;; Why don't we use `(make-directory dir 'parents)'?  That's just one
3034   ;; of the many mysteries of the universe.
3035   (let* ((dir (expand-file-name dir default-directory))
3036          dirs err)
3037     (if (string-match "/$" dir)
3038         (setq dir (substring dir 0 (match-beginning 0))))
3039     ;; First go down the path until we find a directory that exists.
3040     (while (not (file-exists-p dir))
3041       (setq dirs (cons dir dirs))
3042       (string-match "/[^/]+$" dir)
3043       (setq dir (substring dir 0 (match-beginning 0))))
3044     ;; Then create all the subdirs.
3045     (while (and dirs (not err))
3046       (condition-case ()
3047           (make-directory (car dirs))
3048         (error (setq err t)))
3049       (setq dirs (cdr dirs)))
3050     ;; We return whether we were successful or not.
3051     (not dirs)))
3052
3053 (defun gnus-capitalize-newsgroup (newsgroup)
3054   "Capitalize NEWSGROUP name."
3055   (and (not (zerop (length newsgroup)))
3056        (concat (char-to-string (upcase (aref newsgroup 0)))
3057                (substring newsgroup 1))))
3058
3059 ;; Various... things.
3060
3061 (defun gnus-simplify-subject (subject &optional re-only)
3062   "Remove `Re:' and words in parentheses.
3063 If RE-ONLY is non-nil, strip leading `Re:'s only."
3064   (let ((case-fold-search t))           ;Ignore case.
3065     ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
3066     (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
3067       (setq subject (substring subject (match-end 0))))
3068     ;; Remove uninteresting prefixes.
3069     (if (and (not re-only)
3070              gnus-simplify-ignored-prefixes
3071              (string-match gnus-simplify-ignored-prefixes subject))
3072         (setq subject (substring subject (match-end 0))))
3073     ;; Remove words in parentheses from end.
3074     (unless re-only
3075       (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
3076         (setq subject (substring subject 0 (match-beginning 0)))))
3077     ;; Return subject string.
3078     subject))
3079
3080 ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
3081 ;; all whitespace.
3082 ;; Written by Stainless Steel Rat <ratinox@ccs.neu.edu>.
3083 (defun gnus-simplify-buffer-fuzzy ()
3084   (goto-char (point-min))
3085   (while (search-forward "\t" nil t)
3086     (replace-match " " t t))
3087   (goto-char (point-min))
3088   (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *" nil t)
3089   (goto-char (match-beginning 0))
3090   (while (or
3091           (looking-at "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
3092           (looking-at "^[[].*: .*[]]$"))
3093     (goto-char (point-min))
3094     (while (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *"
3095                               nil t)
3096       (replace-match "" t t))
3097     (goto-char (point-min))
3098     (while (re-search-forward "^[[].*: .*[]]$" nil t)
3099       (goto-char (match-end 0))
3100       (delete-char -1)
3101       (delete-region
3102        (progn (goto-char (match-beginning 0)))
3103        (re-search-forward ":"))))
3104   (goto-char (point-min))
3105   (while (re-search-forward " *[[{(][^()\n]*[]})] *$" nil t)
3106     (replace-match "" t t))
3107   (goto-char (point-min))
3108   (while (re-search-forward "  +" nil t)
3109     (replace-match " " t t))
3110   (goto-char (point-min))
3111   (while (re-search-forward " $" nil t)
3112     (replace-match "" t t))
3113   (goto-char (point-min))
3114   (while (re-search-forward "^ +" nil t)
3115     (replace-match "" t t))
3116   (goto-char (point-min))
3117   (when gnus-simplify-subject-fuzzy-regexp
3118     (if (listp gnus-simplify-subject-fuzzy-regexp)
3119         (let ((list gnus-simplify-subject-fuzzy-regexp))
3120           (while list
3121             (goto-char (point-min))
3122             (while (re-search-forward (car list) nil t)
3123               (replace-match "" t t))
3124             (setq list (cdr list))))
3125       (while (re-search-forward gnus-simplify-subject-fuzzy-regexp nil t)
3126         (replace-match "" t t)))))
3127
3128 (defun gnus-simplify-subject-fuzzy (subject)
3129   "Siplify a subject string fuzzily."
3130   (save-excursion
3131     (gnus-set-work-buffer)
3132     (let ((case-fold-search t))
3133       (insert subject)
3134       (inline (gnus-simplify-buffer-fuzzy))
3135       (buffer-string))))
3136
3137 ;; Add the current buffer to the list of buffers to be killed on exit.
3138 (defun gnus-add-current-to-buffer-list ()
3139   (or (memq (current-buffer) gnus-buffer-list)
3140       (setq gnus-buffer-list (cons (current-buffer) gnus-buffer-list))))
3141
3142 (defun gnus-string> (s1 s2)
3143   (not (or (string< s1 s2)
3144            (string= s1 s2))))
3145
3146 (defun gnus-read-active-file-p ()
3147   "Say whether the active file has been read from `gnus-select-method'."
3148   (memq gnus-select-method gnus-have-read-active-file))
3149
3150 ;;; General various misc type functions.
3151
3152 (defun gnus-clear-system ()
3153   "Clear all variables and buffers."
3154   ;; Clear Gnus variables.
3155   (let ((variables gnus-variable-list))
3156     (while variables
3157       (set (car variables) nil)
3158       (setq variables (cdr variables))))
3159   ;; Clear other internal variables.
3160   (setq gnus-list-of-killed-groups nil
3161         gnus-have-read-active-file nil
3162         gnus-newsrc-alist nil
3163         gnus-newsrc-hashtb nil
3164         gnus-killed-list nil
3165         gnus-zombie-list nil
3166         gnus-killed-hashtb nil
3167         gnus-active-hashtb nil
3168         gnus-moderated-list nil
3169         gnus-description-hashtb nil
3170         gnus-current-headers nil
3171         gnus-thread-indent-array nil
3172         gnus-newsgroup-headers nil
3173         gnus-newsgroup-name nil
3174         gnus-server-alist nil
3175         gnus-group-list-mode nil
3176         gnus-opened-servers nil
3177         gnus-current-select-method nil)
3178   (gnus-shutdown 'gnus)
3179   ;; Kill the startup file.
3180   (and gnus-current-startup-file
3181        (get-file-buffer gnus-current-startup-file)
3182        (kill-buffer (get-file-buffer gnus-current-startup-file)))
3183   ;; Clear the dribble buffer.
3184   (gnus-dribble-clear)
3185   ;; Kill global KILL file buffer.
3186   (when (get-file-buffer (gnus-newsgroup-kill-file nil))
3187     (kill-buffer (get-file-buffer (gnus-newsgroup-kill-file nil))))
3188   (gnus-kill-buffer nntp-server-buffer)
3189   ;; Kill Gnus buffers.
3190   (while gnus-buffer-list
3191     (gnus-kill-buffer (pop gnus-buffer-list)))
3192   ;; Remove Gnus frames.
3193   (while gnus-created-frames
3194     (when (frame-live-p (car gnus-created-frames))
3195       ;; We slap a condition-case around this `delete-frame' to ensure 
3196       ;; agains errors if we try do delete the single frame that's left.
3197       (condition-case ()
3198           (delete-frame (car gnus-created-frames))
3199         (error nil)))
3200     (pop gnus-created-frames)))
3201
3202 (defun gnus-windows-old-to-new (setting)
3203   ;; First we take care of the really, really old Gnus 3 actions.
3204   (when (symbolp setting)
3205     (setq setting
3206           ;; Take care of ooold GNUS 3.x values.
3207           (cond ((eq setting 'SelectArticle) 'article)
3208                 ((memq setting '(SelectSubject ExpandSubject)) 'summary)
3209                 ((memq setting '(SelectNewsgroup ExitNewsgroup)) 'group)
3210                 (t setting))))
3211   (if (or (listp setting)
3212           (not (and gnus-window-configuration
3213                     (memq setting '(group summary article)))))
3214       setting
3215     (let* ((setting (if (eq setting 'group)
3216                         (if (assq 'newsgroup gnus-window-configuration)
3217                             'newsgroup
3218                           'newsgroups) setting))
3219            (elem (cadr (assq setting gnus-window-configuration)))
3220            (total (apply '+ elem))
3221            (types '(group summary article))
3222            (pbuf (if (eq setting 'newsgroups) 'group 'summary))
3223            (i 0)
3224            perc
3225            out)
3226       (while (< i 3)
3227         (or (not (numberp (nth i elem)))
3228             (zerop (nth i elem))
3229             (progn
3230               (setq perc  (/ (float (nth 0 elem)) total))
3231               (setq out (cons (if (eq pbuf (nth i types))
3232                                   (vector (nth i types) perc 'point)
3233                                 (vector (nth i types) perc))
3234                               out))))
3235         (setq i (1+ i)))
3236       (list (nreverse out)))))
3237
3238 ;;;###autoload
3239 (defun gnus-add-configuration (conf)
3240   "Add the window configuration CONF to `gnus-buffer-configuration'."
3241   (setq gnus-buffer-configuration
3242         (cons conf (delq (assq (car conf) gnus-buffer-configuration)
3243                          gnus-buffer-configuration))))
3244
3245 (defvar gnus-frame-list nil)
3246
3247 (defun gnus-configure-frame (split &optional window)
3248   "Split WINDOW according to SPLIT."
3249   (unless window
3250     (setq window (get-buffer-window (current-buffer))))
3251   (select-window window)
3252   ;; This might be an old-stylee buffer config.
3253   (when (vectorp split)
3254     (setq split (append split nil)))
3255   (when (or (consp (car split))
3256             (vectorp (car split)))
3257     (push 1.0 split)
3258     (push 'vertical split))
3259   ;; The SPLIT might be something that is to be evaled to
3260   ;; return a new SPLIT.
3261   (while (and (not (assq (car split) gnus-window-to-buffer))
3262               (gnus-functionp (car split)))
3263     (setq split (eval split)))
3264   (let* ((type (car split))
3265          (subs (cddr split))
3266          (len (if (eq type 'horizontal) (window-width) (window-height)))
3267          (total 0)
3268          (window-min-width (or gnus-window-min-width window-min-width))
3269          (window-min-height (or gnus-window-min-height window-min-height))
3270          s result new-win rest comp-subs size sub)
3271     (cond
3272      ;; Nothing to do here.
3273      ((null split))
3274      ;; Don't switch buffers.
3275      ((null type)
3276       (and (memq 'point split) window))
3277      ;; This is a buffer to be selected.
3278      ((not (memq type '(frame horizontal vertical)))
3279       (let ((buffer (cond ((stringp type) type)
3280                           (t (cdr (assq type gnus-window-to-buffer)))))
3281             buf)
3282         (unless buffer
3283           (error "Illegal buffer type: %s" type))
3284         (unless (setq buf (get-buffer (if (symbolp buffer)
3285                                           (symbol-value buffer) buffer)))
3286           (setq buf (get-buffer-create (if (symbolp buffer)
3287                                            (symbol-value buffer) buffer))))
3288         (switch-to-buffer buf)
3289         ;; We return the window if it has the `point' spec.
3290         (and (memq 'point split) window)))
3291      ;; This is a frame split.
3292      ((eq type 'frame)
3293       (unless gnus-frame-list
3294         (setq gnus-frame-list (list (window-frame
3295                                      (get-buffer-window (current-buffer))))))
3296       (let ((i 0)
3297             params frame fresult)
3298         (while (< i (length subs))
3299           ;; Frame parameter is gotten from the sub-split.
3300           (setq params (cadr (elt subs i)))
3301           ;; It should be a list.
3302           (unless (listp params)
3303             (setq params nil))
3304           ;; Create a new frame?
3305           (unless (setq frame (elt gnus-frame-list i))
3306             (nconc gnus-frame-list (list (setq frame (make-frame params))))
3307             (push frame gnus-created-frames))
3308           ;; Is the old frame still alive?
3309           (unless (frame-live-p frame)
3310             (setcar (nthcdr i gnus-frame-list)
3311                     (setq frame (make-frame params))))
3312           ;; Select the frame in question and do more splits there.
3313           (select-frame frame)
3314           (setq fresult (or (gnus-configure-frame (elt subs i)) fresult))
3315           (incf i))
3316         ;; Select the frame that has the selected buffer.
3317         (when fresult
3318           (select-frame (window-frame fresult)))))
3319      ;; This is a normal split.
3320      (t
3321       (when (> (length subs) 0)
3322         ;; First we have to compute the sizes of all new windows.
3323         (while subs
3324           (setq sub (append (pop subs) nil))
3325           (while (and (not (assq (car sub) gnus-window-to-buffer))
3326                       (gnus-functionp (car sub)))
3327             (setq sub (eval sub)))
3328           (when sub
3329             (push sub comp-subs)
3330             (setq size (cadar comp-subs))
3331             (cond ((equal size 1.0)
3332                    (setq rest (car comp-subs))
3333                    (setq s 0))
3334                   ((floatp size)
3335                    (setq s (floor (* size len))))
3336                   ((integerp size)
3337                    (setq s size))
3338                   (t
3339                    (error "Illegal size: %s" size)))
3340             ;; Try to make sure that we are inside the safe limits.
3341             (cond ((zerop s))
3342                   ((eq type 'horizontal)
3343                    (setq s (max s window-min-width)))
3344                   ((eq type 'vertical)
3345                    (setq s (max s window-min-height))))
3346             (setcar (cdar comp-subs) s)
3347             (incf total s)))
3348         ;; Take care of the "1.0" spec.
3349         (if rest
3350             (setcar (cdr rest) (- len total))
3351           (error "No 1.0 specs in %s" split))
3352         ;; The we do the actual splitting in a nice recursive
3353         ;; fashion.
3354         (setq comp-subs (nreverse comp-subs))
3355         (while comp-subs
3356           (if (null (cdr comp-subs))
3357               (setq new-win window)
3358             (setq new-win
3359                   (split-window window (cadar comp-subs)
3360                                 (eq type 'horizontal))))
3361           (setq result (or (gnus-configure-frame
3362                             (car comp-subs) window) result))
3363           (select-window new-win)
3364           (setq window new-win)
3365           (setq comp-subs (cdr comp-subs))))
3366       ;; Return the proper window, if any.
3367       (when result
3368         (select-window result))))))
3369
3370 (defvar gnus-frame-split-p nil)
3371
3372 (defun gnus-configure-windows (setting &optional force)
3373   (setq setting (gnus-windows-old-to-new setting))
3374   (let ((split (if (symbolp setting)
3375                    (cadr (assq setting gnus-buffer-configuration))
3376                  setting))
3377         all-visible)
3378
3379     (setq gnus-frame-split-p nil)
3380
3381     (unless split
3382       (error "No such setting: %s" setting))
3383
3384     (if (and (setq all-visible (gnus-all-windows-visible-p split))
3385              (not force))
3386         ;; All the windows mentioned are already visible, so we just
3387         ;; put point in the assigned buffer, and do not touch the
3388         ;; winconf.
3389         (select-window all-visible)
3390
3391       ;; Either remove all windows or just remove all Gnus windows.
3392       (let ((frame (selected-frame)))
3393         (unwind-protect
3394             (if gnus-use-full-window
3395                 ;; We want to remove all other windows.
3396                 (if (not gnus-frame-split-p)
3397                     ;; This is not a `frame' split, so we ignore the
3398                     ;; other frames.  
3399                     (delete-other-windows)
3400                   ;; This is a `frame' split, so we delete all windows
3401                   ;; on all frames.
3402                   (mapcar 
3403                    (lambda (frame)
3404                      (unless (eq (cdr (assq 'minibuffer
3405                                             (frame-parameters frame)))
3406                                  'only)
3407                        (select-frame frame)
3408                        (delete-other-windows)))
3409                    (frame-list)))
3410               ;; Just remove some windows.
3411               (gnus-remove-some-windows)
3412               (switch-to-buffer nntp-server-buffer))
3413           (select-frame frame)))
3414
3415       (switch-to-buffer nntp-server-buffer)
3416       (gnus-configure-frame split (get-buffer-window (current-buffer))))))
3417
3418 (defun gnus-all-windows-visible-p (split)
3419   "Say whether all buffers in SPLIT are currently visible.
3420 In particular, the value returned will be the window that
3421 should have point."
3422   (let ((stack (list split))
3423         (all-visible t)
3424         type buffer win buf)
3425     (while (and (setq split (pop stack))
3426                 all-visible)
3427       ;; Be backwards compatible.
3428       (when (vectorp split)
3429         (setq split (append split nil)))
3430       (when (or (consp (car split))
3431                 (vectorp (car split)))
3432         (push 1.0 split)
3433         (push 'vertical split))
3434       ;; The SPLIT might be something that is to be evaled to
3435       ;; return a new SPLIT.
3436       (while (and (not (assq (car split) gnus-window-to-buffer))
3437                   (gnus-functionp (car split)))
3438         (setq split (eval split)))
3439
3440       (setq type (elt split 0))
3441       (cond
3442        ;; Nothing here.
3443        ((null split) t)
3444        ;; A buffer.
3445        ((not (memq type '(horizontal vertical frame)))
3446         (setq buffer (cond ((stringp type) type)
3447                            (t (cdr (assq type gnus-window-to-buffer)))))
3448         (unless buffer
3449           (error "Illegal buffer type: %s" type))
3450         (when (setq buf (get-buffer (if (symbolp buffer)
3451                                         (symbol-value buffer)
3452                                       buffer)))
3453           (setq win (get-buffer-window buf t)))
3454         (if win
3455             (when (memq 'point split)
3456                 (setq all-visible win))
3457           (setq all-visible nil)))
3458        (t
3459         (when (eq type 'frame)
3460           (setq gnus-frame-split-p t))
3461         (setq stack (append (cddr split) stack)))))
3462     (unless (eq all-visible t)
3463       all-visible)))
3464
3465 (defun gnus-window-top-edge (&optional window)
3466   (nth 1 (window-edges window)))
3467
3468 (defun gnus-remove-some-windows ()
3469   (let ((buffers gnus-window-to-buffer)
3470         buf bufs lowest-buf lowest)
3471     (save-excursion
3472       ;; Remove windows on all known Gnus buffers.
3473       (while buffers
3474         (setq buf (cdar buffers))
3475         (if (symbolp buf)
3476             (setq buf (and (boundp buf) (symbol-value buf))))
3477         (and buf
3478              (get-buffer-window buf)
3479              (progn
3480                (setq bufs (cons buf bufs))
3481                (pop-to-buffer buf)
3482                (if (or (not lowest)
3483                        (< (gnus-window-top-edge) lowest))
3484                    (progn
3485                      (setq lowest (gnus-window-top-edge))
3486                      (setq lowest-buf buf)))))
3487         (setq buffers (cdr buffers)))
3488       ;; Remove windows on *all* summary buffers.
3489       (walk-windows
3490        (lambda (win)
3491          (let ((buf (window-buffer win)))
3492            (if (string-match    "^\\*Summary" (buffer-name buf))
3493                (progn
3494                  (setq bufs (cons buf bufs))
3495                  (pop-to-buffer buf)
3496                  (if (or (not lowest)
3497                          (< (gnus-window-top-edge) lowest))
3498                      (progn
3499                        (setq lowest-buf buf)
3500                        (setq lowest (gnus-window-top-edge)))))))))
3501       (and lowest-buf
3502            (progn
3503              (pop-to-buffer lowest-buf)
3504              (switch-to-buffer nntp-server-buffer)))
3505       (while bufs
3506         (and (not (eq (car bufs) lowest-buf))
3507              (delete-windows-on (car bufs)))
3508         (setq bufs (cdr bufs))))))
3509
3510 (defun gnus-version ()
3511   "Version numbers of this version of Gnus."
3512   (interactive)
3513   (let ((methods gnus-valid-select-methods)
3514         (mess gnus-version)
3515         meth)
3516     ;; Go through all the legal select methods and add their version
3517     ;; numbers to the total version string.  Only the backends that are
3518     ;; currently in use will have their message numbers taken into
3519     ;; consideration.
3520     (while methods
3521       (setq meth (intern (concat (caar methods) "-version")))
3522       (and (boundp meth)
3523            (stringp (symbol-value meth))
3524            (setq mess (concat mess "; " (symbol-value meth))))
3525       (setq methods (cdr methods)))
3526     (gnus-message 2 mess)))
3527
3528 (defun gnus-info-find-node ()
3529   "Find Info documentation of Gnus."
3530   (interactive)
3531   ;; Enlarge info window if needed.
3532   (let ((mode major-mode)
3533         gnus-info-buffer)
3534     (Info-goto-node (cadr (assq mode gnus-info-nodes)))
3535     (setq gnus-info-buffer (current-buffer))
3536     (gnus-configure-windows 'info)))
3537
3538 (defun gnus-days-between (date1 date2)
3539   ;; Return the number of days between date1 and date2.
3540   (- (gnus-day-number date1) (gnus-day-number date2)))
3541
3542 (defun gnus-day-number (date)
3543   (let ((dat (mapcar (lambda (s) (and s (string-to-int s)) )
3544                      (timezone-parse-date date))))
3545     (timezone-absolute-from-gregorian
3546      (nth 1 dat) (nth 2 dat) (car dat))))
3547
3548 (defun gnus-encode-date (date)
3549   "Convert DATE to internal time."
3550   (let* ((parse (timezone-parse-date date))
3551          (date (mapcar (lambda (d) (and d (string-to-int d))) parse))
3552          (time (mapcar 'string-to-int (timezone-parse-time (aref parse 3)))))
3553     (encode-time (caddr time) (cadr time) (car time)
3554                  (caddr date) (cadr date) (car date) (nth 4 date))))
3555
3556 (defun gnus-time-minus (t1 t2)
3557   "Subtract two internal times."
3558   (let ((borrow (< (cadr t1) (cadr t2))))
3559     (list (- (car t1) (car t2) (if borrow 1 0))
3560           (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
3561
3562 (defun gnus-file-newer-than (file date)
3563   (let ((fdate (nth 5 (file-attributes file))))
3564     (or (> (car fdate) (car date))
3565         (and (= (car fdate) (car date))
3566              (> (nth 1 fdate) (nth 1 date))))))
3567