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