* gnus-sum.el (gnus-summary-select-article-buffer): Doc fix.
[gnus] / lisp / gnus-sum.el
1 ;;; gnus-sum.el --- summary mode commands for Gnus
2
3 ;; Copyright (C) 1996-2011 Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Keywords: news
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27 ;; For Emacs <22.2 and XEmacs.
28 (eval-and-compile
29   (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
30 (eval-when-compile
31   (require 'cl))
32 (eval-when-compile
33   (when (featurep 'xemacs)
34     (require 'easy-mmode))) ; for `define-minor-mode'
35
36 (defvar tool-bar-mode)
37 (defvar gnus-tmp-header)
38
39 (require 'gnus)
40 (require 'gnus-group)
41 (require 'gnus-spec)
42 (require 'gnus-range)
43 (require 'gnus-int)
44 (require 'gnus-undo)
45 (require 'gnus-util)
46 (require 'gmm-utils)
47 (require 'mm-decode)
48 (require 'nnoo)
49
50 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
51 (autoload 'gnus-cache-write-active "gnus-cache")
52 (autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
53 (autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
54 (autoload 'gnus-pick-line-number "gnus-salt" nil t)
55 (autoload 'mm-uu-dissect "mm-uu")
56 (autoload 'gnus-article-outlook-deuglify-article "deuglify"
57   "Deuglify broken Outlook (Express) articles and redisplay."
58   t)
59 (autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
60 (autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
61 (autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
62 (autoload 'nnir-article-rsv "nnir" nil nil 'macro)
63 (autoload 'nnir-article-group "nnir" nil nil 'macro)
64
65 (defcustom gnus-kill-summary-on-exit t
66   "*If non-nil, kill the summary buffer when you exit from it.
67 If nil, the summary will become a \"*Dead Summary*\" buffer, and
68 it will be killed sometime later."
69   :group 'gnus-summary-exit
70   :type 'boolean)
71
72 (defcustom gnus-summary-next-group-on-exit t
73   "If non-nil, go to the next unread newsgroup on summary exit.
74 See `gnus-group-goto-unread'."
75   :link '(custom-manual "(gnus)Group Maneuvering")
76   :group 'gnus-summary-exit
77   :version "23.1" ;; No Gnus
78   :type 'boolean)
79
80 (defcustom gnus-summary-stop-at-end-of-message nil
81   "If non-nil, don't select the next message when using `SPC'."
82   :link '(custom-manual "(gnus)Group Maneuvering")
83   :group 'gnus-summary-maneuvering
84   :version "24.1"
85   :type 'boolean)
86
87 (defcustom gnus-fetch-old-headers nil
88   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
89 If an unread article in the group refers to an older, already
90 read (or just marked as read) article, the old article will not
91 normally be displayed in the Summary buffer.  If this variable is
92 t, Gnus will attempt to grab the headers to the old articles, and
93 thereby build complete threads.  If it has the value `some', all
94 old headers will be fetched but only enough headers to connect
95 otherwise loose threads will be displayed.  This variable can
96 also be a number.  In that case, no more than that number of old
97 headers will be fetched.  If it has the value `invisible', all
98 old headers will be fetched, but none will be displayed.
99
100 The server has to support NOV for any of this to work.
101
102 This feature can seriously impact performance it ignores all
103 locally cached header entries.  Setting it to t for groups for a
104 server that doesn't expire articles (such as news.gmane.org),
105 leads to very slow summary generation."
106   :group 'gnus-thread
107   :type '(choice (const :tag "off" nil)
108                  (const :tag "on" t)
109                  (const some)
110                  (const invisible)
111                  number
112                  (sexp :menu-tag "other" t)))
113
114 (defcustom gnus-refer-thread-limit 500
115   "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
116 If t, fetch all the available old headers."
117   :group 'gnus-thread
118   :type '(choice number
119                  (sexp :menu-tag "other" t)))
120
121 (defcustom gnus-summary-make-false-root 'adopt
122   "*nil means that Gnus won't gather loose threads.
123 If the root of a thread has expired or been read in a previous
124 session, the information necessary to build a complete thread has been
125 lost.  Instead of having many small sub-threads from this original thread
126 scattered all over the summary buffer, Gnus can gather them.
127
128 If non-nil, Gnus will try to gather all loose sub-threads from an
129 original thread into one large thread.
130
131 If this variable is non-nil, it should be one of `none', `adopt',
132 `dummy' or `empty'.
133
134 If this variable is `none', Gnus will not make a false root, but just
135 present the sub-threads after another.
136 If this variable is `dummy', Gnus will create a dummy root that will
137 have all the sub-threads as children.
138 If this variable is `adopt', Gnus will make one of the \"children\"
139 the parent and mark all the step-children as such.
140 If this variable is `empty', the \"children\" are printed with empty
141 subject fields.  (Or rather, they will be printed with a string
142 given by the `gnus-summary-same-subject' variable.)"
143   :group 'gnus-thread
144   :type '(choice (const :tag "off" nil)
145                  (const none)
146                  (const dummy)
147                  (const adopt)
148                  (const empty)))
149
150 (defcustom gnus-summary-make-false-root-always nil
151   "Always make a false dummy root."
152   :version "22.1"
153   :group 'gnus-thread
154   :type 'boolean)
155
156 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
157   "*A regexp to match subjects to be excluded from loose thread gathering.
158 As loose thread gathering is done on subjects only, that means that
159 there can be many false gatherings performed.  By rooting out certain
160 common subjects, gathering might become saner."
161   :group 'gnus-thread
162   :type 'regexp)
163
164 (defcustom gnus-summary-gather-subject-limit nil
165   "*Maximum length of subject comparisons when gathering loose threads.
166 Use nil to compare full subjects.  Setting this variable to a low
167 number will help gather threads that have been corrupted by
168 newsreaders chopping off subject lines, but it might also mean that
169 unrelated articles that have subject that happen to begin with the
170 same few characters will be incorrectly gathered.
171
172 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
173 comparing subjects."
174   :group 'gnus-thread
175   :type '(choice (const :tag "off" nil)
176                  (const fuzzy)
177                  (sexp :menu-tag "on" t)))
178
179 (defcustom gnus-simplify-subject-functions nil
180   "List of functions taking a string argument that simplify subjects.
181 The functions are applied recursively.
182
183 Useful functions to put in this list include:
184 `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
185 `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
186   :group 'gnus-thread
187   :type '(repeat function))
188
189 (defcustom gnus-simplify-ignored-prefixes nil
190   "*Remove matches for this regexp from subject lines when simplifying fuzzily."
191   :group 'gnus-thread
192   :type '(choice (const :tag "off" nil)
193                  regexp))
194
195 (defcustom gnus-build-sparse-threads nil
196   "*If non-nil, fill in the gaps in threads.
197 If `some', only fill in the gaps that are needed to tie loose threads
198 together.  If `more', fill in all leaf nodes that Gnus can find.  If
199 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
200   :group 'gnus-thread
201   :type '(choice (const :tag "off" nil)
202                  (const some)
203                  (const more)
204                  (sexp :menu-tag "all" t)))
205
206 (defcustom gnus-summary-thread-gathering-function
207   'gnus-gather-threads-by-subject
208   "*Function used for gathering loose threads.
209 There are two pre-defined functions: `gnus-gather-threads-by-subject',
210 which only takes Subjects into consideration; and
211 `gnus-gather-threads-by-references', which compared the References
212 headers of the articles to find matches."
213   :group 'gnus-thread
214   :type '(radio (function-item gnus-gather-threads-by-subject)
215                 (function-item gnus-gather-threads-by-references)
216                 (function :tag "other")))
217
218 (defcustom gnus-summary-same-subject ""
219   "*String indicating that the current article has the same subject as the previous.
220 This variable will only be used if the value of
221 `gnus-summary-make-false-root' is `empty'."
222   :group 'gnus-summary-format
223   :type 'string)
224
225 (defcustom gnus-summary-goto-unread nil
226   "*If t, many commands will go to the next unread article.
227 This applies to marking commands as well as other commands that
228 \"naturally\" select the next article, like, for instance, `SPC' at
229 the end of an article.
230
231 If nil, the marking commands do NOT go to the next unread article
232 \(they go to the next article instead).  If `never', commands that
233 usually go to the next unread article, will go to the next article,
234 whether it is read or not."
235   :version "24.1"
236   :group 'gnus-summary-marks
237   :link '(custom-manual "(gnus)Setting Marks")
238   :type '(choice (const :tag "off" nil)
239                  (const never)
240                  (sexp :menu-tag "on" t)))
241
242 (defcustom gnus-summary-default-score 0
243   "*Default article score level.
244 All scores generated by the score files will be added to this score.
245 If this variable is nil, scoring will be disabled."
246   :group 'gnus-score-default
247   :type '(choice (const :tag "disable")
248                  integer))
249
250 (defcustom gnus-summary-default-high-score 0
251   "*Default threshold for a high scored article.
252 An article will be highlighted as high scored if its score is greater
253 than this score."
254   :version "22.1"
255   :group 'gnus-score-default
256   :type 'integer)
257
258 (defcustom gnus-summary-default-low-score 0
259   "*Default threshold for a low scored article.
260 An article will be highlighted as low scored if its score is smaller
261 than this score."
262   :version "22.1"
263   :group 'gnus-score-default
264   :type 'integer)
265
266 (defcustom gnus-summary-zcore-fuzz 0
267   "*Fuzziness factor for the zcore in the summary buffer.
268 Articles with scores closer than this to `gnus-summary-default-score'
269 will not be marked."
270   :group 'gnus-summary-format
271   :type 'integer)
272
273 (defcustom gnus-simplify-subject-fuzzy-regexp nil
274   "*Strings to be removed when doing fuzzy matches.
275 This can either be a regular expression or list of regular expressions
276 that will be removed from subject strings if fuzzy subject
277 simplification is selected."
278   :group 'gnus-thread
279   :type '(repeat regexp))
280
281 (defcustom gnus-show-threads t
282   "*If non-nil, display threads in summary mode."
283   :group 'gnus-thread
284   :type 'boolean)
285
286 (defcustom gnus-thread-hide-subtree nil
287   "*If non-nil, hide all threads initially.
288 This can be a predicate specifier which says which threads to hide.
289 If threads are hidden, you have to run the command
290 `gnus-summary-show-thread' by hand or select an article."
291   :group 'gnus-thread
292   :type '(radio (sexp :format "Non-nil\n"
293                       :match (lambda (widget value)
294                                (not (or (consp value) (functionp value))))
295                       :value t)
296                 (const nil)
297                 (sexp :tag "Predicate specifier")))
298
299 (defcustom gnus-thread-hide-killed t
300   "*If non-nil, hide killed threads automatically."
301   :group 'gnus-thread
302   :type 'boolean)
303
304 (defcustom gnus-thread-ignore-subject t
305   "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
306 If nil, articles that have different subjects from their parents will
307 start separate threads."
308   :group 'gnus-thread
309   :type 'boolean)
310
311 (defcustom gnus-thread-operation-ignore-subject t
312   "*If non-nil, subjects will be ignored when doing thread commands.
313 This affects commands like `gnus-summary-kill-thread' and
314 `gnus-summary-lower-thread'.
315
316 If this variable is nil, articles in the same thread with different
317 subjects will not be included in the operation in question.  If this
318 variable is `fuzzy', only articles that have subjects that are fuzzily
319 equal will be included."
320   :group 'gnus-thread
321   :type '(choice (const :tag "off" nil)
322                  (const fuzzy)
323                  (sexp :tag "on" t)))
324
325 (defcustom gnus-thread-indent-level 4
326   "*Number that says how much each sub-thread should be indented."
327   :group 'gnus-thread
328   :type 'integer)
329
330 (defcustom gnus-auto-extend-newsgroup t
331   "*If non-nil, extend newsgroup forward and backward when requested."
332   :group 'gnus-summary-choose
333   :type 'boolean)
334
335 (defcustom gnus-auto-select-first t
336   "If non-nil, select an article on group entry.
337 An article is selected automatically when entering a group
338 e.g. with \\<gnus-group-mode-map>\\[gnus-group-read-group], or via `gnus-summary-next-page' or
339 `gnus-summary-catchup-and-goto-next-group'.
340
341 Which article is selected is controlled by the variable
342 `gnus-auto-select-subject'.
343
344 If you want to prevent automatic selection of articles in some
345 newsgroups, set the variable to nil in `gnus-select-group-hook'."
346   ;; Commands include...
347   ;; \\<gnus-group-mode-map>\\[gnus-group-read-group]
348   ;; \\<gnus-summary-mode-map>\\[gnus-summary-next-page]
349   ;; \\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]
350   :group 'gnus-group-select
351   :type '(choice (const :tag "none" nil)
352                  (sexp :menu-tag "first" t)))
353
354 (defcustom gnus-auto-select-subject 'unseen-or-unread
355   "*Says what subject to place under point when entering a group.
356
357 This variable can either be the symbols `first' (place point on the
358 first subject), `unread' (place point on the subject line of the first
359 unread article), `best' (place point on the subject line of the
360 higest-scored article), `unseen' (place point on the subject line of
361 the first unseen article), `unseen-or-unread' (place point on the subject
362 line of the first unseen article or, if all articles have been seen, on the
363 subject line of the first unread article), or a function to be called to
364 place point on some subject line."
365   :version "24.1"
366   :group 'gnus-group-select
367   :type '(choice (const best)
368                  (const unread)
369                  (const first)
370                  (const unseen)
371                  (const unseen-or-unread)))
372
373 (defcustom gnus-auto-select-next t
374   "*If non-nil, offer to go to the next group from the end of the previous.
375 If the value is t and the next newsgroup is empty, Gnus will exit
376 summary mode and go back to group mode.  If the value is neither nil
377 nor t, Gnus will select the following unread newsgroup.  In
378 particular, if the value is the symbol `quietly', the next unread
379 newsgroup will be selected without any confirmation, and if it is
380 `almost-quietly', the next group will be selected without any
381 confirmation if you are located on the last article in the group.
382 Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
383 will go to the next group without confirmation."
384   :group 'gnus-summary-maneuvering
385   :type '(choice (const :tag "off" nil)
386                  (const quietly)
387                  (const almost-quietly)
388                  (const slightly-quietly)
389                  (sexp :menu-tag "on" t)))
390
391 (defcustom gnus-auto-select-same nil
392   "*If non-nil, select the next article with the same subject.
393 If there are no more articles with the same subject, go to
394 the first unread article."
395   :group 'gnus-summary-maneuvering
396   :type 'boolean)
397
398 (defcustom gnus-auto-select-on-ephemeral-exit 'next-noselect
399   "What article should be selected after exiting an ephemeral group.
400 Valid values include:
401
402 `next'
403   Select the next article.
404 `next-unread'
405   Select the next unread article.
406 `next-noselect'
407   Move the cursor to the next article.  This is the default.
408 `next-unread-noselect'
409   Move the cursor to the next unread article.
410
411 If it has any other value or there is no next (unread) article, the
412 article selected before entering to the ephemeral group will appear."
413   :version "23.1" ;; No Gnus
414   :group 'gnus-summary-maneuvering
415   :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
416                  (const next) (const next-unread)
417                  (const next-noselect) (const next-unread-noselect)
418                  (sexp :tag "other" :value nil)))
419
420 (defcustom gnus-auto-goto-ignores 'unfetched
421   "*Says how to handle unfetched articles when maneuvering.
422
423 This variable can either be the symbols nil (maneuver to any
424 article), `undownloaded' (maneuvering while unplugged ignores articles
425 that have not been fetched), `always-undownloaded' (maneuvering always
426 ignores articles that have not been fetched), `unfetched' (maneuvering
427 ignores articles whose headers have not been fetched).
428
429 NOTE: The list of unfetched articles will always be nil when plugged
430 and, when unplugged, a subset of the undownloaded article list."
431   :version "22.1"
432   :group 'gnus-summary-maneuvering
433   :type '(choice (const :tag "None" nil)
434                  (const :tag "Undownloaded when unplugged" undownloaded)
435                  (const :tag "Undownloaded" always-undownloaded)
436                  (const :tag "Unfetched" unfetched)))
437
438 (defcustom gnus-summary-check-current nil
439   "*If non-nil, consider the current article when moving.
440 The \"unread\" movement commands will stay on the same line if the
441 current article is unread."
442   :group 'gnus-summary-maneuvering
443   :type 'boolean)
444
445 (defcustom gnus-auto-center-summary 2
446   "*If non-nil, always center the current summary buffer.
447 In particular, if `vertical' do only vertical recentering.  If non-nil
448 and non-`vertical', do both horizontal and vertical recentering."
449   :group 'gnus-summary-maneuvering
450   :type '(choice (const :tag "none" nil)
451                  (const vertical)
452                  (integer :tag "height")
453                  (sexp :menu-tag "both" t)))
454
455 (defcustom gnus-auto-center-group t
456   "If non-nil, always center the group buffer."
457   :group 'gnus-summary-maneuvering
458   :type 'boolean)
459
460 (defcustom gnus-show-all-headers nil
461   "*If non-nil, don't hide any headers."
462   :group 'gnus-article-hiding
463   :group 'gnus-article-headers
464   :type 'boolean)
465
466 (defcustom gnus-summary-ignore-duplicates nil
467   "*If non-nil, ignore articles with identical Message-ID headers."
468   :group 'gnus-summary
469   :type 'boolean)
470
471 (defcustom gnus-single-article-buffer nil
472   "*If non-nil, display all articles in the same buffer.
473 If nil, each group will get its own article buffer."
474   :version "24.1"
475   :group 'gnus-article-various
476   :type 'boolean)
477
478 (defcustom gnus-widen-article-window nil
479   "If non-nil, selecting the article buffer will display only the article buffer."
480   :version "24.1"
481   :group 'gnus-article-various
482   :type 'boolean)
483
484 (defcustom gnus-break-pages t
485   "*If non-nil, do page breaking on articles.
486 The page delimiter is specified by the `gnus-page-delimiter'
487 variable."
488   :group 'gnus-article-various
489   :type 'boolean)
490
491 (defcustom gnus-move-split-methods nil
492   "*Variable used to suggest where articles are to be moved to.
493 It uses the same syntax as the `gnus-split-methods' variable.
494 However, whereas `gnus-split-methods' specifies file names as targets,
495 this variable specifies group names."
496   :group 'gnus-summary-mail
497   :type '(repeat (choice (list :value (fun) function)
498                          (cons :value ("" "") regexp (repeat string))
499                          (sexp :value nil))))
500
501 (defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
502   "Function used to compute default prefix for article move/copy/etc prompts.
503 The function should take one argument, a group name, and return a
504 string with the suggested prefix."
505   :group 'gnus-summary-mail
506   :type 'function)
507
508 ;; FIXME: Although the custom type is `character' for the following variables,
509 ;; using multibyte characters (Latin-1, UTF-8) doesn't work.  -- rs
510
511 (defcustom gnus-unread-mark ?           ;Whitespace
512   "*Mark used for unread articles."
513   :group 'gnus-summary-marks
514   :type 'character)
515
516 (defcustom gnus-ticked-mark ?!
517   "*Mark used for ticked articles."
518   :group 'gnus-summary-marks
519   :type 'character)
520
521 (defcustom gnus-dormant-mark ??
522   "*Mark used for dormant articles."
523   :group 'gnus-summary-marks
524   :type 'character)
525
526 (defcustom gnus-del-mark ?r
527   "*Mark used for del'd articles."
528   :group 'gnus-summary-marks
529   :type 'character)
530
531 (defcustom gnus-read-mark ?R
532   "*Mark used for read articles."
533   :group 'gnus-summary-marks
534   :type 'character)
535
536 (defcustom gnus-expirable-mark ?E
537   "*Mark used for expirable articles."
538   :group 'gnus-summary-marks
539   :type 'character)
540
541 (defcustom gnus-killed-mark ?K
542   "*Mark used for killed articles."
543   :group 'gnus-summary-marks
544   :type 'character)
545
546 (defcustom gnus-spam-mark ?$
547   "*Mark used for spam articles."
548   :version "22.1"
549   :group 'gnus-summary-marks
550   :type 'character)
551
552 (defcustom gnus-kill-file-mark ?X
553   "*Mark used for articles killed by kill files."
554   :group 'gnus-summary-marks
555   :type 'character)
556
557 (defcustom gnus-low-score-mark ?Y
558   "*Mark used for articles with a low score."
559   :group 'gnus-summary-marks
560   :type 'character)
561
562 (defcustom gnus-catchup-mark ?C
563   "*Mark used for articles that are caught up."
564   :group 'gnus-summary-marks
565   :type 'character)
566
567 (defcustom gnus-replied-mark ?A
568   "*Mark used for articles that have been replied to."
569   :group 'gnus-summary-marks
570   :type 'character)
571
572 (defcustom gnus-forwarded-mark ?F
573   "*Mark used for articles that have been forwarded."
574   :version "22.1"
575   :group 'gnus-summary-marks
576   :type 'character)
577
578 (defcustom gnus-recent-mark ?N
579   "*Mark used for articles that are recent."
580   :version "22.1"
581   :group 'gnus-summary-marks
582   :type 'character)
583
584 (defcustom gnus-cached-mark ?*
585   "*Mark used for articles that are in the cache."