(gnus-summary-toggle-header): Make it work even if there's no visible header.
[gnus] / lisp / gnus-sum.el
1 ;;; gnus-sum.el --- summary mode commands for Gnus
2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
3 ;;        Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
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-when-compile
30   (require 'cl)
31   (defvar tool-bar-map))
32
33 (require 'gnus)
34 (require 'gnus-group)
35 (require 'gnus-spec)
36 (require 'gnus-range)
37 (require 'gnus-int)
38 (require 'gnus-undo)
39 (require 'gnus-util)
40 (require 'mm-decode)
41 (require 'nnoo)
42
43 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
44 (autoload 'gnus-cache-write-active "gnus-cache")
45 (autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
46 (autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
47 (autoload 'gnus-pick-line-number "gnus-salt" nil t)
48 (autoload 'mm-uu-dissect "mm-uu")
49 (autoload 'gnus-article-outlook-deuglify-article "deuglify"
50   "Deuglify broken Outlook (Express) articles and redisplay."
51   t)
52 (autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
53 (autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
54 (autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
55
56 (defcustom gnus-kill-summary-on-exit t
57   "*If non-nil, kill the summary buffer when you exit from it.
58 If nil, the summary will become a \"*Dead Summary*\" buffer, and
59 it will be killed sometime later."
60   :group 'gnus-summary-exit
61   :type 'boolean)
62
63 (defcustom gnus-fetch-old-headers nil
64   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
65 If an unread article in the group refers to an older, already read (or
66 just marked as read) article, the old article will not normally be
67 displayed in the Summary buffer.  If this variable is t, Gnus
68 will attempt to grab the headers to the old articles, and thereby
69 build complete threads.  If it has the value `some', only enough
70 headers to connect otherwise loose threads will be displayed.  This
71 variable can also be a number.  In that case, no more than that number
72 of old headers will be fetched.  If it has the value `invisible', all
73 old headers will be fetched, but none will be displayed.
74
75 The server has to support NOV for any of this to work."
76   :group 'gnus-thread
77   :type '(choice (const :tag "off" nil)
78                  (const :tag "on" t)
79                  (const some)
80                  (const invisible)
81                  number
82                  (sexp :menu-tag "other" t)))
83
84 (defcustom gnus-refer-thread-limit 200
85   "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
86 If t, fetch all the available old headers."
87   :group 'gnus-thread
88   :type '(choice number
89                  (sexp :menu-tag "other" t)))
90
91 (defcustom gnus-summary-make-false-root 'adopt
92   "*nil means that Gnus won't gather loose threads.
93 If the root of a thread has expired or been read in a previous
94 session, the information necessary to build a complete thread has been
95 lost.  Instead of having many small sub-threads from this original thread
96 scattered all over the summary buffer, Gnus can gather them.
97
98 If non-nil, Gnus will try to gather all loose sub-threads from an
99 original thread into one large thread.
100
101 If this variable is non-nil, it should be one of `none', `adopt',
102 `dummy' or `empty'.
103
104 If this variable is `none', Gnus will not make a false root, but just
105 present the sub-threads after another.
106 If this variable is `dummy', Gnus will create a dummy root that will
107 have all the sub-threads as children.
108 If this variable is `adopt', Gnus will make one of the \"children\"
109 the parent and mark all the step-children as such.
110 If this variable is `empty', the \"children\" are printed with empty
111 subject fields.  (Or rather, they will be printed with a string
112 given by the `gnus-summary-same-subject' variable.)"
113   :group 'gnus-thread
114   :type '(choice (const :tag "off" nil)
115                  (const none)
116                  (const dummy)
117                  (const adopt)
118                  (const empty)))
119
120 (defcustom gnus-summary-make-false-root-always nil
121   "Always make a false dummy root."
122   :version "21.4"
123   :group 'gnus-thread
124   :type 'boolean)
125
126 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
127   "*A regexp to match subjects to be excluded from loose thread gathering.
128 As loose thread gathering is done on subjects only, that means that
129 there can be many false gatherings performed.  By rooting out certain
130 common subjects, gathering might become saner."
131   :group 'gnus-thread
132   :type 'regexp)
133
134 (defcustom gnus-summary-gather-subject-limit nil
135   "*Maximum length of subject comparisons when gathering loose threads.
136 Use nil to compare full subjects.  Setting this variable to a low
137 number will help gather threads that have been corrupted by
138 newsreaders chopping off subject lines, but it might also mean that
139 unrelated articles that have subject that happen to begin with the
140 same few characters will be incorrectly gathered.
141
142 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
143 comparing subjects."
144   :group 'gnus-thread
145   :type '(choice (const :tag "off" nil)
146                  (const fuzzy)
147                  (sexp :menu-tag "on" t)))
148
149 (defcustom gnus-simplify-subject-functions nil
150   "List of functions taking a string argument that simplify subjects.
151 The functions are applied recursively.
152
153 Useful functions to put in this list include:
154 `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
155 `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
156   :group 'gnus-thread
157   :type '(repeat function))
158
159 (defcustom gnus-simplify-ignored-prefixes nil
160   "*Remove matches for this regexp from subject lines when simplifying fuzzily."
161   :group 'gnus-thread
162   :type '(choice (const :tag "off" nil)
163                  regexp))
164
165 (defcustom gnus-build-sparse-threads nil
166   "*If non-nil, fill in the gaps in threads.
167 If `some', only fill in the gaps that are needed to tie loose threads
168 together.  If `more', fill in all leaf nodes that Gnus can find.  If
169 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
170   :group 'gnus-thread
171   :type '(choice (const :tag "off" nil)
172                  (const some)
173                  (const more)
174                  (sexp :menu-tag "all" t)))
175
176 (defcustom gnus-summary-thread-gathering-function
177   'gnus-gather-threads-by-subject
178   "*Function used for gathering loose threads.
179 There are two pre-defined functions: `gnus-gather-threads-by-subject',
180 which only takes Subjects into consideration; and
181 `gnus-gather-threads-by-references', which compared the References
182 headers of the articles to find matches."
183   :group 'gnus-thread
184   :type '(radio (function-item gnus-gather-threads-by-subject)
185                 (function-item gnus-gather-threads-by-references)
186                 (function :tag "other")))
187
188 (defcustom gnus-summary-same-subject ""
189   "*String indicating that the current article has the same subject as the previous.
190 This variable will only be used if the value of
191 `gnus-summary-make-false-root' is `empty'."
192   :group 'gnus-summary-format
193   :type 'string)
194
195 (defcustom gnus-summary-goto-unread t
196   "*If t, many commands will go to the next unread article.
197 This applies to marking commands as well as other commands that
198 \"naturally\" select the next article, like, for instance, `SPC' at
199 the end of an article.
200
201 If nil, the marking commands do NOT go to the next unread article
202 \(they go to the next article instead).  If `never', commands that
203 usually go to the next unread article, will go to the next article,
204 whether it is read or not."
205   :group 'gnus-summary-marks
206   :link '(custom-manual "(gnus)Setting Marks")
207   :type '(choice (const :tag "off" nil)
208                  (const never)
209                  (sexp :menu-tag "on" t)))
210
211 (defcustom gnus-summary-default-score 0
212   "*Default article score level.
213 All scores generated by the score files will be added to this score.
214 If this variable is nil, scoring will be disabled."
215   :group 'gnus-score-default
216   :type '(choice (const :tag "disable")
217                  integer))
218
219 (defcustom gnus-summary-default-high-score 0
220   "*Default threshold for a high scored article.
221 An article will be highlighted as high scored if its score is greater
222 than this score."
223   :version "21.4"
224   :group 'gnus-score-default
225   :type 'integer)
226
227 (defcustom gnus-summary-default-low-score 0
228   "*Default threshold for a low scored article.
229 An article will be highlighted as low scored if its score is smaller
230 than this score."
231   :version "21.4"
232   :group 'gnus-score-default
233   :type 'integer)
234
235 (defcustom gnus-summary-zcore-fuzz 0
236   "*Fuzziness factor for the zcore in the summary buffer.
237 Articles with scores closer than this to `gnus-summary-default-score'
238 will not be marked."
239   :group 'gnus-summary-format
240   :type 'integer)
241
242 (defcustom gnus-simplify-subject-fuzzy-regexp nil
243   "*Strings to be removed when doing fuzzy matches.
244 This can either be a regular expression or list of regular expressions
245 that will be removed from subject strings if fuzzy subject
246 simplification is selected."
247   :group 'gnus-thread
248   :type '(repeat regexp))
249
250 (defcustom gnus-show-threads t
251   "*If non-nil, display threads in summary mode."
252   :group 'gnus-thread
253   :type 'boolean)
254
255 (defcustom gnus-thread-hide-subtree nil
256   "*If non-nil, hide all threads initially.
257 This can be a predicate specifier which says which threads to hide.
258 If threads are hidden, you have to run the command
259 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
260 to expose hidden threads."
261   :group 'gnus-thread
262   :type '(radio (sexp :format "Non-nil\n"
263                       :match (lambda (widget value)
264                                (not (or (consp value) (functionp value))))
265                       :value t)
266                 (const nil)
267                 (sexp :tag "Predicate specifier" :size 0)))
268
269 (defcustom gnus-thread-hide-killed t
270   "*If non-nil, hide killed threads automatically."
271   :group 'gnus-thread
272   :type 'boolean)
273
274 (defcustom gnus-thread-ignore-subject t
275   "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
276 If nil, articles that have different subjects from their parents will
277 start separate threads."
278   :group 'gnus-thread
279   :type 'boolean)
280
281 (defcustom gnus-thread-operation-ignore-subject t
282   "*If non-nil, subjects will be ignored when doing thread commands.
283 This affects commands like `gnus-summary-kill-thread' and
284 `gnus-summary-lower-thread'.
285
286 If this variable is nil, articles in the same thread with different
287 subjects will not be included in the operation in question.  If this
288 variable is `fuzzy', only articles that have subjects that are fuzzily
289 equal will be included."
290   :group 'gnus-thread
291   :type '(choice (const :tag "off" nil)
292                  (const fuzzy)
293                  (sexp :tag "on" t)))
294
295 (defcustom gnus-thread-indent-level 4
296   "*Number that says how much each sub-thread should be indented."
297   :group 'gnus-thread
298   :type 'integer)
299
300 (defcustom gnus-auto-extend-newsgroup t
301   "*If non-nil, extend newsgroup forward and backward when requested."
302   :group 'gnus-summary-choose
303   :type 'boolean)
304
305 (defcustom gnus-auto-select-first t
306   "*If non-nil, select the article under point.
307 Which article this is is controlled by the `gnus-auto-select-subject'
308 variable.
309
310 If you want to prevent automatic selection of articles in some
311 newsgroups, set the variable to nil in `gnus-select-group-hook'."
312   :group 'gnus-group-select
313   :type '(choice (const :tag "none" nil)
314                  (sexp :menu-tag "first" t)))
315
316 (defcustom gnus-auto-select-subject 'unread
317   "*Says what subject to place under point when entering a group.
318
319 This variable can either be the symbols `first' (place point on the
320 first subject), `unread' (place point on the subject line of the first
321 unread article), `best' (place point on the subject line of the
322 higest-scored article), `unseen' (place point on the subject line of
323 the first unseen article), 'unseen-or-unread' (place point on the subject
324 line of the first unseen article or, if all article have been seen, on the
325 subject line of the first unread article), or a function to be called to
326 place point on some subject line."
327   :version "21.4"
328   :group 'gnus-group-select
329   :type '(choice (const best)
330                  (const unread)
331                  (const first)
332                  (const unseen)
333                  (const unseen-or-unread)))
334
335 (defcustom gnus-auto-select-next t
336   "*If non-nil, offer to go to the next group from the end of the previous.
337 If the value is t and the next newsgroup is empty, Gnus will exit
338 summary mode and go back to group mode.  If the value is neither nil
339 nor t, Gnus will select the following unread newsgroup.  In
340 particular, if the value is the symbol `quietly', the next unread
341 newsgroup will be selected without any confirmation, and if it is
342 `almost-quietly', the next group will be selected without any
343 confirmation if you are located on the last article in the group.
344 Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
345 will go to the next group without confirmation."
346   :group 'gnus-summary-maneuvering
347   :type '(choice (const :tag "off" nil)
348                  (const quietly)
349                  (const almost-quietly)
350                  (const slightly-quietly)
351                  (sexp :menu-tag "on" t)))
352
353 (defcustom gnus-auto-select-same nil
354   "*If non-nil, select the next article with the same subject.
355 If there are no more articles with the same subject, go to
356 the first unread article."
357   :group 'gnus-summary-maneuvering
358   :type 'boolean)
359
360 (defcustom gnus-auto-goto-ignores 'unfetched
361   "*Says how to handle unfetched articles when maneuvering.
362
363 This variable can either be the symbols nil (maneuver to any
364 article), `undownloaded' (maneuvering while unplugged ignores articles
365 that have not been fetched), `always-undownloaded' (maneuvering always
366 ignores articles that have not been fetched), `unfetched' (maneuvering
367 ignores articles whose headers have not been fetched).
368
369 NOTE: The list of unfetched articles will always be nil when plugged
370 and, when unplugged, a subset of the undownloaded article list."
371   :version "21.4"
372   :group 'gnus-summary-maneuvering
373   :type '(choice (const :tag "None" nil)
374                  (const :tag "Undownloaded when unplugged" undownloaded)
375                  (const :tag "Undownloaded" always-undownloaded)
376                  (const :tag "Unfetched" unfetched)))
377
378 (defcustom gnus-summary-check-current nil
379   "*If non-nil, consider the current article when moving.
380 The \"unread\" movement commands will stay on the same line if the
381 current article is unread."
382   :group 'gnus-summary-maneuvering
383   :type 'boolean)
384
385 (defcustom gnus-auto-center-summary 2
386   "*If non-nil, always center the current summary buffer.
387 In particular, if `vertical' do only vertical recentering.  If non-nil
388 and non-`vertical', do both horizontal and vertical recentering."
389   :group 'gnus-summary-maneuvering
390   :type '(choice (const :tag "none" nil)
391                  (const vertical)
392                  (integer :tag "height")
393                  (sexp :menu-tag "both" t)))
394
395 (defvar gnus-auto-center-group t
396   "*If non-nil, always center the group buffer.")
397
398 (defcustom gnus-show-all-headers nil
399   "*If non-nil, don't hide any headers."
400   :group 'gnus-article-hiding
401   :group 'gnus-article-headers
402   :type 'boolean)
403
404 (defcustom gnus-summary-ignore-duplicates nil
405   "*If non-nil, ignore articles with identical Message-ID headers."
406   :group 'gnus-summary
407   :type 'boolean)
408
409 (defcustom gnus-single-article-buffer t
410   "*If non-nil, display all articles in the same buffer.
411 If nil, each group will get its own article buffer."
412   :group 'gnus-article-various
413   :type 'boolean)
414
415 (defcustom gnus-break-pages t
416   "*If non-nil, do page breaking on articles.
417 The page delimiter is specified by the `gnus-page-delimiter'
418 variable."
419   :group 'gnus-article-various
420   :type 'boolean)
421
422 (defcustom gnus-move-split-methods nil
423   "*Variable used to suggest where articles are to be moved to.
424 It uses the same syntax as the `gnus-split-methods' variable.
425 However, whereas `gnus-split-methods' specifies file names as targets,
426 this variable specifies group names."
427   :group 'gnus-summary-mail
428   :type '(repeat (choice (list :value (fun) function)
429                          (cons :value ("" "") regexp (repeat string))
430                          (sexp :value nil))))
431
432 (defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
433   "Function used to compute default prefix for article move/copy/etc prompts.
434 The function should take one argument, a group name, and return a
435 string with the suggested prefix."
436   :group 'gnus-summary-mail
437   :type 'function)
438
439 (defcustom gnus-unread-mark ?           ;Whitespace
440   "*Mark used for unread articles."
441   :group 'gnus-summary-marks
442   :type 'character)
443
444 (defcustom gnus-ticked-mark ?!
445   "*Mark used for ticked articles."
446   :group 'gnus-summary-marks
447   :type 'character)
448
449 (defcustom gnus-dormant-mark ??
450   "*Mark used for dormant articles."
451   :group 'gnus-summary-marks
452   :type 'character)
453
454 (defcustom gnus-del-mark ?r
455   "*Mark used for del'd articles."
456   :group 'gnus-summary-marks
457   :type 'character)
458
459 (defcustom gnus-read-mark ?R
460   "*Mark used for read articles."
461   :group 'gnus-summary-marks
462   :type 'character)
463
464 (defcustom gnus-expirable-mark ?E
465   "*Mark used for expirable articles."
466   :group 'gnus-summary-marks
467   :type 'character)
468
469 (defcustom gnus-killed-mark ?K
470   "*Mark used for killed articles."
471   :group 'gnus-summary-marks
472   :type 'character)
473
474 (defcustom gnus-spam-mark ?$
475   "*Mark used for spam articles."
476   :group 'gnus-summary-marks
477   :type 'character)
478
479 (defcustom gnus-souped-mark ?F
480   "*Mark used for souped articles."
481   :group 'gnus-summary-marks
482   :type 'character)
483
484 (defcustom gnus-kill-file-mark ?X
485   "*Mark used for articles killed by kill files."
486   :group 'gnus-summary-marks
487   :type 'character)
488
489 (defcustom gnus-low-score-mark ?Y
490   "*Mark used for articles with a low score."
491   :group 'gnus-summary-marks
492   :type 'character)
493
494 (defcustom gnus-catchup-mark ?C
495   "*Mark used for articles that are caught up."
496   :group 'gnus-summary-marks
497   :type 'character)
498
499 (defcustom gnus-replied-mark ?A
500   "*Mark used for articles that have been replied to."
501   :group 'gnus-summary-marks
502   :type 'character)
503
504 (defcustom gnus-forwarded-mark ?F
505   "*Mark used for articles that have been forwarded."
506   :version "21.4"
507   :group 'gnus-summary-marks
508   :type 'character)
509
510 (defcustom gnus-recent-mark ?N
511   "*Mark used for articles that are recent."
512   :group 'gnus-summary-marks
513   :type 'character)
514
515 (defcustom gnus-cached-mark ?*
516   "*Mark used for articles that are in the cache."
517   :group 'gnus-summary-marks
518   :type 'character)
519
520 (defcustom gnus-saved-mark ?S
521   "*Mark used for articles that have been saved."
522   :group 'gnus-summary-marks
523   :type 'character)
524
525 (defcustom gnus-unseen-mark ?.
526   "*Mark used for articles that haven't been seen."
527   :version "21.4"
528   :group 'gnus-summary-marks
529   :type 'character)
530
531 (defcustom gnus-no-mark ?               ;Whitespace
532   "*Mark used for articles that have no other secondary mark."
533   :version "21.4"
534   :group 'gnus-summary-marks
535   :type 'character)
536
537 (defcustom gnus-ancient-mark ?O
538   "*Mark used for ancient articles."
539   :group 'gnus-summary-marks
540   :type 'character)
541
542 (defcustom gnus-sparse-mark ?Q
543   "*Mark used for sparsely reffed articles."
544   :group 'gnus-summary-marks
545   :type 'character)
546
547 (defcustom gnus-canceled-mark ?G
548   "*Mark used for canceled articles."
549   :group 'gnus-summary-marks
550   :type 'character)
551
552 (defcustom gnus-duplicate-mark ?M
553   "*Mark used for duplicate articles."
554   :group 'gnus-summary-marks
555   :type 'character)
556
557 (defcustom gnus-undownloaded-mark ?-
558   "*Mark used for articles that weren't downloaded."
559   :group 'gnus-summary-marks
560   :type 'character)
561
562 (defcustom gnus-downloaded-mark ?+
563   "*Mark used for articles that were downloaded."
564   :group 'gnus-summary-marks
565   :type 'character)
566
567 (defcustom gnus-downloadable-mark ?%
568   "*Mark used for articles that are to be downloaded."
569   :group 'gnus-summary-marks
570   :type 'character)
571
572 (defcustom gnus-unsendable-mark ?=
573   "*Mark used for articles that won't be sent."
574   :group 'gnus-summary-marks
575   :type 'character)
576
577 (defcustom gnus-score-over-mark ?+
578   "*Score mark used for articles with high scores."
579   :group 'gnus-summary-marks
580   :type 'character)
581
582 (defcustom gnus-score-below-mark ?-
583   "*Score mark used for articles with low scores."
584   :group 'gnus-summary-marks
585   :type 'character)
586
587 (defcustom gnus-empty-thread-mark ?     ;Whitespace
588   "*There is no thread under the article."
589   :group 'gnus-summary-marks
590   :type 'character)
591
592 (defcustom gnus-not-empty-thread-mark ?=
593   "*There is a thread under the article."
594   :group 'gnus-summary-marks
595   :type 'character)
596
597 (defcustom gnus-view-pseudo-asynchronously nil
598   "*If non-nil, Gnus will view pseudo-articles asynchronously."
599   :group 'gnus-extract-view
600   :type 'boolean)
601
602 (defcustom gnus-auto-expirable-marks
603   (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
604         gnus-low-score-mark gnus-ancient-mark gnus-read-mark
605         gnus-souped-mark gnus-duplicate-mark)
606   "*The list of marks converted into expiration if a group is auto-expirable."
607   :version "21.1"
608   :group 'gnus-summary
609   :type '(repeat character))
610
611 (defcustom gnus-inhibit-user-auto-expire t
612   "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
613   :version "21.1"
614   :group 'gnus-summary
615   :type 'boolean)
616
617 (defcustom gnus-view-pseudos nil
618   "*If `automatic', pseudo-articles will be viewed automatically.
619 If `not-confirm', pseudos will be viewed automatically, and the user
620 will not be asked to confirm the command."
621   :group 'gnus-extract-view
622   :type '(choice (const :tag "off" nil)
623                  (const automatic)
624                  (const not-confirm)))
625
626 (defcustom gnus-view-pseudos-separately t
627   "*If non-nil, one pseudo-article will be created for each file to be viewed.
628 If nil, all files that use the same viewing command will be given as a
629 list of parameters to that command."
630   :group 'gnus-extract-view
631   :type 'boolean)
632
633 (defcustom gnus-insert-pseudo-articles t
634   "*If non-nil, insert pseudo-articles when decoding articles."
635   :group 'gnus-extract-view
636   :type 'boolean)
637
638 (defcustom gnus-summary-dummy-line-format
639   "   %(:                             :%) %S\n"
640   "*The format specification for the dummy roots in the summary buffer.
641 It works along the same lines as a normal formatting string,
642 with some simple extensions.
643
644 %S  The subject
645
646 General format specifiers can also be used.
647 See `(gnus)Formatting Variables'."
648   :link '(custom-manual "(gnus)Formatting Variables")
649   :group 'gnus-threading
650   :type 'string)
651
652 (defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
653   "*The format specification for the summary mode line.
654 It works along the same lines as a normal formatting string,
655 with some simple extensions:
656
657 %G  Group name
658 %p  Unprefixed group name
659 %A  Current article number
660 %z  Current article score
661 %V  Gnus version
662 %U  Number of unread articles in the group
663 %e  Number of unselected articles in the group
664 %Z  A string with unread/unselected article counts
665 %g  Shortish group name
666 %S  Subject of the current article
667 %u  User-defined spec
668 %s  Current score file name
669 %d  Number of dormant articles
670 %r  Number of articles that have been marked as read in this session
671 %E  Number of articles expunged by the score files"
672   :group 'gnus-summary-format
673   :type 'string)
674
675 (defcustom gnus-list-identifiers nil
676   "Regexp that matches list identifiers to be removed from subject.
677 This can also be a list of regexps."
678   :version "21.1"
679   :group 'gnus-summary-format
680   :group 'gnus-article-hiding
681   :type '(choice (const :tag "none" nil)
682                  (regexp :value ".*")
683                  (repeat :value (".*") regexp)))
684
685 (defcustom gnus-summary-mark-below 0
686   "*Mark all articles with a score below this variable as read.
687 This variable is local to each summary buffer and usually set by the
688 score file."
689   :group 'gnus-score-default
690   :type 'integer)
691
692 (defun gnus-widget-reversible-match (widget value)
693   "Ignoring WIDGET, convert VALUE to internal form.
694 VALUE should have the form `FOO' or `(not FOO)', where FOO is an symbol."
695   ;; (debug value)
696   (or (symbolp value)
697       (and (listp value)
698            (eq (length value) 2)
699            (eq (nth 0 value) 'not)
700            (symbolp (nth 1 value)))))
701
702 (defun gnus-widget-reversible-to-internal (widget value)
703   "Ignoring WIDGET, convert VALUE to internal form.
704 VALUE should have the form `FOO' or `(not FOO)', where FOO is an atom.
705 FOO is converted to (FOO nil) and (not FOO) is converted to (FOO t)."
706   ;; (debug value)
707   (if (atom value)
708       (list value nil)
709     (list (nth 1 value) t)))
710
711 (defun gnus-widget-reversible-to-external (widget value)
712   "Ignoring WIDGET, convert VALUE to external form.
713 VALUE should have the form `(FOO nil)' or `(FOO t)', where FOO is an atom.
714 \(FOO  nil) is converted to FOO and (FOO t) is converted to (not FOO)."
715   ;; (debug value)
716   (if (nth 1 value)
717       (list 'not (nth 0 value))
718     (nth 0 value)))
719
720 (define-widget 'gnus-widget-reversible 'group
721   "A `group' that convert values."
722   :match 'gnus-widget-reversible-match
723   :value-to-internal 'gnus-widget-reversible-to-internal
724   :value-to-external 'gnus-widget-reversible-to-external)
725
726 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
727   "*List of functions used for sorting articles in the summary buffer.
728
729 Each function takes two articles and returns non-nil if the first
730 article should be sorted before the other.  If you use more than one
731 function, the primary sort function should be the last.  You should
732 probably always include `gnus-article-sort-by-number' in the list of
733 sorting functions -- preferably first.  Also note that sorting by date
734 is often much slower than sorting by number, and the sorting order is
735 very similar.  (Sorting by date means sorting by the time the message
736 was sent, sorting by number means sorting by arrival time.)
737
738 Each item can also be a list `(not F)' where F is a function;
739 this reverses the sort order.
740
741 Ready-made functions include `gnus-article-sort-by-number',
742 `gnus-article-sort-by-author', `gnus-article-sort-by-subject',
743 `gnus-article-sort-by-date', `gnus-article-sort-by-random'
744 and `gnus-article-sort-by-score'.
745
746 When threading is turned on, the variable `gnus-thread-sort-functions'
747 controls how articles are sorted."
748   :group 'gnus-summary-sort
749   :type '(repeat (gnus-widget-reversible
750                   (choice (function-item gnus-article-sort-by-number)
751                           (function-item gnus-article-sort-by-author)
752                           (function-item gnus-article-sort-by-subject)
753                           (function-item gnus-article-sort-by-date)
754                           (function-item gnus-article-sort-by-score)
755                           (function-item gnus-article-sort-by-random)
756                           (function :tag "other"))
757                   (boolean :tag "Reverse order"))))
758
759
760 (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
761   "*List of functions used for sorting threads in the summary buffer.
762 By default, threads are sorted by article number.
763
764 Each function takes two threads and returns non-nil if the first
765 thread should be sorted before the other.  If you use more than one
766 function, the primary sort function should be the last.  You should
767 probably always include `gnus-thread-sort-by-number' in the list of
768 sorting functions -- preferably first.  Also note that sorting by date
769 is often much slower than sorting by number, and the sorting order is
770 very similar.  (Sorting by date means sorting by the time the message
771 was sent, sorting by number means sorting by arrival time.)
772
773 Each list item can also be a list `(not F)' where F is a
774 function; this specifies reversed sort order.
775
776 Ready-made functions include `gnus-thread-sort-by-number',
777 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
778 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score',
779 `gnus-thread-sort-by-most-recent-number',
780 `gnus-thread-sort-by-most-recent-date',
781 `gnus-thread-sort-by-random', and
782 `gnus-thread-sort-by-total-score' (see `gnus-thread-score-function').
783
784 When threading is turned off, the variable
785 `gnus-article-sort-functions' controls how articles are sorted."
786   :group 'gnus-summary-sort
787   :type '(repeat 
788           (gnus-widget-reversible
789            (choice (function-item gnus-thread-sort-by-number)
790                    (function-item gnus-thread-sort-by-author)
791                    (function-item gnus-thread-sort-by-subject)
792                    (function-item gnus-thread-sort-by-date)
793                    (function-item gnus-thread-sort-by-score)
794                    (function-item gnus-thread-sort-by-most-recent-number)
795                    (function-item gnus-thread-sort-by-most-recent-date)
796                    (function-item gnus-thread-sort-by-random)
797                    (function-item gnus-thread-sort-by-total-score)
798                    (function :tag "other"))
799            (boolean :tag "Reverse order"))))
800
801 (defcustom gnus-thread-score-function '+
802   "*Function used for calculating the total score of a thread.
803
804 The function is called with the scores of the article and each
805 subthread and should then return the score of the thread.
806
807 Some functions you can use are `+', `max', or `min'."
808   :group 'gnus-summary-sort
809   :type 'function)
810
811 (defcustom gnus-summary-expunge-below nil
812   "All articles that have a score less than this variable will be expunged.
813 This variable is local to the summary buffers."
814   :group 'gnus-score-default
815   :type '(choice (const :tag "off" nil)
816                  integer))
817
818 (defcustom gnus-thread-expunge-below nil
819   "All threads that have a total score less than this variable will be expunged.
820 See `gnus-thread-score-function' for en explanation of what a
821 \"thread score\" is.
822
823 This variable is local to the summary buffers."
824   :group 'gnus-threading
825   :group 'gnus-score-default
826   :type '(choice (const :tag "off" nil)
827                  integer))
828
829 (defcustom gnus-summary-mode-hook nil
830   "*A hook for Gnus summary mode.
831 This hook is run before any variables are set in the summary buffer."
832   :options '(turn-on-gnus-mailing-list-mode gnus-pick-mode)
833   :group 'gnus-summary-various
834   :type 'hook)
835
836 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
837 (when (featurep 'xemacs)
838   (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
839   (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
840   (add-hook 'gnus-summary-mode-hook
841             'gnus-xmas-switch-horizontal-scrollbar-off))
842
843 (defcustom gnus-summary-menu-hook nil
844   "*Hook run after the creation of the summary mode menu."
845   :group 'gnus-summary-visual
846   :type 'hook)
847
848 (defcustom gnus-summary-exit-hook nil
849   "*A hook called on exit from the summary buffer.
850 It will be called with point in the group buffer."
851   :group 'gnus-summary-exit
852   :type 'hook)
853
854 (defcustom gnus-summary-prepare-hook nil
855   "*A hook called after the summary buffer has been generated.
856 If you want to modify the summary buffer, you can use this hook."
857   :group 'gnus-summary-various
858   :type 'hook)
859
860 (defcustom gnus-summary-prepared-hook nil
861   "*A hook called as the last thing after the summary buffer has been generated."
862   :group 'gnus-summary-various
863   :type 'hook)
864
865 (defcustom gnus-summary-generate-hook nil
866   "*A hook run just before generating the summary buffer.
867 This hook is commonly used to customize threading variables and the
868 like."
869   :group 'gnus-summary-various
870   :type 'hook)
871
872 (defcustom gnus-select-group-hook nil
873   "*A hook called when a newsgroup is selected.
874
875 If you'd like to simplify subjects like the
876 `gnus-summary-next-same-subject' command does, you can use the
877 following hook:
878
879  (add-hook gnus-select-group-hook
880            (lambda ()
881              (mapcar (lambda (header)
882                        (mail-header-set-subject
883                         header
884                         (gnus-simplify-subject
885                          (mail-header-subject header) 're-only)))
886                      gnus-newsgroup-headers)))"
887   :group 'gnus-group-select
888   :type 'hook)
889
890 (defcustom gnus-select-article-hook nil
891   "*A hook called when an article is selected."
892   :group 'gnus-summary-choose
893   :options '(gnus-agent-fetch-selected-article)
894   :type 'hook)
895
896 (defcustom gnus-visual-mark-article-hook
897   (list 'gnus-highlight-selected-summary)
898   "*Hook run after selecting an article in the summary buffer.
899 It is meant to be used for highlighting the article in some way.  It
900 is not run if `gnus-visual' is nil."
901   :group 'gnus-summary-visual
902   :type 'hook)
903
904 (defcustom gnus-parse-headers-hook nil
905   "*A hook called before parsing the headers."
906   :group 'gnus-various
907   :type 'hook)
908
909 (defcustom gnus-exit-group-hook nil
910   "*A hook called when exiting summary mode.
911 This hook is not called from the non-updating exit commands like `Q'."
912   :group 'gnus-various
913   :type 'hook)
914
915 (defcustom gnus-summary-update-hook
916   (list 'gnus-summary-highlight-line)
917   "*A hook called when a summary line is changed.
918 The hook will not be called if `gnus-visual' is nil.
919
920 The default function `gnus-summary-highlight-line' will
921 highlight the line according to the `gnus-summary-highlight'
922 variable."
923   :group 'gnus-summary-visual
924   :type 'hook)
925
926 (defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
927   "*A hook called when an article is selected for the first time.
928 The hook is intended to mark an article as read (or unread)
929 automatically when it is selected."
930   :group 'gnus-summary-choose
931   :type 'hook)
932
933 (defcustom gnus-group-no-more-groups-hook nil
934   "*A hook run when returning to group mode having no more (unread) groups."
935   :group 'gnus-group-select
936   :type 'hook)
937
938 (defcustom gnus-ps-print-hook nil
939   "*A hook run before ps-printing something from Gnus."
940   :group 'gnus-summary
941   :type 'hook)
942
943 (defcustom gnus-summary-article-move-hook nil
944   "*A hook called after an article is moved, copied, respooled, or crossposted."
945   :group 'gnus-summary
946   :type 'hook)
947
948 (defcustom gnus-summary-article-delete-hook nil
949   "*A hook called after an article is deleted."
950   :group 'gnus-summary
951   :type 'hook)
952
953 (defcustom gnus-summary-article-expire-hook nil
954   "*A hook called after an article is expired."
955   :group 'gnus-summary
956   :type 'hook)
957
958 (defcustom gnus-summary-display-arrow
959   (and (fboundp 'display-graphic-p)
960        (display-graphic-p))
961   "*If non-nil, display an arrow highlighting the current article."
962   :version "21.4"
963   :group 'gnus-summary
964   :type 'boolean)
965
966 (defcustom gnus-summary-selected-face 'gnus-summary-selected-face
967   "Face used for highlighting the current article in the summary buffer."
968   :group 'gnus-summary-visual
969   :type 'face)
970
971 (defvar gnus-tmp-downloaded nil)
972
973 (defcustom gnus-summary-highlight
974   '(((eq mark gnus-canceled-mark)
975      . gnus-summary-cancelled-face)
976     ((and uncached (> score default-high))
977      . gnus-summary-high-undownloaded-face)
978     ((and uncached (< score default-low))
979      . gnus-summary-low-undownloaded-face)
980     (uncached
981      . gnus-summary-normal-undownloaded-face)
982     ((and (> score default-high)
983           (or (eq mark gnus-dormant-mark)
984               (eq mark gnus-ticked-mark)))
985      . gnus-summary-high-ticked-face)
986     ((and (< score default-low)
987           (or (eq mark gnus-dormant-mark)
988               (eq mark gnus-ticked-mark)))
989      . gnus-summary-low-ticked-face)
990     ((or (eq mark gnus-dormant-mark)
991          (eq mark gnus-ticked-mark))
992      . gnus-summary-normal-ticked-face)
993     ((and (> score default-high) (eq mark gnus-ancient-mark))
994      . gnus-summary-high-ancient-face)
995     ((and (< score default-low) (eq mark gnus-ancient-mark))
996      . gnus-summary-low-ancient-face)
997     ((eq mark gnus-ancient-mark)
998      . gnus-summary-normal-ancient-face)
999     ((and (> score default-high) (eq mark gnus-unread-mark))
1000      . gnus-summary-high-unread-face)
1001     ((and (< score default-low) (eq mark gnus-unread-mark))
1002      . gnus-summary-low-unread-face)
1003     ((eq mark gnus-unread-mark)
1004      . gnus-summary-normal-unread-face)
1005     ((> score default-high)
1006      . gnus-summary-high-read-face)
1007     ((< score default-low)
1008      . gnus-summary-low-read-face)
1009     (t
1010      . gnus-summary-normal-read-face))
1011   "*Controls the highlighting of summary buffer lines.
1012
1013 A list of (FORM . FACE) pairs.  When deciding how a a particular
1014 summary line should be displayed, each form is evaluated.  The content
1015 of the face field after the first true form is used.  You can change
1016 how those summary lines are displayed, by editing the face field.
1017
1018 You can use the following variables in the FORM field.
1019
1020 score:        The article's score
1021 default:      The default article score.
1022 default-high: The default score for high scored articles.
1023 default-low:  The default score for low scored articles.
1024 below:        The score below which articles are automatically marked as read.
1025 mark:         The article's mark.
1026 uncached:     Non-nil if the article is uncached."
1027   :group 'gnus-summary-visual
1028   :type '(repeat (cons (sexp :tag "Form" nil)
1029                        face)))
1030
1031 (defcustom gnus-alter-header-function nil
1032   "Function called to allow alteration of article header structures.
1033 The function is called with one parameter, the article header vector,
1034 which it may alter in any way."
1035   :type '(choice (const :tag "None" nil)
1036                  function)
1037   :group 'gnus-summary)
1038
1039 (defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
1040   "Variable that says which function should be used to decode a string with encoded words.")
1041
1042 (defcustom gnus-extra-headers '(To Newsgroups)
1043   "*Extra headers to parse."
1044   :version "21.1"
1045   :group 'gnus-summary
1046   :type '(repeat symbol))
1047
1048 (defcustom gnus-ignored-from-addresses
1049   (and user-mail-address (regexp-quote user-mail-address))
1050   "*Regexp of From headers that may be suppressed in favor of To headers."
1051   :version "21.1"
1052   :group 'gnus-summary
1053   :type 'regexp)
1054
1055 (defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
1056   "List of charsets that should be ignored.
1057 When these charsets are used in the \"charset\" parameter, the
1058 default charset will be used instead."
1059   :version "21.1"
1060   :type '(repeat symbol)
1061   :group 'gnus-charset)
1062
1063 (gnus-define-group-parameter
1064  ignored-charsets
1065  :type list
1066  :function-document
1067  "Return the ignored charsets of GROUP."
1068  :variable gnus-group-ignored-charsets-alist
1069  :variable-default
1070  '(("alt\\.chinese\\.text" iso-8859-1))
1071  :variable-document
1072  "Alist of regexps (to match group names) and charsets that should be ignored.
1073 When these charsets are used in the \"charset\" parameter, the
1074 default charset will be used instead."
1075  :variable-group gnus-charset
1076  :variable-type '(repeat (cons (regexp :tag "Group")
1077                                (repeat symbol)))
1078  :parameter-type '(choice :tag "Ignored charsets"
1079                           :value nil
1080                           (repeat (symbol)))
1081  :parameter-document       "\
1082 List of charsets that should be ignored.
1083
1084 When these charsets are used in the \"charset\" parameter, the
1085 default charset will be used instead.")
1086
1087 (defcustom gnus-group-highlight-words-alist nil
1088   "Alist of group regexps and highlight regexps.
1089 This variable uses the same syntax as `gnus-emphasis-alist'."
1090   :version "21.1"
1091   :type '(repeat (cons (regexp :tag "Group")
1092                        (repeat (list (regexp :tag "Highlight regexp")
1093                                      (number :tag "Group for entire word" 0)
1094                                      (number :tag "Group for displayed part" 0)
1095                                      (symbol :tag "Face"
1096                                              gnus-emphasis-highlight-words)))))
1097   :group 'gnus-summary-visual)
1098
1099 (defcustom gnus-summary-show-article-charset-alist
1100   nil
1101   "Alist of number and charset.
1102 The article will be shown with the charset corresponding to the
1103 numbered argument.
1104 For example: ((1 . cn-gb-2312) (2 . big5))."
1105   :version "21.1"
1106   :type '(repeat (cons (number :tag "Argument" 1)
1107                        (symbol :tag "Charset")))
1108   :group 'gnus-charset)
1109
1110 (defcustom gnus-preserve-marks t
1111   "Whether marks are preserved when moving, copying and respooling messages."
1112   :version "21.1"
1113   :type 'boolean
1114   :group 'gnus-summary-marks)
1115
1116 (defcustom gnus-alter-articles-to-read-function nil
1117   "Function to be called to alter the list of articles to be selected."
1118   :type '(choice (const nil) function)
1119   :group 'gnus-summary)
1120
1121 (defcustom gnus-orphan-score nil
1122   "*All orphans get this score added.  Set in the score file."
1123   :group 'gnus-score-default
1124   :type '(choice (const nil)
1125                  integer))
1126
1127 (defcustom gnus-summary-save-parts-default-mime "image/.*"
1128   "*A regexp to match MIME parts when saving multiple parts of a
1129 message with `gnus-summary-save-parts' (\\<gnus-summary-mode-map>\\[gnus-summary-save-parts]).
1130 This regexp will be used by default when prompting the user for which
1131 type of files to save."
1132   :group 'gnus-summary
1133   :type 'regexp)
1134
1135 (defcustom gnus-read-all-available-headers nil
1136   "Whether Gnus should parse all headers made available to it.
1137 This is mostly relevant for slow back ends where the user may
1138 wish to widen the summary buffer to include all headers
1139 that were fetched.  Say, for nnultimate groups."
1140   :version "21.4"
1141   :group 'gnus-summary
1142   :type '(choice boolean regexp))
1143
1144 (defcustom gnus-summary-muttprint-program "muttprint"
1145   "Command (and optional arguments) used to run Muttprint."
1146   :version "21.4"
1147   :group 'gnus-summary
1148   :type 'string)
1149
1150 (defcustom gnus-article-loose-mime t
1151   "If non-nil, don't require MIME-Version header.
1152 Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
1153 supply the MIME-Version header or deliberately strip it from the mail.
1154 If non-nil (the default), Gnus will treat some articles as MIME
1155 even if the MIME-Version header is missing."
1156   :version "21.4"
1157   :type 'boolean
1158   :group 'gnus-article-mime)
1159
1160 (defcustom gnus-article-emulate-mime t
1161   "If non-nil, use MIME emulation for uuencode and the like.
1162 This means that Gnus will search message bodies for text that look
1163 like uuencoded bits, yEncoded bits, and so on, and present that using
1164 the normal Gnus MIME machinery."
1165   :version "21.4"
1166   :type 'boolean
1167   :group 'gnus-article-mime)
1168
1169 ;;; Internal variables
1170
1171 (defvar gnus-summary-display-cache nil)
1172 (defvar gnus-article-mime-handles nil)
1173 (defvar gnus-article-decoded-p nil)
1174 (defvar gnus-article-charset nil)
1175 (defvar gnus-article-ignored-charsets nil)
1176 (defvar gnus-scores-exclude-files nil)
1177 (defvar gnus-page-broken nil)
1178
1179 (defvar gnus-original-article nil)
1180 (defvar gnus-article-internal-prepare-hook nil)
1181 (defvar gnus-newsgroup-process-stack nil)
1182
1183 (defvar gnus-thread-indent-array nil)
1184 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
1185 (defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
1186   "Function called to sort the articles within a thread after it has been gathered together.")
1187
1188 (defvar gnus-summary-save-parts-type-history nil)
1189 (defvar gnus-summary-save-parts-last-directory mm-default-directory)
1190
1191 ;; Avoid highlighting in kill files.
1192 (defvar gnus-summary-inhibit-highlight nil)
1193 (defvar gnus-newsgroup-selected-overlay nil)
1194 (defvar gnus-inhibit-limiting nil)
1195 (defvar gnus-newsgroup-adaptive-score-file nil)
1196 (defvar gnus-current-score-file nil)
1197 (defvar gnus-current-move-group nil)
1198 (defvar gnus-current-copy-group nil)
1199 (defvar gnus-current-crosspost-group nil)
1200 (defvar gnus-newsgroup-display nil)
1201
1202 (defvar gnus-newsgroup-dependencies nil)
1203 (defvar gnus-newsgroup-adaptive nil)
1204 (defvar gnus-summary-display-article-function nil)
1205 (defvar gnus-summary-highlight-line-function nil
1206   "Function called after highlighting a summary line.")
1207
1208 (defvar gnus-summary-line-format-alist
1209   `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
1210     (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
1211     (?s gnus-tmp-subject-or-nil ?s)
1212     (?n gnus-tmp-name ?s)
1213     (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
1214         ?s)
1215     (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
1216             gnus-tmp-from) ?s)
1217     (?F gnus-tmp-from ?s)
1218     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
1219     (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
1220     (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
1221     (?o (gnus-date-iso8601 (mail-header-date gnus-tmp-header)) ?s)
1222     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
1223     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
1224     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
1225     (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
1226     (?L gnus-tmp-lines ?s)
1227     (?O gnus-tmp-downloaded ?c)
1228     (?I gnus-tmp-indentation ?s)
1229     (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
1230     (?R gnus-tmp-replied ?c)
1231     (?\[ gnus-tmp-opening-bracket ?c)
1232     (?\] gnus-tmp-closing-bracket ?c)
1233     (?\> (make-string gnus-tmp-level ? ) ?s)
1234     (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
1235     (?i gnus-tmp-score ?d)
1236     (?z gnus-tmp-score-char ?c)
1237     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
1238     (?U gnus-tmp-unread ?c)
1239     (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header gnus-tmp-from)
1240         ?s)
1241     (?t (gnus-summary-number-of-articles-in-thread
1242          (and (boundp 'thread) (car thread)) gnus-tmp-level)
1243         ?d)
1244     (?e (gnus-summary-number-of-articles-in-thread
1245          (and (boundp 'thread) (car thread)) gnus-tmp-level t)
1246         ?c)
1247     (?u gnus-tmp-user-defined ?s)
1248     (?P (gnus-pick-line-number) ?d)
1249     (?B gnus-tmp-thread-tree-header-string ?s)
1250     (user-date (gnus-user-date
1251                 ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
1252   "An alist of format specifications that can appear in summary lines.
1253 These are paired with what variables they correspond with, along with
1254 the type of the variable (string, integer, character, etc).")
1255
1256 (defvar gnus-summary-dummy-line-format-alist
1257   `((?S gnus-tmp-subject ?s)
1258     (?N gnus-tmp-number ?d)
1259     (?u gnus-tmp-user-defined ?s)))
1260
1261 (defvar gnus-summary-mode-line-format-alist
1262   `((?G gnus-tmp-group-name ?s)
1263     (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
1264     (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
1265     (?A gnus-tmp-article-number ?d)
1266     (?Z gnus-tmp-unread-and-unselected ?s)
1267     (?V gnus-version ?s)
1268     (?U gnus-tmp-unread-and-unticked ?d)
1269     (?S gnus-tmp-subject ?s)
1270     (?e gnus-tmp-unselected ?d)
1271     (?u gnus-tmp-user-defined ?s)
1272     (?d (length gnus-newsgroup-dormant) ?d)
1273     (?t (length gnus-newsgroup-marked) ?d)
1274     (?h (length gnus-newsgroup-spam-marked) ?d)
1275     (?r (length gnus-newsgroup-reads) ?d)
1276     (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
1277     (?E gnus-newsgroup-expunged-tally ?d)
1278     (?s (gnus-current-score-file-nondirectory) ?s)))
1279
1280 (defvar gnus-last-search-regexp nil
1281   "Default regexp for article search command.")
1282
1283 (defvar gnus-last-shell-command nil
1284   "Default shell command on article.")
1285
1286 (defvar gnus-newsgroup-agentized nil
1287   "Locally bound in each summary buffer to indicate whether the server has been agentized.")
1288 (defvar gnus-newsgroup-begin nil)
1289 (defvar gnus-newsgroup-end nil)
1290 (defvar gnus-newsgroup-last-rmail nil)
1291 (defvar gnus-newsgroup-last-mail nil)
1292 (defvar gnus-newsgroup-last-folder nil)
1293 (defvar gnus-newsgroup-last-file nil)
1294 (defvar gnus-newsgroup-auto-expire nil)
1295 (defvar gnus-newsgroup-active nil)
1296
1297 (defvar gnus-newsgroup-data nil)
1298 (defvar gnus-newsgroup-data-reverse nil)
1299 (defvar gnus-newsgroup-limit nil)
1300 (defvar gnus-newsgroup-limits nil)
1301 (defvar gnus-summary-use-undownloaded-faces nil)
1302
1303 (defvar gnus-newsgroup-unreads nil
1304   "Sorted list of unread articles in the current newsgroup.")
1305
1306 (defvar gnus-newsgroup-unselected nil
1307   "Sorted list of unselected unread articles in the current newsgroup.")
1308
1309 (defvar gnus-newsgroup-reads nil
1310   "Alist of read articles and article marks in the current newsgroup.")
1311
1312 (defvar gnus-newsgroup-expunged-tally nil)
1313
1314 (defvar gnus-newsgroup-marked nil
1315   "Sorted list of ticked articles in the current newsgroup (a subset of unread art).")
1316
1317 (defvar gnus-newsgroup-spam-marked nil
1318   "List of ranges of articles that have been marked as spam.")
1319
1320 (defvar gnus-newsgroup-killed nil
1321   "List of ranges of articles that have been through the scoring process.")
1322
1323 (defvar gnus-newsgroup-cached nil
1324   "Sorted list of articles that come from the article cache.")
1325
1326 (defvar gnus-newsgroup-saved nil
1327   "List of articles that have been saved.")
1328
1329 (defvar gnus-newsgroup-kill-headers nil)
1330
1331 (defvar gnus-newsgroup-replied nil
1332   "List of articles that have been replied to in the current newsgroup.")
1333
1334 (defvar gnus-newsgroup-forwarded nil
1335   "List of articles that have been forwarded in the current newsgroup.")
1336
1337 (defvar gnus-newsgroup-recent nil
1338   "List of articles that have are recent in the current newsgroup.")
1339
1340 (defvar gnus-newsgroup-expirable nil
1341   "Sorted list of articles in the current newsgroup that can be expired.")
1342
1343 (defvar gnus-newsgroup-processable nil
1344   "List of articles in the current newsgroup that can be processed.")
1345
1346 (defvar gnus-newsgroup-downloadable nil
1347   "Sorted list of articles in the current newsgroup that can be processed.")
1348
1349 (defvar gnus-newsgroup-unfetched nil
1350   "Sorted list of articles in the current newsgroup whose headers have
1351 not been fetched into the agent.
1352
1353 This list will always be a subset of gnus-newsgroup-undownloaded.")
1354
1355 (defvar gnus-newsgroup-undownloaded nil
1356   "List of articles in the current newsgroup that haven't been downloaded.")
1357
1358 (defvar gnus-newsgroup-unsendable nil
1359   "List of articles in the current newsgroup that won't be sent.")
1360
1361 (defvar gnus-newsgroup-bookmarks nil
1362   "List of articles in the current newsgroup that have bookmarks.")
1363
1364 (defvar gnus-newsgroup-dormant nil
1365   "Sorted list of dormant articles in the current newsgroup.")
1366
1367 (defvar gnus-newsgroup-unseen nil
1368   "List of unseen articles in the current newsgroup.")
1369
1370 (defvar gnus-newsgroup-seen nil
1371   "Range of seen articles in the current newsgroup.")
1372
1373 (defvar gnus-newsgroup-articles nil
1374   "List of articles in the current newsgroup.")
1375
1376 (defvar gnus-newsgroup-scored nil
1377   "List of scored articles in the current newsgroup.")
1378
1379 (defvar gnus-newsgroup-headers nil
1380   "List of article headers in the current newsgroup.")
1381
1382 (defvar gnus-newsgroup-threads nil)
1383
1384 (defvar gnus-newsgroup-prepared nil
1385   "Whether the current group has been prepared properly.")
1386
1387 (defvar gnus-newsgroup-ancient nil
1388   "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
1389
1390 (defvar gnus-newsgroup-sparse nil)
1391
1392 (defvar gnus-current-article nil)
1393 (defvar gnus-article-current nil)
1394 (defvar gnus-current-headers nil)
1395 (defvar gnus-have-all-headers nil)
1396 (defvar gnus-last-article nil)
1397 (defvar gnus-newsgroup-history nil)
1398 (defvar gnus-newsgroup-charset nil)
1399 (defvar gnus-newsgroup-ephemeral-charset nil)
1400 (defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
1401
1402 (defvar gnus-article-before-search nil)
1403
1404 (defvar gnus-summary-local-variables
1405   '(gnus-newsgroup-name
1406     gnus-newsgroup-begin gnus-newsgroup-end
1407     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
1408     gnus-newsgroup-last-folder gnus-newsgroup-last-file
1409     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
1410     gnus-newsgroup-unselected gnus-newsgroup-marked
1411     gnus-newsgroup-spam-marked
1412     gnus-newsgroup-reads gnus-newsgroup-saved
1413     gnus-newsgroup-replied gnus-newsgroup-forwarded
1414     gnus-newsgroup-recent
1415     gnus-newsgroup-expirable
1416     gnus-newsgroup-processable gnus-newsgroup-killed
1417     gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
1418     gnus-newsgroup-unfetched
1419     gnus-newsgroup-unsendable gnus-newsgroup-unseen
1420     gnus-newsgroup-seen gnus-newsgroup-articles
1421     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
1422     gnus-newsgroup-headers gnus-newsgroup-threads
1423     gnus-newsgroup-prepared gnus-summary-highlight-line-function
1424     gnus-current-article gnus-current-headers gnus-have-all-headers
1425     gnus-last-article gnus-article-internal-prepare-hook
1426     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1427     gnus-newsgroup-scored gnus-newsgroup-kill-headers
1428     gnus-thread-expunge-below
1429     gnus-score-alist gnus-current-score-file
1430     (gnus-summary-expunge-below . global)
1431     (gnus-summary-mark-below . global)
1432     (gnus-orphan-score . global)
1433     gnus-newsgroup-active gnus-scores-exclude-files
1434     gnus-newsgroup-history gnus-newsgroup-ancient
1435     gnus-newsgroup-sparse gnus-newsgroup-process-stack
1436     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
1437     gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
1438     (gnus-newsgroup-expunged-tally . 0)
1439     gnus-cache-removable-articles gnus-newsgroup-cached
1440     gnus-newsgroup-data gnus-newsgroup-data-reverse
1441     gnus-newsgroup-limit gnus-newsgroup-limits
1442     gnus-newsgroup-charset gnus-newsgroup-display
1443     gnus-summary-use-undownloaded-faces)
1444   "Variables that are buffer-local to the summary buffers.")
1445
1446 (defvar gnus-newsgroup-variables nil
1447   "A list of variables that have separate values in different newsgroups.
1448 A list of newsgroup (summary buffer) local variables, or cons of
1449 variables and their default expressions to be evalled (when the default
1450 values are not nil), that should be made global while the summary buffer
1451 is active.
1452
1453 Note: The default expressions will be evaluated (using function `eval')
1454 before assignment to the local variable rather than just assigned to it.
1455 If the default expression is the symbol `global', that symbol will not
1456 be evaluated but the global value of the local variable will be used
1457 instead.
1458
1459 These variables can be used to set variables in the group parameters
1460 while still allowing them to affect operations done in other buffers.
1461 For example:
1462
1463 \(setq gnus-newsgroup-variables
1464      '(message-use-followup-to
1465        (gnus-visible-headers .
1466          \"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
1467 ")
1468
1469 ;; Byte-compiler warning.
1470 (eval-when-compile
1471   ;; Bind features so that require will believe that gnus-sum has
1472   ;; already been loaded (avoids infinite recursion)
1473   (let ((features (cons 'gnus-sum features)))
1474     ;; Several of the declarations in gnus-sum are needed to load the
1475     ;; following files. Right now, these definitions have been
1476     ;; compiled but not defined (evaluated).  We could either do a
1477     ;; eval-and-compile about all of the declarations or evaluate the
1478     ;; source file.
1479     (if (boundp 'gnus-newsgroup-variables)
1480         nil
1481       (load "gnus-sum.el" t t t))
1482     (require 'gnus)
1483     (require 'gnus-art)))
1484
1485 ;; MIME stuff.
1486
1487 (defvar gnus-decode-encoded-word-methods
1488   '(mail-decode-encoded-word-string)
1489   "List of methods used to decode encoded words.
1490
1491 This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
1492 is FUNCTION, FUNCTION will be apply to all newsgroups.  If item is a
1493 \(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
1494 whose names match REGEXP.
1495
1496 For example:
1497 \((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
1498  mail-decode-encoded-word-string
1499  (\"chinese\" . rfc1843-decode-string))")
1500
1501 (defvar gnus-decode-encoded-word-methods-cache nil)
1502
1503 (defun gnus-multi-decode-encoded-word-string (string)
1504   "Apply the functions from `gnus-encoded-word-methods' that match."
1505   (unless (and gnus-decode-encoded-word-methods-cache
1506                (eq gnus-newsgroup-name
1507                    (car gnus-decode-encoded-word-methods-cache)))
1508     (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
1509     (mapcar (lambda (x)
1510               (if (symbolp x)
1511                   (nconc gnus-decode-encoded-word-methods-cache (list x))
1512                 (if (and gnus-newsgroup-name
1513                          (string-match (car x) gnus-newsgroup-name))
1514                     (nconc gnus-decode-encoded-word-methods-cache
1515                            (list (cdr x))))))
1516             gnus-decode-encoded-word-methods))
1517   (let ((xlist gnus-decode-encoded-word-methods-cache))
1518     (pop xlist)
1519     (while xlist
1520       (setq string (funcall (pop xlist) string))))
1521   string)
1522
1523 ;; Subject simplification.
1524
1525 (defun gnus-simplify-whitespace (str)
1526   "Remove excessive whitespace from STR."
1527   ;; Multiple spaces.
1528   (while (string-match "[ \t][ \t]+" str)
1529     (setq str (concat (substring str 0 (match-beginning 0))
1530                         " "
1531                         (substring str (match-end 0)))))
1532   ;; Leading spaces.
1533   (when (string-match "^[ \t]+" str)
1534     (setq str (substring str (match-end 0))))
1535   ;; Trailing spaces.
1536   (when (string-match "[ \t]+$" str)
1537     (setq str (substring str 0 (match-beginning 0))))
1538   str)
1539
1540 (defun gnus-simplify-all-whitespace (str)
1541   "Remove all whitespace from STR."
1542   (while (string-match "[ \t\n]+" str)
1543     (setq str (replace-match "" nil nil str)))
1544   str)
1545
1546 (defsubst gnus-simplify-subject-re (subject)
1547   "Remove \"Re:\" from subject lines."
1548   (if (string-match message-subject-re-regexp subject)
1549       (substring subject (match-end 0))
1550     subject))
1551
1552 (defun gnus-simplify-subject (subject &optional re-only)
1553   "Remove `Re:' and words in parentheses.
1554 If RE-ONLY is non-nil, strip leading `Re:'s only."
1555   (let ((case-fold-search t))           ;Ignore case.
1556     ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
1557     (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
1558       (setq subject (substring subject (match-end 0))))
1559     ;; Remove uninteresting prefixes.
1560     (when (and (not re-only)
1561                gnus-simplify-ignored-prefixes
1562                (string-match gnus-simplify-ignored-prefixes subject))
1563       (setq subject (substring subject (match-end 0))))
1564     ;; Remove words in parentheses from end.
1565     (unless re-only
1566       (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
1567         (setq subject (substring subject 0 (match-beginning 0)))))
1568     ;; Return subject string.
1569     subject))
1570
1571 ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
1572 ;; all whitespace.
1573 (defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
1574   (goto-char (point-min))
1575   (while (re-search-forward regexp nil t)
1576     (replace-match (or newtext ""))))
1577
1578 (defun gnus-simplify-buffer-fuzzy ()
1579   "Simplify string in the buffer fuzzily.
1580 The string in the accessible portion of the current buffer is simplified.
1581 It is assumed to be a single-line subject.
1582 Whitespace is generally cleaned up, and miscellaneous leading/trailing
1583 matter is removed.  Additional things can be deleted by setting
1584 `gnus-simplify-subject-fuzzy-regexp'."
1585   (let ((case-fold-search t)
1586         (modified-tick))
1587     (gnus-simplify-buffer-fuzzy-step "\t" " ")
1588
1589     (while (not (eq modified-tick (buffer-modified-tick)))
1590       (setq modified-tick (buffer-modified-tick))
1591       (cond
1592        ((listp gnus-simplify-subject-fuzzy-regexp)
1593         (mapcar 'gnus-simplify-buffer-fuzzy-step
1594                 gnus-simplify-subject-fuzzy-regexp))
1595        (gnus-simplify-subject-fuzzy-regexp
1596         (gnus-simplify-buffer-fuzzy-step gnus-simplify-subject-fuzzy-regexp)))
1597       (gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
1598       (gnus-simplify-buffer-fuzzy-step
1599        "^ *\\(re\\|fw\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
1600       (gnus-simplify-buffer-fuzzy-step "^[[].*:\\( .*\\)[]]$" "\\1"))
1601
1602     (gnus-simplify-buffer-fuzzy-step " *[[{(][^()\n]*[]})] *$")
1603     (gnus-simplify-buffer-fuzzy-step "  +" " ")
1604     (gnus-simplify-buffer-fuzzy-step " $")
1605     (gnus-simplify-buffer-fuzzy-step "^ +")))
1606
1607 (defun gnus-simplify-subject-fuzzy (subject)
1608   "Simplify a subject string fuzzily.
1609 See `gnus-simplify-buffer-fuzzy' for details."
1610   (save-excursion
1611     (gnus-set-work-buffer)
1612     (let ((case-fold-search t))
1613       ;; Remove uninteresting prefixes.
1614       (when (and gnus-simplify-ignored-prefixes
1615                  (string-match gnus-simplify-ignored-prefixes subject))
1616         (setq subject (substring subject (match-end 0))))
1617       (insert subject)
1618       (inline (gnus-simplify-buffer-fuzzy))
1619       (buffer-string))))
1620
1621 (defsubst gnus-simplify-subject-fully (subject)
1622   "Simplify a subject string according to `gnus-summary-gather-subject-limit'."
1623   (cond
1624    (gnus-simplify-subject-functions
1625     (gnus-map-function gnus-simplify-subject-functions subject))
1626    ((null gnus-summary-gather-subject-limit)
1627     (gnus-simplify-subject-re subject))
1628    ((eq gnus-summary-gather-subject-limit 'fuzzy)
1629     (gnus-simplify-subject-fuzzy subject))
1630    ((numberp gnus-summary-gather-subject-limit)
1631     (gnus-limit-string (gnus-simplify-subject-re subject)
1632                        gnus-summary-gather-subject-limit))
1633    (t
1634     subject)))
1635
1636 (defsubst gnus-subject-equal (s1 s2 &optional simple-first)
1637   "Check whether two subjects are equal.
1638 If optional argument SIMPLE-FIRST is t, first argument is already
1639 simplified."
1640   (cond
1641    ((null simple-first)
1642     (equal (gnus-simplify-subject-fully s1)
1643            (gnus-simplify-subject-fully s2)))
1644    (t
1645     (equal s1
1646            (gnus-simplify-subject-fully s2)))))
1647
1648 (defun gnus-summary-bubble-group ()
1649   "Increase the score of the current group.
1650 This is a handy function to add to `gnus-summary-exit-hook' to
1651 increase the score of each group you read."
1652   (gnus-group-add-score gnus-newsgroup-name))
1653
1654 \f
1655 ;;;
1656 ;;; Gnus summary mode
1657 ;;;
1658
1659 (put 'gnus-summary-mode 'mode-class 'special)
1660
1661 (defvar gnus-article-commands-menu)
1662
1663 ;; Non-orthogonal keys
1664
1665 (gnus-define-keys gnus-summary-mode-map
1666   " " gnus-summary-next-page
1667   "\177" gnus-summary-prev-page
1668   [delete] gnus-summary-prev-page
1669   [backspace] gnus-summary-prev-page
1670   "\r" gnus-summary-scroll-up
1671   "\M-\r" gnus-summary-scroll-down
1672   "n" gnus-summary-next-unread-article
1673   "p" gnus-summary-prev-unread-article
1674   "N" gnus-summary-next-article
1675   "P" gnus-summary-prev-article
1676   "\M-\C-n" gnus-summary-next-same-subject
1677   "\M-\C-p" gnus-summary-prev-same-subject
1678   "\M-n" gnus-summary-next-unread-subject
1679   "\M-p" gnus-summary-prev-unread-subject
1680   "." gnus-summary-first-unread-article
1681   "," gnus-summary-best-unread-article
1682   "\M-s" gnus-summary-search-article-forward
1683   "\M-r" gnus-summary-search-article-backward
1684   "<" gnus-summary-beginning-of-article
1685   ">" gnus-summary-end-of-article
1686   "j" gnus-summary-goto-article
1687   "^" gnus-summary-refer-parent-article
1688   "\M-^" gnus-summary-refer-article
1689   "u" gnus-summary-tick-article-forward
1690   "!" gnus-summary-tick-article-forward
1691   "U" gnus-summary-tick-article-backward
1692   "d" gnus-summary-mark-as-read-forward
1693   "D" gnus-summary-mark-as-read-backward
1694   "E" gnus-summary-mark-as-expirable
1695   "\M-u" gnus-summary-clear-mark-forward
1696   "\M-U" gnus-summary-clear-mark-backward
1697   "k" gnus-summary-kill-same-subject-and-select
1698   "\C-k" gnus-summary-kill-same-subject
1699   "\M-\C-k" gnus-summary-kill-thread
1700   "\M-\C-l" gnus-summary-lower-thread
1701   "e" gnus-summary-edit-article
1702   "#" gnus-summary-mark-as-processable
1703   "\M-#" gnus-summary-unmark-as-processable
1704   "\M-\C-t" gnus-summary-toggle-threads
1705   "\M-\C-s" gnus-summary-show-thread
1706   "\M-\C-h" gnus-summary-hide-thread
1707   "\M-\C-f" gnus-summary-next-thread
1708   "\M-\C-b" gnus-summary-prev-thread
1709   [(meta down)] gnus-summary-next-thread
1710   [(meta up)] gnus-summary-prev-thread
1711   "\M-\C-u" gnus-summary-up-thread
1712   "\M-\C-d" gnus-summary-down-thread
1713   "&" gnus-summary-execute-command
1714   "c" gnus-summary-catchup-and-exit
1715   "\C-w" gnus-summary-mark-region-as-read
1716   "\C-t" gnus-summary-toggle-truncation
1717   "?" gnus-summary-mark-as-dormant
1718   "\C-c\M-\C-s" gnus-summary-limit-include-expunged
1719   "\C-c\C-s\C-n" gnus-summary-sort-by-number
1720   "\C-c\C-s\C-l" gnus-summary-sort-by-lines
1721   "\C-c\C-s\C-c" gnus-summary-sort-by-chars
1722   "\C-c\C-s\C-a" gnus-summary-sort-by-author
1723   "\C-c\C-s\C-s" gnus-summary-sort-by-subject
1724   "\C-c\C-s\C-d" gnus-summary-sort-by-date
1725   "\C-c\C-s\C-i" gnus-summary-sort-by-score
1726   "\C-c\C-s\C-o" gnus-summary-sort-by-original
1727   "\C-c\C-s\C-r" gnus-summary-sort-by-random
1728   "=" gnus-summary-expand-window
1729   "\C-x\C-s" gnus-summary-reselect-current-group
1730   "\M-g" gnus-summary-rescan-group
1731   "w" gnus-summary-stop-page-breaking
1732   "\C-c\C-r" gnus-summary-caesar-message
1733   "f" gnus-summary-followup
1734   "F" gnus-summary-followup-with-original
1735   "C" gnus-summary-cancel-article
1736   "r" gnus-summary-reply
1737   "R" gnus-summary-reply-with-original
1738   "\C-c\C-f" gnus-summary-mail-forward
1739   "o" gnus-summary-save-article
1740   "\C-o" gnus-summary-save-article-mail
1741   "|" gnus-summary-pipe-output
1742   "\M-k" gnus-summary-edit-local-kill
1743   "\M-K" gnus-summary-edit-global-kill
1744   ;; "V" gnus-version
1745   "\C-c\C-d" gnus-summary-describe-group
1746   "q" gnus-summary-exit
1747   "Q" gnus-summary-exit-no-update
1748   "\C-c\C-i" gnus-info-find-node
1749   gnus-mouse-2 gnus-mouse-pick-article
1750   "m" gnus-summary-mail-other-window
1751   "a" gnus-summary-post-news
1752   "i" gnus-summary-news-other-window
1753   "x" gnus-summary-limit-to-unread
1754   "s" gnus-summary-isearch-article
1755   "t" gnus-summary-toggle-header
1756   "g" gnus-summary-show-article
1757   "l" gnus-summary-goto-last-article
1758   "\C-c\C-v\C-v" gnus-uu-decode-uu-view
1759   "\C-d" gnus-summary-enter-digest-group
1760   "\M-\C-d" gnus-summary-read-document
1761   "\M-\C-e" gnus-summary-edit-parameters
1762   "\M-\C-a" gnus-summary-customize-parameters
1763   "\C-c\C-b" gnus-bug
1764   "*" gnus-cache-enter-article
1765   "\M-*" gnus-cache-remove-article
1766   "\M-&" gnus-summary-universal-argument
1767   "\C-l" gnus-recenter
1768   "I" gnus-summary-increase-score
1769   "L" gnus-summary-lower-score
1770   "\M-i" gnus-symbolic-argument
1771   "h" gnus-summary-select-article-buffer
1772
1773   "b" gnus-article-view-part
1774   "\M-t" gnus-summary-toggle-display-buttonized
1775
1776   "V" gnus-summary-score-map
1777   "X" gnus-uu-extract-map
1778   "S" gnus-summary-send-map)
1779
1780 ;; Sort of orthogonal keymap
1781 (gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
1782   "t" gnus-summary-tick-article-forward
1783   "!" gnus-summary-tick-article-forward
1784   "d" gnus-summary-mark-as-read-forward
1785   "r" gnus-summary-mark-as-read-forward
1786   "c" gnus-summary-clear-mark-forward
1787   " " gnus-summary-clear-mark-forward
1788   "e" gnus-summary-mark-as-expirable
1789   "x" gnus-summary-mark-as-expirable
1790   "?" gnus-summary-mark-as-dormant
1791   "b" gnus-summary-set-bookmark
1792   "B" gnus-summary-remove-bookmark
1793   "#" gnus-summary-mark-as-processable
1794   "\M-#" gnus-summary-unmark-as-processable
1795   "S" gnus-summary-limit-include-expunged
1796   "C" gnus-summary-catchup
1797   "H" gnus-summary-catchup-to-here
1798   "h" gnus-summary-catchup-from-here
1799   "\C-c" gnus-summary-catchup-all
1800   "k" gnus-summary-kill-same-subject-and-select
1801   "K" gnus-summary-kill-same-subject
1802   "P" gnus-uu-mark-map)
1803
1804 (gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
1805   "c" gnus-summary-clear-above
1806   "u" gnus-summary-tick-above
1807   "m" gnus-summary-mark-above
1808   "k" gnus-summary-kill-below)
1809
1810 (gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
1811   "/" gnus-summary-limit-to-subject
1812   "n" gnus-summary-limit-to-articles
1813   "w" gnus-summary-pop-limit
1814   "s" gnus-summary-limit-to-subject
1815   "a" gnus-summary-limit-to-author
1816   "u" gnus-summary-limit-to-unread
1817   "m" gnus-summary-limit-to-marks
1818   "M" gnus-summary-limit-exclude-marks
1819   "v" gnus-summary-limit-to-score
1820   "*" gnus-summary-limit-include-cached
1821   "D" gnus-summary-limit-include-dormant
1822   "T" gnus-summary-limit-include-thread
1823   "d" gnus-summary-limit-exclude-dormant
1824   "t" gnus-summary-limit-to-age
1825   "." gnus-summary-limit-to-unseen
1826   "x" gnus-summary-limit-to-extra
1827   "p" gnus-summary-limit-to-display-predicate
1828   "E" gnus-summary-limit-include-expunged
1829   "c" gnus-summary-limit-exclude-childless-dormant
1830   "C" gnus-summary-limit-mark-excluded-as-read
1831   "o" gnus-summary-insert-old-articles
1832   "N" gnus-summary-insert-new-articles
1833   "r" gnus-summary-limit-to-replied)
1834
1835 (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
1836   "n" gnus-summary-next-unread-article
1837   "p" gnus-summary-prev-unread-article
1838   "N" gnus-summary-next-article
1839   "P" gnus-summary-prev-article
1840   "\C-n" gnus-summary-next-same-subject
1841   "\C-p" gnus-summary-prev-same-subject
1842   "\M-n" gnus-summary-next-unread-subject
1843   "\M-p" gnus-summary-prev-unread-subject
1844   "f" gnus-summary-first-unread-article
1845   "b" gnus-summary-best-unread-article
1846   "j" gnus-summary-goto-article
1847   "g" gnus-summary-goto-subject
1848   "l" gnus-summary-goto-last-article
1849   "o" gnus-summary-pop-article)
1850
1851 (gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
1852   "k" gnus-summary-kill-thread
1853   "l" gnus-summary-lower-thread
1854   "i" gnus-summary-raise-thread
1855   "T" gnus-summary-toggle-threads
1856   "t" gnus-summary-rethread-current
1857   "^" gnus-summary-reparent-thread
1858   "s" gnus-summary-show-thread
1859   "S" gnus-summary-show-all-threads
1860   "h" gnus-summary-hide-thread
1861   "H" gnus-summary-hide-all-threads
1862   "n" gnus-summary-next-thread
1863   "p" gnus-summary-prev-thread
1864   "u" gnus-summary-up-thread
1865   "o" gnus-summary-top-thread
1866   "d" gnus-summary-down-thread
1867   "#" gnus-uu-mark-thread
1868   "\M-#" gnus-uu-unmark-thread)
1869
1870 (gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
1871   "g" gnus-summary-prepare
1872   "c" gnus-summary-insert-cached-articles
1873   "d" gnus-summary-insert-dormant-articles)
1874
1875 (gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
1876   "c" gnus-summary-catchup-and-exit
1877   "C" gnus-summary-catchup-all-and-exit
1878   "E" gnus-summary-exit-no-update
1879   "Q" gnus-summary-exit
1880   "Z" gnus-summary-exit
1881   "n" gnus-summary-catchup-and-goto-next-group
1882   "R" gnus-summary-reselect-current-group
1883   "G" gnus-summary-rescan-group
1884   "N" gnus-summary-next-group
1885   "s" gnus-summary-save-newsrc
1886   "P" gnus-summary-prev-group)
1887
1888 (gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
1889   " " gnus-summary-next-page
1890   "n" gnus-summary-next-page
1891   "\177" gnus-summary-prev-page
1892   [delete] gnus-summary-prev-page
1893   "p" gnus-summary-prev-page
1894   "\r" gnus-summary-scroll-up
1895   "\M-\r" gnus-summary-scroll-down
1896   "<" gnus-summary-beginning-of-article
1897   ">" gnus-summary-end-of-article
1898   "b" gnus-summary-beginning-of-article
1899   "e" gnus-summary-end-of-article
1900   "^" gnus-summary-refer-parent-article
1901   "r" gnus-summary-refer-parent-article
1902   "D" gnus-summary-enter-digest-group
1903   "R" gnus-summary-refer-references
1904   "T" gnus-summary-refer-thread
1905   "g" gnus-summary-show-article
1906   "s" gnus-summary-isearch-article
1907   "P" gnus-summary-print-article
1908   "M" gnus-mailing-list-insinuate
1909   "t" gnus-article-babel)
1910
1911 (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
1912   "b" gnus-article-add-buttons
1913   "B" gnus-article-add-buttons-to-head
1914   "o" gnus-article-treat-overstrike
1915   "e" gnus-article-emphasize
1916   "w" gnus-article-fill-cited-article
1917   "Q" gnus-article-fill-long-lines
1918   "C" gnus-article-capitalize-sentences
1919   "c" gnus-article-remove-cr
1920   "q" gnus-article-de-quoted-unreadable
1921   "6" gnus-article-de-base64-unreadable
1922   "Z" gnus-article-decode-HZ
1923   "A" gnus-article-treat-ansi-sequences
1924   "h" gnus-article-wash-html
1925   "u" gnus-article-unsplit-urls
1926   "s" gnus-summary-force-verify-and-decrypt
1927   "f" gnus-article-display-x-face
1928   "l" gnus-summary-stop-page-breaking
1929   "r" gnus-summary-caesar-message
1930   "m" gnus-summary-morse-message
1931   "t" gnus-summary-toggle-header
1932   "g" gnus-treat-smiley
1933   "v" gnus-summary-verbose-headers
1934   "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
1935   "p" gnus-article-verify-x-pgp-sig
1936   "d" gnus-article-treat-dumbquotes)
1937
1938 (gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
1939   ;; mnemonic: deuglif*Y*
1940   "u" gnus-article-outlook-unwrap-lines
1941   "a" gnus-article-outlook-repair-attribution
1942   "c" gnus-article-outlook-rearrange-citation
1943   "f" gnus-article-outlook-deuglify-article) ;; mnemonic: full deuglify
1944
1945 (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
1946   "a" gnus-article-hide
1947   "h" gnus-article-hide-headers
1948   "b" gnus-article-hide-boring-headers
1949   "s" gnus-article-hide-signature
1950   "c" gnus-article-hide-citation
1951   "C" gnus-article-hide-citation-in-followups
1952   "l" gnus-article-hide-list-identifiers
1953   "B" gnus-article-strip-banner
1954   "P" gnus-article-hide-pem
1955   "\C-c" gnus-article-hide-citation-maybe)
1956
1957 (gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
1958   "a" gnus-article-highlight
1959   "h" gnus-article-highlight-headers
1960   "c" gnus-article-highlight-citation
1961   "s" gnus-article-highlight-signature)
1962
1963 (gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
1964   "f" gnus-article-treat-fold-headers
1965   "u" gnus-article-treat-unfold-headers
1966   "n" gnus-article-treat-fold-newsgroups)
1967
1968 (gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
1969   "x" gnus-article-display-x-face
1970   "d" gnus-article-display-face
1971   "s" gnus-treat-smiley
1972   "D" gnus-article-remove-images
1973   "f" gnus-treat-from-picon
1974   "m" gnus-treat-mail-picon
1975   "n" gnus-treat-newsgroups-picon)
1976
1977 (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
1978   "w" gnus-article-decode-mime-words
1979   "c" gnus-article-decode-charset
1980   "v" gnus-mime-view-all-parts
1981   "b" gnus-article-view-part)
1982
1983 (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
1984   "z" gnus-article-date-ut
1985   "u" gnus-article-date-ut
1986   "l" gnus-article-date-local
1987   "p" gnus-article-date-english
1988   "e" gnus-article-date-lapsed
1989   "o" gnus-article-date-original
1990   "i" gnus-article-date-iso8601
1991   "s" gnus-article-date-user)
1992
1993 (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
1994   "t" gnus-article-remove-trailing-blank-lines
1995   "l" gnus-article-strip-leading-blank-lines
1996   "m" gnus-article-strip-multiple-blank-lines
1997   "a" gnus-article-strip-blank-lines
1998   "A" gnus-article-strip-all-blank-lines
1999   "s" gnus-article-strip-leading-space
2000   "e" gnus-article-strip-trailing-space
2001   "w" gnus-article-remove-leading-whitespace)
2002
2003 (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
2004   "v" gnus-version
2005   "f" gnus-summary-fetch-faq
2006   "d" gnus-summary-describe-group
2007   "h" gnus-summary-describe-briefly
2008   "i" gnus-info-find-node
2009   "c" gnus-group-fetch-charter
2010   "C" gnus-group-fetch-control)
2011
2012 (gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
2013   "e" gnus-summary-expire-articles
2014   "\M-\C-e" gnus-summary-expire-articles-now
2015   "\177" gnus-summary-delete-article
2016   [delete] gnus-summary-delete-article
2017   [backspace] gnus-summary-delete-article
2018   "m" gnus-summary-move-article
2019   "r" gnus-summary-respool-article
2020   "w" gnus-summary-edit-article
2021   "c" gnus-summary-copy-article
2022   "B" gnus-summary-crosspost-article
2023   "q" gnus-summary-respool-query
2024   "t" gnus-summary-respool-trace
2025   "i" gnus-summary-import-article
2026   "I" gnus-summary-create-article
2027   "p" gnus-summary-article-posted-p)
2028
2029 (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
2030   "o" gnus-summary-save-article
2031   "m" gnus-summary-save-article-mail
2032   "F" gnus-summary-write-article-file
2033   "r" gnus-summary-save-article-rmail
2034   "f" gnus-summary-save-article-file
2035   "b" gnus-summary-save-article-body-file
2036   "h" gnus-summary-save-article-folder
2037   "v" gnus-summary-save-article-vm
2038   "p" gnus-summary-pipe-output
2039   "P" gnus-summary-muttprint
2040   "s" gnus-soup-add-article)
2041
2042 (gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
2043   "b" gnus-summary-display-buttonized
2044   "m" gnus-summary-repair-multipart
2045   "v" gnus-article-view-part
2046   "o" gnus-article-save-part
2047   "c" gnus-article-copy-part
2048   "C" gnus-article-view-part-as-charset
2049   "e" gnus-article-view-part-externally
2050   "E" gnus-article-encrypt-body
2051   "i" gnus-article-inline-part
2052   "|" gnus-article-pipe-part)
2053
2054 (gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
2055   "p" gnus-summary-mark-as-processable
2056   "u" gnus-summary-unmark-as-processable
2057   "U" gnus-summary-unmark-all-processable
2058   "v" gnus-uu-mark-over
2059   "s" gnus-uu-mark-series
2060   "r" gnus-uu-mark-region
2061   "g" gnus-uu-unmark-region
2062   "R" gnus-uu-mark-by-regexp
2063   "G" gnus-uu-unmark-by-regexp
2064   "t" gnus-uu-mark-thread
2065   "T" gnus-uu-unmark-thread
2066   "a" gnus-uu-mark-all
2067   "b" gnus-uu-mark-buffer
2068   "S" gnus-uu-mark-sparse
2069   "k" gnus-summary-kill-process-mark
2070   "y" gnus-summary-yank-process-mark
2071   "w" gnus-summary-save-process-mark
2072   "i" gnus-uu-invert-processable)
2073
2074 (gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
2075   ;;"x" gnus-uu-extract-any
2076   "m" gnus-summary-save-parts
2077   "u" gnus-uu-decode-uu
2078   "U" gnus-uu-decode-uu-and-save
2079   "s" gnus-uu-decode-unshar
2080   "S" gnus-uu-decode-unshar-and-save
2081   "o" gnus-uu-decode-save
2082   "O" gnus-uu-decode-save
2083   "b" gnus-uu-decode-binhex
2084   "B" gnus-uu-decode-binhex
2085   "p" gnus-uu-decode-postscript
2086   "P" gnus-uu-decode-postscript-and-save)
2087
2088 (gnus-define-keys
2089     (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
2090   "u" gnus-uu-decode-uu-view
2091   "U" gnus-uu-decode-uu-and-save-view
2092   "s" gnus-uu-decode-unshar-view
2093   "S" gnus-uu-decode-unshar-and-save-view
2094   "o" gnus-uu-decode-save-view
2095   "O" gnus-uu-decode-save-view
2096   "b" gnus-uu-decode-binhex-view
2097   "B" gnus-uu-decode-binhex-view
2098   "p" gnus-uu-decode-postscript-view
2099   "P" gnus-uu-decode-postscript-and-save-view)
2100
2101 (defvar gnus-article-post-menu nil)
2102
2103 (defconst gnus-summary-menu-maxlen 20)
2104
2105 (defun gnus-summary-menu-split (menu)
2106   ;; If we have lots of elements, divide them into groups of 20
2107   ;; and make a pane (or submenu) for each one.
2108   (if (> (length menu) (/ (* gnus-summary-menu-maxlen 3) 2))
2109       (let ((menu menu) sublists next
2110             (i 1))
2111         (while menu
2112           ;; Pull off the next gnus-summary-menu-maxlen elements
2113           ;; and make them the next element of sublist.
2114           (setq next (nthcdr gnus-summary-menu-maxlen menu))
2115           (if next
2116               (setcdr (nthcdr (1- gnus-summary-menu-maxlen) menu)
2117                       nil))
2118           (setq sublists (cons (cons (format "%s ... %s" (aref (car menu) 0)
2119                                              (aref (car (last menu)) 0)) menu)
2120                                sublists))
2121           (setq i (1+ i))
2122           (setq menu next))
2123         (nreverse sublists))
2124     ;; Few elements--put them all in one pane.
2125     menu))
2126
2127 (defun gnus-summary-make-menu-bar ()
2128   (gnus-turn-off-edit-menu 'summary)
2129
2130   (unless (boundp 'gnus-summary-misc-menu)
2131
2132     (easy-menu-define
2133       gnus-summary-kill-menu gnus-summary-mode-map ""
2134       (cons
2135        "Score"
2136        (nconc
2137         (list
2138          ["Customize" gnus-score-customize t])
2139         (gnus-make-score-map 'increase)
2140         (gnus-make-score-map 'lower)
2141         '(("Mark"
2142            ["Kill below" gnus-summary-kill-below t]
2143            ["Mark above" gnus-summary-mark-above t]
2144            ["Tick above" gnus-summary-tick-above t]
2145            ["Clear above" gnus-summary-clear-above t])
2146           ["Current score" gnus-summary-current-score t]
2147           ["Set score" gnus-summary-set-score t]
2148           ["Switch current score file..." gnus-score-change-score-file t]
2149           ["Set mark below..." gnus-score-set-mark-below t]
2150           ["Set expunge below..." gnus-score-set-expunge-below t]
2151           ["Edit current score file" gnus-score-edit-current-scores t]
2152           ["Edit score file" gnus-score-edit-file t]
2153           ["Trace score" gnus-score-find-trace t]
2154           ["Find words" gnus-score-find-favourite-words t]
2155           ["Rescore buffer" gnus-summary-rescore t]
2156           ["Increase score..." gnus-summary-increase-score t]
2157           ["Lower score..." gnus-summary-lower-score t]))))
2158
2159     ;; Define both the Article menu in the summary buffer and the
2160     ;; equivalent Commands menu in the article buffer here for
2161     ;; consistency.
2162     (let ((innards
2163            `(("Hide"
2164               ["All" gnus-article-hide t]
2165               ["Headers" gnus-article-hide-headers t]
2166               ["Signature" gnus-article-hide-signature t]
2167               ["Citation" gnus-article-hide-citation t]
2168               ["List identifiers" gnus-article-hide-list-identifiers t]
2169               ["Banner" gnus-article-strip-banner t]
2170               ["Boring headers" gnus-article-hide-boring-headers t])
2171              ("Highlight"
2172               ["All" gnus-article-highlight t]
2173               ["Headers" gnus-article-highlight-headers t]
2174               ["Signature" gnus-article-highlight-signature t]
2175               ["Citation" gnus-article-highlight-citation t])
2176              ("MIME"
2177               ["Words" gnus-article-decode-mime-words t]
2178               ["Charset" gnus-article-decode-charset t]
2179               ["QP" gnus-article-de-quoted-unreadable t]
2180               ["Base64" gnus-article-de-base64-unreadable t]
2181               ["View MIME buttons" gnus-summary-display-buttonized t]
2182               ["View all" gnus-mime-view-all-parts t]
2183               ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
2184               ["Encrypt body" gnus-article-encrypt-body
2185                :active (not (gnus-group-read-only-p))
2186                ,@(if (featurep 'xemacs) nil
2187                    '(:help "Encrypt the message body on disk"))]
2188               ["Extract all parts..." gnus-summary-save-parts t]
2189               ("Multipart"
2190                ["Repair multipart" gnus-summary-repair-multipart t]
2191                ["Pipe part..." gnus-article-pipe-part t]
2192                ["Inline part" gnus-article-inline-part t]
2193                ["Encrypt body" gnus-article-encrypt-body
2194                 :active (not (gnus-group-read-only-p))
2195                ,@(if (featurep 'xemacs) nil
2196                    '(:help "Encrypt the message body on disk"))]
2197                ["View part externally" gnus-article-view-part-externally t]
2198                ["View part with charset..." gnus-article-view-part-as-charset t]
2199                ["Copy part" gnus-article-copy-part t]
2200                ["Save part..." gnus-article-save-part t]
2201                ["View part" gnus-article-view-part t]))
2202              ("Date"
2203               ["Local" gnus-article-date-local t]
2204               ["ISO8601" gnus-article-date-iso8601 t]
2205               ["UT" gnus-article-date-ut t]
2206               ["Original" gnus-article-date-original t]
2207               ["Lapsed" gnus-article-date-lapsed t]
2208               ["User-defined" gnus-article-date-user t])
2209              ("Display"