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