(message-tool-bar-map): Add preview.
[gnus] / lisp / gnus-sum.el
1 ;;; gnus-sum.el --- summary mode commands for Gnus
2 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
3 ;;        Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; Keywords: news
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 (eval-when-compile (require 'cl))
30
31 (require 'gnus)
32 (require 'gnus-group)
33 (require 'gnus-spec)
34 (require 'gnus-range)
35 (require 'gnus-int)
36 (require 'gnus-undo)
37 (require 'gnus-util)
38 (require 'mm-decode)
39 (require 'nnoo)
40
41 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
42 (autoload 'gnus-cache-write-active "gnus-cache")
43 (autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
44 (autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
45 (autoload 'mm-uu-dissect "mm-uu")
46 (autoload 'gnus-article-outlook-deuglify-article "deuglify"
47   "Deuglify broken Outlook (Express) articles and redisplay."
48   t)
49
50 (defcustom gnus-kill-summary-on-exit t
51   "*If non-nil, kill the summary buffer when you exit from it.
52 If nil, the summary will become a \"*Dead Summary*\" buffer, and
53 it will be killed sometime later."
54   :group 'gnus-summary-exit
55   :type 'boolean)
56
57 (defcustom gnus-fetch-old-headers nil
58   "*Non-nil means that Gnus will try to build threads by grabbing old headers.
59 If an unread article in the group refers to an older, already read (or
60 just marked as read) article, the old article will not normally be
61 displayed in the Summary buffer.  If this variable is non-nil, Gnus
62 will attempt to grab the headers to the old articles, and thereby
63 build complete threads.  If it has the value `some', only enough
64 headers to connect otherwise loose threads will be displayed.  This
65 variable can also be a number.  In that case, no more than that number
66 of old headers will be fetched.  If it has the value `invisible', all
67 old headers will be fetched, but none will be displayed.
68
69 The server has to support NOV for any of this to work."
70   :group 'gnus-thread
71   :type '(choice (const :tag "off" nil)
72                  (const some)
73                  number
74                  (sexp :menu-tag "other" t)))
75
76 (defcustom gnus-refer-thread-limit 200
77   "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
78 If t, fetch all the available old headers."
79   :group 'gnus-thread
80   :type '(choice number
81                  (sexp :menu-tag "other" t)))
82
83 (defcustom gnus-summary-make-false-root 'adopt
84   "*nil means that Gnus won't gather loose threads.
85 If the root of a thread has expired or been read in a previous
86 session, the information necessary to build a complete thread has been
87 lost.  Instead of having many small sub-threads from this original thread
88 scattered all over the summary buffer, Gnus can gather them.
89
90 If non-nil, Gnus will try to gather all loose sub-threads from an
91 original thread into one large thread.
92
93 If this variable is non-nil, it should be one of `none', `adopt',
94 `dummy' or `empty'.
95
96 If this variable is `none', Gnus will not make a false root, but just
97 present the sub-threads after another.
98 If this variable is `dummy', Gnus will create a dummy root that will
99 have all the sub-threads as children.
100 If this variable is `adopt', Gnus will make one of the \"children\"
101 the parent and mark all the step-children as such.
102 If this variable is `empty', the \"children\" are printed with empty
103 subject fields.  (Or rather, they will be printed with a string
104 given by the `gnus-summary-same-subject' variable.)"
105   :group 'gnus-thread
106   :type '(choice (const :tag "off" nil)
107                  (const none)
108                  (const dummy)
109                  (const adopt)
110                  (const empty)))
111
112 (defcustom gnus-summary-make-false-root-always t
113   "Always make a false dummy root."
114   :group 'gnus-thread
115   :type 'boolean)
116
117 (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
118   "*A regexp to match subjects to be excluded from loose thread gathering.
119 As loose thread gathering is done on subjects only, that means that
120 there can be many false gatherings performed.  By rooting out certain
121 common subjects, gathering might become saner."
122   :group 'gnus-thread
123   :type 'regexp)
124
125 (defcustom gnus-summary-gather-subject-limit nil
126   "*Maximum length of subject comparisons when gathering loose threads.
127 Use nil to compare full subjects.  Setting this variable to a low
128 number will help gather threads that have been corrupted by
129 newsreaders chopping off subject lines, but it might also mean that
130 unrelated articles that have subject that happen to begin with the
131 same few characters will be incorrectly gathered.
132
133 If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
134 comparing subjects."
135   :group 'gnus-thread
136   :type '(choice (const :tag "off" nil)
137                  (const fuzzy)
138                  (sexp :menu-tag "on" t)))
139
140 (defcustom gnus-simplify-subject-functions nil
141   "List of functions taking a string argument that simplify subjects.
142 The functions are applied recursively.
143
144 Useful functions to put in this list include:
145 `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
146 `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
147   :group 'gnus-thread
148   :type '(repeat function))
149
150 (defcustom gnus-simplify-ignored-prefixes nil
151   "*Remove matches for this regexp from subject lines when simplifying fuzzily."
152   :group 'gnus-thread
153   :type '(choice (const :tag "off" nil)
154                  regexp))
155
156 (defcustom gnus-build-sparse-threads nil
157   "*If non-nil, fill in the gaps in threads.
158 If `some', only fill in the gaps that are needed to tie loose threads
159 together.  If `more', fill in all leaf nodes that Gnus can find.  If
160 non-nil and non-`some', fill in all gaps that Gnus manages to guess."
161   :group 'gnus-thread
162   :type '(choice (const :tag "off" nil)
163                  (const some)
164                  (const more)
165                  (sexp :menu-tag "all" t)))
166
167 (defcustom gnus-summary-thread-gathering-function
168   'gnus-gather-threads-by-subject
169   "*Function used for gathering loose threads.
170 There are two pre-defined functions: `gnus-gather-threads-by-subject',
171 which only takes Subjects into consideration; and
172 `gnus-gather-threads-by-references', which compared the References
173 headers of the articles to find matches."
174   :group 'gnus-thread
175   :type '(radio (function-item gnus-gather-threads-by-subject)
176                 (function-item gnus-gather-threads-by-references)
177                 (function :tag "other")))
178
179 (defcustom gnus-summary-same-subject ""
180   "*String indicating that the current article has the same subject as the previous.
181 This variable will only be used if the value of
182 `gnus-summary-make-false-root' is `empty'."
183   :group 'gnus-summary-format
184   :type 'string)
185
186 (defcustom gnus-summary-goto-unread t
187   "*If t, many commands will go to the next unread article.
188 This applies to marking commands as well as other commands that
189 \"naturally\" select the next article, like, for instance, `SPC' at
190 the end of an article.
191
192 If nil, the marking commands do NOT go to the next unread article
193 \(they go to the next article instead).  If `never', commands that
194 usually go to the next unread article, will go to the next article,
195 whether it is read or not."
196   :group 'gnus-summary-marks
197   :link '(custom-manual "(gnus)Setting Marks")
198   :type '(choice (const :tag "off" nil)
199                  (const never)
200                  (sexp :menu-tag "on" t)))
201
202 (defcustom gnus-summary-default-score 0
203   "*Default article score level.
204 All scores generated by the score files will be added to this score.
205 If this variable is nil, scoring will be disabled."
206   :group 'gnus-score-default
207   :type '(choice (const :tag "disable")
208                  integer))
209
210 (defcustom gnus-summary-default-high-score 0
211   "*Default threshold for a high scored article.
212 An article will be highlighted as high scored if its score is greater
213 than this score."
214   :group 'gnus-score-default
215   :type 'integer)
216
217 (defcustom gnus-summary-default-low-score 0
218   "*Default threshold for a low scored article.
219 An article will be highlighted as low scored if its score is smaller
220 than this score."
221   :group 'gnus-score-default
222   :type 'integer)
223
224 (defcustom gnus-summary-zcore-fuzz 0
225   "*Fuzziness factor for the zcore in the summary buffer.
226 Articles with scores closer than this to `gnus-summary-default-score'
227 will not be marked."
228   :group 'gnus-summary-format
229   :type 'integer)
230
231 (defcustom gnus-simplify-subject-fuzzy-regexp nil
232   "*Strings to be removed when doing fuzzy matches.
233 This can either be a regular expression or list of regular expressions
234 that will be removed from subject strings if fuzzy subject
235 simplification is selected."
236   :group 'gnus-thread
237   :type '(repeat regexp))
238
239 (defcustom gnus-show-threads t
240   "*If non-nil, display threads in summary mode."
241   :group 'gnus-thread
242   :type 'boolean)
243
244 (defcustom gnus-thread-hide-subtree nil
245   "*If non-nil, hide all threads initially.
246 This can be a predicate specifier which says which threads to hide.
247 If threads are hidden, you have to run the command
248 `gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
249 to expose hidden threads."
250   :group 'gnus-thread
251   :type 'boolean)
252
253 (defcustom gnus-thread-hide-killed t
254   "*If non-nil, hide killed threads automatically."
255   :group 'gnus-thread
256   :type 'boolean)
257
258 (defcustom gnus-thread-ignore-subject t
259   "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
260 If nil, articles that have different subjects from their parents will
261 start separate threads."
262   :group 'gnus-thread
263   :type 'boolean)
264
265 (defcustom gnus-thread-operation-ignore-subject t
266   "*If non-nil, subjects will be ignored when doing thread commands.
267 This affects commands like `gnus-summary-kill-thread' and
268 `gnus-summary-lower-thread'.
269
270 If this variable is nil, articles in the same thread with different
271 subjects will not be included in the operation in question.  If this
272 variable is `fuzzy', only articles that have subjects that are fuzzily
273 equal will be included."
274   :group 'gnus-thread
275   :type '(choice (const :tag "off" nil)
276                  (const fuzzy)
277                  (sexp :tag "on" t)))
278
279 (defcustom gnus-thread-indent-level 4
280   "*Number that says how much each sub-thread should be indented."
281   :group 'gnus-thread
282   :type 'integer)
283
284 (defcustom gnus-auto-extend-newsgroup t
285   "*If non-nil, extend newsgroup forward and backward when requested."
286   :group 'gnus-summary-choose
287   :type 'boolean)
288
289 (defcustom gnus-auto-select-first t
290   "*If non-nil, select the article under point.
291 Which article this is is controlled by the `gnus-auto-select-subject'
292 variable.
293
294 If you want to prevent automatic selection of articles in some
295 newsgroups, set the variable to nil in `gnus-select-group-hook'."
296   :group 'gnus-group-select
297   :type '(choice (const :tag "none" nil)
298                  (sexp :menu-tag "first" t)))
299
300 (defcustom gnus-auto-select-subject 'unread
301   "*Says what subject to place under point when entering a group.
302
303 This variable can either be the symbols `first' (place point on the
304 first subject), `unread' (place point on the subject line of the first
305 unread article), `best' (place point on the subject line of the
306 higest-scored article), `unseen' (place point on the subject line of
307 the first unseen article), 'unseen-or-unread' (place point on the subject
308 line of the first unseen article or, if all article have been seen, on the
309 subject line of the first unread article), or a function to be called to
310 place point on some subject line."
311   :group 'gnus-group-select
312   :type '(choice (const best)
313                  (const unread)
314                  (const first)
315                  (const unseen)
316                  (const unseen-or-unread)))
317
318 (defcustom gnus-auto-select-next t
319   "*If non-nil, offer to go to the next group from the end of the previous.
320 If the value is t and the next newsgroup is empty, Gnus will exit
321 summary mode and go back to group mode.  If the value is neither nil
322 nor t, Gnus will select the following unread newsgroup.  In
323 particular, if the value is the symbol `quietly', the next unread
324 newsgroup will be selected without any confirmation, and if it is
325 `almost-quietly', the next group will be selected without any
326 confirmation if you are located on the last article in the group.
327 Finally, if this variable is `slightly-quietly', the `Z n' command
328 will go to the next group without confirmation."
329   :group 'gnus-summary-maneuvering
330   :type '(choice (const :tag "off" nil)
331                  (const quietly)
332                  (const almost-quietly)
333                  (const slightly-quietly)
334                  (sexp :menu-tag "on" t)))
335
336 (defcustom gnus-auto-select-same nil
337   "*If non-nil, select the next article with the same subject.
338 If there are no more articles with the same subject, go to
339 the first unread article."
340   :group 'gnus-summary-maneuvering
341   :type 'boolean)
342
343 (defcustom gnus-summary-check-current nil
344   "*If non-nil, consider the current article when moving.
345 The \"unread\" movement commands will stay on the same line if the
346 current article is unread."
347   :group 'gnus-summary-maneuvering
348   :type 'boolean)
349
350 (defcustom gnus-auto-center-summary t
351   "*If non-nil, always center the current summary buffer.
352 In particular, if `vertical' do only vertical recentering.  If non-nil
353 and non-`vertical', do both horizontal and vertical recentering."
354   :group 'gnus-summary-maneuvering
355   :type '(choice (const :tag "none" nil)
356                  (const vertical)
357                  (integer :tag "height")
358                  (sexp :menu-tag "both" t)))
359
360 (defcustom gnus-show-all-headers nil
361   "*If non-nil, don't hide any headers."
362   :group 'gnus-article-hiding
363   :group 'gnus-article-headers
364   :type 'boolean)
365
366 (defcustom gnus-summary-ignore-duplicates nil
367   "*If non-nil, ignore articles with identical Message-ID headers."
368   :group 'gnus-summary
369   :type 'boolean)
370
371 (defcustom gnus-single-article-buffer t
372   "*If non-nil, display all articles in the same buffer.
373 If nil, each group will get its own article buffer."
374   :group 'gnus-article-various
375   :type 'boolean)
376
377 (defcustom gnus-break-pages t
378   "*If non-nil, do page breaking on articles.
379 The page delimiter is specified by the `gnus-page-delimiter'
380 variable."
381   :group 'gnus-article-various
382   :type 'boolean)
383
384 (defcustom gnus-move-split-methods nil
385   "*Variable used to suggest where articles are to be moved to.
386 It uses the same syntax as the `gnus-split-methods' variable.
387 However, whereas `gnus-split-methods' specifies file names as targets,
388 this variable specifies group names."
389   :group 'gnus-summary-mail
390   :type '(repeat (choice (list :value (fun) function)
391                          (cons :value ("" "") regexp (repeat string))
392                          (sexp :value nil))))
393
394 (defcustom gnus-unread-mark ?           ;Whitespace
395   "*Mark used for unread articles."
396   :group 'gnus-summary-marks
397   :type 'character)
398
399 (defcustom gnus-ticked-mark ?!
400   "*Mark used for ticked articles."
401   :group 'gnus-summary-marks
402   :type 'character)
403
404 (defcustom gnus-dormant-mark ??
405   "*Mark used for dormant articles."
406   :group 'gnus-summary-marks
407   :type 'character)
408
409 (defcustom gnus-del-mark ?r
410   "*Mark used for del'd articles."
411   :group 'gnus-summary-marks
412   :type 'character)
413
414 (defcustom gnus-read-mark ?R
415   "*Mark used for read articles."
416   :group 'gnus-summary-marks
417   :type 'character)
418
419 (defcustom gnus-expirable-mark ?E
420   "*Mark used for expirable articles."
421   :group 'gnus-summary-marks
422   :type 'character)
423
424 (defcustom gnus-killed-mark ?K
425   "*Mark used for killed articles."
426   :group 'gnus-summary-marks
427   :type 'character)
428
429 (defcustom gnus-spam-mark ?H
430   "*Mark used for spam articles."
431   :group 'gnus-summary-marks
432   :type 'character)
433
434 (defcustom gnus-souped-mark ?F
435   "*Mark used for souped articles."
436   :group 'gnus-summary-marks
437   :type 'character)
438
439 (defcustom gnus-kill-file-mark ?X
440   "*Mark used for articles killed by kill files."
441   :group 'gnus-summary-marks
442   :type 'character)
443
444 (defcustom gnus-low-score-mark ?Y
445   "*Mark used for articles with a low score."
446   :group 'gnus-summary-marks
447   :type 'character)
448
449 (defcustom gnus-catchup-mark ?C
450   "*Mark used for articles that are caught up."
451   :group 'gnus-summary-marks
452   :type 'character)
453
454 (defcustom gnus-replied-mark ?A
455   "*Mark used for articles that have been replied to."
456   :group 'gnus-summary-marks
457   :type 'character)
458
459 (defcustom gnus-forwarded-mark ?F
460   "*Mark used for articles that have been forwarded."
461   :group 'gnus-summary-marks
462   :type 'character)
463
464 (defcustom gnus-recent-mark ?N
465   "*Mark used for articles that are recent."
466   :group 'gnus-summary-marks
467   :type 'character)
468
469 (defcustom gnus-cached-mark ?*
470   "*Mark used for articles that are in the cache."
471   :group 'gnus-summary-marks
472   :type 'character)
473
474 (defcustom gnus-saved-mark ?S
475   "*Mark used for articles that have been saved."
476   :group 'gnus-summary-marks
477   :type 'character)
478
479 (defcustom gnus-unseen-mark ?.
480   "*Mark used for articles that haven't been seen."
481   :group 'gnus-summary-marks
482   :type 'character)
483
484 (defcustom gnus-no-mark ?               ;Whitespace
485   "*Mark used for articles that have no other secondary mark."
486   :group 'gnus-summary-marks
487   :type 'character)
488
489 (defcustom gnus-ancient-mark ?O
490   "*Mark used for ancient articles."
491   :group 'gnus-summary-marks
492   :type 'character)
493
494 (defcustom gnus-sparse-mark ?Q
495   "*Mark used for sparsely reffed articles."
496   :group 'gnus-summary-marks
497   :type 'character)
498
499 (defcustom gnus-canceled-mark ?G
500   "*Mark used for canceled articles."
501   :group 'gnus-summary-marks
502   :type 'character)
503
504 (defcustom gnus-duplicate-mark ?M
505   "*Mark used for duplicate articles."
506   :group 'gnus-summary-marks
507   :type 'character)
508
509 (defcustom gnus-undownloaded-mark ?-
510   "*Mark used for articles that weren't downloaded."
511   :group 'gnus-summary-marks
512   :type 'character)
513
514 (defcustom gnus-downloaded-mark ?+
515   "*Mark used for articles that were downloaded."
516   :group 'gnus-summary-marks
517   :type 'character)
518
519 (defcustom gnus-downloadable-mark ?%
520   "*Mark used for articles that are to be downloaded."
521   :group 'gnus-summary-marks
522   :type 'character)
523
524 (defcustom gnus-unsendable-mark ?=
525   "*Mark used for articles that won't be sent."
526   :group 'gnus-summary-marks
527   :type 'character)
528
529 (defcustom gnus-score-over-mark ?+
530   "*Score mark used for articles with high scores."
531   :group 'gnus-summary-marks
532   :type 'character)
533
534 (defcustom gnus-score-below-mark ?-
535   "*Score mark used for articles with low scores."
536   :group 'gnus-summary-marks
537   :type 'character)
538
539 (defcustom gnus-empty-thread-mark ?     ;Whitespace
540   "*There is no thread under the article."
541   :group 'gnus-summary-marks
542   :type 'character)
543
544 (defcustom gnus-not-empty-thread-mark ?=
545   "*There is a thread under the article."
546   :group 'gnus-summary-marks
547   :type 'character)
548
549 (defcustom gnus-view-pseudo-asynchronously nil
550   "*If non-nil, Gnus will view pseudo-articles asynchronously."
551   :group 'gnus-extract-view
552   :type 'boolean)
553
554 (defcustom gnus-auto-expirable-marks
555   (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
556         gnus-low-score-mark gnus-ancient-mark gnus-read-mark
557         gnus-souped-mark gnus-duplicate-mark)
558   "*The list of marks converted into expiration if a group is auto-expirable."
559   :version "21.1"
560   :group 'gnus-summary
561   :type '(repeat character))
562
563 (defcustom gnus-inhibit-user-auto-expire t
564   "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
565   :version "21.1"
566   :group 'gnus-summary
567   :type 'boolean)
568
569 (defcustom gnus-view-pseudos nil
570   "*If `automatic', pseudo-articles will be viewed automatically.
571 If `not-confirm', pseudos will be viewed automatically, and the user
572 will not be asked to confirm the command."
573   :group 'gnus-extract-view
574   :type '(choice (const :tag "off" nil)
575                  (const automatic)
576                  (const not-confirm)))
577
578 (defcustom gnus-view-pseudos-separately t
579   "*If non-nil, one pseudo-article will be created for each file to be viewed.
580 If nil, all files that use the same viewing command will be given as a
581 list of parameters to that command."
582   :group 'gnus-extract-view
583   :type 'boolean)
584
585 (defcustom gnus-insert-pseudo-articles t
586   "*If non-nil, insert pseudo-articles when decoding articles."
587   :group 'gnus-extract-view
588   :type 'boolean)
589
590 (defcustom gnus-summary-dummy-line-format
591   "   %(:                             :%) %S\n"
592   "*The format specification for the dummy roots in the summary buffer.
593 It works along the same lines as a normal formatting string,
594 with some simple extensions.
595
596 %S  The subject
597
598 General format specifiers can also be used.
599 See `(gnus)Formatting Variables'."
600   :link '(custom-manual "(gnus)Formatting Variables")
601   :group 'gnus-threading
602   :type 'string)
603
604 (defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
605   "*The format specification for the summary mode line.
606 It works along the same lines as a normal formatting string,
607 with some simple extensions:
608
609 %G  Group name
610 %p  Unprefixed group name
611 %A  Current article number
612 %z  Current article score
613 %V  Gnus version
614 %U  Number of unread articles in the group
615 %e  Number of unselected articles in the group
616 %Z  A string with unread/unselected article counts
617 %g  Shortish group name
618 %S  Subject of the current article
619 %u  User-defined spec
620 %s  Current score file name
621 %d  Number of dormant articles
622 %r  Number of articles that have been marked as read in this session
623 %E  Number of articles expunged by the score files"
624   :group 'gnus-summary-format
625   :type 'string)
626
627 (defcustom gnus-list-identifiers nil
628   "Regexp that matches list identifiers to be removed from subject.
629 This can also be a list of regexps."
630   :version "21.1"
631   :group 'gnus-summary-format
632   :group 'gnus-article-hiding
633   :type '(choice (const :tag "none" nil)
634                  (regexp :value ".*")
635                  (repeat :value (".*") regexp)))
636
637 (defcustom gnus-summary-mark-below 0
638   "*Mark all articles with a score below this variable as read.
639 This variable is local to each summary buffer and usually set by the
640 score file."
641   :group 'gnus-score-default
642   :type 'integer)
643
644 (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
645   "*List of functions used for sorting articles in the summary buffer.
646
647 Each function takes two articles and returns non-nil if the first
648 article should be sorted before the other.  If you use more than one
649 function, the primary sort function should be the last.  You should
650 probably always include `gnus-article-sort-by-number' in the list of
651 sorting functions -- preferably first.  Also note that sorting by date
652 is often much slower than sorting by number, and the sorting order is
653 very similar.  (Sorting by date means sorting by the time the message
654 was sent, sorting by number means sorting by arrival time.)
655
656 Ready-made functions include `gnus-article-sort-by-number',
657 `gnus-article-sort-by-author', `gnus-article-sort-by-subject',
658 `gnus-article-sort-by-date', `gnus-article-sort-by-random'
659 and `gnus-article-sort-by-score'.
660
661 When threading is turned on, the variable `gnus-thread-sort-functions'
662 controls how articles are sorted."
663   :group 'gnus-summary-sort
664   :type '(repeat (choice (function-item gnus-article-sort-by-number)
665                          (function-item gnus-article-sort-by-author)
666                          (function-item gnus-article-sort-by-subject)
667                          (function-item gnus-article-sort-by-date)
668                          (function-item gnus-article-sort-by-score)
669                          (function-item gnus-article-sort-by-random)
670                          (function :tag "other"))))
671
672 (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
673   "*List of functions used for sorting threads in the summary buffer.
674 By default, threads are sorted by article number.
675
676 Each function takes two threads and returns non-nil if the first
677 thread should be sorted before the other.  If you use more than one
678 function, the primary sort function should be the last.  You should
679 probably always include `gnus-thread-sort-by-number' in the list of
680 sorting functions -- preferably first.  Also note that sorting by date
681 is often much slower than sorting by number, and the sorting order is
682 very similar.  (Sorting by date means sorting by the time the message
683 was sent, sorting by number means sorting by arrival time.)
684
685 Ready-made functions include `gnus-thread-sort-by-number',
686 `gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
687 `gnus-thread-sort-by-date', `gnus-thread-sort-by-score',
688 `gnus-thread-sort-by-most-recent-number',
689 `gnus-thread-sort-by-most-recent-date',
690 `gnus-thread-sort-by-random', and
691 `gnus-thread-sort-by-total-score' (see `gnus-thread-score-function').
692
693 When threading is turned off, the variable
694 `gnus-article-sort-functions' controls how articles are sorted."
695   :group 'gnus-summary-sort
696   :type '(repeat (choice (function-item gnus-thread-sort-by-number)
697                          (function-item gnus-thread-sort-by-author)
698                          (function-item gnus-thread-sort-by-subject)
699                          (function-item gnus-thread-sort-by-date)
700                          (function-item gnus-thread-sort-by-score)
701                          (function-item gnus-thread-sort-by-total-score)
702                          (function-item gnus-thread-sort-by-random)
703                          (function :tag "other"))))
704
705 (defcustom gnus-thread-score-function '+
706   "*Function used for calculating the total score of a thread.
707
708 The function is called with the scores of the article and each
709 subthread and should then return the score of the thread.
710
711 Some functions you can use are `+', `max', or `min'."
712   :group 'gnus-summary-sort
713   :type 'function)
714
715 (defcustom gnus-summary-expunge-below nil
716   "All articles that have a score less than this variable will be expunged.
717 This variable is local to the summary buffers."
718   :group 'gnus-score-default
719   :type '(choice (const :tag "off" nil)
720                  integer))
721
722 (defcustom gnus-thread-expunge-below nil
723   "All threads that have a total score less than this variable will be expunged.
724 See `gnus-thread-score-function' for en explanation of what a
725 \"thread score\" is.
726
727 This variable is local to the summary buffers."
728   :group 'gnus-threading
729   :group 'gnus-score-default
730   :type '(choice (const :tag "off" nil)
731                  integer))
732
733 (defcustom gnus-summary-mode-hook nil
734   "*A hook for Gnus summary mode.
735 This hook is run before any variables are set in the summary buffer."
736   :options '(turn-on-gnus-mailing-list-mode gnus-pick-mode)
737   :group 'gnus-summary-various
738   :type 'hook)
739
740 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
741 (when (featurep 'xemacs)
742   (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
743   (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
744   (add-hook 'gnus-summary-mode-hook
745             'gnus-xmas-switch-horizontal-scrollbar-off))
746
747 (defcustom gnus-summary-menu-hook nil
748   "*Hook run after the creation of the summary mode menu."
749   :group 'gnus-summary-visual
750   :type 'hook)
751
752 (defcustom gnus-summary-exit-hook nil
753   "*A hook called on exit from the summary buffer.
754 It will be called with point in the group buffer."
755   :group 'gnus-summary-exit
756   :type 'hook)
757
758 (defcustom gnus-summary-prepare-hook nil
759   "*A hook called after the summary buffer has been generated.
760 If you want to modify the summary buffer, you can use this hook."
761   :group 'gnus-summary-various
762   :type 'hook)
763
764 (defcustom gnus-summary-prepared-hook nil
765   "*A hook called as the last thing after the summary buffer has been generated."
766   :group 'gnus-summary-various
767   :type 'hook)
768
769 (defcustom gnus-summary-generate-hook nil
770   "*A hook run just before generating the summary buffer.
771 This hook is commonly used to customize threading variables and the
772 like."
773   :group 'gnus-summary-various
774   :type 'hook)
775
776 (defcustom gnus-select-group-hook nil
777   "*A hook called when a newsgroup is selected.
778
779 If you'd like to simplify subjects like the
780 `gnus-summary-next-same-subject' command does, you can use the
781 following hook:
782
783  (add-hook gnus-select-group-hook
784            (lambda ()
785              (mapcar (lambda (header)
786                        (mail-header-set-subject
787                         header
788                         (gnus-simplify-subject
789                          (mail-header-subject header) 're-only)))
790                      gnus-newsgroup-headers)))"
791   :group 'gnus-group-select
792   :type 'hook)
793
794 (defcustom gnus-select-article-hook nil
795   "*A hook called when an article is selected."
796   :group 'gnus-summary-choose
797   :type 'hook)
798
799 (defcustom gnus-visual-mark-article-hook
800   (list 'gnus-highlight-selected-summary)
801   "*Hook run after selecting an article in the summary buffer.
802 It is meant to be used for highlighting the article in some way.  It
803 is not run if `gnus-visual' is nil."
804   :group 'gnus-summary-visual
805   :type 'hook)
806
807 (defcustom gnus-parse-headers-hook nil
808   "*A hook called before parsing the headers."
809   :group 'gnus-various
810   :type 'hook)
811
812 (defcustom gnus-exit-group-hook nil
813   "*A hook called when exiting summary mode.
814 This hook is not called from the non-updating exit commands like `Q'."
815   :group 'gnus-various
816   :type 'hook)
817
818 (defcustom gnus-summary-update-hook
819   (list 'gnus-summary-highlight-line)
820   "*A hook called when a summary line is changed.
821 The hook will not be called if `gnus-visual' is nil.
822
823 The default function `gnus-summary-highlight-line' will
824 highlight the line according to the `gnus-summary-highlight'
825 variable."
826   :group 'gnus-summary-visual
827   :type 'hook)
828
829 (defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
830   "*A hook called when an article is selected for the first time.
831 The hook is intended to mark an article as read (or unread)
832 automatically when it is selected."
833   :group 'gnus-summary-choose
834   :type 'hook)
835
836 (defcustom gnus-group-no-more-groups-hook nil
837   "*A hook run when returning to group mode having no more (unread) groups."
838   :group 'gnus-group-select
839   :type 'hook)
840
841 (defcustom gnus-ps-print-hook nil
842   "*A hook run before ps-printing something from Gnus."
843   :group 'gnus-summary
844   :type 'hook)
845
846 (defcustom gnus-summary-display-arrow
847   (and (fboundp 'display-graphic-p)
848        (display-graphic-p))
849   "*If non-nil, display an arrow highlighting the current article."
850   :version "21.1"
851   :group 'gnus-summary
852   :type 'boolean)
853
854 (defcustom gnus-summary-selected-face 'gnus-summary-selected-face
855   "Face used for highlighting the current article in the summary buffer."
856   :group 'gnus-summary-visual
857   :type 'face)
858
859 (defvar gnus-tmp-downloaded nil)
860
861 (defcustom gnus-summary-highlight
862   '(((eq mark gnus-canceled-mark)
863      . gnus-summary-cancelled-face)
864     ((and uncached (> score default-high))
865      . gnus-summary-high-undownloaded-face)
866     ((and uncached (< score default-low))
867      . gnus-summary-low-undownloaded-face)
868     (uncached
869      . gnus-summary-normal-undownloaded-face)
870     ((and (> score default-high)
871           (or (eq mark gnus-dormant-mark)
872               (eq mark gnus-ticked-mark)))
873      . gnus-summary-high-ticked-face)
874     ((and (< score default-low)
875           (or (eq mark gnus-dormant-mark)
876               (eq mark gnus-ticked-mark)))
877      . gnus-summary-low-ticked-face)
878     ((or (eq mark gnus-dormant-mark)
879          (eq mark gnus-ticked-mark))
880      . gnus-summary-normal-ticked-face)
881     ((and (> score default-high) (eq mark gnus-ancient-mark))
882      . gnus-summary-high-ancient-face)
883     ((and (< score default-low) (eq mark gnus-ancient-mark))
884      . gnus-summary-low-ancient-face)
885     ((eq mark gnus-ancient-mark)
886      . gnus-summary-normal-ancient-face)
887     ((and (> score default-high) (eq mark gnus-unread-mark))
888      . gnus-summary-high-unread-face)
889     ((and (< score default-low) (eq mark gnus-unread-mark))
890      . gnus-summary-low-unread-face)
891     ((eq mark gnus-unread-mark)
892      . gnus-summary-normal-unread-face)
893     ((> score default-high)
894      . gnus-summary-high-read-face)
895     ((< score default-low)
896      . gnus-summary-low-read-face)
897     (t
898      . gnus-summary-normal-read-face))
899   "*Controls the highlighting of summary buffer lines.
900
901 A list of (FORM . FACE) pairs.  When deciding how a a particular
902 summary line should be displayed, each form is evaluated.  The content
903 of the face field after the first true form is used.  You can change
904 how those summary lines are displayed, by editing the face field.
905
906 You can use the following variables in the FORM field.
907
908 score:        The article's score
909 default:      The default article score.
910 default-high: The default score for high scored articles.
911 default-low:  The default score for low scored articles.
912 below:        The score below which articles are automatically marked as read.
913 mark:         The articles mark."
914   :group 'gnus-summary-visual
915   :type '(repeat (cons (sexp :tag "Form" nil)
916                        face)))
917
918 (defcustom gnus-alter-header-function nil
919   "Function called to allow alteration of article header structures.
920 The function is called with one parameter, the article header vector,
921 which it may alter in any way.")
922
923 (defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
924   "Variable that says which function should be used to decode a string with encoded words.")
925
926 (defcustom gnus-extra-headers '(To Newsgroups)
927   "*Extra headers to parse."
928   :version "21.1"
929   :group 'gnus-summary
930   :type '(repeat symbol))
931
932 (defcustom gnus-ignored-from-addresses
933   (and user-mail-address (regexp-quote user-mail-address))
934   "*Regexp of From headers that may be suppressed in favor of To headers."
935   :version "21.1"
936   :group 'gnus-summary
937   :type 'regexp)
938
939 (defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
940   "List of charsets that should be ignored.
941 When these charsets are used in the \"charset\" parameter, the
942 default charset will be used instead."
943   :version "21.1"
944   :type '(repeat symbol)
945   :group 'gnus-charset)
946
947 (gnus-define-group-parameter
948  ignored-charsets
949  :type list
950  :function-document
951  "Return the ignored charsets of GROUP."
952  :variable gnus-group-ignored-charsets-alist
953  :variable-default
954  '(("alt\\.chinese\\.text" iso-8859-1))
955  :variable-document
956  "Alist of regexps (to match group names) and charsets that should be ignored.
957 When these charsets are used in the \"charset\" parameter, the
958 default charset will be used instead."
959  :variable-group gnus-charset
960  :variable-type '(repeat (cons (regexp :tag "Group")
961                                (repeat symbol)))
962  :parameter-type '(choice :tag "Ignored charsets"
963                           :value nil
964                           (repeat (symbol)))
965  :parameter-document       "\
966 List of charsets that should be ignored.
967
968 When these charsets are used in the \"charset\" parameter, the
969 default charset will be used instead.")
970
971 (defcustom gnus-group-highlight-words-alist nil
972   "Alist of group regexps and highlight regexps.
973 This variable uses the same syntax as `gnus-emphasis-alist'."
974   :version "21.1"
975   :type '(repeat (cons (regexp :tag "Group")
976                        (repeat (list (regexp :tag "Highlight regexp")
977                                      (number :tag "Group for entire word" 0)
978                                      (number :tag "Group for displayed part" 0)
979                                      (symbol :tag "Face"
980                                              gnus-emphasis-highlight-words)))))
981   :group 'gnus-summary-visual)
982
983 (defcustom gnus-summary-show-article-charset-alist
984   nil
985   "Alist of number and charset.
986 The article will be shown with the charset corresponding to the
987 numbered argument.
988 For example: ((1 . cn-gb-2312) (2 . big5))."
989   :version "21.1"
990   :type '(repeat (cons (number :tag "Argument" 1)
991                        (symbol :tag "Charset")))
992   :group 'gnus-charset)
993
994 (defcustom gnus-preserve-marks t
995   "Whether marks are preserved when moving, copying and respooling messages."
996   :version "21.1"
997   :type 'boolean
998   :group 'gnus-summary-marks)
999
1000 (defcustom gnus-alter-articles-to-read-function nil
1001   "Function to be called to alter the list of articles to be selected."
1002   :type '(choice (const nil) function)
1003   :group 'gnus-summary)
1004
1005 (defcustom gnus-orphan-score nil
1006   "*All orphans get this score added.  Set in the score file."
1007   :group 'gnus-score-default
1008   :type '(choice (const nil)
1009                  integer))
1010
1011 (defcustom gnus-summary-save-parts-default-mime "image/.*"
1012   "*A regexp to match MIME parts when saving multiple parts of a message
1013 with gnus-summary-save-parts (X m). This regexp will be used by default
1014 when prompting the user for which type of files to save."
1015   :group 'gnus-summary
1016   :type 'regexp)
1017
1018 (defcustom gnus-read-all-available-headers nil
1019   "Whether Gnus should parse all headers made available to it.
1020 This is mostly relevant for slow backends where the user may
1021 wish to widen the summary buffer to include all headers
1022 that were fetched.  Say, for nnultimate groups."
1023   :group 'gnus-summary
1024   :type '(choice boolean regexp))
1025
1026 (defcustom gnus-summary-muttprint-program "muttprint"
1027   "Command (and optional arguments) used to run Muttprint."
1028   :version "21.3"
1029   :group 'gnus-summary
1030   :type 'string)
1031
1032 (defcustom gnus-article-loose-mime nil
1033   "If non-nil, don't require MIME-Version header.
1034 Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
1035 supply the MIME-Version header or deliberately strip it From the mail.
1036 Set it to non-nil, Gnus will treat some articles as MIME even if
1037 the MIME-Version header is missed."
1038   :version "21.3"
1039   :type 'boolean
1040   :group 'gnus-article)
1041
1042 ;;; Internal variables
1043
1044 (defvar gnus-summary-display-cache nil)
1045 (defvar gnus-article-mime-handles nil)
1046 (defvar gnus-article-decoded-p nil)
1047 (defvar gnus-article-charset nil)
1048 (defvar gnus-article-ignored-charsets nil)
1049 (defvar gnus-scores-exclude-files nil)
1050 (defvar gnus-page-broken nil)
1051
1052 (defvar gnus-original-article nil)
1053 (defvar gnus-article-internal-prepare-hook nil)
1054 (defvar gnus-newsgroup-process-stack nil)
1055
1056 (defvar gnus-thread-indent-array nil)
1057 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
1058 (defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
1059   "Function called to sort the articles within a thread after it has been gathered together.")
1060
1061 (defvar gnus-summary-save-parts-type-history nil)
1062 (defvar gnus-summary-save-parts-last-directory nil)
1063
1064 ;; Avoid highlighting in kill files.
1065 (defvar gnus-summary-inhibit-highlight nil)
1066 (defvar gnus-newsgroup-selected-overlay nil)
1067 (defvar gnus-inhibit-limiting nil)
1068 (defvar gnus-newsgroup-adaptive-score-file nil)
1069 (defvar gnus-current-score-file nil)
1070 (defvar gnus-current-move-group nil)
1071 (defvar gnus-current-copy-group nil)
1072 (defvar gnus-current-crosspost-group nil)
1073 (defvar gnus-newsgroup-display nil)
1074
1075 (defvar gnus-newsgroup-dependencies nil)
1076 (defvar gnus-newsgroup-adaptive nil)
1077 (defvar gnus-summary-display-article-function nil)
1078 (defvar gnus-summary-highlight-line-function nil
1079   "Function called after highlighting a summary line.")
1080
1081 (defvar gnus-summary-line-format-alist
1082   `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
1083     (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
1084     (?s gnus-tmp-subject-or-nil ?s)
1085     (?n gnus-tmp-name ?s)
1086     (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
1087         ?s)
1088     (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
1089             gnus-tmp-from) ?s)
1090     (?F gnus-tmp-from ?s)
1091     (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
1092     (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
1093     (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
1094     (?o (gnus-date-iso8601 (mail-header-date gnus-tmp-header)) ?s)
1095     (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
1096     (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
1097     (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
1098     (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
1099     (?L gnus-tmp-lines ?s)
1100     (?O gnus-tmp-downloaded ?c)
1101     (?I gnus-tmp-indentation ?s)
1102     (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
1103     (?R gnus-tmp-replied ?c)
1104     (?\[ gnus-tmp-opening-bracket ?c)
1105     (?\] gnus-tmp-closing-bracket ?c)
1106     (?\> (make-string gnus-tmp-level ? ) ?s)
1107     (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
1108     (?i gnus-tmp-score ?d)
1109     (?z gnus-tmp-score-char ?c)
1110     (?l (bbb-grouplens-score gnus-tmp-header) ?s)
1111     (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
1112     (?U gnus-tmp-unread ?c)
1113     (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header gnus-tmp-from)
1114         ?s)
1115     (?t (gnus-summary-number-of-articles-in-thread
1116          (and (boundp 'thread) (car thread)) gnus-tmp-level)
1117         ?d)
1118     (?e (gnus-summary-number-of-articles-in-thread
1119          (and (boundp 'thread) (car thread)) gnus-tmp-level t)
1120         ?c)
1121     (?u gnus-tmp-user-defined ?s)
1122     (?P (gnus-pick-line-number) ?d)
1123     (?B gnus-tmp-thread-tree-header-string ?s)
1124     (user-date (gnus-user-date
1125                 ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
1126   "An alist of format specifications that can appear in summary lines.
1127 These are paired with what variables they correspond with, along with
1128 the type of the variable (string, integer, character, etc).")
1129
1130 (defvar gnus-summary-dummy-line-format-alist
1131   `((?S gnus-tmp-subject ?s)
1132     (?N gnus-tmp-number ?d)
1133     (?u gnus-tmp-user-defined ?s)))
1134
1135 (defvar gnus-summary-mode-line-format-alist
1136   `((?G gnus-tmp-group-name ?s)
1137     (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
1138     (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
1139     (?A gnus-tmp-article-number ?d)
1140     (?Z gnus-tmp-unread-and-unselected ?s)
1141     (?V gnus-version ?s)
1142     (?U gnus-tmp-unread-and-unticked ?d)
1143     (?S gnus-tmp-subject ?s)
1144     (?e gnus-tmp-unselected ?d)
1145     (?u gnus-tmp-user-defined ?s)
1146     (?d (length gnus-newsgroup-dormant) ?d)
1147     (?t (length gnus-newsgroup-marked) ?d)
1148     (?h (length gnus-newsgroup-spam-marked) ?d)
1149     (?r (length gnus-newsgroup-reads) ?d)
1150     (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
1151     (?E gnus-newsgroup-expunged-tally ?d)
1152     (?s (gnus-current-score-file-nondirectory) ?s)))
1153
1154 (defvar gnus-last-search-regexp nil
1155   "Default regexp for article search command.")
1156
1157 (defvar gnus-last-shell-command nil
1158   "Default shell command on article.")
1159
1160 (defvar gnus-newsgroup-agentized nil
1161   "Locally bound in each summary buffer to indicate whether the server has been agentized.")
1162 (defvar gnus-newsgroup-begin nil)
1163 (defvar gnus-newsgroup-end nil)
1164 (defvar gnus-newsgroup-last-rmail nil)
1165 (defvar gnus-newsgroup-last-mail nil)
1166 (defvar gnus-newsgroup-last-folder nil)
1167 (defvar gnus-newsgroup-last-file nil)
1168 (defvar gnus-newsgroup-auto-expire nil)
1169 (defvar gnus-newsgroup-active nil)
1170
1171 (defvar gnus-newsgroup-data nil)
1172 (defvar gnus-newsgroup-data-reverse nil)
1173 (defvar gnus-newsgroup-limit nil)
1174 (defvar gnus-newsgroup-limits nil)
1175
1176 (defvar gnus-newsgroup-unreads nil
1177   "Sorted list of unread articles in the current newsgroup.")
1178
1179 (defvar gnus-newsgroup-unselected nil
1180   "Sorted list of unselected unread articles in the current newsgroup.")
1181
1182 (defvar gnus-newsgroup-reads nil
1183   "Alist of read articles and article marks in the current newsgroup.")
1184
1185 (defvar gnus-newsgroup-expunged-tally nil)
1186
1187 (defvar gnus-newsgroup-marked nil
1188   "Sorted list of ticked articles in the current newsgroup (a subset of unread art).")
1189
1190 (defvar gnus-newsgroup-spam-marked nil
1191   "List of ranges of articles that have been marked as spam.")
1192
1193 (defvar gnus-newsgroup-killed nil
1194   "List of ranges of articles that have been through the scoring process.")
1195
1196 (defvar gnus-newsgroup-cached nil
1197   "Sorted list of articles that come from the article cache.")
1198
1199 (defvar gnus-newsgroup-saved nil
1200   "List of articles that have been saved.")
1201
1202 (defvar gnus-newsgroup-kill-headers nil)
1203
1204 (defvar gnus-newsgroup-replied nil
1205   "List of articles that have been replied to in the current newsgroup.")
1206
1207 (defvar gnus-newsgroup-forwarded nil
1208   "List of articles that have been forwarded in the current newsgroup.")
1209
1210 (defvar gnus-newsgroup-recent nil
1211   "List of articles that have are recent in the current newsgroup.")
1212
1213 (defvar gnus-newsgroup-expirable nil
1214   "Sorted list of articles in the current newsgroup that can be expired.")
1215
1216 (defvar gnus-newsgroup-processable nil
1217   "List of articles in the current newsgroup that can be processed.")
1218
1219 (defvar gnus-newsgroup-downloadable nil
1220   "Sorted list of articles in the current newsgroup that can be processed.")
1221
1222 (defvar gnus-newsgroup-undownloaded nil
1223   "List of articles in the current newsgroup that haven't been downloaded..")
1224
1225 (defvar gnus-newsgroup-unsendable nil
1226   "List of articles in the current newsgroup that won't be sent.")
1227
1228 (defvar gnus-newsgroup-bookmarks nil
1229   "List of articles in the current newsgroup that have bookmarks.")
1230
1231 (defvar gnus-newsgroup-dormant nil
1232   "Sorted list of dormant articles in the current newsgroup.")
1233
1234 (defvar gnus-newsgroup-unseen nil
1235   "List of unseen articles in the current newsgroup.")
1236
1237 (defvar gnus-newsgroup-seen nil
1238   "Range of seen articles in the current newsgroup.")
1239
1240 (defvar gnus-newsgroup-articles nil
1241   "List of articles in the current newsgroup.")
1242
1243 (defvar gnus-newsgroup-scored nil
1244   "List of scored articles in the current newsgroup.")
1245
1246 (defvar gnus-newsgroup-headers nil
1247   "List of article headers in the current newsgroup.")
1248
1249 (defvar gnus-newsgroup-threads nil)
1250
1251 (defvar gnus-newsgroup-prepared nil
1252   "Whether the current group has been prepared properly.")
1253
1254 (defvar gnus-newsgroup-ancient nil
1255   "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
1256
1257 (defvar gnus-newsgroup-sparse nil)
1258
1259 (defvar gnus-current-article nil)
1260 (defvar gnus-article-current nil)
1261 (defvar gnus-current-headers nil)
1262 (defvar gnus-have-all-headers nil)
1263 (defvar gnus-last-article nil)
1264 (defvar gnus-newsgroup-history nil)
1265 (defvar gnus-newsgroup-charset nil)
1266 (defvar gnus-newsgroup-ephemeral-charset nil)
1267 (defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
1268
1269 (defvar gnus-article-before-search nil)
1270
1271 (defconst gnus-summary-local-variables
1272   '(gnus-newsgroup-name
1273     gnus-newsgroup-begin gnus-newsgroup-end
1274     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
1275     gnus-newsgroup-last-folder gnus-newsgroup-last-file
1276     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
1277     gnus-newsgroup-unselected gnus-newsgroup-marked
1278     gnus-newsgroup-spam-marked
1279     gnus-newsgroup-reads gnus-newsgroup-saved
1280     gnus-newsgroup-replied gnus-newsgroup-forwarded
1281     gnus-newsgroup-recent
1282     gnus-newsgroup-expirable
1283     gnus-newsgroup-processable gnus-newsgroup-killed
1284     gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
1285     gnus-newsgroup-unsendable gnus-newsgroup-unseen
1286     gnus-newsgroup-seen gnus-newsgroup-articles
1287     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
1288     gnus-newsgroup-headers gnus-newsgroup-threads
1289     gnus-newsgroup-prepared gnus-summary-highlight-line-function
1290     gnus-current-article gnus-current-headers gnus-have-all-headers
1291     gnus-last-article gnus-article-internal-prepare-hook
1292     gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1293     gnus-newsgroup-scored gnus-newsgroup-kill-headers
1294     gnus-thread-expunge-below
1295     gnus-score-alist gnus-current-score-file
1296     (gnus-summary-expunge-below . global)
1297     (gnus-summary-mark-below . global)
1298     (gnus-orphan-score . global)
1299     gnus-newsgroup-active gnus-scores-exclude-files
1300     gnus-newsgroup-history gnus-newsgroup-ancient
1301     gnus-newsgroup-sparse gnus-newsgroup-process-stack
1302     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
1303     gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
1304     (gnus-newsgroup-expunged-tally . 0)
1305     gnus-cache-removable-articles gnus-newsgroup-cached
1306     gnus-newsgroup-data gnus-newsgroup-data-reverse
1307     gnus-newsgroup-limit gnus-newsgroup-limits
1308     gnus-newsgroup-charset gnus-newsgroup-display)
1309   "Variables that are buffer-local to the summary buffers.")
1310
1311 (defvar gnus-newsgroup-variables nil
1312   "A list of variables that have separate values in different newsgroups.
1313 A list of newsgroup (summary buffer) local variables, or cons of
1314 variables and their default values (when the default values are not
1315 nil), that should be made global while the summary buffer is active.
1316 These variables can be used to set variables in the group parameters
1317 while still allowing them to affect operations done in other
1318 buffers. For example:
1319
1320 \(setq gnus-newsgroup-variables
1321      '(message-use-followup-to
1322        (gnus-visible-headers .
1323          \"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
1324 ")
1325
1326 ;; Byte-compiler warning.
1327 ;(eval-when-compile (defvar gnus-article-mode-map))
1328 (eval-when-compile
1329   (let ((features (cons 'gnus-sum features)))
1330     (require 'gnus)
1331     (require 'gnus-agent)
1332     (require 'gnus-art)))
1333
1334 ;; MIME stuff.
1335
1336 (defvar gnus-decode-encoded-word-methods
1337   '(mail-decode-encoded-word-string)
1338   "List of methods used to decode encoded words.
1339
1340 This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
1341 is FUNCTION, FUNCTION will be apply to all newsgroups.  If item is a
1342 \(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
1343 whose names match REGEXP.
1344
1345 For example:
1346 \((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
1347  mail-decode-encoded-word-string
1348  (\"chinese\" . rfc1843-decode-string))")
1349
1350 (defvar gnus-decode-encoded-word-methods-cache nil)
1351
1352 (defun gnus-multi-decode-encoded-word-string (string)
1353   "Apply the functions from `gnus-encoded-word-methods' that match."
1354   (unless (and gnus-decode-encoded-word-methods-cache
1355                (eq gnus-newsgroup-name
1356                    (car gnus-decode-encoded-word-methods-cache)))
1357     (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
1358     (mapcar (lambda (x)
1359               (if (symbolp x)
1360                   (nconc gnus-decode-encoded-word-methods-cache (list x))
1361                 (if (and gnus-newsgroup-name
1362                          (string-match (car x) gnus-newsgroup-name))
1363                     (nconc gnus-decode-encoded-word-methods-cache
1364                            (list (cdr x))))))
1365             gnus-decode-encoded-word-methods))
1366   (let ((xlist gnus-decode-encoded-word-methods-cache))
1367     (pop xlist)
1368     (while xlist
1369       (setq string (funcall (pop xlist) string))))
1370   string)
1371
1372 ;; Subject simplification.
1373
1374 (defun gnus-simplify-whitespace (str)
1375   "Remove excessive whitespace from STR."
1376   (let ((mystr str))
1377     ;; Multiple spaces.
1378     (while (string-match "[ \t][ \t]+" mystr)
1379       (setq mystr (concat (substring mystr 0 (match-beginning 0))
1380                           " "
1381                           (substring mystr (match-end 0)))))
1382     ;; Leading spaces.
1383     (when (string-match "^[ \t]+" mystr)
1384       (setq mystr (substring mystr (match-end 0))))
1385     ;; Trailing spaces.
1386     (when (string-match "[ \t]+$" mystr)
1387       (setq mystr (substring mystr 0 (match-beginning 0))))
1388     mystr))
1389
1390 (defun gnus-simplify-all-whitespace (str)
1391   "Remove all whitespace from STR."
1392   (let ((mystr str))
1393     (while (string-match "[ \t\n]+" mystr)
1394       (setq mystr (replace-match "" nil nil mystr)))
1395     mystr))
1396
1397 (defsubst gnus-simplify-subject-re (subject)
1398   "Remove \"Re:\" from subject lines."
1399   (if (string-match message-subject-re-regexp subject)
1400       (substring subject (match-end 0))
1401     subject))
1402
1403 (defun gnus-simplify-subject (subject &optional re-only)
1404   "Remove `Re:' and words in parentheses.
1405 If RE-ONLY is non-nil, strip leading `Re:'s only."
1406   (let ((case-fold-search t))           ;Ignore case.
1407     ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
1408     (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
1409       (setq subject (substring subject (match-end 0))))
1410     ;; Remove uninteresting prefixes.
1411     (when (and (not re-only)
1412                gnus-simplify-ignored-prefixes
1413                (string-match gnus-simplify-ignored-prefixes subject))
1414       (setq subject (substring subject (match-end 0))))
1415     ;; Remove words in parentheses from end.
1416     (unless re-only
1417       (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
1418         (setq subject (substring subject 0 (match-beginning 0)))))
1419     ;; Return subject string.
1420     subject))
1421
1422 ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
1423 ;; all whitespace.
1424 (defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
1425   (goto-char (point-min))
1426   (while (re-search-forward regexp nil t)
1427     (replace-match (or newtext ""))))
1428
1429 (defun gnus-simplify-buffer-fuzzy ()
1430   "Simplify string in the buffer fuzzily.
1431 The string in the accessible portion of the current buffer is simplified.
1432 It is assumed to be a single-line subject.
1433 Whitespace is generally cleaned up, and miscellaneous leading/trailing
1434 matter is removed.  Additional things can be deleted by setting
1435 `gnus-simplify-subject-fuzzy-regexp'."
1436   (let ((case-fold-search t)
1437         (modified-tick))
1438     (gnus-simplify-buffer-fuzzy-step "\t" " ")
1439
1440     (while (not (eq modified-tick (buffer-modified-tick)))
1441       (setq modified-tick (buffer-modified-tick))
1442       (cond
1443        ((listp gnus-simplify-subject-fuzzy-regexp)
1444         (mapcar 'gnus-simplify-buffer-fuzzy-step
1445                 gnus-simplify-subject-fuzzy-regexp))
1446        (gnus-simplify-subject-fuzzy-regexp
1447         (gnus-simplify-buffer-fuzzy-step gnus-simplify-subject-fuzzy-regexp)))
1448       (gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
1449       (gnus-simplify-buffer-fuzzy-step
1450        "^ *\\(re\\|fw\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
1451       (gnus-simplify-buffer-fuzzy-step "^[[].*:\\( .*\\)[]]$" "\\1"))
1452
1453     (gnus-simplify-buffer-fuzzy-step " *[[{(][^()\n]*[]})] *$")
1454     (gnus-simplify-buffer-fuzzy-step "  +" " ")
1455     (gnus-simplify-buffer-fuzzy-step " $")
1456     (gnus-simplify-buffer-fuzzy-step "^ +")))
1457
1458 (defun gnus-simplify-subject-fuzzy (subject)
1459   "Simplify a subject string fuzzily.
1460 See `gnus-simplify-buffer-fuzzy' for details."
1461   (save-excursion
1462     (gnus-set-work-buffer)
1463     (let ((case-fold-search t))
1464       ;; Remove uninteresting prefixes.
1465       (when (and gnus-simplify-ignored-prefixes
1466                  (string-match gnus-simplify-ignored-prefixes subject))
1467         (setq subject (substring subject (match-end 0))))
1468       (insert subject)
1469       (inline (gnus-simplify-buffer-fuzzy))
1470       (buffer-string))))
1471
1472 (defsubst gnus-simplify-subject-fully (subject)
1473   "Simplify a subject string according to gnus-summary-gather-subject-limit."
1474   (cond
1475    (gnus-simplify-subject-functions
1476     (gnus-map-function gnus-simplify-subject-functions subject))
1477    ((null gnus-summary-gather-subject-limit)
1478     (gnus-simplify-subject-re subject))
1479    ((eq gnus-summary-gather-subject-limit 'fuzzy)
1480     (gnus-simplify-subject-fuzzy subject))
1481    ((numberp gnus-summary-gather-subject-limit)
1482     (gnus-limit-string (gnus-simplify-subject-re subject)
1483                        gnus-summary-gather-subject-limit))
1484    (t
1485     subject)))
1486
1487 (defsubst gnus-subject-equal (s1 s2 &optional simple-first)
1488   "Check whether two subjects are equal.
1489 If optional argument simple-first is t, first argument is already
1490 simplified."
1491   (cond
1492    ((null simple-first)
1493     (equal (gnus-simplify-subject-fully s1)
1494            (gnus-simplify-subject-fully s2)))
1495    (t
1496     (equal s1
1497            (gnus-simplify-subject-fully s2)))))
1498
1499 (defun gnus-summary-bubble-group ()
1500   "Increase the score of the current group.
1501 This is a handy function to add to `gnus-summary-exit-hook' to
1502 increase the score of each group you read."
1503   (gnus-group-add-score gnus-newsgroup-name))
1504
1505 \f
1506 ;;;
1507 ;;; Gnus summary mode
1508 ;;;
1509
1510 (put 'gnus-summary-mode 'mode-class 'special)
1511
1512 (defvar gnus-article-commands-menu)
1513
1514 (when t
1515   ;; Non-orthogonal keys
1516
1517   (gnus-define-keys gnus-summary-mode-map
1518     " " gnus-summary-next-page
1519     "\177" gnus-summary-prev-page
1520     [delete] gnus-summary-prev-page
1521     [backspace] gnus-summary-prev-page
1522     "\r" gnus-summary-scroll-up
1523     "\M-\r" gnus-summary-scroll-down
1524     "n" gnus-summary-next-unread-article
1525     "p" gnus-summary-prev-unread-article
1526     "N" gnus-summary-next-article
1527     "P" gnus-summary-prev-article
1528     "\M-\C-n" gnus-summary-next-same-subject
1529     "\M-\C-p" gnus-summary-prev-same-subject
1530     "\M-n" gnus-summary-next-unread-subject
1531     "\M-p" gnus-summary-prev-unread-subject
1532     "." gnus-summary-first-unread-article
1533     "," gnus-summary-best-unread-article
1534     "\M-s" gnus-summary-search-article-forward
1535     "\M-r" gnus-summary-search-article-backward
1536     "<" gnus-summary-beginning-of-article
1537     ">" gnus-summary-end-of-article
1538     "j" gnus-summary-goto-article
1539     "^" gnus-summary-refer-parent-article
1540     "\M-^" gnus-summary-refer-article
1541     "u" gnus-summary-tick-article-forward
1542     "!" gnus-summary-tick-article-forward
1543     "U" gnus-summary-tick-article-backward
1544     "d" gnus-summary-mark-as-read-forward
1545     "D" gnus-summary-mark-as-read-backward
1546     "E" gnus-summary-mark-as-expirable
1547     "\M-u" gnus-summary-clear-mark-forward
1548     "\M-U" gnus-summary-clear-mark-backward
1549     "k" gnus-summary-kill-same-subject-and-select
1550     "\C-k" gnus-summary-kill-same-subject
1551     "\M-\C-k" gnus-summary-kill-thread
1552     "\M-\C-l" gnus-summary-lower-thread
1553     "e" gnus-summary-edit-article
1554     "#" gnus-summary-mark-as-processable
1555     "\M-#" gnus-summary-unmark-as-processable
1556     "\M-\C-t" gnus-summary-toggle-threads
1557     "\M-\C-s" gnus-summary-show-thread
1558     "\M-\C-h" gnus-summary-hide-thread
1559     "\M-\C-f" gnus-summary-next-thread
1560     "\M-\C-b" gnus-summary-prev-thread
1561     [(meta down)] gnus-summary-next-thread
1562     [(meta up)] gnus-summary-prev-thread
1563     "\M-\C-u" gnus-summary-up-thread
1564     "\M-\C-d" gnus-summary-down-thread
1565     "&" gnus-summary-execute-command
1566     "c" gnus-summary-catchup-and-exit
1567     "\C-w" gnus-summary-mark-region-as-read
1568     "\C-t" gnus-summary-toggle-truncation
1569     "?" gnus-summary-mark-as-dormant
1570     "\C-c\M-\C-s" gnus-summary-limit-include-expunged
1571     "\C-c\C-s\C-n" gnus-summary-sort-by-number
1572     "\C-c\C-s\C-l" gnus-summary-sort-by-lines
1573     "\C-c\C-s\C-c" gnus-summary-sort-by-chars
1574     "\C-c\C-s\C-a" gnus-summary-sort-by-author
1575     "\C-c\C-s\C-s" gnus-summary-sort-by-subject
1576     "\C-c\C-s\C-d" gnus-summary-sort-by-date
1577     "\C-c\C-s\C-i" gnus-summary-sort-by-score
1578     "\C-c\C-s\C-o" gnus-summary-sort-by-original
1579     "\C-c\C-s\C-r" gnus-summary-sort-by-random
1580     "=" gnus-summary-expand-window
1581     "\C-x\C-s" gnus-summary-reselect-current-group
1582     "\M-g" gnus-summary-rescan-group
1583     "w" gnus-summary-stop-page-breaking
1584     "\C-c\C-r" gnus-summary-caesar-message
1585     "f" gnus-summary-followup
1586     "F" gnus-summary-followup-with-original
1587     "C" gnus-summary-cancel-article
1588     "r" gnus-summary-reply
1589     "R" gnus-summary-reply-with-original
1590     "\C-c\C-f" gnus-summary-mail-forward
1591     "o" gnus-summary-save-article
1592     "\C-o" gnus-summary-save-article-mail
1593     "|" gnus-summary-pipe-output
1594     "\M-k" gnus-summary-edit-local-kill
1595     "\M-K" gnus-summary-edit-global-kill
1596     ;; "V" gnus-version
1597     "\C-c\C-d" gnus-summary-describe-group
1598     "q" gnus-summary-exit
1599     "Q" gnus-summary-exit-no-update
1600     "\C-c\C-i" gnus-info-find-node
1601     gnus-mouse-2 gnus-mouse-pick-article
1602     "m" gnus-summary-mail-other-window
1603     "a" gnus-summary-post-news
1604     "i" gnus-summary-news-other-window
1605     "x" gnus-summary-limit-to-unread
1606     "s" gnus-summary-isearch-article
1607     "t" gnus-summary-toggle-header
1608     "g" gnus-summary-show-article
1609     "l" gnus-summary-goto-last-article
1610     "\C-c\C-v\C-v" gnus-uu-decode-uu-view
1611     "\C-d" gnus-summary-enter-digest-group
1612     "\M-\C-d" gnus-summary-read-document
1613     "\M-\C-e" gnus-summary-edit-parameters
1614     "\M-\C-a" gnus-summary-customize-parameters
1615     "\C-c\C-b" gnus-bug
1616     "*" gnus-cache-enter-article
1617     "\M-*" gnus-cache-remove-article
1618     "\M-&" gnus-summary-universal-argument
1619     "\C-l" gnus-recenter
1620     "I" gnus-summary-increase-score
1621     "L" gnus-summary-lower-score
1622     "\M-i" gnus-symbolic-argument
1623     "h" gnus-summary-select-article-buffer
1624
1625     "b" gnus-article-view-part
1626     "\M-t" gnus-summary-toggle-display-buttonized
1627
1628     "V" gnus-summary-score-map
1629     "X" gnus-uu-extract-map
1630     "S" gnus-summary-send-map)
1631
1632   ;; Sort of orthogonal keymap
1633   (gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
1634     "t" gnus-summary-tick-article-forward
1635     "!" gnus-summary-tick-article-forward
1636     "d" gnus-summary-mark-as-read-forward
1637     "r" gnus-summary-mark-as-read-forward
1638     "c" gnus-summary-clear-mark-forward
1639     " " gnus-summary-clear-mark-forward
1640     "e" gnus-summary-mark-as-expirable
1641     "x" gnus-summary-mark-as-expirable
1642     "?" gnus-summary-mark-as-dormant
1643     "b" gnus-summary-set-bookmark
1644     "B" gnus-summary-remove-bookmark
1645     "#" gnus-summary-mark-as-processable
1646     "\M-#" gnus-summary-unmark-as-processable
1647     "S" gnus-summary-limit-include-expunged
1648     "C" gnus-summary-catchup
1649     "H" gnus-summary-catchup-to-here
1650     "h" gnus-summary-catchup-from-here
1651     "\C-c" gnus-summary-catchup-all
1652     "k" gnus-summary-kill-same-subject-and-select
1653     "K" gnus-summary-kill-same-subject
1654     "P" gnus-uu-mark-map)
1655
1656   (gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
1657     "c" gnus-summary-clear-above
1658     "u" gnus-summary-tick-above
1659     "m" gnus-summary-mark-above
1660     "k" gnus-summary-kill-below)
1661
1662   (gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
1663     "/" gnus-summary-limit-to-subject
1664     "n" gnus-summary-limit-to-articles
1665     "w" gnus-summary-pop-limit
1666     "s" gnus-summary-limit-to-subject
1667     "a" gnus-summary-limit-to-author
1668     "u" gnus-summary-limit-to-unread
1669     "m" gnus-summary-limit-to-marks
1670     "M" gnus-summary-limit-exclude-marks
1671     "v" gnus-summary-limit-to-score
1672     "*" gnus-summary-limit-include-cached
1673     "D" gnus-summary-limit-include-dormant
1674     "T" gnus-summary-limit-include-thread
1675     "d" gnus-summary-limit-exclude-dormant
1676     "t" gnus-summary-limit-to-age
1677     "." gnus-summary-limit-to-unseen
1678     "x" gnus-summary-limit-to-extra
1679     "p" gnus-summary-limit-to-display-predicate
1680     "E" gnus-summary-limit-include-expunged
1681     "c" gnus-summary-limit-exclude-childless-dormant
1682     "C" gnus-summary-limit-mark-excluded-as-read
1683     "o" gnus-summary-insert-old-articles
1684     "N" gnus-summary-insert-new-articles)
1685
1686   (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
1687     "n" gnus-summary-next-unread-article
1688     "p" gnus-summary-prev-unread-article
1689     "N" gnus-summary-next-article
1690     "P" gnus-summary-prev-article
1691     "\C-n" gnus-summary-next-same-subject
1692     "\C-p" gnus-summary-prev-same-subject
1693     "\M-n" gnus-summary-next-unread-subject
1694     "\M-p" gnus-summary-prev-unread-subject
1695     "f" gnus-summary-first-unread-article
1696     "b" gnus-summary-best-unread-article
1697     "j" gnus-summary-goto-article
1698     "g" gnus-summary-goto-subject
1699     "l" gnus-summary-goto-last-article
1700     "o" gnus-summary-pop-article)
1701
1702   (gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
1703     "k" gnus-summary-kill-thread
1704     "l" gnus-summary-lower-thread
1705     "i" gnus-summary-raise-thread
1706     "T" gnus-summary-toggle-threads
1707     "t" gnus-summary-rethread-current
1708     "^" gnus-summary-reparent-thread
1709     "s" gnus-summary-show-thread
1710     "S" gnus-summary-show-all-threads
1711     "h" gnus-summary-hide-thread
1712     "H" gnus-summary-hide-all-threads
1713     "n" gnus-summary-next-thread
1714     "p" gnus-summary-prev-thread
1715     "u" gnus-summary-up-thread
1716     "o" gnus-summary-top-thread
1717     "d" gnus-summary-down-thread
1718     "#" gnus-uu-mark-thread
1719     "\M-#" gnus-uu-unmark-thread)
1720
1721   (gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
1722     "g" gnus-summary-prepare
1723     "c" gnus-summary-insert-cached-articles
1724     "d" gnus-summary-insert-dormant-articles)
1725
1726   (gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
1727     "c" gnus-summary-catchup-and-exit
1728     "C" gnus-summary-catchup-all-and-exit
1729     "E" gnus-summary-exit-no-update
1730     "Q" gnus-summary-exit
1731     "Z" gnus-summary-exit
1732     "n" gnus-summary-catchup-and-goto-next-group
1733     "R" gnus-summary-reselect-current-group
1734     "G" gnus-summary-rescan-group
1735     "N" gnus-summary-next-group
1736     "s" gnus-summary-save-newsrc
1737     "P" gnus-summary-prev-group)
1738
1739   (gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
1740     " " gnus-summary-next-page
1741     "n" gnus-summary-next-page
1742     "\177" gnus-summary-prev-page
1743     [delete] gnus-summary-prev-page
1744     "p" gnus-summary-prev-page
1745     "\r" gnus-summary-scroll-up
1746     "\M-\r" gnus-summary-scroll-down
1747     "<" gnus-summary-beginning-of-article
1748     ">" gnus-summary-end-of-article
1749     "b" gnus-summary-beginning-of-article
1750     "e" gnus-summary-end-of-article
1751     "^" gnus-summary-refer-parent-article
1752     "r" gnus-summary-refer-parent-article
1753     "D" gnus-summary-enter-digest-group
1754     "R" gnus-summary-refer-references
1755     "T" gnus-summary-refer-thread
1756     "g" gnus-summary-show-article
1757     "s" gnus-summary-isearch-article
1758     "P" gnus-summary-print-article
1759     "M" gnus-mailing-list-insinuate
1760     "t" gnus-article-babel)
1761
1762   (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
1763     "b" gnus-article-add-buttons
1764     "B" gnus-article-add-buttons-to-head
1765     "o" gnus-article-treat-overstrike
1766     "e" gnus-article-emphasize
1767     "w" gnus-article-fill-cited-article
1768     "Q" gnus-article-fill-long-lines
1769     "C" gnus-article-capitalize-sentences
1770     "c" gnus-article-remove-cr
1771     "q" gnus-article-de-quoted-unreadable
1772     "6" gnus-article-de-base64-unreadable
1773     "Z" gnus-article-decode-HZ
1774     "h" gnus-article-wash-html
1775     "u" gnus-article-unsplit-urls
1776     "s" gnus-summary-force-verify-and-decrypt
1777     "f" gnus-article-display-x-face
1778     "l" gnus-summary-stop-page-breaking
1779     "r" gnus-summary-caesar-message
1780     "m" gnus-summary-morse-message
1781     "t" gnus-summary-toggle-header
1782     "g" gnus-treat-smiley
1783     "v" gnus-summary-verbose-headers
1784     "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
1785     "p" gnus-article-verify-x-pgp-sig
1786     "d" gnus-article-treat-dumbquotes
1787     "k" gnus-article-outlook-deuglify-article)
1788
1789   (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
1790     "a" gnus-article-hide
1791     "h" gnus-article-hide-headers
1792     "b" gnus-article-hide-boring-headers
1793     "s" gnus-article-hide-signature
1794     "c" gnus-article-hide-citation
1795     "C" gnus-article-hide-citation-in-followups
1796     "l" gnus-article-hide-list-identifiers
1797     "p" gnus-article-hide-pgp
1798     "B" gnus-article-strip-banner
1799     "P" gnus-article-hide-pem
1800     "\C-c" gnus-article-hide-citation-maybe)
1801
1802   (gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
1803     "a" gnus-article-highlight
1804     "h" gnus-article-highlight-headers
1805     "c" gnus-article-highlight-citation
1806     "s" gnus-article-highlight-signature)
1807
1808   (gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
1809     "f" gnus-article-treat-fold-headers
1810     "u" gnus-article-treat-unfold-headers
1811     "n" gnus-article-treat-fold-newsgroups)
1812
1813   (gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
1814     "x" gnus-article-display-x-face
1815     "s" gnus-treat-smiley
1816     "D" gnus-article-remove-images
1817     "f" gnus-treat-from-picon
1818     "m" gnus-treat-mail-picon
1819     "n" gnus-treat-newsgroups-picon)
1820
1821   (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
1822     "w" gnus-article-decode-mime-words
1823     "c" gnus-article-decode-charset
1824     "v" gnus-mime-view-all-parts
1825     "b" gnus-article-view-part)
1826
1827   (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
1828     "z" gnus-article-date-ut
1829     "u" gnus-article-date-ut
1830     "l" gnus-article-date-local
1831     "p" gnus-article-date-english
1832     "e" gnus-article-date-lapsed
1833     "o" gnus-article-date-original
1834     "i" gnus-article-date-iso8601
1835     "s" gnus-article-date-user)
1836
1837   (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
1838     "t" gnus-article-remove-trailing-blank-lines
1839     "l" gnus-article-strip-leading-blank-lines
1840     "m" gnus-article-strip-multiple-blank-lines
1841     "a" gnus-article-strip-blank-lines
1842     "A" gnus-article-strip-all-blank-lines
1843     "s" gnus-article-strip-leading-space
1844     "e" gnus-article-strip-trailing-space
1845     "w" gnus-article-remove-leading-whitespace)
1846
1847   (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
1848     "v" gnus-version
1849     "f" gnus-summary-fetch-faq
1850     "d" gnus-summary-describe-group
1851     "h" gnus-summary-describe-briefly
1852     "i" gnus-info-find-node
1853     "c" gnus-group-fetch-charter
1854     "C" gnus-group-fetch-control)
1855
1856   (gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
1857     "e" gnus-summary-expire-articles
1858     "\M-\C-e" gnus-summary-expire-articles-now
1859     "\177" gnus-summary-delete-article
1860     [delete] gnus-summary-delete-article
1861     [backspace] gnus-summary-delete-article
1862     "m" gnus-summary-move-article
1863     "r" gnus-summary-respool-article
1864     "w" gnus-summary-edit-article
1865     "c" gnus-summary-copy-article
1866     "B" gnus-summary-crosspost-article
1867     "q" gnus-summary-respool-query
1868     "t" gnus-summary-respool-trace
1869     "i" gnus-summary-import-article
1870     "I" gnus-summary-create-article
1871     "p" gnus-summary-article-posted-p)
1872
1873   (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
1874     "o" gnus-summary-save-article
1875     "m" gnus-summary-save-article-mail
1876     "F" gnus-summary-write-article-file
1877     "r" gnus-summary-save-article-rmail
1878     "f" gnus-summary-save-article-file
1879     "b" gnus-summary-save-article-body-file
1880     "h" gnus-summary-save-article-folder
1881     "v" gnus-summary-save-article-vm
1882     "p" gnus-summary-pipe-output
1883     "P" gnus-summary-muttprint
1884     "s" gnus-soup-add-article)
1885
1886   (gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
1887     "b" gnus-summary-display-buttonized
1888     "m" gnus-summary-repair-multipart
1889     "v" gnus-article-view-part
1890     "o" gnus-article-save-part
1891     "c" gnus-article-copy-part
1892     "C" gnus-article-view-part-as-charset
1893     "e" gnus-article-view-part-externally
1894     "E" gnus-article-encrypt-body
1895     "i" gnus-article-inline-part
1896     "|" gnus-article-pipe-part)
1897
1898   (gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
1899     "p" gnus-summary-mark-as-processable
1900     "u" gnus-summary-unmark-as-processable
1901     "U" gnus-summary-unmark-all-processable
1902     "v" gnus-uu-mark-over
1903     "s" gnus-uu-mark-series
1904     "r" gnus-uu-mark-region
1905     "g" gnus-uu-unmark-region
1906     "R" gnus-uu-mark-by-regexp
1907     "G" gnus-uu-unmark-by-regexp
1908     "t" gnus-uu-mark-thread
1909     "T" gnus-uu-unmark-thread
1910     "a" gnus-uu-mark-all
1911     "b" gnus-uu-mark-buffer
1912     "S" gnus-uu-mark-sparse
1913     "k" gnus-summary-kill-process-mark
1914     "y" gnus-summary-yank-process-mark
1915     "w" gnus-summary-save-process-mark
1916     "i" gnus-uu-invert-processable)
1917
1918   (gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
1919     ;;"x" gnus-uu-extract-any
1920     "m" gnus-summary-save-parts
1921     "u" gnus-uu-decode-uu
1922     "U" gnus-uu-decode-uu-and-save
1923     "s" gnus-uu-decode-unshar
1924     "S" gnus-uu-decode-unshar-and-save
1925     "o" gnus-uu-decode-save
1926     "O" gnus-uu-decode-save
1927     "b" gnus-uu-decode-binhex
1928     "B" gnus-uu-decode-binhex
1929     "p" gnus-uu-decode-postscript
1930     "P" gnus-uu-decode-postscript-and-save)
1931
1932   (gnus-define-keys
1933       (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
1934     "u" gnus-uu-decode-uu-view
1935     "U" gnus-uu-decode-uu-and-save-view
1936     "s" gnus-uu-decode-unshar-view
1937     "S" gnus-uu-decode-unshar-and-save-view
1938     "o" gnus-uu-decode-save-view
1939     "O" gnus-uu-decode-save-view
1940     "b" gnus-uu-decode-binhex-view
1941     "B" gnus-uu-decode-binhex-view
1942     "p" gnus-uu-decode-postscript-view
1943     "P" gnus-uu-decode-postscript-and-save-view))
1944
1945 (defvar gnus-article-post-menu nil)
1946
1947 (defconst gnus-summary-menu-maxlen 20)
1948
1949 (defun gnus-summary-menu-split (menu)
1950   ;; If we have lots of elements, divide them into groups of 20
1951   ;; and make a pane (or submenu) for each one.
1952   (if (> (length menu) (/ (* gnus-summary-menu-maxlen 3) 2))
1953       (let ((menu menu) sublists next
1954             (i 1))
1955         (while menu
1956           ;; Pull off the next gnus-summary-menu-maxlen elements
1957           ;; and make them the next element of sublist.
1958           (setq next (nthcdr gnus-summary-menu-maxlen menu))
1959           (if next
1960               (setcdr (nthcdr (1- gnus-summary-menu-maxlen) menu)
1961                       nil))
1962           (setq sublists (cons (cons (format "%s ... %s" (aref (car menu) 0)
1963                                              (aref (car (last menu)) 0)) menu)
1964                                sublists))
1965           (setq i (1+ i))
1966           (setq menu next))
1967         (nreverse sublists))
1968     ;; Few elements--put them all in one pane.
1969     menu))
1970
1971 (defun gnus-summary-make-menu-bar ()
1972   (gnus-turn-off-edit-menu 'summary)
1973
1974   (unless (boundp 'gnus-summary-misc-menu)
1975
1976     (easy-menu-define
1977       gnus-summary-kill-menu gnus-summary-mode-map ""
1978       (cons
1979        "Score"
1980        (nconc
1981         (list
1982          ["Customize" gnus-score-customize t])
1983         (gnus-make-score-map 'increase)
1984         (gnus-make-score-map 'lower)
1985         '(("Mark"
1986            ["Kill below" gnus-summary-kill-below t]
1987            ["Mark above" gnus-summary-mark-above t]
1988            ["Tick above" gnus-summary-tick-above t]
1989            ["Clear above" gnus-summary-clear-above t])
1990           ["Current score" gnus-summary-current-score t]
1991           ["Set score" gnus-summary-set-score t]
1992           ["Switch current score file..." gnus-score-change-score-file t]
1993           ["Set mark below..." gnus-score-set-mark-below t]
1994           ["Set expunge below..." gnus-score-set-expunge-below t]
1995           ["Edit current score file" gnus-score-edit-current-scores t]
1996           ["Edit score file" gnus-score-edit-file t]
1997           ["Trace score" gnus-score-find-trace t]
1998           ["Find words" gnus-score-find-favourite-words t]
1999           ["Rescore buffer" gnus-summary-rescore t]
2000           ["Increase score..." gnus-summary-increase-score t]
2001           ["Lower score..." gnus-summary-lower-score t]))))
2002
2003     ;; Define both the Article menu in the summary buffer and the
2004     ;; equivalent Commands menu in the article buffer here for
2005     ;; consistency.
2006     (let ((innards
2007            `(("Hide"
2008               ["All" gnus-article-hide t]
2009               ["Headers" gnus-article-hide-headers t]
2010               ["Signature" gnus-article-hide-signature t]
2011               ["Citation" gnus-article-hide-citation t]
2012               ["List identifiers" gnus-article-hide-list-identifiers t]
2013               ["PGP" gnus-article-hide-pgp t]
2014               ["Banner" gnus-article-strip-banner t]
2015               ["Boring headers" gnus-article-hide-boring-headers t])
2016              ("Highlight"
2017               ["All" gnus-article-highlight t]
2018               ["Headers" gnus-article-highlight-headers t]
2019               ["Signature" gnus-article-highlight-signature t]
2020               ["Citation" gnus-article-highlight-citation t])
2021              ("MIME"
2022               ["Words" gnus-article-decode-mime-words t]
2023               ["Charset" gnus-article-decode-charset t]
2024               ["QP" gnus-article-de-quoted-unreadable t]
2025               ["Base64" gnus-article-de-base64-unreadable t]
2026               ["View MIME buttons" gnus-summary-display-buttonized t]
2027               ["View all" gnus-mime-view-all-parts t]
2028               ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
2029               ["Encrypt body" gnus-article-encrypt-body t]
2030               ["Extract all parts" gnus-summary-save-parts t])
2031              ("Date"
2032               ["Local" gnus-article-date-local t]
2033               ["ISO8601" gnus-article-date-iso8601 t]
2034               ["UT" gnus-article-date-ut t]
2035               ["Original" gnus-article-date-original t]
2036               ["Lapsed" gnus-article-date-lapsed t]
2037               ["User-defined" gnus-article-date-user t])
2038              ("Display"
2039               ["Remove images" gnus-article-remove-images t]
2040               ["Toggle smiley" gnus-treat-smiley t]
2041               ["Show X-Face" gnus-article-display-x-face t]
2042               ["Show picons in From" gnus-treat-from-picon t]
2043               ["Show picons in mail headers" gnus-treat-mail-picon t]
2044               ["Show picons in news headers" gnus-treat-newsgroups-picon t]
2045               ("View as different encoding"
2046                ,@(gnus-summary-menu-split
2047                   (mapcar
2048                    (lambda (cs)
2049                      ;; Since easymenu under FSF Emacs doesn't allow lambda
2050                      ;; forms for menu commands, we should provide intern'ed
2051                      ;; function symbols.
2052                      (let ((command (intern (format "\
2053 gnus-summary-show-article-from-menu-as-charset-%s" cs))))
2054                        (fset command
2055                              `(lambda ()
2056                                 (interactive)
2057                                 (let ((gnus-summary-show-article-charset-alist
2058                                        '((1 . ,cs))))
2059                                   (gnus-summary-show-article 1))))
2060                        `[,(symbol-name cs) ,command t]))
2061                    (sort (if (fboundp 'coding-system-list)
2062                              (coding-system-list)
2063                            (mapcar 'car mm-mime-mule-charset-alist))
2064                          'string<)))))
2065              ("Washing"
2066               ("Remove Blanks"
2067                ["Leading" gnus-article-strip-leading-blank-lines t]
2068                ["Multiple" gnus-article-strip-multiple-blank-lines t]
2069                ["Trailing" gnus-article-remove-trailing-blank-lines t]
2070                ["All of the above" gnus-article-strip-blank-lines t]
2071                ["All" gnus-article-strip-all-blank-lines t]
2072                ["Leading space" gnus-article-strip-leading-space t]
2073                ["Trailing space" gnus-article-strip-trailing-space t]
2074                ["Leading space in headers"
2075                 gnus-article-remove-leading-whitespace t])
2076               ["Overstrike" gnus-article-treat-overstrike t]
2077               ["Dumb quotes" gnus-article-treat-dumbquotes t]
2078               ["Emphasis" gnus-article-emphasize t]
2079               ["Word wrap" gnus-article-fill-cited-article t]
2080               ["Fill long lines" gnus-article-fill-long-lines t]
2081               ["Capitalize sentences" gnus-article-capitalize-sentences t]
2082               ["CR" gnus-article-remove-cr t]
2083               ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
2084               ["Base64" gnus-article-de-base64-unreadable t]
2085               ["Rot 13" gnus-summary-caesar-message
2086                ,@(if (featurep 'xemacs) '(t)
2087                    '(:help "\"Caesar rotate\" article by 13"))]
2088               ["Morse decode" gnus-summary-morse-message t]
2089               ["Unix pipe..." gnus-summary-pipe-message t]
2090               ["Add buttons" gnus-article-add-buttons t]
2091               ["Add buttons to head" gnus-article-add-buttons-to-head t]
2092               ["Stop page breaking" gnus-summary-stop-page-breaking t]
2093               ["Verbose header" gnus-summary-verbose-headers t]
2094               ["Toggle header" gnus-summary-toggle-header t]
2095               ["Unfold headers" gnus-article-treat-unfold-headers t]
2096               ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
2097               ["Html" gnus-article-wash-html t]
2098               ["URLs" gnus-article-unsplit-urls t]
2099               ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
2100               ["HZ" gnus-article-decode-HZ t]
2101               ["OutlooK deuglify" gnus-article-outlook-deuglify-article t]
2102               )
2103              ("Output"
2104               ["Save in default format" gnus-summary-save-article
2105                ,@(if (featurep 'xemacs) '(t)
2106                    '(:help "Save article using default method"))]
2107               ["Save in file" gnus-summary-save-article-file
2108                ,@(if (featurep 'xemacs) '(t)
2109                    '(:help "Save article in file"))]
2110               ["Save in Unix mail format" gnus-summary-save-article-mail t]
2111               ["Save in MH folder" gnus-summary-save-article-folder t]
2112               ["Save in VM folder" gnus-summary-save-article-vm t]
2113               ["Save in RMAIL mbox" gnus-summary-save-article-rmail t]
2114               ["Save body in file" gnus-summary-save-article-body-file t]
2115               ["Pipe through a filter" gnus-summary-pipe-output t]
2116               ["Add to SOUP packet" gnus-soup-add-article t]
2117               ["Print with Muttprint" gnus-summary-muttprint t]
2118               ["Print" gnus-summary-print-article t])
2119              ("Backend"
2120               ["Respool article..." gnus-summary-respool-article t]
2121               ["Move article..." gnus-summary-move-article
2122                (gnus-check-backend-function
2123                 'request-move-article gnus-newsgroup-name)]
2124               ["Copy article..." gnus-summary-copy-article t]
2125               ["Crosspost article..." gnus-summary-crosspost-article
2126                (gnus-check-backend-function
2127                 'request-replace-article gnus-newsgroup-name)]
2128               ["Import file..." gnus-summary-import-article t]
2129               ["Create article..." gnus-summary-create-article t]
2130               ["Check if posted" gnus-summary-article-posted-p t]
2131               ["Edit article" gnus-summary-edit-article
2132                (not (gnus-group-read-only-p))]
2133               ["Delete article" gnus-summary-delete-article
2134                (gnus-check-backend-function
2135                 'request-expire-articles gnus-newsgroup-name)]
2136               ["Query respool" gnus-summary-respool-query t]
2137               ["Trace respool" gnus-summary-respool-trace t]
2138               ["Delete expirable articles" gnus-summary-expire-articles-now
2139                (gnus-check-backend-function
2140                 'request-expire-articles gnus-newsgroup-name)])
2141              ("Extract"
2142               ["Uudecode" gnus-uu-decode-uu
2143                ,@(if (featurep 'xemacs) '(t)
2144                    '(:help "Decode uuencoded article(s)"))]
2145               ["Uudecode and save" gnus-uu-decode-uu-and-save t]
2146               ["Unshar" gnus-uu-decode-unshar t]
2147               ["Unshar and save" gnus-uu-decode-unshar-and-save t]
2148               ["Save" gnus-uu-decode-save t]
2149               ["Binhex" gnus-uu-decode-binhex t]
2150               ["Postscript" gnus-uu-decode-postscript t]
2151               ["All MIME parts" gnus-summary-save-parts t])
2152              ("Cache"
2153               ["Enter article" gnus-cache-enter-article t]
2154               ["Remove article" gnus-cache-remove-article t])
2155              ["Translate" gnus-article-babel t]
2156              ["Select article buffer" gnus-summary-select-article-buffer t]
2157              ["Enter digest buffer" gnus-summary-enter-digest-group t]
2158              ["Isearch article..." gnus-summary-isearch-article t]
2159              ["Beginning of the article" gnus-summary-beginning-of-article t]
2160              ["End of the article" gnus-summary-end-of-article t]
2161              ["Fetch parent of article" gnus-summary-refer-parent-article t]
2162              ["Fetch referenced articles" gnus-summary-refer-references t]
2163              ["Fetch current thread" gnus-summary-refer-thread t]
2164              ["Fetch article with id..." gnus-summary-refer-article t]
2165              ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
2166              ["Redisplay" gnus-summary-show-article t]
2167              ["Raw article" gnus-summary-show-raw-article :keys "C-u g"])))
2168       (easy-menu-define
2169         gnus-summary-article-menu gnus-summary-mode-map ""
2170         (cons "Article" innards))
2171
2172       (if (not (keymapp gnus-summary-article-menu))
2173           (easy-menu-define
2174             gnus-article-commands-menu gnus-article-mode-map ""
2175             (cons "Commands" innards))
2176         ;; in Emacs, don't share menu.
2177         (setq gnus-article-commands-menu
2178               (copy-keymap gnus-summary-article-menu))
2179         (define-key gnus-article-mode-map [menu-bar commands]
2180           (cons "Commands" gnus-article-commands-menu))))
2181
2182     (easy-menu-define
2183       gnus-summary-thread-menu gnus-summary-mode-map ""
2184       '("Threads"
2185         ["Find all messages in thread" gnus-summary-refer-thread t]
2186         ["Toggle threading" gnus-summary-toggle-threads t]
2187         ["Hide threads" gnus-summary-hide-all-threads t]
2188         ["Show threads" gnus-summary-show-all-threads t]
2189         ["Hide thread" gnus-summary-hide-thread t]
2190         ["Show thread" gnus-summary-show-thread t]
2191         ["Go to next thread" gnus-summary-next-thread t]
2192         ["Go to previous thread" gnus-summary-prev-thread t]
2193         ["Go down thread" gnus-summary-down-thread t]
2194         ["Go up thread" gnus-summary-up-thread t]
2195         ["Top of thread" gnus-summary-top-thread t]
2196         ["Mark thread as read" gnus-summary-kill-thread t]
2197         ["Lower thread score" gnus-summary-lower-thread t]
2198         ["Raise thread score" gnus-summary-raise-thread t]
2199         ["Rethread current" gnus-summary-rethread-current t]))
2200
2201     (easy-menu-define
2202       gnus-summary-post-menu gnus-summary-mode-map ""
2203       `("Post"
2204         ["Send a message (mail or news)" gnus-summary-post-news
2205          ,@(if (featurep 'xemacs) '(t)
2206              '(:help "Post an article"))]
2207         ["Followup" gnus-summary-followup
2208          ,@(if (featurep 'xemacs) '(t)
2209              '(:help "Post followup to this article"))]
2210         ["Followup and yank" gnus-summary-followup-with-original
2211          ,@(if (featurep 'xemacs) '(t)
2212              '(:help "Post followup to this article, quoting its contents"))]
2213         ["Supersede article" gnus-summary-supersede-article t]
2214         ["Cancel article" gnus-summary-cancel-article
2215          ,@(if (featurep 'xemacs) '(t)
2216              '(:help "Cancel an article you posted"))]
2217         ["Reply" gnus-summary-reply t]
2218         ["Reply and yank" gnus-summary-reply-with-original t]
2219         ["Wide reply" gnus-summary-wide-reply t]
2220         ["Wide reply and yank" gnus-summary-wide-reply-with-original
2221          ,@(if (featurep 'xemacs) '(t)
2222              '(:help "Mail a reply, quoting this article"))]
2223         ["Very wide reply" gnus-summary-very-wide-reply t]
2224         ["Very wide reply and yank" gnus-summary-very-wide-reply-with-original
2225          ,@(if (featurep 'xemacs) '(t)
2226              '(:help "Mail a very wide reply, quoting this article"))]
2227         ["Mail forward" gnus-summary-mail-forward t]
2228         ["Post forward" gnus-summary-post-forward t]
2229         ["Digest and mail" gnus-uu-digest-mail-forward t]
2230         ["Digest and post" gnus-uu-digest-post-forward t]
2231         ["Resend message" gnus-summary-resend-message t]
2232         ["Resend message edit" gnus-summary-resend-message-edit t]
2233         ["Send bounced mail" gnus-summary-resend-bounced-mail t]
2234         ["Send a mail" gnus-summary-mail-other-window t]
2235         ["Create a local message" gnus-summary-news-other-window t]
2236         ["Uuencode and post" gnus-uu-post-news
2237          ,@(if (featurep 'xemacs) '(t)
2238              '(:help "Post a uuencoded article"))]
2239         ["Followup via news" gnus-summary-followup-to-mail t]
2240         ["Followup via news and yank"
2241          gnus-summary-followup-to-mail-with-original t]
2242         ;;("Draft"
2243         ;;["Send" gnus-summary-send-draft t]
2244         ;;["Send bounced" gnus-resend-bounced-mail t])
2245         ))
2246
2247     (cond
2248      ((not (keymapp gnus-summary-post-menu))
2249       (setq gnus-article-post-menu gnus-summary-post-menu))
2250      ((not gnus-article-post-menu)
2251       ;; Don't share post menu.
2252       (setq gnus-article-post-menu
2253             (copy-keymap gnus-summary-post-menu))))
2254     (define-key gnus-article-mode-map [menu-bar post]
2255       (cons "Post" gnus-article-post-menu))
2256
2257     (easy-menu-define
2258       gnus-summary-misc-menu gnus-summary-mode-map ""
2259       `("Gnus"
2260         ("Mark Read"
2261          ["Mark as read" gnus-summary-mark-as-read-forward t]
2262          ["Mark same subject and select"
2263           gnus-summary-kill-same-subject-and-select t]
2264          ["Mark same subject" gnus-summary-kill-same-subject t]
2265          ["Catchup" gnus-summary-catchup
2266           ,@(if (featurep 'xemacs) '(t)
2267               '(:help "Mark unread articles in this group as read"))]
2268          ["Catchup all" gnus-summary-catchup-all t]
2269          ["Catchup to here" gnus-summary-catchup-to-here t]
2270          ["Catchup from here" gnus-summary-catchup-from-here t]
2271          ["Catchup region" gnus-summary-mark-region-as-read t]
2272          ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
2273         ("Mark Various"
2274          ["Tick" gnus-summary-tick-article-forward t]
2275          ["Mark as dormant" gnus-summary-mark-as-dormant t]
2276          ["Remove marks" gnus-summary-clear-mark-forward t]
2277          ["Set expirable mark" gnus-summary-mark-as-expirable t]
2278          ["Set bookmark" gnus-summary-set-bookmark t]
2279          ["Remove bookmark" gnus-summary-remove-bookmark t])
2280         ("Limit to"
2281          ["Marks..." gnus-summary-limit-to-marks t]
2282          ["Subject..." gnus-summary-limit-to-subject t]
2283          ["Author..." gnus-summary-limit-to-author t]
2284          ["Age..." gnus-summary-limit-to-age t]
2285          ["Extra..." gnus-summary-limit-to-extra t]
2286          ["Score..." gnus-summary-limit-to-score t]
2287          ["Display Predicate" gnus-summary-limit-to-display-predicate t]
2288          ["Unread" gnus-summary-limit-to-unread t]
2289          ["Unseen" gnus-summary-limit-to-unseen t]
2290          ["Non-dormant" gnus-summary-limit-exclude-dormant t]
2291          ["Next articles" gnus-summary-limit-to-articles t]
2292          ["Pop limit" gnus-summary-pop-limit t]
2293          ["Show dormant" gnus-summary-limit-include-dormant t]
2294          ["Hide childless dormant"
2295           gnus-summary-limit-exclude-childless-dormant t]
2296          ;;["Hide thread" gnus-summary-limit-exclude-thread t]
2297          ["Hide marked" gnus-summary-limit-exclude-marks t]
2298          ["Show expunged" gnus-summary-limit-include-expunged t])
2299         ("Process Mark"
2300          ["Set mark" gnus-summary-mark-as-processable t]
2301          ["Remove mark" gnus-summary-unmark-as-processable t]
2302          ["Remove all marks" gnus-summary-unmark-all-processable t]
2303          ["Mark above" gnus-uu-mark-over t]
2304          ["Mark series" gnus-uu-mark-series t]
2305          ["Mark region" gnus-uu-mark-region t]
2306          ["Unmark region" gnus-uu-unmark-region t]
2307          ["Mark by regexp..." gnus-uu-mark-by-regexp t]
2308          ["Unmark by regexp..." gnus-uu-unmark-by-regexp t]
2309          ["Mark all" gnus-uu-mark-all t]
2310          ["Mark buffer" gnus-uu-mark-buffer t]
2311          ["Mark sparse" gnus-uu-mark-sparse t]
2312          ["Mark thread" gnus-uu-mark-thread t]
2313          ["Unmark thread" gnus-uu-unmark-thread t]
2314          ("Process Mark Sets"
2315           ["Kill" gnus-summary-kill-process-mark t]
2316           ["Yank" gnus-summary-yank-process-mark
2317            gnus-newsgroup-process-stack]
2318           ["Save" gnus-summary-save-process-mark t]))
2319         ("Scroll article"
2320          ["Page forward" gnus-summary-next-page
2321           ,@(if (featurep 'xemacs) '(t)
2322               '(:help "Show next page of article"))]
2323          ["Page backward" gnus-summary-prev-page
2324           ,@(if (featurep 'xemacs) '(t)
2325               '(:help "Show previous page of article"))]
2326          ["Line forward" gnus-summary-scroll-up t])
2327         ("Move"
2328          ["Next unread article" gnus-summary-next-unread-article t]
2329          ["Previous unread article" gnus-summary-prev-unread-article t]
2330          ["Next article" gnus-summary-next-article t]
2331          ["Previous article" gnus-summary-prev-article t]
2332          ["Next unread subject" gnus-summary-next-unread-subject t]
2333          ["Previous unread subject" gnus-summary-prev-unread-subject t]
2334          ["Next article same subject" gnus-summary-next-same-subject t]
2335          ["Previous article same subject" gnus-summary-prev-same-subject t]
2336          ["First unread article" gnus-summary-first-unread-article t]
2337          ["Best unread article" gnus-summary-best-unread-article t]
2338          ["Go to subject number..." gnus-summary-goto-subject t]
2339          ["Go to article number..." gnus-summary-goto-article t]
2340          ["Go to the last article" gnus-summary-goto-last-article t]
2341          ["Pop article off history" gnus-summary-pop-article t])
2342         ("Sort"
2343          ["Sort by number" gnus-summary-sort-by-number t]
2344          ["Sort by author" gnus-summary-sort-by-author t]
2345          ["Sort by subject" gnus-summary-sort-by-subject t]
2346          ["Sort by date" gnus-summary-sort-by-date t]
2347          ["Sort by score" gnus-summary-sort-by-score t]
2348          ["Sort by lines" gnus-summary-sort-by-lines t]
2349          ["Sort by characters" gnus-summary-sort-by-chars t]
2350          ["Randomize" gnus-summary-sort-by-random t]
2351          ["Original sort" gnus-summary-sort-by-original t])
2352         ("Help"
2353          ["Fetch group FAQ" gnus-summary-fetch-faq t]
2354          ["Describe group" gnus-summary-describe-group t]
2355          ["Fetch charter" gnus-group-fetch-charter
2356           ,@(if (featurep 'xemacs) nil
2357               '(:help "Display the charter of the current group"))]
2358          ["Fetch control message" gnus-group-fetch-control
2359           ,@(if (featurep 'xemacs) nil
2360               '(:help "Display the archived control message for the current group"))]
2361          ["Read manual" gnus-info-find-node t])
2362         ("Modes"
2363          ["Pick and read" gnus-pick-mode t]
2364          ["Binary" gnus-binary-mode t])
2365         ("Regeneration"
2366          ["Regenerate" gnus-summary-prepare t]
2367          ["Insert cached articles" gnus-summary-insert-cached-articles t]
2368          ["Insert dormant articles" gnus-summary-insert-dormant-articles t]
2369          ["Toggle threading" gnus-summary-toggle-threads t])
2370         ["See old articles" gnus-summary-insert-old-articles t]
2371         ["See new articles" gnus-summary-insert-new-articles t]
2372         ["Filter articles..." gnus-summary-execute-command t]
2373         ["Run command on subjects..." gnus-summary-universal-argument t]
2374         ["Search articles forward..." gnus-summary-search-article-forward t]
2375         ["Search articles backward..." gnus-summary-search-article-backward t]
2376         ["Toggle line truncation" gnus-summary-toggle-truncation t]
2377         ["Expand window" gnus-summary-expand-window t]
2378         ["Expire expirable articles" gnus-summary-expire-articles
2379          (gnus-check-backend-function
2380           'request-expire-articles gnus-newsgroup-name)]
2381         ["Edit local kill file" gnus-summary-edit-local-kill t]
2382         ["Edit main kill file" gnus-summary-edit-global-kill t]
2383         ["Edit group parameters" gnus-summary-edit-parameters t]
2384         ["Customize group parameters" gnus-summary-customize-parameters t]
2385         ["Send a bug report" gnus-bug t]
2386         ("Exit"
2387          ["Catchup and exit" gnus-summary-catchup-and-exit
2388           ,@(if (featurep 'xemacs) '(t)
2389               '(:help "Mark unread articles in this group as read, then exit"))]
2390          ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
2391          ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
2392          ["Exit group" gnus-summary-exit
2393           ,@(if (featurep 'xemacs) '(t)
2394               '(:help "Exit current group, return to group selection mode"))]
2395          ["Exit group without updating" gnus-summary-exit-no-update t]
2396          ["Exit and goto next group" gnus-summary-next-group t]
2397          ["Exit and goto prev group" gnus-summary-prev-group t]
2398          ["Reselect group" gnus-summary-reselect-current-group t]
2399          ["Rescan group" gnus-summary-rescan-group t]
2400          ["Update dribble" gnus-summary-save-newsrc t])))
2401
2402     (gnus-run-hooks 'gnus-summary-menu-hook)))
2403
2404 (defvar gnus-summary-tool-bar-map nil)
2405
2406 ;; Emacs 21 tool bar.  Should be no-op otherwise.
2407 (defun gnus-summary-make-tool-bar ()
2408   (if (and (fboundp 'tool-bar-add-item-from-menu)
2409            (default-value 'tool-bar-mode)
2410            (not gnus-summary-tool-bar-map))
2411       (setq gnus-summary-tool-bar-map
2412             (let ((tool-bar-map (make-sparse-keymap))
2413                   (load-path (mm-image-load-path)))
2414               (tool-bar-add-item-from-menu
2415                'gnus-summary-prev-unread "prev-ur" gnus-summary-mode-map)
2416               (tool-bar-add-item-from-menu
2417                'gnus-summary-next-unread "next-ur" gnus-summary-mode-map)
2418               (tool-bar-add-item-from-menu
2419                'gnus-summary-post-news "post" gnus-summary-mode-map)
2420               (tool-bar-add-item-from-menu
2421                'gnus-summary-followup-with-original "fuwo" gnus-summary-mode-map)
2422               (tool-bar-add-item-from-menu
2423                'gnus-summary-followup "followup" gnus-summary-mode-map)
2424               (tool-bar-add-item-from-menu
2425                'gnus-summary-reply-with-original "reply-wo" gnus-summary-mode-map)
2426               (tool-bar-add-item-from-menu
2427                'gnus-summary-reply "reply" gnus-summary-mode-map)
2428               (tool-bar-add-item-from-menu
2429                'gnus-summary-caesar-message "rot13" gnus-summary-mode-map)
2430               (tool-bar-add-item-from-menu
2431                'gnus-uu-decode-uu "uu-decode" gnus-summary-mode-map)
2432               (tool-bar-add-item-from-menu
2433                'gnus-summary-save-article-file "save-aif" gnus-summary-mode-map)
2434               (tool-bar-add-item-from-menu
2435                'gnus-summary-save-article "save-art" gnus-summary-mode-map)
2436               (tool-bar-add-item-from-menu
2437                'gnus-uu-post-news "uu-post" gnus-summary-mode-map)
2438               (tool-bar-add-item-from-menu
2439                'gnus-summary-catchup "catchup" gnus-summary-mode-map)
2440               (tool-bar-add-item-from-menu
2441                'gnus-summary-catchup-and-exit "cu-exit" gnus-summary-mode-map)
2442               (tool-bar-add-item-from-menu
2443                'gnus-summary-exit "exit-summ" gnus-summary-mode-map)
2444               tool-bar-map)))
2445   (if gnus-summary-tool-bar-map
2446       (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
2447
2448 (defun gnus-score-set-default (var value)
2449   "A version of set that updates the GNU Emacs menu-bar."
2450   (set var value)
2451   ;; It is the message that forces the active status to be updated.
2452   (message ""))
2453
2454 (defun gnus-make-score-map (type)
2455   "Make a summary score map of type TYPE."
2456   (if t
2457       nil
2458     (let ((headers '(("author" "from" string)
2459                      ("subject" "subject" string)
2460                      ("article body" "body" string)
2461                      ("article head" "head" string)
2462                      ("xref" "xref" string)
2463                      ("extra header" "extra" string)
2464                      ("lines" "lines" number)
2465                      ("followups to author" "followup" string)))
2466           (types '((number ("less than" <)
2467                            ("greater than" >)
2468                            ("equal" =))
2469                    (string ("substring" s)
2470                            ("exact string" e)
2471                            ("fuzzy string" f)
2472                            ("regexp" r))))
2473           (perms '(("temporary" (current-time-string))
2474                    ("permanent" nil)
2475                    ("immediate" now)))
2476           header)
2477       (list
2478        (apply
2479         'nconc
2480         (list
2481          (if (eq type 'lower)
2482              "Lower score"
2483            "Increase score"))
2484         (let (outh)
2485           (while headers
2486             (setq header (car headers))
2487             (setq outh
2488                   (cons
2489                    (apply
2490                     'nconc
2491                     (list (car header))
2492                     (let ((ts (cdr (assoc (nth 2 header) types)))
2493                           outt)
2494                       (while ts
2495                         (setq outt
2496                               (cons
2497                                (apply
2498                                 'nconc
2499                                 (list (caar ts))
2500                                 (let ((ps perms)
2501                                       outp)
2502                                   (while ps
2503                                     (setq outp
2504                                           (cons
2505                                            (vector
2506                                             (caar ps)
2507                                             (list
2508                                              'gnus-summary-score-entry
2509                                              (nth 1 header)
2510                                              (if (or (string= (nth 1 header)
2511                                                               "head")
2512                                                      (string= (nth 1 header)
2513                                                               "body"))
2514                                                  ""
2515                                                (list 'gnus-summary-header
2516                                                      (nth 1 header)))
2517                                              (list 'quote (nth 1 (car ts)))
2518                                              (list 'gnus-score-delta-default
2519                                                    nil)
2520                                              (nth 1 (car ps))
2521                                              t)
2522                                             t)
2523                                            outp))
2524                                     (setq ps (cdr ps)))
2525                                   (list (nreverse outp))))
2526                                outt))
2527                         (setq ts (cdr ts)))
2528                       (list (nreverse outt))))
2529                    outh))
2530             (setq headers (cdr headers)))
2531           (list (nreverse outh))))))))
2532
2533 \f
2534
2535 (defun gnus-summary-mode (&optional group)
2536   "Major mode for reading articles.
2537
2538 All normal editing commands are switched off.
2539 \\<gnus-summary-mode-map>
2540 Each line in this buffer represents one article.  To read an
2541 article, you can, for instance, type `\\[gnus-summary-next-page]'.  To move forwards
2542 and backwards while displaying articles, type `\\[gnus-summary-next-unread-article]' and `\\[gnus-summary-prev-unread-article]',
2543 respectively.
2544
2545 You can also post articles and send mail from this buffer.  To
2546 follow up an article, type `\\[gnus-summary-followup]'.  To mail a reply to the author
2547 of an article, type `\\[gnus-summary-reply]'.
2548
2549 There are approx. one gazillion commands you can execute in this
2550 buffer; read the info pages for more information (`\\[gnus-info-find-node]').
2551
2552 The following commands are available:
2553
2554 \\{gnus-summary-mode-map}"
2555   (interactive)
2556   (kill-all-local-variables)
2557   (when (gnus-visual-p 'summary-menu 'menu)
2558     (gnus-summary-make-menu-bar)
2559     (gnus-summary-make-tool-bar))
2560   (gnus-summary-make-local-variables)
2561   (let ((gnus-summary-local-variables gnus-newsgroup-variables))
2562     (gnus-summary-make-local-variables))
2563   (gnus-make-thread-indent-array)
2564   (gnus-simplify-mode-line)
2565   (setq major-mode 'gnus-summary-mode)
2566   (setq mode-name "Summary")
2567   (make-local-variable 'minor-mode-alist)
2568   (use-local-map gnus-summary-mode-map)
2569   (buffer-disable-undo)
2570   (setq buffer-read-only t)             ;Disable modification
2571   (setq truncate-lines t)
2572   (setq selective-display t)
2573   (setq selective-display-ellipses t)   ;Display `...'
2574   (gnus-summary-set-display-table)
2575   (gnus-set-default-directory)
2576   (setq gnus-newsgroup-name group)
2577   (make-local-variable 'gnus-summary-line-format)
2578   (make-local-variable 'gnus-summary-line-format-spec)
2579   (make-local-variable 'gnus-summary-dummy-line-format)
2580   (make-local-variable 'gnus-summary-dummy-line-format-spec)
2581   (make-local-variable 'gnus-summary-mark-positions)
2582   (make-local-hook 'pre-command-hook)
2583   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
2584   (gnus-run-hooks 'gnus-summary-mode-hook)
2585   (turn-on-gnus-mailing-list-mode)
2586   (mm-enable-multibyte)
2587   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
2588   (gnus-update-summary-mark-positions))
2589
2590 (defun gnus-summary-make-local-variables ()
2591   "Make all the local summary buffer variables."
2592   (let (global)
2593     (dolist (local gnus-summary-local-variables)
2594       (if (consp local)
2595           (progn
2596             (if (eq (cdr local) 'global)
2597                 ;; Copy the global value of the variable.
2598                 (setq global (symbol-value (car local)))
2599               ;; Use the value from the list.
2600               (setq global (eval (cdr local))))
2601             (set (make-local-variable (car local)) global))
2602         ;; Simple nil-valued local variable.
2603         (set (make-local-variable local) nil)))))
2604
2605 (defun gnus-summary-clear-local-variables ()
2606   (let ((locals gnus-summary-local-variables))
2607     (while locals
2608       (if (consp (car locals))
2609           (and (vectorp (caar locals))
2610                (set (caar locals) nil))
2611         (and (vectorp (car locals))
2612              (set (car locals) nil)))
2613       (setq locals (cdr locals)))))
2614
2615 ;; Summary data functions.
2616
2617 (defmacro gnus-data-number (data)
2618   `(car ,data))
2619
2620 (defmacro gnus-data-set-number (data number)
2621   `(setcar ,data ,number))
2622
2623 (defmacro gnus-data-mark (data)
2624   `(nth 1 ,data))
2625
2626 (defmacro gnus-data-set-mark (data mark)
2627   `(setcar (nthcdr 1 ,data) ,mark))
2628
2629 (defmacro gnus-data-pos (data)
2630   `(nth 2 ,data))
2631
2632 (defmacro gnus-data-set-pos (data pos)
2633   `(setcar (nthcdr 2 ,data) ,pos))
2634
2635 (defmacro gnus-data-header (data)
2636   `(nth 3 ,data))
2637
2638 (defmacro gnus-data-set-header (data header)
2639   `(setf (nth 3 ,data) ,header))
2640
2641 (defmacro gnus-data-level (data)
2642   `(nth 4 ,data))
2643
2644 (defmacro gnus-data-unread-p (data)
2645   `(= (nth 1 ,data) gnus-unread-mark))
2646
2647 (defmacro gnus-data-read-p (data)
2648   `(/= (nth 1 ,data) gnus-unread-mark))
2649
2650 (defmacro gnus-data-pseudo-p (data)
2651   `(consp (nth 3 ,data)))
2652
2653 (defmacro gnus-data-find (number)
2654   `(assq ,number gnus-newsgroup-data))
2655
2656 (defmacro gnus-data-find-list (number &optional data)
2657   `(let ((bdata ,(or data 'gnus-newsgroup-data)))
2658      (memq (assq ,number bdata)
2659            bdata)))
2660
2661 (defmacro gnus-data-make (number mark pos header level)
2662   `(list ,number ,mark ,pos ,header ,level))
2663
2664 (defun gnus-data-enter (after-article number mark pos header level offset)
2665   (let ((data (gnus-data-find-list after-article)))
2666     (unless data
2667       (error "No such article: %d" after-article))
2668     (setcdr data (cons (gnus-data-make number mark pos header level)
2669                        (cdr data)))
2670     (setq gnus-newsgroup-data-reverse nil)
2671     (gnus-data-update-list (cddr data) offset)))
2672
2673 (defun gnus-data-enter-list (after-article list &optional offset)
2674   (when list
2675     (let ((data (and after-article (gnus-data-find-list after-article)))
2676           (ilist list))
2677       (if (not (or data
2678                    after-article))
2679           (let ((odata gnus-newsgroup-data))
2680             (setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
2681             (when offset
2682               (gnus-data-update-list odata offset)))
2683       ;; Find the last element in the list to be spliced into the main
2684         ;; list.
2685         (while (cdr list)
2686           (setq list (cdr list)))
2687         (if (not data)
2688             (progn
2689               (setcdr list gnus-newsgroup-data)
2690               (setq gnus-newsgroup-data ilist)
2691               (when offset
2692                 (gnus-data-update-list (cdr list) offset)))
2693           (setcdr list (cdr data))
2694           (setcdr data ilist)
2695           (when offset
2696             (gnus-data-update-list (cdr list) offset))))
2697       (setq gnus-newsgroup-data-reverse nil))))
2698
2699 (defun gnus-data-remove (article &optional offset)
2700   (let ((data gnus-newsgroup-data))
2701     (if (= (gnus-data-number (car data)) article)
2702         (progn
2703           (setq gnus-newsgroup-data (cdr gnus-newsgroup-data)
2704                 gnus-newsgroup-data-reverse nil)
2705           (when offset
2706             (gnus-data-update-list gnus-newsgroup-data offset)))
2707       (while (cdr data)
2708         (when (= (gnus-data-number (cadr data)) article)
2709           (setcdr data (cddr data))
2710           (when offset
2711             (gnus-data-update-list (cdr data) offset))
2712           (setq data nil
2713                 gnus-newsgroup-data-reverse nil))
2714         (setq data (cdr data))))))
2715
2716 (defmacro gnus-data-list (backward)
2717   `(if ,backward
2718        (or gnus-newsgroup-data-reverse
2719            (setq gnus-newsgroup-data-reverse
2720                  (reverse gnus-newsgroup-data)))
2721      gnus-newsgroup-data))
2722
2723 (defun gnus-data-update-list (data offset)
2724   "Add OFFSET to the POS of all data entries in DATA."
2725   (setq gnus-newsgroup-data-reverse nil)
2726   (while data
2727     (setcar (nthcdr 2 (car data)) (+ offset (nth 2 (car data))))
2728     (setq data (cdr data))))
2729
2730 (defun gnus-summary-article-pseudo-p (article)
2731   "Say whether this article is a pseudo article or not."
2732   (not (vectorp (gnus-data-header (gnus-data-find article)))))
2733
2734 (defmacro gnus-summary-article-sparse-p (article)
2735   "Say whether this article is a sparse article or not."
2736   `(memq ,article gnus-newsgroup-sparse))
2737
2738 (defmacro gnus-summary-article-ancient-p (article)
2739   "Say whether this article is a sparse article or not."
2740   `(memq ,article gnus-newsgroup-ancient))
2741
2742 (defun gnus-article-parent-p (number)
2743   "Say whether this article is a parent or not."
2744   (let ((data (gnus-data-find-list number)))
2745     (and (cdr data)              ; There has to be an article after...
2746          (< (gnus-data-level (car data)) ; And it has to have a higher level.
2747             (gnus-data-level (nth 1 data))))))
2748
2749 (defun gnus-article-children (number)
2750   "Return a list of all children to NUMBER."
2751   (let* ((data (gnus-data-find-list number))
2752          (level (gnus-data-level (car data)))
2753          children)
2754     (setq data (cdr data))
2755     (while (and data
2756                 (= (gnus-data-level (car data)) (1+ level)))
2757       (push (gnus-data-number (car data)) children)
2758       (setq data (cdr data)))
2759     children))
2760
2761 (defmacro gnus-summary-skip-intangible ()
2762   "If the current article is intangible, then jump to a different article."
2763   '(let ((to (get-text-property (point) 'gnus-intangible)))
2764      (and to (gnus-summary-goto-subject to))))
2765
2766 (defmacro gnus-summary-article-intangible-p ()
2767   "Say whether this article is intangible or not."
2768   '(get-text-property (point) 'gnus-intangible))
2769
2770 (defun gnus-article-read-p (article)
2771   "Say whether ARTICLE is read or not."
2772   (not (or (memq article gnus-newsgroup-marked)
2773            (memq article gnus-newsgroup-spam-marked)
2774            (memq article gnus-newsgroup-unreads)
2775            (memq article gnus-newsgroup-unselected)
2776            (memq article gnus-newsgroup-dormant))))
2777
2778 ;; Some summary mode macros.
2779
2780 (defmacro gnus-summary-article-number ()
2781   "The article number of the article on the current line.
2782 If there isn't an article number here, then we return the current
2783 article number."
2784   '(progn
2785      (gnus-summary-skip-intangible)
2786      (or (get-text-property (point) 'gnus-number)
2787          (gnus-summary-last-subject))))
2788
2789 (defmacro gnus-summary-article-header (&optional number)
2790   "Return the header of article NUMBER."
2791   `(gnus-data-header (gnus-data-find
2792                       ,(or number '(gnus-summary-article-number)))))
2793
2794 (defmacro gnus-summary-thread-level (&optional number)
2795   "Return the level of thread that starts with article NUMBER."
2796   `(if (and (eq gnus-summary-make-false-root 'dummy)
2797             (get-text-property (point) 'gnus-intangible))
2798        0
2799      (gnus-data-level (gnus-data-find
2800                        ,(or number '(gnus-summary-article-number))))))
2801
2802 (defmacro gnus-summary-article-mark (&optional number)
2803   "Return the mark of article NUMBER."
2804   `(gnus-data-mark (gnus-data-find
2805                     ,(or number '(gnus-summary-article-number)))))
2806
2807 (defmacro gnus-summary-article-pos (&optional number)
2808   "Return the position of the line of article NUMBER."
2809   `(gnus-data-pos (gnus-data-find
2810                    ,(or number '(gnus-summary-article-number)))))
2811
2812 (defalias 'gnus-summary-subject-string 'gnus-summary-article-subject)
2813 (defmacro gnus-summary-article-subject (&optional number)
2814   "Return current subject string or nil if nothing."
2815   `(let ((headers
2816           ,(if number
2817                `(gnus-data-header (assq ,number gnus-newsgroup-data))
2818              '(gnus-data-header (assq (gnus-summary-article-number)
2819                                       gnus-newsgroup-data)))))
2820      (and headers
2821           (vectorp headers)
2822           (mail-header-subject headers))))
2823
2824 (defmacro gnus-summary-article-score (&optional number)
2825   "Return current article score."
2826   `(or (cdr (assq ,(or number '(gnus-summary-article-number))
2827                   gnus-newsgroup-scored))
2828        gnus-summary-default-score 0))
2829
2830 (defun gnus-summary-article-children (&optional number)
2831   "Return a list of article numbers that are children of article NUMBER."
2832   (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))))
2833          (level (gnus-data-level (car data)))
2834          l children)
2835     (while (and (setq data (cdr data))
2836                 (> (setq l (gnus-data-level (car data))) level))
2837       (and (= (1+ level) l)
2838            (push (gnus-data-number (car data))
2839                  children)))
2840     (nreverse children)))
2841
2842 (defun gnus-summary-article-parent (&optional number)
2843   "Return the article number of the parent of article NUMBER."
2844   (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))
2845                                     (gnus-data-list t)))
2846          (level (gnus-data-level (car data))))
2847     (if (zerop level)
2848         ()                              ; This is a root.
2849       ;; We search until we find an article with a level less than
2850       ;; this one.  That function has to be the parent.
2851       (while (and (setq data (cdr data))
2852                   (not (< (gnus-data-level (car data)) level))))
2853       (and data (gnus-data-number (car data))))))
2854
2855 (defun gnus-unread-mark-p (mark)
2856   "Say whether MARK is the unread mark."
2857   (= mark gnus-unread-mark))
2858
2859 (defun gnus-read-mark-p (mark)
2860   "Say whether MARK is one of the marks that mark as read.
2861 This is all marks except unread, ticked, dormant, and expirable."
2862   (not (or (= mark gnus-unread-mark)
2863            (= mark gnus-ticked-mark)
2864            (= mark gnus-spam-mark)
2865            (= mark gnus-dormant-mark)
2866            (= mark gnus-expirable-mark))))
2867
2868 (defmacro gnus-article-mark (number)
2869   "Return the MARK of article NUMBER.
2870 This macro should only be used when computing the mark the \"first\"
2871 time; i.e., when generating the summary lines.  After that,
2872 `gnus-summary-article-mark' should be used to examine the
2873 marks of articles."
2874   `(cond
2875     ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
2876     ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
2877     ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
2878     ((memq ,number gnus-newsgroup-marked) gnus-ticked-mark)
2879     ((memq ,number gnus-newsgroup-spam-marked) gnus-spam-mark)
2880     ((memq ,number gnus-newsgroup-dormant) gnus-dormant-mark)
2881     ((memq ,number gnus-newsgroup-expirable) gnus-expirable-mark)
2882     (t (or (cdr (assq ,number gnus-newsgroup-reads))
2883            gnus-ancient-mark))))
2884
2885 ;; Saving hidden threads.
2886
2887 (defmacro gnus-save-hidden-threads (&rest forms)
2888   "Save hidden threads, eval FORMS, and restore the hidden threads."
2889   (let ((config (make-symbol "config")))
2890     `(let ((,config (gnus-hidden-threads-configuration)))
2891        (unwind-protect
2892            (save-excursion
2893              ,@forms)
2894          (gnus-restore-hidden-threads-configuration ,config)))))
2895 (put 'gnus-save-hidden-threads 'lisp-indent-function 0)
2896 (put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
2897
2898 (defun gnus-data-compute-positions ()
2899   "Compute the positions of all articles."
2900   (setq gnus-newsgroup-data-reverse nil)
2901   (let ((data gnus-newsgroup-data))
2902     (save-excursion
2903       (gnus-save-hidden-threads
2904         (gnus-summary-show-all-threads)
2905         (goto-char (point-min))
2906         (while data
2907           (while (get-text-property (point) 'gnus-intangible)
2908             (forward-line 1))
2909           (gnus-data-set-pos (car data) (+ (point) 3))
2910           (setq data (cdr data))
2911           (forward-line 1))))))
2912
2913 (defun gnus-hidden-threads-configuration ()
2914   "Return the current hidden threads configuration."
2915   (save-excursion
2916     (let (config)
2917       (goto-char (point-min))
2918       (while (search-forward "\r" nil t)
2919         (push (1- (point)) config))
2920       config)))
2921
2922 (defun gnus-restore-hidden-threads-configuration (config)
2923   "Restore hidden threads configuration from CONFIG."
2924   (save-excursion
2925     (let (point buffer-read-only)
2926       (while (setq point (pop config))
2927         (when (and (< point (point-max))
2928                    (goto-char point)
2929                    (eq (char-after) ?\n))
2930           (subst-char-in-region point (1+ point) ?\n ?\r))))))
2931
2932 ;; Various summary mode internalish functions.
2933
2934 (defun gnus-mouse-pick-article (e)
2935   (interactive "e")
2936   (mouse-set-point e)
2937   (gnus-summary-next-page nil t))
2938
2939 (defun gnus-summary-set-display-table ()
2940   "Change the display table.
2941 Odd characters have a tendency to mess
2942 up nicely formatted displays - we make all possible glyphs
2943 display only a single character."
2944
2945   ;; We start from the standard display table, if any.
2946   (let ((table (or (copy-sequence standard-display-table)
2947                    (make-display-table)))
2948         (i 32))
2949     ;; Nix out all the control chars...
2950     (while (>= (setq i (1- i)) 0)
2951       (aset table i [??]))
2952    ;; ... but not newline and cr, of course.  (cr is necessary for the
2953     ;; selective display).
2954     (aset table ?\n nil)
2955     (aset table ?\r nil)
2956     ;; We keep TAB as well.
2957     (aset table ?\t nil)
2958     ;; We nix out any glyphs over 126 that are not set already.
2959     (let ((i 256))
2960       (while (>= (setq i (1- i)) 127)
2961         ;; Only modify if the entry is nil.
2962         (unless (aref table i)
2963           (aset table i [??]))))
2964     (setq buffer-display-table table)))
2965
2966 (defun gnus-summary-set-article-display-arrow (pos)
2967   "Update the overlay arrow to point to line at position POS."
2968   (when (and gnus-summary-display-arrow
2969              (boundp 'overlay-arrow-position)
2970              (boundp 'overlay-arrow-string))
2971     (save-excursion
2972       (goto-char pos)
2973       (beginning-of-line)
2974       (unless overlay-arrow-position
2975         (setq overlay-arrow-position (make-marker)))
2976       (setq overlay-arrow-string "=>"
2977             overlay-arrow-position (set-marker overlay-arrow-position
2978                                                (point)
2979                                                (current-buffer))))))
2980
2981 (defun gnus-summary-buffer-name (group)
2982   "Return the summary buffer name of GROUP."
2983   (concat "*Summary " (gnus-group-decoded-name group) "*"))
2984
2985 (defun gnus-summary-setup-buffer (group)
2986   "Initialize summary buffer."
2987   (let ((buffer (gnus-summary-buffer-name group))
2988         (dead-name (concat "*Dead Summary "
2989                            (gnus-group-decoded-name group) "*")))
2990     ;; If a dead summary buffer exists, we kill it.
2991     (when (gnus-buffer-live-p dead-name)
2992       (gnus-kill-buffer dead-name))
2993     (if (get-buffer buffer)
2994         (progn
2995           (set-buffer buffer)
2996           (setq gnus-summary-buffer (current-buffer))
2997           (not gnus-newsgroup-prepared))
2998       ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>
2999       (setq gnus-summary-buffer (set-buffer (gnus-get-buffer-create buffer)))
3000       (gnus-summary-mode group)
3001       (when gnus-carpal
3002         (gnus-carpal-setup-buffer 'summary))
3003       (unless gnus-single-article-buffer
3004         (make-local-variable 'gnus-article-buffer)
3005         (make-local-variable 'gnus-article-current)
3006         (make-local-variable 'gnus-original-article-buffer))
3007       (setq gnus-newsgroup-name group)
3008       ;; Set any local variables in the group parameters.
3009       (gnus-summary-set-local-parameters gnus-newsgroup-name)
3010       t)))
3011
3012 (defun gnus-set-global-variables ()
3013   "Set the global equivalents of the buffer-local variables.
3014 They are set to the latest values they had.  These reflect the summary
3015 buffer that was in action when the last article was fetched."
3016   (when (eq major-mode 'gnus-summary-mode)
3017     (setq gnus-summary-buffer (current-buffer))
3018     (let ((name gnus-newsgroup-name)
3019           (marked gnus-newsgroup-marked)
3020           (spam gnus-newsgroup-spam-marked)
3021           (unread gnus-newsgroup-unreads)
3022           (headers gnus-current-headers)
3023           (data gnus-newsgroup-data)
3024           (summary gnus-summary-buffer)
3025           (article-buffer gnus-article-buffer)
3026           (original gnus-original-article-buffer)
3027           (gac gnus-article-current)
3028           (reffed gnus-reffed-article-number)
3029           (score-file gnus-current-score-file)
3030           (default-charset gnus-newsgroup-charset)
3031           vlist)
3032       (let ((locals gnus-newsgroup-variables))
3033         (while locals
3034           (if (consp (car locals))
3035               (push (eval (caar locals)) vlist)
3036             (push (eval (car locals)) vlist))
3037           (setq locals (cdr locals)))
3038         (setq vlist (nreverse vlist)))
3039       (save-excursion
3040         (set-buffer gnus-group-buffer)
3041         (setq gnus-newsgroup-name name
3042               gnus-newsgroup-marked marked
3043               gnus-newsgroup-spam-marked spam
3044               gnus-newsgroup-unreads unread
3045               gnus-current-headers headers
3046               gnus-newsgroup-data data
3047               gnus-article-current gac
3048               gnus-summary-buffer summary
3049               gnus-article-buffer article-buffer
3050               gnus-original-article-buffer original
3051               gnus-reffed-article-number reffed
3052               gnus-current-score-file score-file
3053               gnus-newsgroup-charset default-charset)
3054         (let ((locals gnus-newsgroup-variables))
3055           (while locals
3056             (if (consp (car locals))
3057                 (set (caar locals) (pop vlist))
3058               (set (car locals) (pop vlist)))
3059             (setq locals (cdr locals))))
3060         ;; The article buffer also has local variables.
3061         (when (gnus-buffer-live-p gnus-article-buffer)
3062           (set-buffer gnus-article-buffer)
3063           (setq gnus-summary-buffer summary))))))
3064
3065 (defun gnus-summary-article-unread-p (article)
3066   "Say whether ARTICLE is unread or not."
3067   (memq article gnus-newsgroup-unreads))
3068
3069 (defun gnus-summary-first-article-p (&optional article)
3070   "Return whether ARTICLE is the first article in the buffer."
3071   (if (not (setq article (or article (gnus-summary-article-number))))
3072       nil
3073     (eq article (caar gnus-newsgroup-data))))
3074
3075 (defun gnus-summary-last-article-p (&optional article)
3076   "Return whether ARTICLE is the last article in the buffer."
3077   (if (not (setq article (or article (gnus-summary-article-number))))
3078       ;; All non-existent numbers are the last article.  :-)
3079       t
3080     (not (cdr (gnus-data-find-list article)))))
3081
3082 (defun gnus-make-thread-indent-array ()
3083   (let ((n 200))
3084     (unless (and gnus-thread-indent-array
3085                  (= gnus-thread-indent-level gnus-thread-indent-array-level))
3086       (setq gnus-thread-indent-array (make-vector 201 "")
3087             gnus-thread-indent-array-level gnus-thread-indent-level)
3088       (while (>= n 0)
3089         (aset gnus-thread-indent-array n
3090               (make-string (* n gnus-thread-indent-level) ? ))
3091         (setq n (1- n))))))
3092
3093 (defun gnus-update-summary-mark-positions ()
3094   "Compute where the summary marks are to go."
3095   (save-excursion
3096     (when (gnus-buffer-exists-p gnus-summary-buffer)
3097       (set-buffer gnus-summary-buffer))
3098     (let ((gnus-replied-mark 129)
3099           (gnus-score-below-mark 130)
3100           (gnus-score-over-mark 130)
3101           (gnus-undownloaded-mark 131)
3102           (spec gnus-summary-line-format-spec)
3103           gnus-visual pos)
3104       (save-excursion
3105         (gnus-set-work-buffer)
3106         (let ((gnus-summary-line-format-spec spec)
3107               (gnus-newsgroup-downloadable '(0)))
3108           (gnus-summary-insert-line
3109            [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil]
3110            0 nil t 128 t nil "" nil 1)
3111           (goto-char (point-min))
3112           (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
3113                                              (- (point) (point-min) 1)))))
3114           (goto-char (point-min))
3115           (push (cons 'replied (and (search-forward "\201" nil t)
3116                                     (- (point) (point-min) 1)))
3117                 pos)
3118           (goto-char (point-min))
3119           (push (cons 'score (and (search-forward "\202" nil t)
3120                                   (- (point) (point-min) 1)))
3121                 pos)
3122           (goto-char (point-min))
3123           (push (cons 'download
3124                       (and (search-forward "\203" nil t)
3125                            (- (point) (point-min) 1)))
3126                 pos)))
3127       (setq gnus-summary-mark-positions pos))))
3128
3129 (defun gnus-summary-insert-dummy-line (gnus-tmp-subject gnus-tmp-number)
3130   "Insert a dummy root in the summary buffer."
3131   (beginning-of-line)
3132   (gnus-add-text-properties
3133    (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
3134    (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
3135
3136 (defun gnus-summary-extract-address-component (from)
3137   (or (car (funcall gnus-extract-address-components from))
3138       from))
3139
3140 (defun gnus-summary-from-or-to-or-newsgroups (header gnus-tmp-from)
3141   (let ((mail-parse-charset gnus-newsgroup-charset)
3142         ; Is it really necessary to do this next part for each summary line?
3143         ; Luckily, doesn't seem to slow things down much.
3144         (mail-parse-ignored-charsets
3145          (save-excursion (set-buffer gnus-summary-buffer)
3146                          gnus-newsgroup-ignored-charsets)))
3147     (or
3148      (and gnus-ignored-from-addresses
3149           (string-match gnus-ignored-from-addresses gnus-tmp-from)
3150           (let ((extra-headers (mail-header-extra header))
3151                 to
3152                 newsgroups)
3153             (cond
3154              ((setq to (cdr (assq 'To extra-headers)))
3155               (concat "-> "
3156                       (inline
3157                         (gnus-summary-extract-address-component
3158                          (funcall gnus-decode-encoded-word-function to)))))
3159              ((setq newsgroups (cdr (assq 'Newsgroups extra-headers)))
3160               (concat "=> " newsgroups)))))
3161      (inline (gnus-summary-extract-address-component gnus-tmp-from)))))
3162
3163 (defun gnus-summary-insert-line (gnus-tmp-header
3164                                  gnus-tmp-level gnus-tmp-current
3165                                  undownloaded gnus-tmp-unread gnus-tmp-replied
3166                                  gnus-tmp-expirable gnus-tmp-subject-or-nil
3167                                  &optional gnus-tmp-dummy gnus-tmp-score
3168                                  gnus-tmp-process)
3169   (let* ((gnus-tmp-indentation (aref gnus-thread-indent-array gnus-tmp-level))
3170          (gnus-tmp-lines (mail-header-lines gnus-tmp-header))
3171          (gnus-tmp-score (or gnus-tmp-score gnus-summary-default-score 0))
3172          (gnus-tmp-score-char
3173           (if (or (null gnus-summary-default-score)
3174                   (<= (abs (- gnus-tmp-score gnus-summary-default-score))
3175                       gnus-summary-zcore-fuzz))
3176               ?                         ;Whitespace
3177             (if (< gnus-tmp-score gnus-summary-default-score)
3178                 gnus-score-below-mark gnus-score-over-mark)))
3179          (gnus-tmp-number (mail-header-number gnus-tmp-header))
3180          (gnus-tmp-replied
3181           (cond (gnus-tmp-process gnus-process-mark)
3182                 ((memq gnus-tmp-current gnus-newsgroup-cached)
3183                  gnus-cached-mark)
3184                 (gnus-tmp-replied gnus-replied-mark)
3185                 ((memq gnus-tmp-current gnus-newsgroup-forwarded)
3186                  gnus-forwarded-mark)
3187                 ((memq gnus-tmp-current gnus-newsgroup-saved)
3188                  gnus-saved-mark)
3189                 ((memq gnus-tmp-number gnus-newsgroup-recent)
3190                  gnus-recent-mark)
3191                 ((memq gnus-tmp-number gnus-newsgroup-unseen)
3192                  gnus-unseen-mark)
3193                 (t gnus-no-mark)))
3194          (gnus-tmp-downloaded
3195           (cond (undownloaded 
3196                  gnus-undownloaded-mark)
3197                 (gnus-newsgroup-agentized
3198                  gnus-downloaded-mark)
3199                 (t
3200                  gnus-no-mark)))
3201          (gnus-tmp-from (mail-header-from gnus-tmp-header))
3202          (gnus-tmp-name
3203           (cond
3204            ((string-match "<[^>]+> *$" gnus-tmp-from)
3205             (let ((beg (match-beginning 0)))
3206               (or (and (string-match "^\".+\"" gnus-tmp-from)
3207                        (substring gnus-tmp-from 1 (1- (match-end 0))))
3208                   (substring gnus-tmp-from 0 beg))))
3209            ((string-match "(.+)" gnus-tmp-from)
3210             (substring gnus-tmp-from
3211                        (1+ (match-beginning 0)) (1- (match-end 0))))
3212            (t gnus-tmp-from)))
3213          (gnus-tmp-subject (mail-header-subject gnus-tmp-header))
3214          (gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
3215          (gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
3216          (buffer-read-only nil))
3217     (when (string= gnus-tmp-name "")
3218       (setq gnus-tmp-name gnus-tmp-from))
3219     (unless (numberp gnus-tmp-lines)
3220       (setq gnus-tmp-lines -1))
3221     (if (= gnus-tmp-lines -1)
3222         (setq gnus-tmp-lines "?")
3223       (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
3224     (gnus-put-text-property
3225      (point)
3226      (progn (eval gnus-summary-line-format-spec) (point))
3227      'gnus-number gnus-tmp-number)
3228     (when (gnus-visual-p 'summary-highlight 'highlight)
3229       (forward-line -1)
3230       (gnus-run-hooks 'gnus-summary-update-hook)
3231       (forward-line 1))))
3232
3233 (defun gnus-summary-update-line (&optional dont-update)
3234   "Update summary line after change."
3235   (when (and gnus-summary-default-score
3236              (not gnus-summary-inhibit-highlight))
3237     (let* ((gnus-summary-inhibit-highlight t) ; Prevent recursion.
3238            (article (gnus-summary-article-number))
3239            (score (gnus-summary-article-score article)))
3240       (unless dont-update
3241         (if (and gnus-summary-mark-below
3242                  (< (gnus-summary-article-score)
3243                     gnus-summary-mark-below))
3244             ;; This article has a low score, so we mark it as read.
3245             (when (memq article gnus-newsgroup-unreads)
3246               (gnus-summary-mark-article-as-read gnus-low-score-mark))
3247           (when (eq (gnus-summary-article-mark) gnus-low-score-mark)
3248             ;; This article was previously marked as read on account
3249             ;; of a low score, but now it has risen, so we mark it as
3250             ;; unread.
3251             (gnus-summary-mark-article-as-unread gnus-unread-mark)))
3252         (gnus-summary-update-mark
3253          (if (or (null gnus-summary-default-score)
3254                  (<= (abs (- score gnus-summary-default-score))
3255                      gnus-summary-zcore-fuzz))
3256              ?                          ;Whitespace
3257            (if (< score gnus-summary-default-score)
3258                gnus-score-below-mark gnus-score-over-mark))
3259          'score))
3260       ;; Do visual highlighting.
3261       (when (gnus-visual-p 'summary-highlight 'highlight)
3262         (gnus-run-hooks 'gnus-summary-update-hook)))))
3263
3264 (defvar gnus-tmp-new-adopts nil)
3265
3266 (defun gnus-summary-number-of-articles-in-thread (thread &optional level char)
3267   "Return the number of articles in THREAD.
3268 This may be 0 in some cases -- if none of the articles in
3269 the thread are to be displayed."
3270   (let* ((number
3271          ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
3272           (cond
3273            ((not (listp thread))
3274             1)
3275            ((and (consp thread) (cdr thread))
3276             (apply
3277              '+ 1 (mapcar
3278                    'gnus-summary-number-of-articles-in-thread (cdr thread))))
3279            ((null thread)
3280             1)
3281            ((memq (mail-header-number (car thread)) gnus-newsgroup-limit)
3282             1)
3283            (t 0))))
3284     (when (and level (zerop level) gnus-tmp-new-adopts)
3285       (incf number
3286             (apply '+ (mapcar
3287                        'gnus-summary-number-of-articles-in-thread
3288                        gnus-tmp-new-adopts))))
3289     (if char
3290         (if (> number 1) gnus-not-empty-thread-mark
3291           gnus-empty-thread-mark)
3292       number)))
3293
3294 (defsubst gnus-summary-line-message-size (head)
3295   "Return pretty-printed version of message size.
3296 This function is intended to be used in
3297 `gnus-summary-line-format-alist', which see."
3298   (let ((c (or (mail-header-chars head) -1)))
3299     (cond ((< c 0) "n/a")               ; chars not available
3300           ((< c (* 1000 10)) (format "%1.1fk" (/ c 1024.0)))
3301           ((< c (* 1000 100)) (format "%dk" (/ c 1024.0)))
3302           ((< c (* 1000 10000)) (format "%1.1fM" (/ c (* 1024.0 1024))))
3303           (t (format "%dM" (/ c (* 1024.0 1024)))))))
3304
3305
3306 (defun gnus-summary-set-local-parameters (group)
3307   "Go through the local params of GROUP and set all variable specs in that list."
3308   (let ((params (gnus-group-find-parameter group))
3309         (vars '(quit-config))           ; Ignore quit-config.
3310         elem)
3311     (while params
3312       (setq elem (car params)
3313             params (cdr params))
3314       (and (consp elem)                 ; Has to be a cons.
3315            (consp (cdr elem))           ; The cdr has to be a list.
3316            (symbolp (car elem))         ; Has to be a symbol in there.
3317            (not (memq (car elem) vars))
3318            (ignore-errors               ; So we set it.
3319              (push (car elem) vars)
3320              (make-local-variable (car elem))
3321              (set (car elem) (eval (nth 1 elem))))))))
3322
3323 (defun gnus-summary-read-group (group &optional show-all no-article
3324                                       kill-buffer no-display backward
3325                                       select-articles)
3326   "Start reading news in newsgroup GROUP.
3327 If SHOW-ALL is non-nil, already read articles are also listed.
3328 If NO-ARTICLE is non-nil, no article is selected initially.
3329 If NO-DISPLAY, don't generate a summary buffer."
3330   (let (result)
3331     (while (and group
3332                 (null (setq result
3333                             (let ((gnus-auto-select-next nil))
3334                               (or (gnus-summary-read-group-1
3335                                    group show-all no-article
3336                                    kill-buffer no-display
3337                                    select-articles)
3338                                   (setq show-all nil
3339                                         select-articles nil)))))
3340                 (eq gnus-auto-select-next 'quietly))
3341       (set-buffer gnus-group-buffer)
3342       ;; The entry function called above goes to the next
3343       ;; group automatically, so we go two groups back
3344       ;; if we are searching for the previous group.
3345       (when backward
3346         (gnus-group-prev-unread-group 2))
3347       (if (not (equal group (gnus-group-group-name)))
3348           (setq group (gnus-group-group-name))
3349         (setq group nil)))
3350     result))
3351
3352 (defun gnus-summary-read-group-1 (group show-all no-article
3353                                         kill-buffer no-display
3354                                         &optional select-articles)
3355   ;; Killed foreign groups can't be entered.
3356   ;;  (when (and (not (gnus-group-native-p group))
3357   ;;         (not (gnus-gethash group gnus-newsrc-hashtb)))
3358   ;;    (error "Dead non-native groups can't be entered"))
3359   (gnus-message 5 "Retrieving newsgroup: %s..."
3360                 (gnus-group-decoded-name group))
3361   (let* ((new-group (gnus-summary-setup-buffer group))
3362          (quit-config (gnus-group-quit-config group))
3363          (did-select (and new-group (gnus-select-newsgroup
3364                                      group show-all select-articles))))
3365     (cond
3366      ;; This summary buffer exists already, so we just select it.
3367      ((not new-group)
3368       (gnus-set-global-variables)
3369       (when kill-buffer
3370         (gnus-kill-or-deaden-summary kill-buffer))
3371       (gnus-configure-windows 'summary 'force)
3372       (gnus-set-mode-line 'summary)
3373       (gnus-summary-position-point)
3374       (message "")
3375       t)
3376      ;; We couldn't select this group.
3377      ((null did-select)
3378       (when (and (eq major-mode 'gnus-summary-mode)
3379                  (not (equal (current-buffer) kill-buffer)))
3380         (kill-buffer (current-buffer))
3381         (if (not quit-config)
3382             (progn
3383               ;; Update the info -- marks might need to be removed,
3384               ;; for instance.
3385               (gnus-summary-update-info)
3386               (set-buffer gnus-group-buffer)
3387               (gnus-group-jump-to-group group)
3388               (gnus-group-next-unread-group 1))
3389           (gnus-handle-ephemeral-exit quit-config)))
3390       (let ((grpinfo (gnus-get-info group)))
3391         (if (null (gnus-info-read grpinfo))
3392             (gnus-message 3 "Group %s contains no messages"
3393                           (gnus-group-decoded-name group))
3394           (gnus-message 3 "Can't select group")))
3395       nil)
3396      ;; The user did a `C-g' while prompting for number of articles,
3397      ;; so we exit this group.
3398      ((eq did-select 'quit)
3399       (and (eq major-mode 'gnus-summary-mode)
3400            (not (equal (current-buffer) kill-buffer))
3401            (kill-buffer (current-buffer)))
3402       (when kill-buffer
3403         (gnus-kill-or-deaden-summary kill-buffer))
3404       (if (not quit-config)
3405           (progn
3406             (set-buffer gnus-group-buffer)
3407             (gnus-group-jump-to-group group)
3408             (gnus-group-next-unread-group 1)
3409             (gnus-configure-windows 'group 'force))
3410         (gnus-handle-ephemeral-exit quit-config))
3411       ;; Finally signal the quit.
3412       (signal 'quit nil))
3413      ;; The group was successfully selected.
3414      (t
3415       (gnus-set-global-variables)
3416       ;; Save the active value in effect when the group was entered.
3417       (setq gnus-newsgroup-active
3418             (gnus-copy-sequence
3419              (gnus-active gnus-newsgroup-name)))
3420       ;; You can change the summary buffer in some way with this hook.
3421       (gnus-run-hooks 'gnus-select-group-hook)
3422       (gnus-update-format-specifications
3423        nil 'summary 'summary-mode 'summary-dummy)
3424       (gnus-update-summary-mark-positions)
3425       ;; Do score processing.
3426       (when gnus-use-scoring
3427         (gnus-possibly-score-headers))
3428       ;; Check whether to fill in the gaps in the threads.
3429       (when gnus-build-sparse-threads
3430         (gnus-build-sparse-threads))
3431       ;; Find the initial limit.
3432       (if gnus-show-threads
3433           (if show-all
3434               (let ((gnus-newsgroup-dormant nil))
3435                 (gnus-summary-initial-limit show-all))
3436             (gnus-summary-initial-limit show-all))
3437         ;; When unthreaded, all articles are always shown.
3438         (setq gnus-newsgroup-limit
3439               (mapcar
3440                (lambda (header) (mail-header-number header))
3441                gnus-newsgroup-headers)))
3442       ;; Generate the summary buffer.
3443       (unless no-display
3444         (gnus-summary-prepare))
3445       (when gnus-use-trees
3446         (gnus-tree-open group)
3447         (setq gnus-summary-highlight-line-function
3448               'gnus-tree-highlight-article))
3449       ;; If the summary buffer is empty, but there are some low-scored
3450       ;; articles or some excluded dormants, we include these in the
3451       ;; buffer.
3452       (when (and (zerop (buffer-size))
3453                  (not no-display))
3454         (cond (gnus-newsgroup-dormant
3455                (gnus-summary-limit-include-dormant))
3456               ((and gnus-newsgroup-scored show-all)
3457                (gnus-summary-limit-include-expunged t))))
3458       ;; Function `gnus-apply-kill-file' must be called in this hook.
3459       (gnus-run-hooks 'gnus-apply-kill-hook)
3460       (if (and (zerop (buffer-size))
3461                (not no-display))
3462           (progn
3463             ;; This newsgroup is empty.
3464             (gnus-summary-catchup-and-exit nil t)
3465             (gnus-message 6 "No unread news")
3466             (when kill-buffer
3467               (gnus-kill-or-deaden-summary kill-buffer))
3468             ;; Return nil from this function.
3469             nil)
3470         ;; Hide conversation thread subtrees.  We cannot do this in
3471         ;; gnus-summary-prepare-hook since kill processing may not
3472         ;; work with hidden articles.
3473         (gnus-summary-maybe-hide-threads)
3474         (when kill-buffer
3475           (gnus-kill-or-deaden-summary kill-buffer))
3476         (gnus-summary-auto-select-subject)
3477         ;; Show first unread article if requested.
3478         (if (and (not no-article)
3479                  (not no-display)
3480                  gnus-newsgroup-unreads
3481                  gnus-auto-select-first)
3482             (progn
3483               (gnus-configure-windows 'summary)
3484               (let ((art (gnus-summary-article-number)))
3485                 (unless (or (memq art gnus-newsgroup-undownloaded)
3486                             (memq art gnus-newsgroup-downloadable))
3487                   (gnus-summary-goto-article art))))
3488           ;; Don't select any articles.
3489           (gnus-summary-position-point)
3490           (gnus-configure-windows 'summary 'force)
3491           (gnus-set-mode-line 'summary))
3492         (when (get-buffer-window gnus-group-buffer t)
3493           ;; Gotta use windows, because recenter does weird stuff if
3494           ;; the current buffer ain't the displayed window.
3495           (let ((owin (selected-window)))
3496             (select-window (get-buffer-window gnus-group-buffer t))
3497             (when (gnus-group-goto-group group)
3498               (recenter))
3499             (select-window owin)))
3500         ;; Mark this buffer as "prepared".
3501         (setq gnus-newsgroup-prepared t)
3502         (gnus-run-hooks 'gnus-summary-prepared-hook)
3503         (unless (gnus-ephemeral-group-p group)
3504           (gnus-group-update-group group))
3505         t)))))
3506
3507 (defun gnus-summary-auto-select-subject ()
3508   "Select the subject line on initial group entry."
3509   (goto-char (point-min))
3510   (cond
3511    ((eq gnus-auto-select-subject 'best)
3512     (gnus-summary-best-unread-subject))
3513    ((eq gnus-auto-select-subject 'unread)
3514     (gnus-summary-first-unread-subject))
3515    ((eq gnus-auto-select-subject 'unseen)
3516     (gnus-summary-first-unseen-subject))
3517    ((eq gnus-auto-select-subject 'unseen-or-unread)
3518     (gnus-summary-first-unseen-or-unread-subject))
3519    ((eq gnus-auto-select-subject 'first)
3520     ;; Do nothing.
3521     )
3522    ((gnus-functionp gnus-auto-select-subject)
3523     (funcall gnus-auto-select-subject))))
3524
3525 (defun gnus-summary-prepare ()
3526   "Generate the summary buffer."
3527   (interactive)
3528   (let ((buffer-read-only nil))
3529     (erase-buffer)
3530     (setq gnus-newsgroup-data nil
3531           gnus-newsgroup-data-reverse nil)
3532     (gnus-run-hooks 'gnus-summary-generate-hook)
3533     ;; Generate the buffer, either with threads or without.
3534     (when gnus-newsgroup-headers
3535       (gnus-summary-prepare-threads
3536        (if gnus-show-threads
3537            (gnus-sort-gathered-threads
3538             (funcall gnus-summary-thread-gathering-function
3539                      (gnus-sort-threads
3540                       (gnus-cut-threads (gnus-make-threads)))))
3541          ;; Unthreaded display.
3542          (gnus-sort-articles gnus-newsgroup-headers))))
3543     (setq gnus-newsgroup-data (nreverse gnus-newsgroup-data))
3544     ;; Call hooks for modifying summary buffer.
3545     (goto-char (point-min))
3546     (gnus-run-hooks 'gnus-summary-prepare-hook)))
3547
3548 (defsubst gnus-general-simplify-subject (subject)
3549   "Simply subject by the same rules as gnus-gather-threads-by-subject."
3550   (setq subject
3551         (cond
3552          ;; Truncate the subject.
3553          (gnus-simplify-subject-functions
3554           (gnus-map-function gnus-simplify-subject-functions subject))
3555          ((numberp gnus-summary-gather-subject-limit)
3556           (setq subject (gnus-simplify-subject-re subject))
3557           (if (> (length subject) gnus-summary-gather-subject-limit)
3558               (substring subject 0 gnus-summary-gather-subject-limit)
3559             subject))
3560          ;; Fuzzily simplify it.
3561          ((eq 'fuzzy gnus-summary-gather-subject-limit)
3562           (gnus-simplify-subject-fuzzy subject))
3563          ;; Just remove the leading "Re:".
3564          (t
3565           (gnus-simplify-subject-re subject))))
3566
3567   (if (and gnus-summary-gather-exclude-subject
3568            (string-match gnus-summary-gather-exclude-subject subject))
3569       nil                         ; This article shouldn't be gathered
3570     subject))
3571
3572 (defun gnus-summary-simplify-subject-query ()
3573   "Query where the respool algorithm would put this article."
3574   (interactive)
3575   (gnus-summary-select-article)
3576   (message (gnus-general-simplify-subject (gnus-summary-article-subject))))
3577
3578 (defun gnus-gather-threads-by-subject (threads)
3579   "Gather threads by looking at Subject headers."
3580   (if (not gnus-summary-make-false-root)
3581       threads
3582     (let ((hashtb (gnus-make-hashtable 1024))
3583           (prev threads)
3584           (result threads)
3585           subject hthread whole-subject)
3586       (while threads
3587         (setq subject (gnus-general-simplify-subject
3588                        (setq whole-subject (mail-header-subject
3589                                             (caar threads)))))
3590         (when subject
3591           (if (setq hthread (gnus-gethash subject hashtb))
3592               (progn
3593                 ;; We enter a dummy root into the thread, if we
3594                 ;; haven't done that already.
3595                 (unless (stringp (caar hthread))
3596                   (setcar hthread (list whole-subject (car hthread))))
3597                 ;; We add this new gathered thread to this gathered
3598                 ;; thread.
3599                 (setcdr (car hthread)
3600                         (nconc (cdar hthread) (list (car threads))))
3601                 ;; Remove it from the list of threads.
3602                 (setcdr prev (cdr threads))
3603                 (setq threads prev))
3604             ;; Enter this thread into the hash table.
3605             (gnus-sethash subject
3606                           (if gnus-summary-make-false-root-always
3607                               (progn
3608                                 ;; If you want a dummy root above all
3609                                 ;; threads...
3610                                 (setcar threads (list whole-subject
3611                                                       (car threads)))
3612                                 threads)
3613                             threads)
3614                           hashtb)))
3615         (setq prev threads)
3616         (setq threads (cdr threads)))
3617       result)))
3618
3619 (defun gnus-gather-threads-by-references (threads)
3620   "Gather threads by looking at References headers."
3621   (let ((idhashtb (gnus-make-hashtable 1024))
3622         (thhashtb (gnus-make-hashtable 1024))
3623         (prev threads)
3624         (result threads)
3625         ids references id gthread gid entered ref)
3626     (while threads
3627       (when (setq references (mail-header-references (caar threads)))
3628         (setq id (mail-header-id (caar threads))
3629               ids (inline (gnus-split-references references))
3630               entered nil)
3631         (while (setq ref (pop ids))
3632           (setq ids (delete ref ids))
3633           (if (not (setq gid (gnus-gethash ref idhashtb)))
3634               (progn
3635                 (gnus-sethash ref id idhashtb)
3636                 (gnus-sethash id threads thhashtb))
3637             (setq gthread (gnus-gethash gid thhashtb))
3638             (unless entered
3639               ;; We enter a dummy root into the thread, if we
3640               ;; haven't done that already.
3641               (unless (stringp (caar gthread))
3642                 (setcar gthread (list (mail-header-subject (caar gthread))
3643                                       (car gthread))))
3644               ;; We add this new gathered thread to this gathered
3645               ;; thread.
3646               (setcdr (car gthread)
3647                       (nconc (cdar gthread) (list (car threads)))))
3648             ;; Add it into the thread hash table.
3649             (gnus-sethash id gthread thhashtb)
3650             (setq entered t)
3651             ;; Remove it from the list of threads.
3652             (setcdr prev (cdr threads))
3653             (setq threads prev))))
3654       (setq prev threads)
3655       (setq threads (cdr threads)))
3656     result))
3657
3658 (defun gnus-sort-gathered-threads (threads)
3659   "Sort subtreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
3660   (let ((result threads))
3661     (while threads
3662       (when (stringp (caar threads))
3663         (setcdr (car threads)
3664                 (sort (cdar threads) gnus-sort-gathered-threads-function)))
3665       (setq threads (cdr threads)))
3666     result))
3667
3668 (defun gnus-thread-loop-p (root thread)
3669   "Say whether ROOT is in THREAD."
3670   (let ((stack (list thread))
3671         (infloop 0)
3672         th)
3673     (while (setq thread (pop stack))
3674       (setq th (cdr thread))
3675       (while (and th
3676                   (not (eq (caar th) root)))
3677         (pop th))
3678       (if th
3679           ;; We have found a loop.
3680           (let (ref-dep)
3681             (setcdr thread (delq (car th) (cdr thread)))
3682             (if (boundp (setq ref-dep (intern "none"
3683                                               gnus-newsgroup-dependencies)))
3684                 (setcdr (symbol-value ref-dep)
3685                         (nconc (cdr (symbol-value ref-dep))
3686                                (list (car th))))
3687               (set ref-dep (list nil (car th))))
3688             (setq infloop 1
3689                   stack nil))
3690         ;; Push all the subthreads onto the stack.
3691         (push (cdr thread) stack)))
3692     infloop))
3693
3694 (defun gnus-make-threads ()
3695   "Go through the dependency hashtb and find the roots.  Return all threads."
3696   (let (threads)
3697     (while (catch 'infloop
3698              (mapatoms
3699               (lambda (refs)
3700                 ;; Deal with self-referencing References loops.
3701                 (when (and (car (symbol-value refs))
3702                            (not (zerop
3703                                  (apply
3704                                   '+
3705                                   (mapcar
3706                                    (lambda (thread)
3707                                      (gnus-thread-loop-p
3708                                       (car (symbol-value refs)) thread))
3709                                    (cdr (symbol-value refs)))))))
3710                   (setq threads nil)
3711                   (throw 'infloop t))
3712                 (unless (car (symbol-value refs))
3713                   ;; These threads do not refer back to any other
3714                   ;; articles, so they're roots.
3715                   (setq threads (append (cdr (symbol-value refs)) threads))))
3716               gnus-newsgroup-dependencies)))
3717     threads))
3718
3719 ;; Build the thread tree.
3720 (defsubst gnus-dependencies-add-header (header dependencies force-new)
3721   "Enter HEADER into the DEPENDENCIES table if it is not already there.
3722
3723 If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
3724 if it was already present.
3725
3726 If `gnus-summary-ignore-duplicates' is nil then duplicate Message-IDs
3727 will not be entered in the DEPENDENCIES table.  Otherwise duplicate
3728 Message-IDs will be renamed to a unique Message-ID before being
3729 entered.
3730
3731 Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
3732   (let* ((id (mail-header-id header))
3733          (id-dep (and id (intern id dependencies)))
3734          parent-id ref ref-dep ref-header replaced)
3735     ;; Enter this `header' in the `dependencies' table.
3736     (cond
3737      ((not id-dep)
3738       (setq header nil))
3739      ;; The first two cases do the normal part: enter a new `header'
3740      ;; in the `dependencies' table.
3741      ((not (boundp id-dep))
3742       (set id-dep (list header)))
3743      ((null (car (symbol-value id-dep)))
3744       (setcar (symbol-value id-dep) header))
3745
3746      ;; From here the `header' was already present in the
3747      ;; `dependencies' table.
3748      (force-new
3749       ;; Overrides an existing entry;
3750       ;; just set the header part of the entry.
3751       (setcar (symbol-value id-dep) header)
3752       (setq replaced t))
3753
3754      ;; Renames the existing `header' to a unique Message-ID.
3755      ((not gnus-summary-ignore-duplicates)
3756       ;; An article with this Message-ID has already been seen.
3757       ;; We rename the Message-ID.
3758       (set (setq id-dep (intern (setq id (nnmail-message-id)) dependencies))
3759            (list header))
3760       (mail-header-set-id header id))
3761
3762      ;; The last case ignores an existing entry, except it adds any
3763      ;; additional Xrefs (in case the two articles came from different
3764      ;; servers.
3765      ;; Also sets `header' to `nil' meaning that the `dependencies'
3766      ;; table was *not* modified.
3767      (t
3768       (mail-header-set-xref
3769        (car (symbol-value id-dep))
3770        (concat (or (mail-header-xref (car (symbol-value id-dep)))
3771                    "")
3772                (or (mail-header-xref header) "")))
3773       (setq header nil)))
3774
3775     (when (and header (not replaced))
3776       ;; First check that we are not creating a References loop.
3777       (setq parent-id (gnus-parent-id (mail-header-references header)))
3778       (setq ref parent-id)
3779       (while (and ref
3780                   (setq ref-dep (intern-soft ref dependencies))
3781                   (boundp ref-dep)
3782                   (setq ref-header (car (symbol-value ref-dep))))
3783         (if (string= id ref)
3784             ;; Yuk!  This is a reference loop.  Make the article be a
3785             ;; root article.
3786             (progn
3787               (mail-header-set-references (car (symbol-value id-dep)) "none")
3788               (setq ref nil)
3789               (setq parent-id nil))
3790           (setq ref (gnus-parent-id (mail-header-references ref-header)))))
3791       (setq ref-dep (intern (or parent-id "none") dependencies))
3792       (if (boundp ref-dep)
3793           (setcdr (symbol-value ref-dep)
3794                   (nconc (cdr (symbol-value ref-dep))
3795                          (list (symbol-value id-dep))))
3796         (set ref-dep (list nil (symbol-value id-dep)))))
3797     header))
3798
3799 (defun gnus-extract-message-id-from-in-reply-to (string)
3800   (if (string-match "<[^>]+>" string)
3801       (substring string (match-beginning 0) (match-end 0))
3802     nil))
3803
3804 (defun gnus-build-sparse-threads ()
3805   (let ((headers gnus-newsgroup-headers)
3806         (mail-parse-charset gnus-newsgroup-charset)
3807         (gnus-summary-ignore-duplicates t)
3808         header references generation relations
3809         subject child end new-child date)
3810     ;; First we create an alist of generations/relations, where
3811     ;; generations is how much we trust the relation, and the relation
3812     ;; is parent/child.
3813     (gnus-message 7 "Making sparse threads...")
3814     (save-excursion
3815       (nnheader-set-temp-buffer " *gnus sparse threads*")
3816       (while (setq header (pop headers))
3817         (when (and (setq references (mail-header-references header))
3818                    (not (string= references "")))
3819           (insert references)
3820           (setq child (mail-header-id header)
3821                 subject (mail-header-subject header)
3822                 date (mail-header-date header)
3823                 generation 0)
3824           (while (search-backward ">" nil t)
3825             (setq end (1+ (point)))
3826             (when (search-backward "<" nil t)
3827               (setq new-child (buffer-substring (point) end))
3828               (push (list (incf generation)
3829                           child (setq child new-child)
3830                           subject date)
3831                     relations)))
3832           (when child
3833             (push (list (1+ generation) child nil subject) relations))
3834           (erase-buffer)))
3835       (kill-buffer (current-buffer)))
3836     ;; Sort over trustworthiness.
3837     (mapcar
3838      (lambda (relation)
3839        (when (gnus-dependencies-add-header
3840               (make-full-mail-header
3841                gnus-reffed-article-number
3842                (nth 3 relation) "" (or (nth 4 relation) "")
3843                (nth 1 relation)
3844                (or (nth 2 relation) "") 0 0 "")
3845               gnus-newsgroup-dependencies nil)
3846          (push gnus-reffed-article-number gnus-newsgroup-limit)
3847          (push gnus-reffed-article-number gnus-newsgroup-sparse)
3848          (push (cons gnus-reffed-article-number gnus-sparse-mark)
3849                gnus-newsgroup-reads)
3850          (decf gnus-reffed-article-number)))
3851      (sort relations 'car-less-than-car))
3852     (gnus-message 7 "Making sparse threads...done")))
3853
3854 (defun gnus-build-old-threads ()
3855   ;; Look at all the articles that refer back to old articles, and
3856   ;; fetch the headers for the articles that aren't there.  This will
3857   ;; build complete threads - if the roots haven't been expired by the
3858   ;; server, that is.
3859   (let ((mail-parse-charset gnus-newsgroup-charset)
3860         id heads)
3861     (mapatoms
3862      (lambda (refs)
3863        (when (not (car (symbol-value refs)))
3864          (setq heads (cdr (symbol-value refs)))
3865          (while heads
3866            (if (memq (mail-header-number (caar heads))
3867                      gnus-newsgroup-dormant)
3868                (setq heads (cdr heads))
3869              (setq id (symbol-name refs))
3870              (while (and (setq id (gnus-build-get-header id))
3871                          (not (car (gnus-id-to-thread id)))))
3872              (setq heads nil)))))
3873      gnus-newsgroup-dependencies)))
3874
3875 ;; This function has to be called with point after the article number
3876 ;; on the beginning of the line.
3877 (defsubst gnus-nov-parse-line (number dependencies &optional force-new)
3878   (let ((eol (gnus-point-at-eol))
3879         (buffer (current-buffer))
3880         header references in-reply-to)
3881
3882     ;; overview: [num subject from date id refs chars lines misc]
3883     (unwind-protect
3884         (let (x)
3885           (narrow-to-region (point) eol)
3886           (unless (eobp)
3887             (forward-char))
3888
3889           (setq header
3890                 (make-full-mail-header
3891                  number                 ; number
3892                  (condition-case ()     ; subject
3893                      (funcall gnus-decode-encoded-word-function
3894                               (setq x (nnheader-nov-field)))
3895                    (error x))
3896                  (condition-case ()     ; from
3897                      (funcall gnus-decode-encoded-word-function
3898                               (setq x (nnheader-nov-field)))
3899                    (error x))
3900                  (nnheader-nov-field)   ; date
3901                  (nnheader-nov-read-message-id) ; id
3902                  (setq references (nnheader-nov-field)) ; refs
3903                  (nnheader-nov-read-integer) ; chars
3904                  (nnheader-nov-read-integer) ; lines
3905                  (unless (eobp)
3906                    (if (looking-at "Xref: ")
3907                        (goto-char (match-end 0)))
3908                    (nnheader-nov-field)) ; Xref
3909                  (nnheader-nov-parse-extra)))) ; extra
3910
3911       (widen))
3912
3913     (when (and (string= references "")
3914                (setq in-reply-to (mail-header-extra header))
3915                (setq in-reply-to (cdr (assq 'In-Reply-To in-reply-to))))
3916       (mail-header-set-references
3917        header (gnus-extract-message-id-from-in-reply-to in-reply-to)))
3918
3919     (when gnus-alter-header-function
3920       (funcall gnus-alter-header-function header))
3921     (gnus-dependencies-add-header header dependencies force-new)))
3922
3923 (defun gnus-build-get-header (id)
3924   "Look through the buffer of NOV lines and find the header to ID.
3925 Enter this line into the dependencies hash table, and return
3926 the id of the parent article (if any)."
3927   (let ((deps gnus-newsgroup-dependencies)
3928         found header)
3929     (prog1
3930         (save-excursion
3931           (set-buffer nntp-server-buffer)
3932           (let ((case-fold-search nil))
3933             (goto-char (point-min))
3934             (while (and (not found)
3935                         (search-forward id nil t))
3936               (beginning-of-line)
3937               (setq found (looking-at
3938                            (format "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t%s"
3939                                    (regexp-quote id))))
3940               (or found (beginning-of-line 2)))
3941             (when found
3942               (beginning-of-line)
3943               (and
3944                (setq header (gnus-nov-parse-line
3945                              (read (current-buffer)) deps))
3946                (gnus-parent-id (mail-header-references header))))))
3947       (when header
3948         (let ((number (mail-header-number header)))
3949           (push number gnus-newsgroup-limit)
3950           (push header gnus-newsgroup-headers)
3951           (if (memq number gnus-newsgroup-unselected)
3952               (progn
3953                 (setq gnus-newsgroup-unreads
3954                       (gnus-add-to-sorted-list gnus-newsgroup-unreads
3955                                                number))
3956                 (setq gnus-newsgroup-unselected
3957                       (delq number gnus-newsgroup-unselected)))
3958             (push number gnus-newsgroup-ancient)))))))
3959
3960 (defun gnus-build-all-threads ()
3961   "Read all the headers."
3962   (let ((gnus-summary-ignore-duplicates t)
3963         (mail-parse-charset gnus-newsgroup-charset)
3964         (dependencies gnus-newsgroup-dependencies)
3965         header article)
3966     (save-excursion
3967       (set-buffer nntp-server-buffer)
3968       (let ((case-fold-search nil))
3969         (goto-char (point-min))
3970         (while (not (eobp))
3971           (ignore-errors
3972             (setq article (read (current-buffer))
3973                   header (gnus-nov-parse-line article dependencies)))
3974           (when header
3975             (save-excursion
3976               (set-buffer gnus-summary-buffer)
3977               (push header gnus-newsgroup-headers)
3978               (if (memq (setq article (mail-header-number header))
3979                         gnus-newsgroup-unselected)
3980                   (progn
3981                     (setq gnus-newsgroup-unreads
3982                           (gnus-add-to-sorted-list
3983                            gnus-newsgroup-unreads article))
3984                     (setq gnus-newsgroup-unselected
3985                           (delq article gnus-newsgroup-unselected)))
3986                 (push article gnus-newsgroup-ancient)))
3987             (forward-line 1)))))))
3988
3989 (defun gnus-summary-update-article-line (article header)
3990   "Update the line for ARTICLE using HEADERS."
3991   (let* ((id (mail-header-id header))
3992          (thread (gnus-id-to-thread id)))
3993     (unless thread
3994       (error "Article in no thread"))
3995     ;; Update the thread.
3996     (setcar thread header)
3997     (gnus-summary-goto-subject article)
3998     (let* ((datal (gnus-data-find-list article))
3999            (data (car datal))
4000            (length (when (cdr datal)
4001                      (- (gnus-data-pos data)
4002                         (gnus-data-pos (cadr datal)))))
4003            (buffer-read-only nil)
4004            (level (gnus-summary-thread-level)))
4005       (gnus-delete-line)
4006       (gnus-summary-insert-line
4007        header level nil 
4008        (memq article gnus-newsgroup-undownloaded)
4009        (gnus-article-mark article)
4010        (memq article gnus-newsgroup-replied)
4011        (memq article gnus-newsgroup-expirable)
4012        ;; Only insert the Subject string when it's different
4013        ;; from the previous Subject string.
4014        (if (and
4015             gnus-show-threads
4016             (gnus-subject-equal
4017              (condition-case ()
4018                  (mail-header-subject
4019                   (gnus-data-header
4020                    (cadr
4021                     (gnus-data-find-list
4022                      article
4023                      (gnus-data-list t)))))
4024                ;; Error on the side of excessive subjects.
4025                (error ""))
4026              (mail-header-subject header)))
4027            ""
4028          (mail-header-subject header))
4029        nil (cdr (assq article gnus-newsgroup-scored))
4030        (memq article gnus-newsgroup-processable))
4031       (when length
4032         (gnus-data-update-list
4033          (cdr datal) (- length (- (gnus-data-pos data) (point))))))))
4034
4035 (defun gnus-summary-update-article (article &optional iheader)
4036   "Update ARTICLE in the summary buffer."
4037   (set-buffer gnus-summary-buffer)
4038   (let* ((header (gnus-summary-article-header article))
4039          (id (mail-header-id header))
4040          (data (gnus-data-find article))
4041          (thread (gnus-id-to-thread id))
4042          (references (mail-header-references header))
4043          (parent
4044           (gnus-id-to-thread
4045            (or (gnus-parent-id
4046                 (when (and references
4047                            (not (equal "" references)))
4048                   references))
4049                "none")))
4050          (buffer-read-only nil)
4051          (old (car thread)))
4052     (when thread
4053       (unless iheader
4054         (setcar thread nil)