*** empty log message ***
[gnus] / lisp / gnus-sum.el
1 ;;; gnus-sum.el --- summary mode commands for Gnus
2 ;; Copyright (C) 1996 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Keywords: news
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
23
24 ;;; Commentary:
25
26 ;;; Code:
27
28 (require 'gnus)
29 (require 'gnus-group)
30 (require 'gnus-spec)
31 (require 'gnus-range)
32 (require 'gnus-int)
33 (require 'gnus-undo)
34
35 (defgroup gnus-summary nil
36   "Summary buffers."
37   :group 'gnus)
38
39 (defcustom gnus-kill-summary-on-exit t
40   "*If non-nil, kill the summary buffer when you exit from it.
41 If nil, the summary will become a \"*Dead Summary*\" buffer, and
42 it will be killed sometime later."
43   :group 'gnus-summary
44   :type 'boolean)
45
46 (defcustom gnus-fetch-old-headers nil
47   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
48 If an unread article in the group refers to an older, already read (or
49 just marked as read) article, the old article will not normally be
50 displayed in the Summary buffer.  If this variable is non-nil, Gnus
51 will attempt to grab the headers to the old articles, and thereby
52 build complete threads.  If it has the value `some', only enough
53 headers to connect otherwise loose threads will be displayed.
54 This variable can also be a number.  In that case, no more than that
55 number of old headers will be fetched.
56
57 The server has to support NOV for any of this to work."
58   :group 'gnus-summary
59   :type '(choice (const :tag "off" nil)
60                  (const some)
61                  number
62                  (sexp :menu-tag "other" t)))
63
64 (defcustom gnus-summary-make-false-root 'adopt
65   "*nil means that Gnus won't gather loose threads.
66 If the root of a thread has expired or been read in a previous
67 session, the information necessary to build a complete thread has been
68 lost.  Instead of having many small sub-threads from this original thread
69 scattered all over the summary buffer, Gnus can gather them.
70
71 If non-nil, Gnus will try to gather all loose sub-threads from an
72 original thread into one large thread.
73
74 If this variable is non-nil, it should be one of `none', `adopt',
75 `dummy' or `empty'.
76
77 If this variable is `none', Gnus will not make a false root, but just
78 present the sub-threads after another.
79 If this variable is `dummy', Gnus will create a dummy root that will
80 have all the sub-threads as children.
81 If this variable is `adopt', Gnus will make one of the \"children\"
82 the parent and mark all the step-children as such.
83 If this variable is `empty', the \"children\" are printed with empty
84 subject fields.  (Or rather, they will be printed with a string
85 given by the `gnus-summary-same-subject' variable.)"
86   :group 'gnus-summary
87   :type '(choice (const :tag "off" nil)
88                  (const none)
89                  (const dummy)
90                  (const adopt)
91                  (const empty)))
92
93 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
94   "*A regexp to match subjects to be excluded from loose thread gathering.
95 As loose thread gathering is done on subjects only, that means that
96 there can be many false gatherings performed.  By rooting out certain
97 common subjects, gathering might become saner."
98   :group 'gnus-summary
99   :type 'regexp)
100
101 (defcustom gnus-summary-gather-subject-limit nil
102   "*Maximum length of subject comparisons when gathering loose threads.
103 Use nil to compare full subjects.  Setting this variable to a low
104 number will help gather threads that have been corrupted by
105 newsreaders chopping off subject lines, but it might also mean that
106 unrelated articles that have subject that happen to begin with the
107 same few characters will be incorrectly gathered.
108
109 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
110 comparing subjects."
111   :group 'gnus-summary
112   :type '(choice (const :tag "off" nil)
113                  (const fuzzy)
114                  (sexp :menu-tag "on" t)))
115
116 (defcustom gnus-simplify-ignored-prefixes nil
117   "*Regexp, matches for which are removed from subject lines when simplifying fuzzily."
118   :group 'gnus-summary
119   :type '(choice (const :tag "off" nil)
120                  regexp))
121
122 (defcustom gnus-build-sparse-threads nil
123   "*If non-nil, fill in the gaps in threads.
124 If `some', only fill in the gaps that are needed to tie loose threads
125 together.  If `more', fill in all leaf nodes that Gnus can find.  If
126 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
127   :group 'gnus-summary
128   :type '(choice (const :tag "off" nil)
129                  (const some)
130                  (const more)
131                  (sexp :menu-tag "all" t)))
132
133 (defcustom gnus-summary-thread-gathering-function 'gnus-gather-threads-by-subject
134   "Function used for gathering loose threads.
135 There are two pre-defined functions: `gnus-gather-threads-by-subject',
136 which only takes Subjects into consideration; and
137 `gnus-gather-threads-by-references', which compared the References
138 headers of the articles to find matches."
139   :group 'gnus-summary
140   :type '(set (function-item gnus-gather-threads-by-subject)
141               (function-item gnus-gather-threads-by-references)
142               (function :tag "other")))
143
144 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
145 (defcustom gnus-summary-same-subject ""
146   "*String indicating that the current article has the same subject as the previous.
147 This variable will only be used if the value of
148 `gnus-summary-make-false-root' is `empty'."
149   :group 'gnus-summary
150   :type 'string)
151
152 (defcustom gnus-summary-goto-unread t
153   "*If t, marking commands will go to the next unread article.
154 If `never', commands that usually go to the next unread article, will
155 go to the next article, whether it is read or not.
156 If nil, only the marking commands will go to the next (un)read article."
157   :group 'gnus-summary
158   :type '(choice (const :tag "off" nil)
159                  (const never)
160                  (sexp :menu-tag "on" t)))
161
162 (defcustom gnus-summary-default-score 0
163   "*Default article score level.
164 If this variable is nil, scoring will be disabled."
165   :group 'gnus-summary
166   :type '(choice (const :tag "disable")
167                  integer))
168
169 (defcustom gnus-summary-zcore-fuzz 0
170   "*Fuzziness factor for the zcore in the summary buffer.
171 Articles with scores closer than this to `gnus-summary-default-score'
172 will not be marked."
173   :group 'gnus-summary
174   :type 'integer)
175
176 (defcustom gnus-simplify-subject-fuzzy-regexp nil
177   "*Strings to be removed when doing fuzzy matches.
178 This can either be a regular expression or list of regular expressions
179 that will be removed from subject strings if fuzzy subject
180 simplification is selected."
181   :group 'gnus-summary
182   :type '(repeat regexp))
183
184 (defcustom gnus-show-threads t
185   "*If non-nil, display threads in summary mode."
186   :group 'gnus-summary
187   :type 'boolean)
188
189 (defcustom gnus-thread-hide-subtree nil
190   "*If non-nil, hide all threads initially.
191 If threads are hidden, you have to run the command
192 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
193 to expose hidden threads."
194   :group 'gnus-summary
195   :type 'boolean)
196
197 (defcustom gnus-thread-hide-killed t
198   "*If non-nil, hide killed threads automatically."
199   :group 'gnus-summary
200   :type 'boolean)
201
202 (defcustom gnus-thread-ignore-subject nil
203   "*If non-nil, ignore subjects and do all threading based on the Reference header.
204 If nil, which is the default, articles that have different subjects
205 from their parents will start separate threads."
206   :group 'gnus-summary
207   :type 'boolean)
208
209 (defcustom gnus-thread-operation-ignore-subject t
210   "*If non-nil, subjects will be ignored when doing thread commands.
211 This affects commands like `gnus-summary-kill-thread' and
212 `gnus-summary-lower-thread'.
213
214 If this variable is nil, articles in the same thread with different
215 subjects will not be included in the operation in question.  If this
216 variable is `fuzzy', only articles that have subjects that are fuzzily
217 equal will be included."
218   :group 'gnus-summary
219   :type '(choice (const :tag "off" nil)
220                  (const fuzzy)
221                  (sexp :tag "on" t)))
222
223 (defcustom gnus-thread-indent-level 4
224   "*Number that says how much each sub-thread should be indented."
225   :group 'gnus-summary
226   :type 'integer)
227
228 (defcustom gnus-auto-extend-newsgroup t
229   "*If non-nil, extend newsgroup forward and backward when requested."
230   :group 'gnus-summary
231   :type 'boolean)
232
233 (defcustom gnus-auto-select-first t
234   "*If nil, don't select the first unread article when entering a group.
235 If this variable is `best', select the highest-scored unread article
236 in the group.  If neither nil nor `best', select the first unread
237 article.
238
239 If you want to prevent automatic selection of the first unread article
240 in some newsgroups, set the variable to nil in
241 `gnus-select-group-hook'."
242   :group 'gnus-summary
243   :type '(choice (const :tag "none" nil)
244                  (const best)
245                  (sexp :menu-tag "first" t)))
246
247 (defcustom gnus-auto-select-next t
248   "*If non-nil, offer to go to the next group from the end of the previous.
249 If the value is t and the next newsgroup is empty, Gnus will exit
250 summary mode and go back to group mode.  If the value is neither nil
251 nor t, Gnus will select the following unread newsgroup.  In
252 particular, if the value is the symbol `quietly', the next unread
253 newsgroup will be selected without any confirmation, and if it is
254 `almost-quietly', the next group will be selected without any
255 confirmation if you are located on the last article in the group.
256 Finally, if this variable is `slightly-quietly', the `Z n' command
257 will go to the next group without confirmation."
258   :group 'gnus-summary
259   :type '(choice (const :tag "off" nil)
260                  (const quietly)
261                  (const almost-quietly)
262                  (const slightly-quietly)
263                  (sexp :menu-tag "on" t)))
264
265 (defcustom gnus-auto-select-same nil
266   "*If non-nil, select the next article with the same subject."
267   :group 'gnus-summary
268   :type 'boolean)
269
270 (defcustom gnus-summary-check-current nil
271   "*If non-nil, consider the current article when moving.
272 The \"unread\" movement commands will stay on the same line if the
273 current article is unread."
274   :group 'gnus-summary
275   :type 'boolean)
276
277 (defcustom gnus-auto-center-summary t
278   "*If non-nil, always center the current summary buffer.
279 In particular, if `vertical' do only vertical recentering.  If non-nil
280 and non-`vertical', do both horizontal and vertical recentering."
281   :group 'gnus-summary
282   :type '(choice (const :tag "none" nil)
283                  (const vertical)
284                  (sexp :menu-tag "both" t)))
285
286 (defcustom gnus-show-all-headers nil
287   "*If non-nil, don't hide any headers."
288   :group 'gnus-summary
289   :type 'boolean)
290
291 (defcustom gnus-single-article-buffer t
292   "*If non-nil, display all articles in the same buffer.
293 If nil, each group will get its own article buffer."
294   :group 'gnus-summary
295   :type 'boolean)
296
297 (defcustom gnus-break-pages t
298   "*If non-nil, do page breaking on articles.
299 The page delimiter is specified by the `gnus-page-delimiter'
300 variable."
301   :group 'gnus-summary
302   :type 'boolean)
303
304 (defcustom gnus-show-mime nil
305   "*If non-nil, do mime processing of articles.
306 The articles will simply be fed to the function given by
307 `gnus-show-mime-method'."
308   :group 'gnus-summary
309   :type 'boolean)
310
311 (defcustom gnus-move-split-methods nil
312   "*Variable used to suggest where articles are to be moved to.
313 It uses the same syntax as the `gnus-split-methods' variable."
314   :group 'gnus-summary
315   :type '(repeat (choice (list function)
316                          (cons regexp (repeat string))
317                          sexp)))
318
319 ;; Mark variables suggested by Thomas Michanek
320 ;; <Thomas.Michanek@telelogic.se>.
321
322 (defgroup gnus-summary-marks nil
323   "Marks used in summary buffers."
324   :group 'gnus-summary)
325
326 (defcustom gnus-unread-mark ? 
327   "*Mark used for unread articles."
328   :group 'gnus-summary-marks
329   :type 'character)
330
331 (defcustom gnus-ticked-mark ?!
332   "*Mark used for ticked articles."
333   :group 'gnus-summary-marks
334   :type 'character)
335
336 (defcustom gnus-dormant-mark ??
337   "*Mark used for dormant articles."
338   :group 'gnus-summary-marks
339   :type 'character)
340
341 (defcustom gnus-del-mark ?r
342   "*Mark used for del'd articles."
343   :group 'gnus-summary-marks
344   :type 'character)
345
346 (defcustom gnus-read-mark ?R
347   "*Mark used for read articles."
348   :group 'gnus-summary-marks
349   :type 'character)
350
351 (defcustom gnus-expirable-mark ?E
352   "*Mark used for expirable articles."
353   :group 'gnus-summary-marks
354   :type 'character)
355
356 (defcustom gnus-killed-mark ?K
357   "*Mark used for killed articles."
358   :group 'gnus-summary-marks
359   :type 'character)
360
361 (defcustom gnus-souped-mark ?F
362   "*Mark used for killed articles."
363   :group 'gnus-summary-marks
364   :type 'character)
365
366 (defcustom gnus-kill-file-mark ?X
367   "*Mark used for articles killed by kill files."
368   :group 'gnus-summary-marks
369   :type 'character)
370
371 (defcustom gnus-low-score-mark ?Y
372   "*Mark used for articles with a low score."
373   :group 'gnus-summary-marks
374   :type 'character)
375
376 (defcustom gnus-catchup-mark ?C
377   "*Mark used for articles that are caught up."
378   :group 'gnus-summary-marks
379   :type 'character)
380
381 (defcustom gnus-replied-mark ?A
382   "*Mark used for articles that have been replied to."
383   :group 'gnus-summary-marks
384   :type 'character)
385
386 (defcustom gnus-cached-mark ?*
387   "*Mark used for articles that are in the cache."
388   :group 'gnus-summary-marks
389   :type 'character)
390
391 (defcustom gnus-saved-mark ?S
392   "*Mark used for articles that have been saved to."
393   :group 'gnus-summary-marks
394   :type 'character)
395
396 (defcustom gnus-ancient-mark ?O
397   "*Mark used for ancient articles."
398   :group 'gnus-summary-marks
399   :type 'character)
400
401 (defcustom gnus-sparse-mark ?Q
402   "*Mark used for sparsely reffed articles."
403   :group 'gnus-summary-marks
404   :type 'character)
405
406 (defcustom gnus-canceled-mark ?G
407   "*Mark used for canceled articles."
408   :group 'gnus-summary-marks
409   :type 'character)
410
411 (defcustom gnus-duplicate-mark ?M
412   "*Mark used for duplicate articles."
413   :group 'gnus-summary-marks
414   :type 'character)
415
416 (defcustom gnus-score-over-mark ?+
417   "*Score mark used for articles with high scores."
418   :group 'gnus-summary-marks
419   :type 'character)
420
421 (defcustom gnus-score-below-mark ?-
422   "*Score mark used for articles with low scores."
423   :group 'gnus-summary-marks
424   :type 'character)
425
426 (defcustom gnus-empty-thread-mark ? 
427   "*There is no thread under the article."
428   :group 'gnus-summary-marks
429   :type 'character)
430
431 (defcustom gnus-not-empty-thread-mark ?=
432   "*There is a thread under the article."
433   :group 'gnus-summary-marks
434   :type 'character)
435
436 (defcustom gnus-view-pseudo-asynchronously nil
437   "*If non-nil, Gnus will view pseudo-articles asynchronously."
438   :group 'gnus-summary
439   :type 'boolean)
440
441 (defcustom gnus-view-pseudos nil
442   "*If `automatic', pseudo-articles will be viewed automatically.
443 If `not-confirm', pseudos will be viewed automatically, and the user
444 will not be asked to confirm the command."
445   :group 'gnus-summary
446   :type '(choice (const :tag "off" nil)
447                  (const automatic)
448                  (const not-confirm)))
449
450 (defcustom gnus-view-pseudos-separately t
451   "*If non-nil, one pseudo-article will be created for each file to be viewed.
452 If nil, all files that use the same viewing command will be given as a
453 list of parameters to that command."
454   :group 'gnus-summary
455   :type 'boolean)
456
457 (defcustom gnus-insert-pseudo-articles t
458   "*If non-nil, insert pseudo-articles when decoding articles."
459   :group 'gnus-summary
460   :type 'boolean)
461
462 (defcustom gnus-summary-dummy-line-format
463   "*  %(:                          :%) %S\n"
464   "*The format specification for the dummy roots in the summary buffer.
465 It works along the same lines as a normal formatting string,
466 with some simple extensions.
467
468 %S  The subject"
469   :group 'gnus-summary
470   :type 'string)
471
472 (defcustom gnus-summary-mode-line-format "Gnus: %%b [%A] %Z"
473   "*The format specification for the summary mode line.
474 It works along the same lines as a normal formatting string,
475 with some simple extensions:
476
477 %G  Group name
478 %p  Unprefixed group name
479 %A  Current article number
480 %V  Gnus version
481 %U  Number of unread articles in the group
482 %e  Number of unselected articles in the group
483 %Z  A string with unread/unselected article counts
484 %g  Shortish group name
485 %S  Subject of the current article
486 %u  User-defined spec
487 %s  Current score file name
488 %d  Number of dormant articles
489 %r  Number of articles that have been marked as read in this session
490 %E  Number of articles expunged by the score files"
491   :group 'gnus-summary
492   :type 'string)
493
494 (defcustom gnus-summary-mark-below 0
495   "*Mark all articles with a score below this variable as read.
496 This variable is local to each summary buffer and usually set by the
497 score file."
498   :group 'gnus-summary
499   :type 'integer)
500
501 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
502   "*List of functions used for sorting articles in the summary buffer.
503 This variable is only used when not using a threaded display."
504   :group 'gnus-summary
505   :type '(repeat (choice (function-item gnus-article-sort-by-number)
506                          (function-item gnus-article-sort-by-author)
507                          (function-item gnus-article-sort-by-subject)
508                          (function-item gnus-article-sort-by-date)
509                          (function-item gnus-article-sort-by-score)
510                          (function :tag "other"))))
511
512 (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
513   "*List of functions used for sorting threads in the summary buffer.
514 By default, threads are sorted by article number.
515
516 Each function takes two threads and return non-nil if the first thread
517 should be sorted before the other.  If you use more than one function,
518 the primary sort function should be the last.  You should probably
519 always include `gnus-thread-sort-by-number' in the list of sorting
520 functions -- preferably first.
521
522 Ready-made functions include `gnus-thread-sort-by-number',
523 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
524 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score' and
525 `gnus-thread-sort-by-total-score' (see `gnus-thread-score-function')."
526   :group 'gnus-summary
527   :type '(repeat (choice (function-item gnus-thread-sort-by-number)
528                          (function-item gnus-thread-sort-by-author)
529                          (function-item gnus-thread-sort-by-subject)
530                          (function-item gnus-thread-sort-by-date)
531                          (function-item gnus-thread-sort-by-score)
532                          (function-item gnus-thread-sort-by-total-score)
533                          (function :tag "other"))))
534
535 (defcustom gnus-thread-score-function '+
536   "*Function used for calculating the total score of a thread.
537
538 The function is called with the scores of the article and each
539 subthread and should then return the score of the thread.
540
541 Some functions you can use are `+', `max', or `min'."
542   :group 'gnus-summary
543   :type 'function)
544
545 (defcustom gnus-summary-expunge-below nil
546   "All articles that have a score less than this variable will be expunged."
547   :group 'gnus-summary
548   :type '(choice (const :tag "off" nil)
549                  integer))
550
551 (defcustom gnus-thread-expunge-below nil
552   "All threads that have a total score less than this variable will be expunged.
553 See `gnus-thread-score-function' for en explanation of what a
554 \"thread score\" is."
555   :group 'gnus-summary
556   :type '(choice (const :tag "off" nil)
557                  integer))
558
559 (defcustom gnus-summary-mode-hook nil
560   "*A hook for Gnus summary mode.
561 This hook is run before any variables are set in the summary buffer."
562   :group 'gnus-summary
563   :type 'hook)
564
565 (defcustom gnus-summary-menu-hook nil
566   "*Hook run after the creation of the summary mode menu."
567   :group 'gnus-summary
568   :type 'hook)
569
570 (defcustom gnus-summary-exit-hook nil
571   "*A hook called on exit from the summary buffer."
572   :group 'gnus-summary
573   :type 'hook)
574
575 (defcustom gnus-summary-prepare-hook nil
576   "*A hook called after the summary buffer has been generated.
577 If you want to modify the summary buffer, you can use this hook."
578   :group 'gnus-summary
579   :type 'hook)
580
581 (defcustom gnus-summary-generate-hook nil
582   "*A hook run just before generating the summary buffer.
583 This hook is commonly used to customize threading variables and the
584 like."
585   :group 'gnus-summary
586   :type 'hook)
587
588 (defcustom gnus-select-group-hook nil
589   "*A hook called when a newsgroup is selected.
590
591 If you'd like to simplify subjects like the
592 `gnus-summary-next-same-subject' command does, you can use the
593 following hook:
594
595  (setq gnus-select-group-hook
596       (list
597         (lambda ()
598           (mapcar (lambda (header)
599                      (mail-header-set-subject
600                       header
601                       (gnus-simplify-subject
602                        (mail-header-subject header) 're-only)))
603                   gnus-newsgroup-headers))))"
604   :group 'gnus-summary
605   :type 'hook)
606
607 (defcustom gnus-select-article-hook nil
608   "*A hook called when an article is selected."
609   :group 'gnus-summary
610   :type 'hook)
611
612 (defcustom gnus-visual-mark-article-hook
613   (list 'gnus-highlight-selected-summary)
614   "*Hook run after selecting an article in the summary buffer.
615 It is meant to be used for highlighting the article in some way.  It
616 is not run if `gnus-visual' is nil."
617   :group 'gnus-summary
618   :type 'hook)
619
620 (defcustom gnus-parse-headers-hook 
621   (list 'gnus-decode-rfc1522)
622   "*A hook called before parsing the headers."
623   :group 'gnus-summary
624   :type 'hook)
625
626 (defcustom gnus-exit-group-hook nil
627   "*A hook called when exiting (not quitting) summary mode."
628   :group 'gnus-summary
629   :type 'hook)
630
631 (defcustom gnus-summary-update-hook
632   (list 'gnus-summary-highlight-line)
633   "*A hook called when a summary line is changed.
634 The hook will not be called if `gnus-visual' is nil.
635
636 The default function `gnus-summary-highlight-line' will
637 highlight the line according to the `gnus-summary-highlight'
638 variable."
639   :group 'gnus-summary
640   :type 'hook)
641
642 (defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
643   "*A hook called when an article is selected for the first time.
644 The hook is intended to mark an article as read (or unread)
645 automatically when it is selected."
646   :group 'gnus-summary
647   :type 'hook)
648
649 (defcustom gnus-group-no-more-groups-hook nil
650   "*A hook run when returning to group mode having no more (unread) groups."
651   :group 'gnus-summary
652   :type 'hook)
653
654 (defface gnus-summary-selected-face '((t 
655                                        (:underline t)))
656   "Face used for selected articles.")
657
658 (defcustom gnus-summary-selected-face 'gnus-summary-selected-face
659   "Face used for highlighting the current article in the summary buffer."
660   :group 'gnus-summary
661   :type 'face)
662
663 (defface gnus-summary-cancelled-face 
664   '((((class color))
665      (:foreground "yellow" :background "black")))
666   "Face used for cancelled articles.")
667
668 (defface gnus-summary-high-ticked-face
669   '((((class color)
670       (background dark))
671      (:foreground "pink" :bold t))
672     (((class color)
673       (background light))
674      (:foreground "firebrick" :bold t))
675     (t 
676      (:bold t)))
677   "Face used for high interest ticked articles.")
678
679 (defface gnus-summary-low-ticked-face
680   '((((class color)
681       (background dark))
682      (:foreground "pink" :italic t))
683     (((class color)
684       (background light))
685      (:foreground "firebrick" :italic t))
686     (t 
687      (:italic t)))
688   "Face used for low interest ticked articles.")
689
690 (defface gnus-summary-normal-ticked-face
691   '((((class color)
692       (background dark))
693      (:foreground "pink"))
694     (((class color)
695       (background light))
696      (:foreground "firebrick"))
697     (t 
698      ()))
699   "Face used for normal interest ticked articles.")
700   
701 (defface gnus-summary-high-ancient-face
702   '((((class color)
703       (background dark))
704      (:foreground "SkyBlue" :bold t))
705     (((class color)
706       (background light))
707      (:foreground "RoyalBlue" :bold t))
708     (t 
709      (:bold t)))
710   "Face used for high interest ancient articles.")
711
712 (defface gnus-summary-low-ancient-face
713   '((((class color)
714       (background dark))
715      (:foreground "SkyBlue" :italic t))
716     (((class color)
717       (background light))
718      (:foreground "RoyalBlue" :italic t))
719     (t 
720      (:italic t)))
721   "Face used for low interest ancient articles.")
722
723 (defface gnus-summary-normal-ancient-face
724   '((((class color)
725       (background dark))
726      (:foreground "SkyBlue"))
727     (((class color)
728       (background light))
729      (:foreground "RoyalBlue"))
730     (t 
731      ()))
732   "Face used for normal interest ancient articles.")
733   
734 (defface gnus-summary-high-unread-face
735   '((t 
736      (:bold t)))
737   "Face used for high interest unread articles.")
738
739 (defface gnus-summary-low-unread-face
740   '((t 
741      (:italic t)))
742   "Face used for low interest unread articles.")
743
744 (defface gnus-summary-normal-unread-face
745   '((t 
746      ()))
747   "Face used for normal interest unread articles.")
748   
749 (defface gnus-summary-high-read-face
750   '((((class color)
751       (background dark))
752      (:foreground "PaleGreen"
753                   :bold t))
754     (((class color)
755       (background light))
756      (:foreground "DarkGreen"
757                   :bold t))
758     (t 
759      (:bold t)))
760   "Face used for high interest read articles.")
761
762 (defface gnus-summary-low-read-face
763   '((((class color)
764       (background dark))
765      (:foreground "PaleGreen"
766                   :italic t))
767     (((class color)
768       (background light))
769      (:foreground "DarkGreen"
770                   :italic t))
771     (t 
772      (:italic t)))
773   "Face used for low interest read articles.")
774
775 (defface gnus-summary-normal-read-face
776   '((((class color)
777       (background dark))
778      (:foreground "PaleGreen"))
779     (((class color)
780       (background light))
781      (:foreground "DarkGreen"))
782     (t 
783      ()))
784   "Face used for normal interest read articles.")
785
786 (defcustom gnus-summary-highlight 
787   '(((= mark gnus-canceled-mark)
788      . gnus-summary-cancelled-face)
789     ((and (> score default)
790           (or (= mark gnus-dormant-mark)
791               (= mark gnus-ticked-mark)))
792      . gnus-summary-high-ticked-face)
793     ((and (< score default)
794           (or (= mark gnus-dormant-mark)
795               (= mark gnus-ticked-mark)))
796      . gnus-summary-low-ticked-face)
797     ((or (= mark gnus-dormant-mark)
798          (= mark gnus-ticked-mark))
799      . gnus-summary-normal-ticked-face)
800     ((and (> score default) (= mark gnus-ancient-mark))
801      . gnus-summary-high-ancient-face)
802     ((and (< score default) (= mark gnus-ancient-mark))
803      . gnus-summary-low-ancient-face)
804     ((= mark gnus-ancient-mark)
805      . gnus-summary-normal-ancient-face)
806     ((and (> score default) (= mark gnus-unread-mark))
807      . gnus-summary-high-unread-face)
808     ((and (< score default) (= mark gnus-unread-mark))
809      . gnus-summary-low-unread-face)
810     ((and (= mark gnus-unread-mark))
811      . gnus-summary-normal-unread-face)
812     ((> score default) 
813      . gnus-summary-high-read-face)
814     ((< score default) 
815      . gnus-summary-low-read-face)
816     (t 
817      . gnus-summary-normal-read-face))
818   "Controls the highlighting of summary buffer lines. 
819
820 A list of (FORM . FACE) pairs.  When deciding how a a particular
821 summary line should be displayed, each form is evaluated.  The content
822 of the face field after the first true form is used.  You can change
823 how those summary lines are displayed, by editing the face field.
824
825 You can use the following variables in the FORM field.
826
827 score:   The articles score
828 default: The default article score.
829 below:   The score below which articles are automatically marked as read. 
830 mark:    The articles mark."
831   :group 'gnus-summary
832   :type '(repeat (cons (sexp :tag "Form" nil)
833                        face)))
834
835 ;;; Internal variables
836
837 (defvar gnus-scores-exclude-files nil)
838
839 (defvar gnus-summary-display-table 
840   ;; Change the display table.  Odd characters have a tendency to mess
841   ;; up nicely formatted displays - we make all possible glyphs
842   ;; display only a single character.
843
844   ;; We start from the standard display table, if any.
845   (let ((table (or (copy-sequence standard-display-table)
846                    (make-display-table)))
847         ;; Nix out all the control chars...
848         (i 32))
849     (while (>= (setq i (1- i)) 0)
850       (aset table i [??]))
851     ;; ... but not newline and cr, of course.  (cr is necessary for the
852     ;; selective display).
853     (aset table ?\n nil)
854     (aset table ?\r nil)
855     ;; We nix out any glyphs over 126 that are not set already.
856     (let ((i 256))
857       (while (>= (setq i (1- i)) 127)
858         ;; Only modify if the entry is nil.
859         (or (aref table i)
860             (aset table i [??]))))
861     table)
862   "Display table used in summary mode buffers.")
863
864 (defvar gnus-original-article nil)
865 (defvar gnus-article-internal-prepare-hook nil)
866 (defvar gnus-newsgroup-process-stack nil)
867
868 (defvar gnus-thread-indent-array nil)
869 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
870
871 ;; Avoid highlighting in kill files.
872 (defvar gnus-summary-inhibit-highlight nil)
873 (defvar gnus-newsgroup-selected-overlay nil)
874 (defvar gnus-inhibit-limiting nil)
875 (defvar gnus-newsgroup-adaptive-score-file nil)
876 (defvar gnus-current-score-file nil)
877 (defvar gnus-current-move-group nil)
878 (defvar gnus-current-copy-group nil)
879 (defvar gnus-current-crosspost-group nil)
880
881 (defvar gnus-newsgroup-dependencies nil)
882 (defvar gnus-newsgroup-adaptive nil)
883 (defvar gnus-summary-display-article-function nil)
884 (defvar gnus-summary-highlight-line-function nil
885   "Function called after highlighting a summary line.")
886
887 (defvar gnus-summary-line-format-alist
888   `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
889     (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
890     (?s gnus-tmp-subject-or-nil ?s)
891     (?n gnus-tmp-name ?s)
892     (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
893         ?s)
894     (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
895             gnus-tmp-from) ?s)
896     (?F gnus-tmp-from ?s)
897     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
898     (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
899     (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
900     (?o (gnus-date-iso8601 gnus-tmp-header) ?s)
901     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
902     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
903     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
904     (?L gnus-tmp-lines ?d)
905     (?I gnus-tmp-indentation ?s)
906     (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
907     (?R gnus-tmp-replied ?c)
908     (?\[ gnus-tmp-opening-bracket ?c)
909     (?\] gnus-tmp-closing-bracket ?c)
910     (?\> (make-string gnus-tmp-level ? ) ?s)
911     (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
912     (?i gnus-tmp-score ?d)
913     (?z gnus-tmp-score-char ?c)
914     (?l (bbb-grouplens-score gnus-tmp-header) ?s)
915     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
916     (?U gnus-tmp-unread ?c)
917     (?t (gnus-summary-number-of-articles-in-thread
918          (and (boundp 'thread) (car thread)) gnus-tmp-level)
919         ?d)
920     (?e (gnus-summary-number-of-articles-in-thread
921          (and (boundp 'thread) (car thread)) gnus-tmp-level t)
922         ?c)
923     (?u gnus-tmp-user-defined ?s)
924     (?P (gnus-pick-line-number) ?d))
925   "An alist of format specifications that can appear in summary lines,
926 and what variables they correspond with, along with the type of the
927 variable (string, integer, character, etc).")
928
929 (defvar gnus-summary-dummy-line-format-alist
930   `((?S gnus-tmp-subject ?s)
931     (?N gnus-tmp-number ?d)
932     (?u gnus-tmp-user-defined ?s)))
933
934 (defvar gnus-summary-mode-line-format-alist
935   `((?G gnus-tmp-group-name ?s)
936     (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
937     (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
938     (?A gnus-tmp-article-number ?d)
939     (?Z gnus-tmp-unread-and-unselected ?s)
940     (?V gnus-version ?s)
941     (?U gnus-tmp-unread-and-unticked ?d)
942     (?S gnus-tmp-subject ?s)
943     (?e gnus-tmp-unselected ?d)
944     (?u gnus-tmp-user-defined ?s)
945     (?d (length gnus-newsgroup-dormant) ?d)
946     (?t (length gnus-newsgroup-marked) ?d)
947     (?r (length gnus-newsgroup-reads) ?d)
948     (?E gnus-newsgroup-expunged-tally ?d)
949     (?s (gnus-current-score-file-nondirectory) ?s)))
950
951 (defvar gnus-last-search-regexp nil
952   "Default regexp for article search command.")
953
954 (defvar gnus-last-shell-command nil
955   "Default shell command on article.")
956
957 (defvar gnus-newsgroup-begin nil)
958 (defvar gnus-newsgroup-end nil)
959 (defvar gnus-newsgroup-last-rmail nil)
960 (defvar gnus-newsgroup-last-mail nil)
961 (defvar gnus-newsgroup-last-folder nil)
962 (defvar gnus-newsgroup-last-file nil)
963 (defvar gnus-newsgroup-auto-expire nil)
964 (defvar gnus-newsgroup-active nil)
965
966 (defvar gnus-newsgroup-data nil)
967 (defvar gnus-newsgroup-data-reverse nil)
968 (defvar gnus-newsgroup-limit nil)
969 (defvar gnus-newsgroup-limits nil)
970
971 (defvar gnus-newsgroup-unreads nil
972   "List of unread articles in the current newsgroup.")
973
974 (defvar gnus-newsgroup-unselected nil
975   "List of unselected unread articles in the current newsgroup.")
976
977 (defvar gnus-newsgroup-reads nil
978   "Alist of read articles and article marks in the current newsgroup.")
979
980 (defvar gnus-newsgroup-expunged-tally nil)
981
982 (defvar gnus-newsgroup-marked nil
983   "List of ticked articles in the current newsgroup (a subset of unread art).")
984
985 (defvar gnus-newsgroup-killed nil
986   "List of ranges of articles that have been through the scoring process.")
987
988 (defvar gnus-newsgroup-cached nil
989   "List of articles that come from the article cache.")
990
991 (defvar gnus-newsgroup-saved nil
992   "List of articles that have been saved.")
993
994 (defvar gnus-newsgroup-kill-headers nil)
995
996 (defvar gnus-newsgroup-replied nil
997   "List of articles that have been replied to in the current newsgroup.")
998
999 (defvar gnus-newsgroup-expirable nil
1000   "List of articles in the current newsgroup that can be expired.")
1001
1002 (defvar gnus-newsgroup-processable nil
1003   "List of articles in the current newsgroup that can be processed.")
1004
1005 (defvar gnus-newsgroup-bookmarks nil
1006   "List of articles in the current newsgroup that have bookmarks.")
1007
1008 (defvar gnus-newsgroup-dormant nil
1009   "List of dormant articles in the current newsgroup.")
1010
1011 (defvar gnus-newsgroup-scored nil
1012   "List of scored articles in the current newsgroup.")
1013
1014 (defvar gnus-newsgroup-headers nil
1015   "List of article headers in the current newsgroup.")
1016
1017 (defvar gnus-newsgroup-threads nil)
1018
1019 (defvar gnus-newsgroup-prepared nil
1020   "Whether the current group has been prepared properly.")
1021
1022 (defvar gnus-newsgroup-ancient nil
1023   "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
1024
1025 (defvar gnus-newsgroup-sparse nil)
1026
1027 (defvar gnus-current-article nil)
1028 (defvar gnus-article-current nil)
1029 (defvar gnus-current-headers nil)
1030 (defvar gnus-have-all-headers nil)
1031 (defvar gnus-last-article nil)
1032 (defvar gnus-newsgroup-history nil)
1033
1034 (defconst gnus-summary-local-variables
1035   '(gnus-newsgroup-name
1036     gnus-newsgroup-begin gnus-newsgroup-end
1037     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
1038     gnus-newsgroup-last-folder gnus-newsgroup-last-file
1039     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
1040     gnus-newsgroup-unselected gnus-newsgroup-marked
1041     gnus-newsgroup-reads gnus-newsgroup-saved
1042     gnus-newsgroup-replied gnus-newsgroup-expirable
1043     gnus-newsgroup-processable gnus-newsgroup-killed
1044     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
1045     gnus-newsgroup-headers gnus-newsgroup-threads
1046     gnus-newsgroup-prepared gnus-summary-highlight-line-function
1047     gnus-current-article gnus-current-headers gnus-have-all-headers
1048     gnus-last-article gnus-article-internal-prepare-hook
1049     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1050     gnus-newsgroup-scored gnus-newsgroup-kill-headers
1051     gnus-thread-expunge-below
1052     gnus-score-alist gnus-current-score-file gnus-summary-expunge-below
1053     (gnus-summary-mark-below . global)
1054     gnus-newsgroup-active gnus-scores-exclude-files
1055     gnus-newsgroup-history gnus-newsgroup-ancient
1056     gnus-newsgroup-sparse gnus-newsgroup-process-stack
1057     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
1058     gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
1059     (gnus-newsgroup-expunged-tally . 0)
1060     gnus-cache-removable-articles gnus-newsgroup-cached
1061     gnus-newsgroup-data gnus-newsgroup-data-reverse
1062     gnus-newsgroup-limit gnus-newsgroup-limits)
1063   "Variables that are buffer-local to the summary buffers.")
1064
1065 ;; Byte-compiler warning.
1066 (defvar gnus-article-mode-map)
1067
1068 ;; Subject simplification.
1069
1070 (defsubst gnus-simplify-subject-re (subject)
1071   "Remove \"Re:\" from subject lines."
1072   (if (string-match "^[Rr][Ee]: *" subject)
1073       (substring subject (match-end 0))
1074     subject))
1075
1076 (defun gnus-simplify-subject (subject &optional re-only)
1077   "Remove `Re:' and words in parentheses.
1078 If RE-ONLY is non-nil, strip leading `Re:'s only."
1079   (let ((case-fold-search t))           ;Ignore case.
1080     ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
1081     (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
1082       (setq subject (substring subject (match-end 0))))
1083     ;; Remove uninteresting prefixes.
1084     (when (and (not re-only)
1085                gnus-simplify-ignored-prefixes
1086                (string-match gnus-simplify-ignored-prefixes subject))
1087       (setq subject (substring subject (match-end 0))))
1088     ;; Remove words in parentheses from end.
1089     (unless re-only
1090       (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
1091         (setq subject (substring subject 0 (match-beginning 0)))))
1092     ;; Return subject string.
1093     subject))
1094
1095 ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
1096 ;; all whitespace.
1097 ;; Written by Stainless Steel Rat <ratinox@ccs.neu.edu>.
1098 (defun gnus-simplify-buffer-fuzzy ()
1099   (let ((case-fold-search t))
1100     (goto-char (point-min))
1101     (while (search-forward "\t" nil t)
1102       (replace-match " " t t))
1103     (goto-char (point-min))
1104     (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *" nil t)
1105     (goto-char (match-beginning 0))
1106     (while (or
1107             (looking-at "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
1108             (looking-at "^[[].*: .*[]]$"))
1109       (goto-char (point-min))
1110       (while (re-search-forward "^ *\\(re\\|fwd\\)[[{(^0-9]*[])}]?[:;] *"
1111                                 nil t)
1112         (replace-match "" t t))
1113       (goto-char (point-min))
1114       (while (re-search-forward "^[[].*: .*[]]$" nil t)
1115         (goto-char (match-end 0))
1116         (delete-char -1)
1117         (delete-region
1118          (progn (goto-char (match-beginning 0)))
1119          (re-search-forward ":"))))
1120     (goto-char (point-min))
1121     (while (re-search-forward " *[[{(][^()\n]*[]})] *$" nil t)
1122       (replace-match "" t t))
1123     (goto-char (point-min))
1124     (while (re-search-forward "  +" nil t)
1125       (replace-match " " t t))
1126     (goto-char (point-min))
1127     (while (re-search-forward " $" nil t)
1128       (replace-match "" t t))
1129     (goto-char (point-min))
1130     (while (re-search-forward "^ +" nil t)
1131       (replace-match "" t t))
1132     (goto-char (point-min))
1133     (when gnus-simplify-subject-fuzzy-regexp
1134       (if (listp gnus-simplify-subject-fuzzy-regexp)
1135           (let ((list gnus-simplify-subject-fuzzy-regexp))
1136             (while list
1137               (goto-char (point-min))
1138               (while (re-search-forward (car list) nil t)
1139                 (replace-match "" t t))
1140               (setq list (cdr list))))
1141         (while (re-search-forward gnus-simplify-subject-fuzzy-regexp nil t)
1142           (replace-match "" t t))))))
1143
1144 (defun gnus-simplify-subject-fuzzy (subject)
1145   "Simplify a subject string fuzzily."
1146   (save-excursion
1147     (gnus-set-work-buffer)
1148     (let ((case-fold-search t))
1149       (insert subject)
1150       (inline (gnus-simplify-buffer-fuzzy))
1151       (buffer-string))))
1152
1153 (defsubst gnus-simplify-subject-fully (subject)
1154   "Simplify a subject string according to the user's wishes."
1155   (cond
1156    ((null gnus-summary-gather-subject-limit)
1157     (gnus-simplify-subject-re subject))
1158    ((eq gnus-summary-gather-subject-limit 'fuzzy)
1159     (gnus-simplify-subject-fuzzy subject))
1160    ((numberp gnus-summary-gather-subject-limit)
1161     (gnus-limit-string (gnus-simplify-subject-re subject)
1162                        gnus-summary-gather-subject-limit))
1163    (t
1164     subject)))
1165
1166 (defsubst gnus-subject-equal (s1 s2 &optional simple-first)
1167   "Check whether two subjects are equal.  If optional argument
1168 simple-first is t, first argument is already simplified."
1169   (cond
1170    ((null simple-first)
1171     (equal (gnus-simplify-subject-fully s1)
1172            (gnus-simplify-subject-fully s2)))
1173    (t
1174     (equal s1
1175            (gnus-simplify-subject-fully s2)))))
1176
1177 (defun gnus-offer-save-summaries ()
1178   "Offer to save all active summary buffers."
1179   (save-excursion
1180     (let ((buflist (buffer-list))
1181           buffers bufname)
1182       ;; Go through all buffers and find all summaries.
1183       (while buflist
1184         (and (setq bufname (buffer-name (car buflist)))
1185              (string-match "Summary" bufname)
1186              (save-excursion
1187                (set-buffer bufname)
1188                ;; We check that this is, indeed, a summary buffer.
1189                (and (eq major-mode 'gnus-summary-mode)
1190                     ;; Also make sure this isn't bogus.
1191                     gnus-newsgroup-prepared))
1192              (push bufname buffers))
1193         (setq buflist (cdr buflist)))
1194       ;; Go through all these summary buffers and offer to save them.
1195       (when buffers
1196         (map-y-or-n-p
1197          "Update summary buffer %s? "
1198          (lambda (buf) (set-buffer buf) (gnus-summary-exit))
1199          buffers)))))
1200
1201 (defun gnus-summary-bubble-group ()
1202   "Increase the score of the current group.
1203 This is a handy function to add to `gnus-summary-exit-hook' to
1204 increase the score of each group you read."
1205   (gnus-group-add-score gnus-newsgroup-name))
1206
1207 \f
1208 ;;;
1209 ;;; Gnus summary mode
1210 ;;;
1211
1212 (put 'gnus-summary-mode 'mode-class 'special)
1213
1214 (when t
1215   ;; Non-orthogonal keys
1216
1217   (gnus-define-keys gnus-summary-mode-map
1218     " " gnus-summary-next-page
1219     "\177" gnus-summary-prev-page
1220     [delete] gnus-summary-prev-page
1221     "\r" gnus-summary-scroll-up
1222     "n" gnus-summary-next-unread-article
1223     "p" gnus-summary-prev-unread-article
1224     "N" gnus-summary-next-article
1225     "P" gnus-summary-prev-article
1226     "\M-\C-n" gnus-summary-next-same-subject
1227     "\M-\C-p" gnus-summary-prev-same-subject
1228     "\M-n" gnus-summary-next-unread-subject
1229     "\M-p" gnus-summary-prev-unread-subject
1230     "." gnus-summary-first-unread-article
1231     "," gnus-summary-best-unread-article
1232     "\M-s" gnus-summary-search-article-forward
1233     "\M-r" gnus-summary-search-article-backward
1234     "<" gnus-summary-beginning-of-article
1235     ">" gnus-summary-end-of-article
1236     "j" gnus-summary-goto-article
1237     "^" gnus-summary-refer-parent-article
1238     "\M-^" gnus-summary-refer-article
1239     "u" gnus-summary-tick-article-forward
1240     "!" gnus-summary-tick-article-forward
1241     "U" gnus-summary-tick-article-backward
1242     "d" gnus-summary-mark-as-read-forward
1243     "D" gnus-summary-mark-as-read-backward
1244     "E" gnus-summary-mark-as-expirable
1245     "\M-u" gnus-summary-clear-mark-forward
1246     "\M-U" gnus-summary-clear-mark-backward
1247     "k" gnus-summary-kill-same-subject-and-select
1248     "\C-k" gnus-summary-kill-same-subject
1249     "\M-\C-k" gnus-summary-kill-thread
1250     "\M-\C-l" gnus-summary-lower-thread
1251     "e" gnus-summary-edit-article
1252     "#" gnus-summary-mark-as-processable
1253     "\M-#" gnus-summary-unmark-as-processable
1254     "\M-\C-t" gnus-summary-toggle-threads
1255     "\M-\C-s" gnus-summary-show-thread
1256     "\M-\C-h" gnus-summary-hide-thread
1257     "\M-\C-f" gnus-summary-next-thread
1258     "\M-\C-b" gnus-summary-prev-thread
1259     "\M-\C-u" gnus-summary-up-thread
1260     "\M-\C-d" gnus-summary-down-thread
1261     "&" gnus-summary-execute-command
1262     "c" gnus-summary-catchup-and-exit
1263     "\C-w" gnus-summary-mark-region-as-read
1264     "\C-t" gnus-summary-toggle-truncation
1265     "?" gnus-summary-mark-as-dormant
1266     "\C-c\M-\C-s" gnus-summary-limit-include-expunged
1267     "\C-c\C-s\C-n" gnus-summary-sort-by-number
1268     "\C-c\C-s\C-a" gnus-summary-sort-by-author
1269     "\C-c\C-s\C-s" gnus-summary-sort-by-subject
1270     "\C-c\C-s\C-d" gnus-summary-sort-by-date
1271     "\C-c\C-s\C-i" gnus-summary-sort-by-score
1272     "=" gnus-summary-expand-window
1273     "\C-x\C-s" gnus-summary-reselect-current-group
1274     "\M-g" gnus-summary-rescan-group
1275     "w" gnus-summary-stop-page-breaking
1276     "\C-c\C-r" gnus-summary-caesar-message
1277     "\M-t" gnus-summary-toggle-mime
1278     "f" gnus-summary-followup
1279     "F" gnus-summary-followup-with-original
1280     "C" gnus-summary-cancel-article
1281     "r" gnus-summary-reply
1282     "R" gnus-summary-reply-with-original
1283     "\C-c\C-f" gnus-summary-mail-forward
1284     "o" gnus-summary-save-article
1285     "\C-o" gnus-summary-save-article-mail
1286     "|" gnus-summary-pipe-output
1287     "\M-k" gnus-summary-edit-local-kill
1288     "\M-K" gnus-summary-edit-global-kill
1289     ;; "V" gnus-version
1290     "\C-c\C-d" gnus-summary-describe-group
1291     "q" gnus-summary-exit
1292     "Q" gnus-summary-exit-no-update
1293     "\C-c\C-i" gnus-info-find-node
1294     gnus-mouse-2 gnus-mouse-pick-article
1295     "m" gnus-summary-mail-other-window
1296     "a" gnus-summary-post-news
1297     "x" gnus-summary-limit-to-unread
1298     "s" gnus-summary-isearch-article
1299     "t" gnus-article-hide-headers
1300     "g" gnus-summary-show-article
1301     "l" gnus-summary-goto-last-article
1302     "\C-c\C-v\C-v" gnus-uu-decode-uu-view
1303     "\C-d" gnus-summary-enter-digest-group
1304     "\M-\C-d" gnus-summary-read-document
1305     "\C-c\C-b" gnus-bug
1306     "*" gnus-cache-enter-article
1307     "\M-*" gnus-cache-remove-article
1308     "\M-&" gnus-summary-universal-argument
1309     "\C-l" gnus-recenter
1310     "I" gnus-summary-increase-score
1311     "L" gnus-summary-lower-score
1312
1313     "V" gnus-summary-score-map
1314     "X" gnus-uu-extract-map
1315     "S" gnus-summary-send-map)
1316
1317   ;; Sort of orthogonal keymap
1318   (gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
1319     "t" gnus-summary-tick-article-forward
1320     "!" gnus-summary-tick-article-forward
1321     "d" gnus-summary-mark-as-read-forward
1322     "r" gnus-summary-mark-as-read-forward
1323     "c" gnus-summary-clear-mark-forward
1324     " " gnus-summary-clear-mark-forward
1325     "e" gnus-summary-mark-as-expirable
1326     "x" gnus-summary-mark-as-expirable
1327     "?" gnus-summary-mark-as-dormant
1328     "b" gnus-summary-set-bookmark
1329     "B" gnus-summary-remove-bookmark
1330     "#" gnus-summary-mark-as-processable
1331     "\M-#" gnus-summary-unmark-as-processable
1332     "S" gnus-summary-limit-include-expunged
1333     "C" gnus-summary-catchup
1334     "H" gnus-summary-catchup-to-here
1335     "\C-c" gnus-summary-catchup-all
1336     "k" gnus-summary-kill-same-subject-and-select
1337     "K" gnus-summary-kill-same-subject
1338     "P" gnus-uu-mark-map)
1339
1340   (gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
1341     "c" gnus-summary-clear-above
1342     "u" gnus-summary-tick-above
1343     "m" gnus-summary-mark-above
1344     "k" gnus-summary-kill-below)
1345
1346   (gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
1347     "/" gnus-summary-limit-to-subject
1348     "n" gnus-summary-limit-to-articles
1349     "w" gnus-summary-pop-limit
1350     "s" gnus-summary-limit-to-subject
1351     "a" gnus-summary-limit-to-author
1352     "u" gnus-summary-limit-to-unread
1353     "m" gnus-summary-limit-to-marks
1354     "v" gnus-summary-limit-to-score
1355     "D" gnus-summary-limit-include-dormant
1356     "d" gnus-summary-limit-exclude-dormant
1357     ;;  "t" gnus-summary-limit-exclude-thread
1358     "E" gnus-summary-limit-include-expunged
1359     "c" gnus-summary-limit-exclude-childless-dormant
1360     "C" gnus-summary-limit-mark-excluded-as-read)
1361
1362   (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
1363     "n" gnus-summary-next-unread-article
1364     "p" gnus-summary-prev-unread-article
1365     "N" gnus-summary-next-article
1366     "P" gnus-summary-prev-article
1367     "\C-n" gnus-summary-next-same-subject
1368     "\C-p" gnus-summary-prev-same-subject
1369     "\M-n" gnus-summary-next-unread-subject
1370     "\M-p" gnus-summary-prev-unread-subject
1371     "f" gnus-summary-first-unread-article
1372     "b" gnus-summary-best-unread-article
1373     "j" gnus-summary-goto-article
1374     "g" gnus-summary-goto-subject
1375     "l" gnus-summary-goto-last-article
1376     "p" gnus-summary-pop-article)
1377
1378   (gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
1379     "k" gnus-summary-kill-thread
1380     "l" gnus-summary-lower-thread
1381     "i" gnus-summary-raise-thread
1382     "T" gnus-summary-toggle-threads
1383     "t" gnus-summary-rethread-current
1384     "^" gnus-summary-reparent-thread
1385     "s" gnus-summary-show-thread
1386     "S" gnus-summary-show-all-threads
1387     "h" gnus-summary-hide-thread
1388     "H" gnus-summary-hide-all-threads
1389     "n" gnus-summary-next-thread
1390     "p" gnus-summary-prev-thread
1391     "u" gnus-summary-up-thread
1392     "o" gnus-summary-top-thread
1393     "d" gnus-summary-down-thread
1394     "#" gnus-uu-mark-thread
1395     "\M-#" gnus-uu-unmark-thread)
1396
1397   (gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
1398     "g" gnus-summary-prepare 
1399     "c" gnus-summary-insert-cached-articles)
1400
1401   (gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
1402     "c" gnus-summary-catchup-and-exit
1403     "C" gnus-summary-catchup-all-and-exit
1404     "E" gnus-summary-exit-no-update
1405     "Q" gnus-summary-exit
1406     "Z" gnus-summary-exit
1407     "n" gnus-summary-catchup-and-goto-next-group
1408     "R" gnus-summary-reselect-current-group
1409     "G" gnus-summary-rescan-group
1410     "N" gnus-summary-next-group
1411     "P" gnus-summary-prev-group)
1412
1413   (gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
1414     " " gnus-summary-next-page
1415     "n" gnus-summary-next-page
1416     "\177" gnus-summary-prev-page
1417     [delete] gnus-summary-prev-page
1418     "p" gnus-summary-prev-page
1419     "\r" gnus-summary-scroll-up
1420     "<" gnus-summary-beginning-of-article
1421     ">" gnus-summary-end-of-article
1422     "b" gnus-summary-beginning-of-article
1423     "e" gnus-summary-end-of-article
1424     "^" gnus-summary-refer-parent-article
1425     "r" gnus-summary-refer-parent-article
1426     "R" gnus-summary-refer-references
1427     "g" gnus-summary-show-article
1428     "s" gnus-summary-isearch-article)
1429
1430   (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
1431     "b" gnus-article-add-buttons
1432     "B" gnus-article-add-buttons-to-head
1433     "o" gnus-article-treat-overstrike
1434     "e" gnus-article-emphasize
1435     "w" gnus-article-fill-cited-article
1436     "c" gnus-article-remove-cr
1437     "q" gnus-article-de-quoted-unreadable
1438     "f" gnus-article-display-x-face
1439     "l" gnus-summary-stop-page-breaking
1440     "r" gnus-summary-caesar-message
1441     "t" gnus-article-hide-headers
1442     "v" gnus-summary-verbose-headers
1443     "m" gnus-summary-toggle-mime)
1444
1445   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
1446     "a" gnus-article-hide
1447     "h" gnus-article-hide-headers
1448     "b" gnus-article-hide-boring-headers
1449     "s" gnus-article-hide-signature
1450     "c" gnus-article-hide-citation
1451     "p" gnus-article-hide-pgp
1452     "P" gnus-article-hide-pem
1453     "\C-c" gnus-article-hide-citation-maybe)
1454
1455   (gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
1456     "a" gnus-article-highlight
1457     "h" gnus-article-highlight-headers
1458     "c" gnus-article-highlight-citation
1459     "s" gnus-article-highlight-signature)
1460
1461   (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
1462     "z" gnus-article-date-ut
1463     "u" gnus-article-date-ut
1464     "l" gnus-article-date-local
1465     "e" gnus-article-date-lapsed
1466     "o" gnus-article-date-original)
1467
1468   (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
1469     "t" gnus-article-remove-trailing-blank-lines
1470     "l" gnus-article-strip-leading-blank-lines
1471     "m" gnus-article-strip-multiple-blank-lines
1472     "a" gnus-article-strip-blank-lines)
1473
1474   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
1475     "v" gnus-version
1476     "f" gnus-summary-fetch-faq
1477     "d" gnus-summary-describe-group
1478     "h" gnus-summary-describe-briefly
1479     "i" gnus-info-find-node)
1480
1481   (gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
1482     "e" gnus-summary-expire-articles
1483     "\M-\C-e" gnus-summary-expire-articles-now
1484     "\177" gnus-summary-delete-article
1485     [delete] gnus-summary-delete-article
1486     "m" gnus-summary-move-article
1487     "r" gnus-summary-respool-article
1488     "w" gnus-summary-edit-article
1489     "c" gnus-summary-copy-article
1490     "B" gnus-summary-crosspost-article
1491     "q" gnus-summary-respool-query
1492     "i" gnus-summary-import-article
1493     "p" gnus-summary-article-posted-p)
1494
1495   (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
1496     "o" gnus-summary-save-article
1497     "m" gnus-summary-save-article-mail
1498     "F" gnus-summary-write-article-file
1499     "r" gnus-summary-save-article-rmail
1500     "f" gnus-summary-save-article-file
1501     "b" gnus-summary-save-article-body-file
1502     "h" gnus-summary-save-article-folder
1503     "v" gnus-summary-save-article-vm
1504     "p" gnus-summary-pipe-output
1505     "s" gnus-soup-add-article))
1506
1507 (defun gnus-summary-make-menu-bar ()
1508   (gnus-turn-off-edit-menu 'summary)
1509
1510   (unless (boundp 'gnus-summary-misc-menu)
1511
1512     (easy-menu-define
1513      gnus-summary-kill-menu gnus-summary-mode-map ""
1514      (cons
1515       "Score"
1516       (nconc
1517        (list
1518         ["Enter score..." gnus-summary-score-entry t])
1519        (gnus-make-score-map 'increase)
1520        (gnus-make-score-map 'lower)
1521        '(("Mark"
1522           ["Kill below" gnus-summary-kill-below t]
1523           ["Mark above" gnus-summary-mark-above t]
1524           ["Tick above" gnus-summary-tick-above t]
1525           ["Clear above" gnus-summary-clear-above t])
1526          ["Current score" gnus-summary-current-score t]
1527          ["Set score" gnus-summary-set-score t]
1528          ["Switch current score file..." gnus-score-change-score-file t]
1529          ["Set mark below..." gnus-score-set-mark-below t]
1530          ["Set expunge below..." gnus-score-set-expunge-below t]
1531          ["Edit current score file" gnus-score-edit-current-scores t]
1532          ["Edit score file" gnus-score-edit-file t]
1533          ["Trace score" gnus-score-find-trace t]
1534          ["Find words" gnus-score-find-favourite-words t]
1535          ["Rescore buffer" gnus-summary-rescore t]
1536          ["Increase score..." gnus-summary-increase-score t]
1537          ["Lower score..." gnus-summary-lower-score t]))))
1538
1539     '(("Default header"
1540        ["Ask" (gnus-score-set-default 'gnus-score-default-header nil)
1541         :style radio 
1542         :selected (null gnus-score-default-header)]
1543        ["From" (gnus-score-set-default 'gnus-score-default-header 'a)
1544         :style radio 
1545         :selected (eq gnus-score-default-header 'a)]
1546        ["Subject" (gnus-score-set-default 'gnus-score-default-header 's)
1547         :style radio 
1548         :selected (eq gnus-score-default-header 's)]
1549        ["Article body"
1550         (gnus-score-set-default 'gnus-score-default-header 'b)
1551         :style radio 
1552         :selected (eq gnus-score-default-header 'b )]
1553        ["All headers"
1554         (gnus-score-set-default 'gnus-score-default-header 'h)
1555         :style radio 
1556         :selected (eq gnus-score-default-header 'h )]
1557        ["Message-ID" (gnus-score-set-default 'gnus-score-default-header 'i)
1558         :style radio 
1559         :selected (eq gnus-score-default-header 'i )]
1560        ["Thread" (gnus-score-set-default 'gnus-score-default-header 't)
1561         :style radio 
1562         :selected (eq gnus-score-default-header 't )]
1563        ["Crossposting"
1564         (gnus-score-set-default 'gnus-score-default-header 'x)
1565         :style radio 
1566         :selected (eq gnus-score-default-header 'x )]
1567        ["Lines" (gnus-score-set-default 'gnus-score-default-header 'l)
1568         :style radio 
1569         :selected (eq gnus-score-default-header 'l )]
1570        ["Date" (gnus-score-set-default 'gnus-score-default-header 'd)
1571         :style radio 
1572         :selected (eq gnus-score-default-header 'd )]
1573        ["Followups to author"
1574         (gnus-score-set-default 'gnus-score-default-header 'f)
1575         :style radio 
1576         :selected (eq gnus-score-default-header 'f )])
1577       ("Default type"
1578        ["Ask" (gnus-score-set-default 'gnus-score-default-type nil)
1579         :style radio 
1580         :selected (null gnus-score-default-type)]
1581        ;; The `:active' key is commented out in the following,
1582        ;; because the GNU Emacs hack to support radio buttons use
1583        ;; active to indicate which button is selected.  
1584        ["Substring" (gnus-score-set-default 'gnus-score-default-type 's)
1585         :style radio 
1586         ;; :active (not (memq gnus-score-default-header '(l d)))
1587         :selected (eq gnus-score-default-type 's)]
1588        ["Regexp" (gnus-score-set-default 'gnus-score-default-type 'r)
1589         :style radio
1590         ;; :active (not (memq gnus-score-default-header '(l d)))
1591         :selected (eq gnus-score-default-type 'r)]
1592        ["Exact" (gnus-score-set-default 'gnus-score-default-type 'e)
1593         :style radio
1594         ;; :active (not (memq gnus-score-default-header '(l d)))
1595         :selected (eq gnus-score-default-type 'e)]
1596        ["Fuzzy" (gnus-score-set-default 'gnus-score-default-type 'f)
1597         :style radio 
1598         ;; :active (not (memq gnus-score-default-header '(l d)))
1599         :selected (eq gnus-score-default-type 'f)]
1600        ["Before date" (gnus-score-set-default 'gnus-score-default-type 'b)
1601         :style radio 
1602         ;; :active (eq (gnus-score-default-header 'd))
1603         :selected (eq gnus-score-default-type 'b)]
1604        ["At date" (gnus-score-set-default 'gnus-score-default-type 'n)
1605         :style radio