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