Disable starttls.el on Windows and MS-DOS
[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-refer-thread-use-nnir nil
122   "*Use nnir to search an entire server when referring threads. A
123 nil value will only search for thread-related articles in the
124 current group."
125   :group 'gnus-thread
126   :type 'boolean)
127
128 (defcustom gnus-summary-make-false-root 'adopt
129   "*nil means that Gnus won't gather loose threads.
130 If the root of a thread has expired or been read in a previous
131 session, the information necessary to build a complete thread has been
132 lost.  Instead of having many small sub-threads from this original thread
133 scattered all over the summary buffer, Gnus can gather them.
134
135 If non-nil, Gnus will try to gather all loose sub-threads from an
136 original thread into one large thread.
137
138 If this variable is non-nil, it should be one of `none', `adopt',
139 `dummy' or `empty'.
140
141 If this variable is `none', Gnus will not make a false root, but just
142 present the sub-threads after another.
143 If this variable is `dummy', Gnus will create a dummy root that will
144 have all the sub-threads as children.
145 If this variable is `adopt', Gnus will make one of the \"children\"
146 the parent and mark all the step-children as such.
147 If this variable is `empty', the \"children\" are printed with empty
148 subject fields.  (Or rather, they will be printed with a string
149 given by the `gnus-summary-same-subject' variable.)"
150   :group 'gnus-thread
151   :type '(choice (const :tag "off" nil)
152                  (const none)
153                  (const dummy)
154                  (const adopt)
155                  (const empty)))
156
157 (defcustom gnus-summary-make-false-root-always nil
158   "Always make a false dummy root."
159   :version "22.1"
160   :group 'gnus-thread
161   :type 'boolean)
162
163 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
164   "*A regexp to match subjects to be excluded from loose thread gathering.
165 As loose thread gathering is done on subjects only, that means that
166 there can be many false gatherings performed.  By rooting out certain
167 common subjects, gathering might become saner."
168   :group 'gnus-thread
169   :type 'regexp)
170
171 (defcustom gnus-summary-gather-subject-limit nil
172   "*Maximum length of subject comparisons when gathering loose threads.
173 Use nil to compare full subjects.  Setting this variable to a low
174 number will help gather threads that have been corrupted by
175 newsreaders chopping off subject lines, but it might also mean that
176 unrelated articles that have subject that happen to begin with the
177 same few characters will be incorrectly gathered.
178
179 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
180 comparing subjects."
181   :group 'gnus-thread
182   :type '(choice (const :tag "off" nil)
183                  (const fuzzy)
184                  (sexp :menu-tag "on" t)))
185
186 (defcustom gnus-simplify-subject-functions nil
187   "List of functions taking a string argument that simplify subjects.
188 The functions are applied recursively.
189
190 Useful functions to put in this list include:
191 `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
192 `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
193   :group 'gnus-thread
194   :type '(repeat function))
195
196 (defcustom gnus-simplify-ignored-prefixes nil
197   "*Remove matches for this regexp from subject lines when simplifying fuzzily."
198   :group 'gnus-thread
199   :type '(choice (const :tag "off" nil)
200                  regexp))
201
202 (defcustom gnus-build-sparse-threads nil
203   "*If non-nil, fill in the gaps in threads.
204 If `some', only fill in the gaps that are needed to tie loose threads
205 together.  If `more', fill in all leaf nodes that Gnus can find.  If
206 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
207   :group 'gnus-thread
208   :type '(choice (const :tag "off" nil)
209                  (const some)
210                  (const more)
211                  (sexp :menu-tag "all" t)))
212
213 (defcustom gnus-summary-thread-gathering-function
214   'gnus-gather-threads-by-subject
215   "*Function used for gathering loose threads.
216 There are two pre-defined functions: `gnus-gather-threads-by-subject',
217 which only takes Subjects into consideration; and
218 `gnus-gather-threads-by-references', which compared the References
219 headers of the articles to find matches."
220   :group 'gnus-thread
221   :type '(radio (function-item gnus-gather-threads-by-subject)
222                 (function-item gnus-gather-threads-by-references)
223                 (function :tag "other")))
224
225 (defcustom gnus-summary-same-subject ""
226   "*String indicating that the current article has the same subject as the previous.
227 This variable will only be used if the value of
228 `gnus-summary-make-false-root' is `empty'."
229   :group 'gnus-summary-format
230   :type 'string)
231
232 (defcustom gnus-summary-goto-unread nil
233   "*If t, many commands will go to the next unread article.
234 This applies to marking commands as well as other commands that
235 \"naturally\" select the next article, like, for instance, `SPC' at
236 the end of an article.
237
238 If nil, the marking commands do NOT go to the next unread article
239 \(they go to the next article instead).  If `never', commands that
240 usually go to the next unread article, will go to the next article,
241 whether it is read or not."
242   :version "24.1"
243   :group 'gnus-summary-marks
244   :link '(custom-manual "(gnus)Setting Marks")
245   :type '(choice (const :tag "off" nil)
246                  (const never)
247                  (sexp :menu-tag "on" t)))
248
249 (defcustom gnus-summary-default-score 0
250   "*Default article score level.
251 All scores generated by the score files will be added to this score.
252 If this variable is nil, scoring will be disabled."
253   :group 'gnus-score-default
254   :type '(choice (const :tag "disable")
255                  integer))
256
257 (defcustom gnus-summary-default-high-score 0
258   "*Default threshold for a high scored article.
259 An article will be highlighted as high scored if its score is greater
260 than this score."
261   :version "22.1"
262   :group 'gnus-score-default
263   :type 'integer)
264
265 (defcustom gnus-summary-default-low-score 0
266   "*Default threshold for a low scored article.
267 An article will be highlighted as low scored if its score is smaller
268 than this score."
269   :version "22.1"
270   :group 'gnus-score-default
271   :type 'integer)
272
273 (defcustom gnus-summary-zcore-fuzz 0
274   "*Fuzziness factor for the zcore in the summary buffer.
275 Articles with scores closer than this to `gnus-summary-default-score'
276 will not be marked."
277   :group 'gnus-summary-format
278   :type 'integer)
279
280 (defcustom gnus-simplify-subject-fuzzy-regexp nil
281   "*Strings to be removed when doing fuzzy matches.
282 This can either be a regular expression or list of regular expressions
283 that will be removed from subject strings if fuzzy subject
284 simplification is selected."
285   :group 'gnus-thread
286   :type '(repeat regexp))
287
288 (defcustom gnus-show-threads t
289   "*If non-nil, display threads in summary mode."
290   :group 'gnus-thread
291   :type 'boolean)
292
293 (defcustom gnus-thread-hide-subtree nil
294   "*If non-nil, hide all threads initially.
295 This can be a predicate specifier which says which threads to hide.
296 If threads are hidden, you have to run the command
297 `gnus-summary-show-thread' by hand or select an article."
298   :group 'gnus-thread
299   :type '(radio (sexp :format "Non-nil\n"
300                       :match (lambda (widget value)
301                                (not (or (consp value) (functionp value))))
302                       :value t)
303                 (const nil)
304                 (sexp :tag "Predicate specifier")))
305
306 (defcustom gnus-thread-hide-killed t
307   "*If non-nil, hide killed threads automatically."
308   :group 'gnus-thread
309   :type 'boolean)
310
311 (defcustom gnus-thread-ignore-subject t
312   "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
313 If nil, articles that have different subjects from their parents will
314 start separate threads."
315   :group 'gnus-thread
316   :type 'boolean)
317
318 (defcustom gnus-thread-operation-ignore-subject t
319   "*If non-nil, subjects will be ignored when doing thread commands.
320 This affects commands like `gnus-summary-kill-thread' and
321 `gnus-summary-lower-thread'.
322
323 If this variable is nil, articles in the same thread with different
324 subjects will not be included in the operation in question.  If this
325 variable is `fuzzy', only articles that have subjects that are fuzzily
326 equal will be included."
327   :group 'gnus-thread
328   :type '(choice (const :tag "off" nil)
329                  (const fuzzy)
330                  (sexp :tag "on" t)))
331
332 (defcustom gnus-thread-indent-level 4
333   "*Number that says how much each sub-thread should be indented."
334   :group 'gnus-thread
335   :type 'integer)
336
337 (defcustom gnus-auto-extend-newsgroup t
338   "*If non-nil, extend newsgroup forward and backward when requested."
339   :group 'gnus-summary-choose
340   :type 'boolean)
341
342 (defcustom gnus-auto-select-first t
343   "If non-nil, select an article on group entry.
344 An article is selected automatically when entering a group
345 e.g. with \\<gnus-group-mode-map>\\[gnus-group-read-group], or via `gnus-summary-next-page' or
346 `gnus-summary-catchup-and-goto-next-group'.
347
348 Which article is selected is controlled by the variable
349 `gnus-auto-select-subject'.
350
351 If you want to prevent automatic selection of articles in some
352 newsgroups, set the variable to nil in `gnus-select-group-hook'."
353   ;; Commands include...
354   ;; \\<gnus-group-mode-map>\\[gnus-group-read-group]
355   ;; \\<gnus-summary-mode-map>\\[gnus-summary-next-page]
356   ;; \\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]
357   :group 'gnus-group-select
358   :type '(choice (const :tag "none" nil)
359                  (sexp :menu-tag "first" t)))
360
361 (defcustom gnus-auto-select-subject 'unseen-or-unread
362   "*Says what subject to place under point when entering a group.
363
364 This variable can either be the symbols `first' (place point on the
365 first subject), `unread' (place point on the subject line of the first
366 unread article), `best' (place point on the subject line of the
367 highest-scored article), `unseen' (place point on the subject line of
368 the first unseen article), `unseen-or-unread' (place point on the subject
369 line of the first unseen article or, if all articles have been seen, on the
370 subject line of the first unread article), or a function to be called to
371 place point on some subject line."
372   :version "24.1"
373   :group 'gnus-group-select
374   :type '(choice (const best)
375                  (const unread)
376                  (const first)
377                  (const unseen)
378                  (const unseen-or-unread)
379                  (function :tag "Function to call")))
380
381 (defcustom gnus-auto-select-next t
382   "*If non-nil, offer to go to the next group from the end of the previous.
383 If the value is t and the next newsgroup is empty, Gnus will exit
384 summary mode and go back to group mode.  If the value is neither nil
385 nor t, Gnus will select the following unread newsgroup.  In
386 particular, if the value is the symbol `quietly', the next unread
387 newsgroup will be selected without any confirmation, and if it is
388 `almost-quietly', the next group will be selected without any
389 confirmation if you are located on the last article in the group.
390 Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
391 will go to the next group without confirmation."
392   :group 'gnus-summary-maneuvering
393   :type '(choice (const :tag "off" nil)
394                  (const quietly)
395                  (const almost-quietly)
396                  (const slightly-quietly)
397                  (sexp :menu-tag "on" t)))
398
399 (defcustom gnus-auto-select-same nil
400   "*If non-nil, select the next article with the same subject.
401 If there are no more articles with the same subject, go to
402 the first unread article."
403   :group 'gnus-summary-maneuvering
404   :type 'boolean)
405
406 (defcustom gnus-auto-select-on-ephemeral-exit 'next-noselect
407   "What article should be selected after exiting an ephemeral group.
408 Valid values include:
409
410 `next'
411   Select the next article.
412 `next-unread'
413   Select the next unread article.
414 `next-noselect'
415   Move the cursor to the next article.  This is the default.
416 `next-unread-noselect'
417   Move the cursor to the next unread article.
418
419 If it has any other value or there is no next (unread) article, the
420 article selected before entering to the ephemeral group will appear."
421   :version "23.1" ;; No Gnus
422   :group 'gnus-summary-maneuvering
423   :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
424                  (const next) (const next-unread)
425                  (const next-noselect) (const next-unread-noselect)
426                  (sexp :tag "other" :value nil)))
427
428 (defcustom gnus-auto-goto-ignores 'unfetched
429   "*Says how to handle unfetched articles when maneuvering.
430
431 This variable can either be the symbols nil (maneuver to any
432 article), `undownloaded' (maneuvering while unplugged ignores articles
433 that have not been fetched), `always-undownloaded' (maneuvering always
434 ignores articles that have not been fetched), `unfetched' (maneuvering
435 ignores articles whose headers have not been fetched).
436
437 NOTE: The list of unfetched articles will always be nil when plugged
438 and, when unplugged, a subset of the undownloaded article list."
439   :version "22.1"
440   :group 'gnus-summary-maneuvering
441   :type '(choice (const :tag "None" nil)
442                  (const :tag "Undownloaded when unplugged" undownloaded)
443                  (const :tag "Undownloaded" always-undownloaded)
444                  (const :tag "Unfetched" unfetched)))
445
446 (defcustom gnus-summary-check-current nil
447   "*If non-nil, consider the current article when moving.
448 The \"unread\" movement commands will stay on the same line if the
449 current article is unread."
450   :group 'gnus-summary-maneuvering
451   :type 'boolean)
452
453 (defcustom gnus-auto-center-summary 2
454   "*If non-nil, always center the current summary buffer.
455 In particular, if `vertical' do only vertical recentering.  If non-nil
456 and non-`vertical', do both horizontal and vertical recentering."
457   :group 'gnus-summary-maneuvering
458   :type '(choice (const :tag "none" nil)
459                  (const vertical)
460                  (integer :tag "height")
461                  (sexp :menu-tag "both" t)))
462
463 (defcustom gnus-auto-center-group t
464   "If non-nil, always center the group buffer."
465   :group 'gnus-summary-maneuvering
466   :type 'boolean)
467
468 (defcustom gnus-show-all-headers nil
469   "*If non-nil, don't hide any headers."
470   :group 'gnus-article-hiding
471   :group 'gnus-article-headers
472   :type 'boolean)
473
474 (defcustom gnus-summary-ignore-duplicates nil
475   "*If non-nil, ignore articles with identical Message-ID headers."
476   :group 'gnus-summary
477   :type 'boolean)
478
479 (defcustom gnus-single-article-buffer nil
480   "*If non-nil, display all articles in the same buffer.
481 If nil, each group will get its own article buffer."
482   :version "24.1"
483   :group 'gnus-article-various
484   :type 'boolean)
485
486 (defcustom gnus-widen-article-window nil
487   "If non-nil, selecting the article buffer will display only the article buffer."
488   :version "24.1"
489   :group 'gnus-article-various
490   :type 'boolean)
491
492 (defcustom gnus-break-pages t
493   "*If non-nil, do page breaking on articles.
494 The page delimiter is specified by the `gnus-page-delimiter'
495 variable."
496   :group 'gnus-article-various
497   :type 'boolean)
498
499 (defcustom gnus-move-split-methods nil
500   "*Variable used to suggest where articles are to be moved to.
501 It uses the same syntax as the `gnus-split-methods' variable.
502 However, whereas `gnus-split-methods' specifies file names as targets,
503 this variable specifies group names."
504   :group 'gnus-summary-mail
505   :type '(repeat (choice (list :value (fun) function)
506                          (cons :value ("" "") regexp (repeat string))
507                          (sexp :value nil))))
508
509 (defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
510   "Function used to compute default prefix for article move/copy/etc prompts.
511 The function should take one argument, a group name, and return a
512 string with the suggested prefix."
513   :group 'gnus-summary-mail
514   :type 'function)
515
516 ;; FIXME: Although the custom type is `character' for the following variables,
517 ;; using multibyte characters (Latin-1, UTF-8) doesn't work.  -- rs
518
519 (defcustom gnus-unread-mark ?           ;Whitespace
520   "*Mark used for unread articles."
521   :group 'gnus-summary-marks
522   :type 'character)
523
524 (defcustom gnus-ticked-mark ?!
525   "*Mark used for ticked articles."
526   :group 'gnus-summary-marks
527   :type 'character)
528
529 (defcustom gnus-dormant-mark ??
530   "*Mark used for dormant articles."
531   :group 'gnus-summary-marks
532   :type 'character)
533
534 (defcustom gnus-del-mark ?r
535   "*Mark used for del'd articles."
536   :group 'gnus-summary-marks
537   :type 'character)
538
539 (defcustom gnus-read-mark ?R
540   "*Mark used for read articles."
541   :group 'gnus-summary-marks
542   :type 'character)
543
544 (defcustom gnus-expirable-mark ?E
545   "*Mark used for expirable articles."
546   :group 'gnus-summary-marks
547   :type 'character)
548
549 (defcustom gnus-killed-mark ?K
550   "*Mark used for killed articles."
551   :group 'gnus-summary-marks
552   :type 'character)
553
554 (defcustom gnus-spam-mark ?$
555   "*Mark used for spam articles."
556   :version "22.1"
557   :group 'gnus-summary-marks
558   :type 'character)
559
560 (defcustom gnus-kill-file-mark ?X
561   "*Mark used for articles killed by kill files."
562   :group 'gnus-summary-marks
563   :type 'character)
564
565 (defcustom gnus-low-score-mark ?Y
566   "*Mark used for articles with a low score."
567   :group 'gnus-summary-marks
568   :type 'character)
569
570 (defcustom gnus-catchup-mark ?C
571   "*Mark used for articles that are caught up."
572   :group 'gnus-summary-marks
573   :type 'character)
574
575 (defcustom gnus-replied-mark ?A
576   "*Mark used for articles that have been replied to."
577   :group 'gnus-summary-marks
578   :type 'character)
579
580 (defcustom gnus-forwarded-mark ?F
581   "*Mark used for articles that have been forwarded."