1 ;;; gnus-sum.el --- summary mode commands for Gnus
2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
3 ;; Free Software Foundation, Inc.
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
8 ;; This file is part of GNU Emacs.
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)
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.
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.
31 (defvar tool-bar-map))
43 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
44 (autoload 'gnus-cache-write-active "gnus-cache")
45 (autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
46 (autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
47 (autoload 'gnus-pick-line-number "gnus-salt" nil t)
48 (autoload 'mm-uu-dissect "mm-uu")
49 (autoload 'gnus-article-outlook-deuglify-article "deuglify"
50 "Deuglify broken Outlook (Express) articles and redisplay."
52 (autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
53 (autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
54 (autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
56 (defcustom gnus-kill-summary-on-exit t
57 "*If non-nil, kill the summary buffer when you exit from it.
58 If nil, the summary will become a \"*Dead Summary*\" buffer, and
59 it will be killed sometime later."
60 :group 'gnus-summary-exit
63 (defcustom gnus-fetch-old-headers nil
64 "*Non-nil means that Gnus will try to build threads by grabbing old headers.
65 If an unread article in the group refers to an older, already read (or
66 just marked as read) article, the old article will not normally be
67 displayed in the Summary buffer. If this variable is non-nil, Gnus
68 will attempt to grab the headers to the old articles, and thereby
69 build complete threads. If it has the value `some', only enough
70 headers to connect otherwise loose threads will be displayed. This
71 variable can also be a number. In that case, no more than that number
72 of old headers will be fetched. If it has the value `invisible', all
73 old headers will be fetched, but none will be displayed.
75 The server has to support NOV for any of this to work."
77 :type '(choice (const :tag "off" nil)
80 (sexp :menu-tag "other" t)))
82 (defcustom gnus-refer-thread-limit 200
83 "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
84 If t, fetch all the available old headers."
87 (sexp :menu-tag "other" t)))
89 (defcustom gnus-summary-make-false-root 'adopt
90 "*nil means that Gnus won't gather loose threads.
91 If the root of a thread has expired or been read in a previous
92 session, the information necessary to build a complete thread has been
93 lost. Instead of having many small sub-threads from this original thread
94 scattered all over the summary buffer, Gnus can gather them.
96 If non-nil, Gnus will try to gather all loose sub-threads from an
97 original thread into one large thread.
99 If this variable is non-nil, it should be one of `none', `adopt',
102 If this variable is `none', Gnus will not make a false root, but just
103 present the sub-threads after another.
104 If this variable is `dummy', Gnus will create a dummy root that will
105 have all the sub-threads as children.
106 If this variable is `adopt', Gnus will make one of the \"children\"
107 the parent and mark all the step-children as such.
108 If this variable is `empty', the \"children\" are printed with empty
109 subject fields. (Or rather, they will be printed with a string
110 given by the `gnus-summary-same-subject' variable.)"
112 :type '(choice (const :tag "off" nil)
118 (defcustom gnus-summary-make-false-root-always nil
119 "Always make a false dummy root."
123 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
124 "*A regexp to match subjects to be excluded from loose thread gathering.
125 As loose thread gathering is done on subjects only, that means that
126 there can be many false gatherings performed. By rooting out certain
127 common subjects, gathering might become saner."
131 (defcustom gnus-summary-gather-subject-limit nil
132 "*Maximum length of subject comparisons when gathering loose threads.
133 Use nil to compare full subjects. Setting this variable to a low
134 number will help gather threads that have been corrupted by
135 newsreaders chopping off subject lines, but it might also mean that
136 unrelated articles that have subject that happen to begin with the
137 same few characters will be incorrectly gathered.
139 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
142 :type '(choice (const :tag "off" nil)
144 (sexp :menu-tag "on" t)))
146 (defcustom gnus-simplify-subject-functions nil
147 "List of functions taking a string argument that simplify subjects.
148 The functions are applied recursively.
150 Useful functions to put in this list include:
151 `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
152 `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
154 :type '(repeat function))
156 (defcustom gnus-simplify-ignored-prefixes nil
157 "*Remove matches for this regexp from subject lines when simplifying fuzzily."
159 :type '(choice (const :tag "off" nil)
162 (defcustom gnus-build-sparse-threads nil
163 "*If non-nil, fill in the gaps in threads.
164 If `some', only fill in the gaps that are needed to tie loose threads
165 together. If `more', fill in all leaf nodes that Gnus can find. If
166 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
168 :type '(choice (const :tag "off" nil)
171 (sexp :menu-tag "all" t)))
173 (defcustom gnus-summary-thread-gathering-function
174 'gnus-gather-threads-by-subject
175 "*Function used for gathering loose threads.
176 There are two pre-defined functions: `gnus-gather-threads-by-subject',
177 which only takes Subjects into consideration; and
178 `gnus-gather-threads-by-references', which compared the References
179 headers of the articles to find matches."
181 :type '(radio (function-item gnus-gather-threads-by-subject)
182 (function-item gnus-gather-threads-by-references)
183 (function :tag "other")))
185 (defcustom gnus-summary-same-subject ""
186 "*String indicating that the current article has the same subject as the previous.
187 This variable will only be used if the value of
188 `gnus-summary-make-false-root' is `empty'."
189 :group 'gnus-summary-format
192 (defcustom gnus-summary-goto-unread t
193 "*If t, many commands will go to the next unread article.
194 This applies to marking commands as well as other commands that
195 \"naturally\" select the next article, like, for instance, `SPC' at
196 the end of an article.
198 If nil, the marking commands do NOT go to the next unread article
199 \(they go to the next article instead). If `never', commands that
200 usually go to the next unread article, will go to the next article,
201 whether it is read or not."
202 :group 'gnus-summary-marks
203 :link '(custom-manual "(gnus)Setting Marks")
204 :type '(choice (const :tag "off" nil)
206 (sexp :menu-tag "on" t)))
208 (defcustom gnus-summary-default-score 0
209 "*Default article score level.
210 All scores generated by the score files will be added to this score.
211 If this variable is nil, scoring will be disabled."
212 :group 'gnus-score-default
213 :type '(choice (const :tag "disable")
216 (defcustom gnus-summary-default-high-score 0
217 "*Default threshold for a high scored article.
218 An article will be highlighted as high scored if its score is greater
220 :group 'gnus-score-default
223 (defcustom gnus-summary-default-low-score 0
224 "*Default threshold for a low scored article.
225 An article will be highlighted as low scored if its score is smaller
227 :group 'gnus-score-default
230 (defcustom gnus-summary-zcore-fuzz 0
231 "*Fuzziness factor for the zcore in the summary buffer.
232 Articles with scores closer than this to `gnus-summary-default-score'
234 :group 'gnus-summary-format
237 (defcustom gnus-simplify-subject-fuzzy-regexp nil
238 "*Strings to be removed when doing fuzzy matches.
239 This can either be a regular expression or list of regular expressions
240 that will be removed from subject strings if fuzzy subject
241 simplification is selected."
243 :type '(repeat regexp))
245 (defcustom gnus-show-threads t
246 "*If non-nil, display threads in summary mode."
250 (defcustom gnus-thread-hide-subtree nil
251 "*If non-nil, hide all threads initially.
252 This can be a predicate specifier which says which threads to hide.
253 If threads are hidden, you have to run the command
254 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
255 to expose hidden threads."
257 :type '(radio (sexp :format "Non-nil\n"
258 :match (lambda (widget value)
259 (not (or (consp value) (functionp value))))
262 (sexp :tag "Predicate specifier" :size 0)))
264 (defcustom gnus-thread-hide-killed t
265 "*If non-nil, hide killed threads automatically."
269 (defcustom gnus-thread-ignore-subject t
270 "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
271 If nil, articles that have different subjects from their parents will
272 start separate threads."
276 (defcustom gnus-thread-operation-ignore-subject t
277 "*If non-nil, subjects will be ignored when doing thread commands.
278 This affects commands like `gnus-summary-kill-thread' and
279 `gnus-summary-lower-thread'.
281 If this variable is nil, articles in the same thread with different
282 subjects will not be included in the operation in question. If this
283 variable is `fuzzy', only articles that have subjects that are fuzzily
284 equal will be included."
286 :type '(choice (const :tag "off" nil)
290 (defcustom gnus-thread-indent-level 4
291 "*Number that says how much each sub-thread should be indented."
295 (defcustom gnus-auto-extend-newsgroup t
296 "*If non-nil, extend newsgroup forward and backward when requested."
297 :group 'gnus-summary-choose
300 (defcustom gnus-auto-select-first t
301 "*If non-nil, select the article under point.
302 Which article this is is controlled by the `gnus-auto-select-subject'
305 If you want to prevent automatic selection of articles in some
306 newsgroups, set the variable to nil in `gnus-select-group-hook'."
307 :group 'gnus-group-select
308 :type '(choice (const :tag "none" nil)
309 (sexp :menu-tag "first" t)))
311 (defcustom gnus-auto-select-subject 'unread
312 "*Says what subject to place under point when entering a group.
314 This variable can either be the symbols `first' (place point on the
315 first subject), `unread' (place point on the subject line of the first
316 unread article), `best' (place point on the subject line of the
317 higest-scored article), `unseen' (place point on the subject line of
318 the first unseen article), 'unseen-or-unread' (place point on the subject
319 line of the first unseen article or, if all article have been seen, on the
320 subject line of the first unread article), or a function to be called to
321 place point on some subject line."
322 :group 'gnus-group-select
323 :type '(choice (const best)
327 (const unseen-or-unread)))
329 (defcustom gnus-auto-select-next t
330 "*If non-nil, offer to go to the next group from the end of the previous.
331 If the value is t and the next newsgroup is empty, Gnus will exit
332 summary mode and go back to group mode. If the value is neither nil
333 nor t, Gnus will select the following unread newsgroup. In
334 particular, if the value is the symbol `quietly', the next unread
335 newsgroup will be selected without any confirmation, and if it is
336 `almost-quietly', the next group will be selected without any
337 confirmation if you are located on the last article in the group.
338 Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
339 will go to the next group without confirmation."
340 :group 'gnus-summary-maneuvering
341 :type '(choice (const :tag "off" nil)
343 (const almost-quietly)
344 (const slightly-quietly)
345 (sexp :menu-tag "on" t)))
347 (defcustom gnus-auto-select-same nil
348 "*If non-nil, select the next article with the same subject.
349 If there are no more articles with the same subject, go to
350 the first unread article."
351 :group 'gnus-summary-maneuvering
354 (defcustom gnus-auto-goto-ignores 'unfetched
355 "*Says how to handle unfetched articles when maneuvering.
357 This variable can either be the symbols nil (maneuver to any
358 article), `undownloaded' (maneuvering while unplugged ignores articles
359 that have not been fetched), `always-undownloaded' (maneuvering always
360 ignores articles that have not been fetched), `unfetched' (maneuvering
361 ignores articles whose headers have not been fetched).
363 NOTE: The list of unfetched articles will always be nil when plugged
364 and, when unplugged, a subset of the undownloaded article list."
365 :group 'gnus-summary-maneuvering
366 :type '(choice (const :tag "None" nil)
367 (const :tag "Undownloaded when unplugged" undownloaded)
368 (const :tag "Undownloaded" always-undownloaded)
369 (const :tag "Unfetched" unfetched)))
371 (defcustom gnus-summary-check-current nil
372 "*If non-nil, consider the current article when moving.
373 The \"unread\" movement commands will stay on the same line if the
374 current article is unread."
375 :group 'gnus-summary-maneuvering
378 (defcustom gnus-auto-center-summary t
379 "*If non-nil, always center the current summary buffer.
380 In particular, if `vertical' do only vertical recentering. If non-nil
381 and non-`vertical', do both horizontal and vertical recentering."
382 :group 'gnus-summary-maneuvering
383 :type '(choice (const :tag "none" nil)
385 (integer :tag "height")
386 (sexp :menu-tag "both" t)))
388 (defvar gnus-auto-center-group t
389 "*If non-nil, always center the group buffer.")
391 (defcustom gnus-show-all-headers nil
392 "*If non-nil, don't hide any headers."
393 :group 'gnus-article-hiding
394 :group 'gnus-article-headers
397 (defcustom gnus-summary-ignore-duplicates nil
398 "*If non-nil, ignore articles with identical Message-ID headers."
402 (defcustom gnus-single-article-buffer t
403 "*If non-nil, display all articles in the same buffer.
404 If nil, each group will get its own article buffer."
405 :group 'gnus-article-various
408 (defcustom gnus-break-pages t
409 "*If non-nil, do page breaking on articles.
410 The page delimiter is specified by the `gnus-page-delimiter'
412 :group 'gnus-article-various
415 (defcustom gnus-move-split-methods nil
416 "*Variable used to suggest where articles are to be moved to.
417 It uses the same syntax as the `gnus-split-methods' variable.
418 However, whereas `gnus-split-methods' specifies file names as targets,
419 this variable specifies group names."
420 :group 'gnus-summary-mail
421 :type '(repeat (choice (list :value (fun) function)
422 (cons :value ("" "") regexp (repeat string))
425 (defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
426 "Function used to compute default prefix for article move/copy/etc prompts.
427 The function should take one argument, a group name, and return a
428 string with the suggested prefix."
429 :group 'gnus-summary-mail
432 (defcustom gnus-unread-mark ? ;Whitespace
433 "*Mark used for unread articles."
434 :group 'gnus-summary-marks
437 (defcustom gnus-ticked-mark ?!
438 "*Mark used for ticked articles."
439 :group 'gnus-summary-marks
442 (defcustom gnus-dormant-mark ??
443 "*Mark used for dormant articles."
444 :group 'gnus-summary-marks
447 (defcustom gnus-del-mark ?r
448 "*Mark used for del'd articles."
449 :group 'gnus-summary-marks
452 (defcustom gnus-read-mark ?R
453 "*Mark used for read articles."
454 :group 'gnus-summary-marks
457 (defcustom gnus-expirable-mark ?E
458 "*Mark used for expirable articles."
459 :group 'gnus-summary-marks
462 (defcustom gnus-killed-mark ?K
463 "*Mark used for killed articles."
464 :group 'gnus-summary-marks
467 (defcustom gnus-spam-mark ?$
468 "*Mark used for spam articles."
469 :group 'gnus-summary-marks
472 (defcustom gnus-souped-mark ?F
473 "*Mark used for souped articles."
474 :group 'gnus-summary-marks
477 (defcustom gnus-kill-file-mark ?X
478 "*Mark used for articles killed by kill files."
479 :group 'gnus-summary-marks
482 (defcustom gnus-low-score-mark ?Y
483 "*Mark used for articles with a low score."
484 :group 'gnus-summary-marks
487 (defcustom gnus-catchup-mark ?C
488 "*Mark used for articles that are caught up."
489 :group 'gnus-summary-marks
492 (defcustom gnus-replied-mark ?A
493 "*Mark used for articles that have been replied to."
494 :group 'gnus-summary-marks
497 (defcustom gnus-forwarded-mark ?F
498 "*Mark used for articles that have been forwarded."
499 :group 'gnus-summary-marks
502 (defcustom gnus-recent-mark ?N
503 "*Mark used for articles that are recent."
504 :group 'gnus-summary-marks
507 (defcustom gnus-cached-mark ?*
508 "*Mark used for articles that are in the cache."
509 :group 'gnus-summary-marks
512 (defcustom gnus-saved-mark ?S
513 "*Mark used for articles that have been saved."
514 :group 'gnus-summary-marks
517 (defcustom gnus-unseen-mark ?.
518 "*Mark used for articles that haven't been seen."
519 :group 'gnus-summary-marks
522 (defcustom gnus-no-mark ? ;Whitespace
523 "*Mark used for articles that have no other secondary mark."
524 :group 'gnus-summary-marks
527 (defcustom gnus-ancient-mark ?O
528 "*Mark used for ancient articles."
529 :group 'gnus-summary-marks
532 (defcustom gnus-sparse-mark ?Q
533 "*Mark used for sparsely reffed articles."
534 :group 'gnus-summary-marks
537 (defcustom gnus-canceled-mark ?G
538 "*Mark used for canceled articles."
539 :group 'gnus-summary-marks
542 (defcustom gnus-duplicate-mark ?M
543 "*Mark used for duplicate articles."
544 :group 'gnus-summary-marks
547 (defcustom gnus-undownloaded-mark ?-
548 "*Mark used for articles that weren't downloaded."
549 :group 'gnus-summary-marks
552 (defcustom gnus-downloaded-mark ?+
553 "*Mark used for articles that were downloaded."
554 :group 'gnus-summary-marks
557 (defcustom gnus-downloadable-mark ?%
558 "*Mark used for articles that are to be downloaded."
559 :group 'gnus-summary-marks
562 (defcustom gnus-unsendable-mark ?=
563 "*Mark used for articles that won't be sent."
564 :group 'gnus-summary-marks
567 (defcustom gnus-score-over-mark ?+
568 "*Score mark used for articles with high scores."
569 :group 'gnus-summary-marks
572 (defcustom gnus-score-below-mark ?-
573 "*Score mark used for articles with low scores."
574 :group 'gnus-summary-marks
577 (defcustom gnus-empty-thread-mark ? ;Whitespace
578 "*There is no thread under the article."
579 :group 'gnus-summary-marks
582 (defcustom gnus-not-empty-thread-mark ?=
583 "*There is a thread under the article."
584 :group 'gnus-summary-marks
587 (defcustom gnus-view-pseudo-asynchronously nil
588 "*If non-nil, Gnus will view pseudo-articles asynchronously."
589 :group 'gnus-extract-view
592 (defcustom gnus-auto-expirable-marks
593 (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
594 gnus-low-score-mark gnus-ancient-mark gnus-read-mark
595 gnus-souped-mark gnus-duplicate-mark)
596 "*The list of marks converted into expiration if a group is auto-expirable."
599 :type '(repeat character))
601 (defcustom gnus-inhibit-user-auto-expire t
602 "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
607 (defcustom gnus-view-pseudos nil
608 "*If `automatic', pseudo-articles will be viewed automatically.
609 If `not-confirm', pseudos will be viewed automatically, and the user
610 will not be asked to confirm the command."
611 :group 'gnus-extract-view
612 :type '(choice (const :tag "off" nil)
614 (const not-confirm)))
616 (defcustom gnus-view-pseudos-separately t
617 "*If non-nil, one pseudo-article will be created for each file to be viewed.
618 If nil, all files that use the same viewing command will be given as a
619 list of parameters to that command."
620 :group 'gnus-extract-view
623 (defcustom gnus-insert-pseudo-articles t
624 "*If non-nil, insert pseudo-articles when decoding articles."
625 :group 'gnus-extract-view
628 (defcustom gnus-summary-dummy-line-format
630 "*The format specification for the dummy roots in the summary buffer.
631 It works along the same lines as a normal formatting string,
632 with some simple extensions.
636 General format specifiers can also be used.
637 See `(gnus)Formatting Variables'."
638 :link '(custom-manual "(gnus)Formatting Variables")
639 :group 'gnus-threading
642 (defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
643 "*The format specification for the summary mode line.
644 It works along the same lines as a normal formatting string,
645 with some simple extensions:
648 %p Unprefixed group name
649 %A Current article number
650 %z Current article score