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