*** empty log message ***
[bpt/emacs.git] / lisp / gnus / gnus-sum.el
CommitLineData
eec82323 1;;; gnus-sum.el --- summary mode commands for Gnus
23f87bed 2;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
16409b0b 3;; Free Software Foundation, Inc.
eec82323 4
6748645f 5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
eec82323
LMI
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
23f87bed
MB
29(eval-when-compile
30 (require 'cl)
31 (defvar tool-bar-map))
5ab7173c 32
eec82323
LMI
33(require 'gnus)
34(require 'gnus-group)
35(require 'gnus-spec)
36(require 'gnus-range)
37(require 'gnus-int)
38(require 'gnus-undo)
6748645f 39(require 'gnus-util)
16409b0b 40(require 'mm-decode)
08c9a385 41(require 'nnoo)
23f87bed 42
6748645f 43(autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
d4dfaa19 44(autoload 'gnus-cache-write-active "gnus-cache")
23f87bed
MB
45(autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
46(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
08c9a385 47(autoload 'mm-uu-dissect "mm-uu")
23f87bed
MB
48(autoload 'gnus-article-outlook-deuglify-article "deuglify"
49 "Deuglify broken Outlook (Express) articles and redisplay."
50 t)
51(autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
52(autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
53(autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
eec82323
LMI
54
55(defcustom gnus-kill-summary-on-exit t
56 "*If non-nil, kill the summary buffer when you exit from it.
57If nil, the summary will become a \"*Dead Summary*\" buffer, and
58it will be killed sometime later."
59 :group 'gnus-summary-exit
60 :type 'boolean)
61
62(defcustom gnus-fetch-old-headers nil
63 "*Non-nil means that Gnus will try to build threads by grabbing old headers.
64If an unread article in the group refers to an older, already read (or
65just marked as read) article, the old article will not normally be
66displayed in the Summary buffer. If this variable is non-nil, Gnus
67will attempt to grab the headers to the old articles, and thereby
6748645f
LMI
68build complete threads. If it has the value `some', only enough
69headers to connect otherwise loose threads will be displayed. This
70variable can also be a number. In that case, no more than that number
71of old headers will be fetched. If it has the value `invisible', all
72old headers will be fetched, but none will be displayed.
eec82323
LMI
73
74The server has to support NOV for any of this to work."
75 :group 'gnus-thread
76 :type '(choice (const :tag "off" nil)
77 (const some)
78 number
79 (sexp :menu-tag "other" t)))
80
6748645f
LMI
81(defcustom gnus-refer-thread-limit 200
82 "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
83If t, fetch all the available old headers."
84 :group 'gnus-thread
85 :type '(choice number
86 (sexp :menu-tag "other" t)))
87
eec82323
LMI
88(defcustom gnus-summary-make-false-root 'adopt
89 "*nil means that Gnus won't gather loose threads.
90If the root of a thread has expired or been read in a previous
91session, the information necessary to build a complete thread has been
92lost. Instead of having many small sub-threads from this original thread
93scattered all over the summary buffer, Gnus can gather them.
94
95If non-nil, Gnus will try to gather all loose sub-threads from an
96original thread into one large thread.
97
98If this variable is non-nil, it should be one of `none', `adopt',
99`dummy' or `empty'.
100
101If this variable is `none', Gnus will not make a false root, but just
102present the sub-threads after another.
103If this variable is `dummy', Gnus will create a dummy root that will
104have all the sub-threads as children.
105If this variable is `adopt', Gnus will make one of the \"children\"
106the parent and mark all the step-children as such.
107If this variable is `empty', the \"children\" are printed with empty
108subject fields. (Or rather, they will be printed with a string
109given by the `gnus-summary-same-subject' variable.)"
110 :group 'gnus-thread
111 :type '(choice (const :tag "off" nil)
112 (const none)
113 (const dummy)
114 (const adopt)
115 (const empty)))
116
23f87bed
MB
117(defcustom gnus-summary-make-false-root-always nil
118 "Always make a false dummy root."
119 :group 'gnus-thread
120 :type 'boolean)
121
eec82323
LMI
122(defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
123 "*A regexp to match subjects to be excluded from loose thread gathering.
124As loose thread gathering is done on subjects only, that means that
125there can be many false gatherings performed. By rooting out certain
126common subjects, gathering might become saner."
127 :group 'gnus-thread
128 :type 'regexp)
129
130(defcustom gnus-summary-gather-subject-limit nil
131 "*Maximum length of subject comparisons when gathering loose threads.
132Use nil to compare full subjects. Setting this variable to a low
133number will help gather threads that have been corrupted by
134newsreaders chopping off subject lines, but it might also mean that
135unrelated articles that have subject that happen to begin with the
136same few characters will be incorrectly gathered.
137
138If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
139comparing subjects."
140 :group 'gnus-thread
141 :type '(choice (const :tag "off" nil)
142 (const fuzzy)
143 (sexp :menu-tag "on" t)))
144
6748645f
LMI
145(defcustom gnus-simplify-subject-functions nil
146 "List of functions taking a string argument that simplify subjects.
147The functions are applied recursively.
148
23f87bed
MB
149Useful functions to put in this list include:
150`gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
151`gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
6748645f
LMI
152 :group 'gnus-thread
153 :type '(repeat function))
154
eec82323 155(defcustom gnus-simplify-ignored-prefixes nil
23f87bed 156 "*Remove matches for this regexp from subject lines when simplifying fuzzily."
eec82323
LMI
157 :group 'gnus-thread
158 :type '(choice (const :tag "off" nil)
159 regexp))
160
161(defcustom gnus-build-sparse-threads nil
162 "*If non-nil, fill in the gaps in threads.
163If `some', only fill in the gaps that are needed to tie loose threads
164together. If `more', fill in all leaf nodes that Gnus can find. If
165non-nil and non-`some', fill in all gaps that Gnus manages to guess."
166 :group 'gnus-thread
167 :type '(choice (const :tag "off" nil)
168 (const some)
169 (const more)
170 (sexp :menu-tag "all" t)))
171
172(defcustom gnus-summary-thread-gathering-function
173 'gnus-gather-threads-by-subject
6748645f 174 "*Function used for gathering loose threads.
eec82323
LMI
175There are two pre-defined functions: `gnus-gather-threads-by-subject',
176which only takes Subjects into consideration; and
177`gnus-gather-threads-by-references', which compared the References
178headers of the articles to find matches."
179 :group 'gnus-thread
22115a9e
RS
180 :type '(radio (function-item gnus-gather-threads-by-subject)
181 (function-item gnus-gather-threads-by-references)
182 (function :tag "other")))
eec82323 183
eec82323
LMI
184(defcustom gnus-summary-same-subject ""
185 "*String indicating that the current article has the same subject as the previous.
186This variable will only be used if the value of
187`gnus-summary-make-false-root' is `empty'."
188 :group 'gnus-summary-format
189 :type 'string)
190
191(defcustom gnus-summary-goto-unread t
16409b0b
GM
192 "*If t, many commands will go to the next unread article.
193This applies to marking commands as well as other commands that
194\"naturally\" select the next article, like, for instance, `SPC' at
195the end of an article.
196
197If nil, the marking commands do NOT go to the next unread article
2642ac8f 198\(they go to the next article instead). If `never', commands that
16409b0b
GM
199usually go to the next unread article, will go to the next article,
200whether it is read or not."
eec82323
LMI
201 :group 'gnus-summary-marks
202 :link '(custom-manual "(gnus)Setting Marks")
203 :type '(choice (const :tag "off" nil)
204 (const never)
205 (sexp :menu-tag "on" t)))
206
207(defcustom gnus-summary-default-score 0
208 "*Default article score level.
209All scores generated by the score files will be added to this score.
210If this variable is nil, scoring will be disabled."
211 :group 'gnus-score-default
212 :type '(choice (const :tag "disable")
213 integer))
214
23f87bed
MB
215(defcustom gnus-summary-default-high-score 0
216 "*Default threshold for a high scored article.
217An article will be highlighted as high scored if its score is greater
218than this score."
219 :group 'gnus-score-default
220 :type 'integer)
221
222(defcustom gnus-summary-default-low-score 0
223 "*Default threshold for a low scored article.
224An article will be highlighted as low scored if its score is smaller
225than this score."
226 :group 'gnus-score-default
227 :type 'integer)
228
eec82323
LMI
229(defcustom gnus-summary-zcore-fuzz 0
230 "*Fuzziness factor for the zcore in the summary buffer.
231Articles with scores closer than this to `gnus-summary-default-score'
232will not be marked."
233 :group 'gnus-summary-format
234 :type 'integer)
235
236(defcustom gnus-simplify-subject-fuzzy-regexp nil
237 "*Strings to be removed when doing fuzzy matches.
238This can either be a regular expression or list of regular expressions
239that will be removed from subject strings if fuzzy subject
240simplification is selected."
241 :group 'gnus-thread
242 :type '(repeat regexp))
243
244(defcustom gnus-show-threads t
245 "*If non-nil, display threads in summary mode."
246 :group 'gnus-thread
247 :type 'boolean)
248
249(defcustom gnus-thread-hide-subtree nil
250 "*If non-nil, hide all threads initially.
23f87bed 251This can be a predicate specifier which says which threads to hide.
eec82323
LMI
252If threads are hidden, you have to run the command
253`gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
254to expose hidden threads."
255 :group 'gnus-thread
23f87bed
MB
256 :type '(radio (sexp :format "Non-nil\n"
257 :match (lambda (widget value)
258 (not (or (consp value) (functionp value))))
259 :value t)
260 (const nil)
261 (sexp :tag "Predicate specifier" :size 0)))
eec82323
LMI
262
263(defcustom gnus-thread-hide-killed t
264 "*If non-nil, hide killed threads automatically."
265 :group 'gnus-thread
266 :type 'boolean)
267
6748645f
LMI
268(defcustom gnus-thread-ignore-subject t
269 "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
270If nil, articles that have different subjects from their parents will
271start separate threads."
eec82323
LMI
272 :group 'gnus-thread
273 :type 'boolean)
274
275(defcustom gnus-thread-operation-ignore-subject t
276 "*If non-nil, subjects will be ignored when doing thread commands.
277This affects commands like `gnus-summary-kill-thread' and
278`gnus-summary-lower-thread'.
279
280If this variable is nil, articles in the same thread with different
281subjects will not be included in the operation in question. If this
282variable is `fuzzy', only articles that have subjects that are fuzzily
283equal will be included."
284 :group 'gnus-thread
285 :type '(choice (const :tag "off" nil)
286 (const fuzzy)
287 (sexp :tag "on" t)))
288
289(defcustom gnus-thread-indent-level 4
290 "*Number that says how much each sub-thread should be indented."
291 :group 'gnus-thread
292 :type 'integer)
293
294(defcustom gnus-auto-extend-newsgroup t
295 "*If non-nil, extend newsgroup forward and backward when requested."
296 :group 'gnus-summary-choose
297 :type 'boolean)
298
299(defcustom gnus-auto-select-first t
23f87bed
MB
300 "*If non-nil, select the article under point.
301Which article this is is controlled by the `gnus-auto-select-subject'
302variable.
303
304If you want to prevent automatic selection of articles in some
305newsgroups, set the variable to nil in `gnus-select-group-hook'."
eec82323
LMI
306 :group 'gnus-group-select
307 :type '(choice (const :tag "none" nil)
23f87bed
MB
308 (sexp :menu-tag "first" t)))
309
310(defcustom gnus-auto-select-subject 'unread
311 "*Says what subject to place under point when entering a group.
312
313This variable can either be the symbols `first' (place point on the
314first subject), `unread' (place point on the subject line of the first
315unread article), `best' (place point on the subject line of the
316higest-scored article), `unseen' (place point on the subject line of
317the first unseen article), 'unseen-or-unread' (place point on the subject
318line of the first unseen article or, if all article have been seen, on the
319subject line of the first unread article), or a function to be called to
320place point on some subject line."
321 :group 'gnus-group-select
322 :type '(choice (const best)
323 (const unread)
324 (const first)
325 (const unseen)
326 (const unseen-or-unread)))
eec82323
LMI
327
328(defcustom gnus-auto-select-next t
329 "*If non-nil, offer to go to the next group from the end of the previous.
330If the value is t and the next newsgroup is empty, Gnus will exit
23f87bed
MB
331summary mode and go back to group mode. If the value is neither nil
332nor t, Gnus will select the following unread newsgroup. In
eec82323
LMI
333particular, if the value is the symbol `quietly', the next unread
334newsgroup will be selected without any confirmation, and if it is
335`almost-quietly', the next group will be selected without any
336confirmation if you are located on the last article in the group.
23f87bed 337Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
eec82323
LMI
338will go to the next group without confirmation."
339 :group 'gnus-summary-maneuvering
340 :type '(choice (const :tag "off" nil)
341 (const quietly)
342 (const almost-quietly)
343 (const slightly-quietly)
344 (sexp :menu-tag "on" t)))
345
346(defcustom gnus-auto-select-same nil
6748645f
LMI
347 "*If non-nil, select the next article with the same subject.
348If there are no more articles with the same subject, go to
349the first unread article."
eec82323
LMI
350 :group 'gnus-summary-maneuvering
351 :type 'boolean)
352
23f87bed
MB
353(defcustom gnus-auto-goto-ignores 'unfetched
354 "*Says how to handle unfetched articles when maneuvering.
355
356This variable can either be the symbols nil (maneuver to any
357article), `undownloaded' (maneuvering while unplugged ignores articles
358that have not been fetched), `always-undownloaded' (maneuvering always
359ignores articles that have not been fetched), `unfetched' (maneuvering
360ignores articles whose headers have not been fetched).
361
362NOTE: The list of unfetched articles will always be nil when plugged
363and, when unplugged, a subset of the undownloaded article list."
364 :group 'gnus-summary-maneuvering
365 :type '(choice (const :tag "None" nil)
366 (const :tag "Undownloaded when unplugged" undownloaded)
367 (const :tag "Undownloaded" always-undownloaded)
368 (const :tag "Unfetched" unfetched)))
369
eec82323
LMI
370(defcustom gnus-summary-check-current nil
371 "*If non-nil, consider the current article when moving.
372The \"unread\" movement commands will stay on the same line if the
373current article is unread."
374 :group 'gnus-summary-maneuvering
375 :type 'boolean)
376
377(defcustom gnus-auto-center-summary t
378 "*If non-nil, always center the current summary buffer.
379In particular, if `vertical' do only vertical recentering. If non-nil
380and non-`vertical', do both horizontal and vertical recentering."
381 :group 'gnus-summary-maneuvering
382 :type '(choice (const :tag "none" nil)
383 (const vertical)
16409b0b 384 (integer :tag "height")
eec82323
LMI
385 (sexp :menu-tag "both" t)))
386
23f87bed
MB
387(defvar gnus-auto-center-group t
388 "*If non-nil, always center the group buffer.")
389
eec82323
LMI
390(defcustom gnus-show-all-headers nil
391 "*If non-nil, don't hide any headers."
392 :group 'gnus-article-hiding
393 :group 'gnus-article-headers
394 :type 'boolean)
395
396(defcustom gnus-summary-ignore-duplicates nil
397 "*If non-nil, ignore articles with identical Message-ID headers."
398 :group 'gnus-summary
399 :type 'boolean)
6748645f 400
eec82323
LMI
401(defcustom gnus-single-article-buffer t
402 "*If non-nil, display all articles in the same buffer.
403If nil, each group will get its own article buffer."
404 :group 'gnus-article-various
405 :type 'boolean)
406
407(defcustom gnus-break-pages t
408 "*If non-nil, do page breaking on articles.
409The page delimiter is specified by the `gnus-page-delimiter'
410variable."
411 :group 'gnus-article-various
412 :type 'boolean)
413
eec82323
LMI
414(defcustom gnus-move-split-methods nil
415 "*Variable used to suggest where articles are to be moved to.
23f87bed
MB
416It uses the same syntax as the `gnus-split-methods' variable.
417However, whereas `gnus-split-methods' specifies file names as targets,
418this variable specifies group names."
eec82323 419 :group 'gnus-summary-mail
6748645f
LMI
420 :type '(repeat (choice (list :value (fun) function)
421 (cons :value ("" "") regexp (repeat string))
422 (sexp :value nil))))
eec82323 423
23f87bed 424(defcustom gnus-unread-mark ? ;Whitespace
eec82323
LMI
425 "*Mark used for unread articles."
426 :group 'gnus-summary-marks
427 :type 'character)
428
429(defcustom gnus-ticked-mark ?!
430 "*Mark used for ticked articles."
431 :group 'gnus-summary-marks
432 :type 'character)
433
434(defcustom gnus-dormant-mark ??
435 "*Mark used for dormant articles."
436 :group 'gnus-summary-marks
437 :type 'character)
438
439(defcustom gnus-del-mark ?r
440 "*Mark used for del'd articles."
441 :group 'gnus-summary-marks
442 :type 'character)
443
444(defcustom gnus-read-mark ?R
445 "*Mark used for read articles."
446 :group 'gnus-summary-marks
447 :type 'character)
448
449(defcustom gnus-expirable-mark ?E
450 "*Mark used for expirable articles."
451 :group 'gnus-summary-marks
452 :type 'character)
453
454(defcustom gnus-killed-mark ?K
455 "*Mark used for killed articles."
456 :group 'gnus-summary-marks
457 :type 'character)
458
23f87bed
MB
459(defcustom gnus-spam-mark ?$
460 "*Mark used for spam articles."
461 :group 'gnus-summary-marks
462 :type 'character)
463
eec82323 464(defcustom gnus-souped-mark ?F
23f87bed 465 "*Mark used for souped articles."
eec82323
LMI
466 :group 'gnus-summary-marks
467 :type 'character)
468
469(defcustom gnus-kill-file-mark ?X
470 "*Mark used for articles killed by kill files."
471 :group 'gnus-summary-marks
472 :type 'character)
473
474(defcustom gnus-low-score-mark ?Y
475 "*Mark used for articles with a low score."
476 :group 'gnus-summary-marks
477 :type 'character)
478
479(defcustom gnus-catchup-mark ?C
480 "*Mark used for articles that are caught up."
481 :group 'gnus-summary-marks
482 :type 'character)
483
484(defcustom gnus-replied-mark ?A
485 "*Mark used for articles that have been replied to."
486 :group 'gnus-summary-marks
487 :type 'character)
488
23f87bed
MB
489(defcustom gnus-forwarded-mark ?F
490 "*Mark used for articles that have been forwarded."
491 :group 'gnus-summary-marks
492 :type 'character)
493
494(defcustom gnus-recent-mark ?N
495 "*Mark used for articles that are recent."
496 :group 'gnus-summary-marks
497 :type 'character)
498
eec82323
LMI
499(defcustom gnus-cached-mark ?*
500 "*Mark used for articles that are in the cache."
501 :group 'gnus-summary-marks
502 :type 'character)
503
504(defcustom gnus-saved-mark ?S
23f87bed
MB
505 "*Mark used for articles that have been saved."
506 :group 'gnus-summary-marks
507 :type 'character)
508
509(defcustom gnus-unseen-mark ?.
510 "*Mark used for articles that haven't been seen."
511 :group 'gnus-summary-marks
512 :type 'character)
513
514(defcustom gnus-no-mark ? ;Whitespace
515 "*Mark used for articles that have no other secondary mark."
eec82323
LMI
516 :group 'gnus-summary-marks
517 :type 'character)
518
519(defcustom gnus-ancient-mark ?O
520 "*Mark used for ancient articles."
521 :group 'gnus-summary-marks
522 :type 'character)
523
524(defcustom gnus-sparse-mark ?Q
525 "*Mark used for sparsely reffed articles."
526 :group 'gnus-summary-marks
527 :type 'character)
528
529(defcustom gnus-canceled-mark ?G
530 "*Mark used for canceled articles."
531 :group 'gnus-summary-marks
532 :type 'character)
533
534(defcustom gnus-duplicate-mark ?M
535 "*Mark used for duplicate articles."
536 :group 'gnus-summary-marks
537 :type 'character)
538
23f87bed 539(defcustom gnus-undownloaded-mark ?-
6748645f
LMI
540 "*Mark used for articles that weren't downloaded."
541 :group 'gnus-summary-marks
542 :type 'character)
543
23f87bed
MB
544(defcustom gnus-downloaded-mark ?+
545 "*Mark used for articles that were downloaded."
546 :group 'gnus-summary-marks
547 :type 'character)
548
6748645f
LMI
549(defcustom gnus-downloadable-mark ?%
550 "*Mark used for articles that are to be downloaded."
551 :group 'gnus-summary-marks
552 :type 'character)
553
554(defcustom gnus-unsendable-mark ?=
555 "*Mark used for articles that won't be sent."
556 :group 'gnus-summary-marks
557 :type 'character)
558
eec82323
LMI
559(defcustom gnus-score-over-mark ?+
560 "*Score mark used for articles with high scores."
561 :group 'gnus-summary-marks
562 :type 'character)
563
564(defcustom gnus-score-below-mark ?-
565 "*Score mark used for articles with low scores."
566 :group 'gnus-summary-marks
567 :type 'character)
568
23f87bed 569(defcustom gnus-empty-thread-mark ? ;Whitespace
eec82323
LMI
570 "*There is no thread under the article."
571 :group 'gnus-summary-marks
572 :type 'character)
573
574(defcustom gnus-not-empty-thread-mark ?=
575 "*There is a thread under the article."
576 :group 'gnus-summary-marks
577 :type 'character)
578
579(defcustom gnus-view-pseudo-asynchronously nil
580 "*If non-nil, Gnus will view pseudo-articles asynchronously."
581 :group 'gnus-extract-view
582 :type 'boolean)
583
16409b0b
GM
584(defcustom gnus-auto-expirable-marks
585 (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
586 gnus-low-score-mark gnus-ancient-mark gnus-read-mark
587 gnus-souped-mark gnus-duplicate-mark)
588 "*The list of marks converted into expiration if a group is auto-expirable."
58e39d05 589 :version "21.1"
16409b0b
GM
590 :group 'gnus-summary
591 :type '(repeat character))
592
593(defcustom gnus-inhibit-user-auto-expire t
594 "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
58e39d05 595 :version "21.1"
16409b0b
GM
596 :group 'gnus-summary
597 :type 'boolean)
598
eec82323
LMI
599(defcustom gnus-view-pseudos nil
600 "*If `automatic', pseudo-articles will be viewed automatically.
601If `not-confirm', pseudos will be viewed automatically, and the user
602will not be asked to confirm the command."
603 :group 'gnus-extract-view
604 :type '(choice (const :tag "off" nil)
605 (const automatic)
606 (const not-confirm)))
607
608(defcustom gnus-view-pseudos-separately t
609 "*If non-nil, one pseudo-article will be created for each file to be viewed.
610If nil, all files that use the same viewing command will be given as a
611list of parameters to that command."
612 :group 'gnus-extract-view
613 :type 'boolean)
614
615(defcustom gnus-insert-pseudo-articles t
616 "*If non-nil, insert pseudo-articles when decoding articles."
617 :group 'gnus-extract-view
618 :type 'boolean)
619
620(defcustom gnus-summary-dummy-line-format
23f87bed 621 " %(: :%) %S\n"
eec82323
LMI
622 "*The format specification for the dummy roots in the summary buffer.
623It works along the same lines as a normal formatting string,
624with some simple extensions.
625
23f87bed
MB
626%S The subject
627
628General format specifiers can also be used.
629See `(gnus)Formatting Variables'."
630 :link '(custom-manual "(gnus)Formatting Variables")
eec82323
LMI
631 :group 'gnus-threading
632 :type 'string)
633
16409b0b 634(defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
eec82323
LMI
635 "*The format specification for the summary mode line.
636It works along the same lines as a normal formatting string,
637with some simple extensions:
638
639%G Group name
640%p Unprefixed group name
641%A Current article number
6748645f 642%z Current article score
eec82323
LMI
643%V Gnus version
644%U Number of unread articles in the group
645%e Number of unselected articles in the group
646%Z A string with unread/unselected article counts
647%g Shortish group name
648%S Subject of the current article
649%u User-defined spec
650%s Current score file name
651%d Number of dormant articles
652%r Number of articles that have been marked as read in this session
653%E Number of articles expunged by the score files"
654 :group 'gnus-summary-format
655 :type 'string)
656
16409b0b
GM
657(defcustom gnus-list-identifiers nil
658 "Regexp that matches list identifiers to be removed from subject.
659This can also be a list of regexps."
58e39d05 660 :version "21.1"
16409b0b
GM
661 :group 'gnus-summary-format
662 :group 'gnus-article-hiding
663 :type '(choice (const :tag "none" nil)
664 (regexp :value ".*")
665 (repeat :value (".*") regexp)))
666
eec82323
LMI
667(defcustom gnus-summary-mark-below 0
668 "*Mark all articles with a score below this variable as read.
669This variable is local to each summary buffer and usually set by the
670score file."
671 :group 'gnus-score-default
672 :type 'integer)
673
674(defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
675 "*List of functions used for sorting articles in the summary buffer.
23f87bed
MB
676
677Each function takes two articles and returns non-nil if the first
678article should be sorted before the other. If you use more than one
679function, the primary sort function should be the last. You should
680probably always include `gnus-article-sort-by-number' in the list of
681sorting functions -- preferably first. Also note that sorting by date
682is often much slower than sorting by number, and the sorting order is
683very similar. (Sorting by date means sorting by the time the message
684was sent, sorting by number means sorting by arrival time.)
685
686Ready-made functions include `gnus-article-sort-by-number',
687`gnus-article-sort-by-author', `gnus-article-sort-by-subject',
688`gnus-article-sort-by-date', `gnus-article-sort-by-random'
689and `gnus-article-sort-by-score'.
690
691When threading is turned on, the variable `gnus-thread-sort-functions'
692controls how articles are sorted."
eec82323
LMI
693 :group 'gnus-summary-sort
694 :type '(repeat (choice (function-item gnus-article-sort-by-number)
695 (function-item gnus-article-sort-by-author)
696 (function-item gnus-article-sort-by-subject)
697 (function-item gnus-article-sort-by-date)
698 (function-item gnus-article-sort-by-score)
23f87bed 699 (function-item gnus-article-sort-by-random)
eec82323
LMI
700 (function :tag "other"))))
701
702(defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
703 "*List of functions used for sorting threads in the summary buffer.
704By default, threads are sorted by article number.
705
23f87bed
MB
706Each function takes two threads and returns non-nil if the first
707thread should be sorted before the other. If you use more than one
708function, the primary sort function should be the last. You should
709probably always include `gnus-thread-sort-by-number' in the list of
710sorting functions -- preferably first. Also note that sorting by date
711is often much slower than sorting by number, and the sorting order is
712very similar. (Sorting by date means sorting by the time the message
713was sent, sorting by number means sorting by arrival time.)
eec82323
LMI
714
715Ready-made functions include `gnus-thread-sort-by-number',
716`gnus-thread-sort-by-author', `gnus-thread-sort-by-subject',
23f87bed
MB
717`gnus-thread-sort-by-date', `gnus-thread-sort-by-score',
718`gnus-thread-sort-by-most-recent-number',
719`gnus-thread-sort-by-most-recent-date',
720`gnus-thread-sort-by-random', and
721`gnus-thread-sort-by-total-score' (see `gnus-thread-score-function').
722
723When threading is turned off, the variable
724`gnus-article-sort-functions' controls how articles are sorted."
eec82323
LMI
725 :group 'gnus-summary-sort
726 :type '(repeat (choice (function-item gnus-thread-sort-by-number)
727 (function-item gnus-thread-sort-by-author)
728 (function-item gnus-thread-sort-by-subject)
729 (function-item gnus-thread-sort-by-date)
730 (function-item gnus-thread-sort-by-score)
731 (function-item gnus-thread-sort-by-total-score)
23f87bed 732 (function-item gnus-thread-sort-by-random)
eec82323
LMI
733 (function :tag "other"))))
734
735(defcustom gnus-thread-score-function '+
736 "*Function used for calculating the total score of a thread.
737
738The function is called with the scores of the article and each
739subthread and should then return the score of the thread.
740
741Some functions you can use are `+', `max', or `min'."
742 :group 'gnus-summary-sort
743 :type 'function)
744
745(defcustom gnus-summary-expunge-below nil
6748645f
LMI
746 "All articles that have a score less than this variable will be expunged.
747This variable is local to the summary buffers."
eec82323
LMI
748 :group 'gnus-score-default
749 :type '(choice (const :tag "off" nil)
750 integer))
751
752(defcustom gnus-thread-expunge-below nil
753 "All threads that have a total score less than this variable will be expunged.
754See `gnus-thread-score-function' for en explanation of what a
6748645f
LMI
755\"thread score\" is.
756
757This variable is local to the summary buffers."
16409b0b 758 :group 'gnus-threading
eec82323
LMI
759 :group 'gnus-score-default
760 :type '(choice (const :tag "off" nil)
761 integer))
762
763(defcustom gnus-summary-mode-hook nil
764 "*A hook for Gnus summary mode.
765This hook is run before any variables are set in the summary buffer."
23f87bed 766 :options '(turn-on-gnus-mailing-list-mode gnus-pick-mode)
eec82323
LMI
767 :group 'gnus-summary-various
768 :type 'hook)
769
23f87bed
MB
770;; Extracted from gnus-xmas-redefine in order to preserve user settings
771(when (featurep 'xemacs)
772 (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
773 (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
774 (add-hook 'gnus-summary-mode-hook
775 'gnus-xmas-switch-horizontal-scrollbar-off))
776
eec82323
LMI
777(defcustom gnus-summary-menu-hook nil
778 "*Hook run after the creation of the summary mode menu."
779 :group 'gnus-summary-visual
780 :type 'hook)
781
782(defcustom gnus-summary-exit-hook nil
783 "*A hook called on exit from the summary buffer.
784It will be called with point in the group buffer."
785 :group 'gnus-summary-exit
786 :type 'hook)
787
788(defcustom gnus-summary-prepare-hook nil
789 "*A hook called after the summary buffer has been generated.
790If you want to modify the summary buffer, you can use this hook."
791 :group 'gnus-summary-various
792 :type 'hook)
793
6748645f
LMI
794(defcustom gnus-summary-prepared-hook nil
795 "*A hook called as the last thing after the summary buffer has been generated."
796 :group 'gnus-summary-various
797 :type 'hook)
798
eec82323
LMI
799(defcustom gnus-summary-generate-hook nil
800 "*A hook run just before generating the summary buffer.
801This hook is commonly used to customize threading variables and the
802like."
803 :group 'gnus-summary-various
804 :type 'hook)
805
806(defcustom gnus-select-group-hook nil
807 "*A hook called when a newsgroup is selected.
808
809If you'd like to simplify subjects like the
810`gnus-summary-next-same-subject' command does, you can use the
811following hook:
812
23f87bed
MB
813 (add-hook gnus-select-group-hook
814 (lambda ()
815 (mapcar (lambda (header)
816 (mail-header-set-subject
817 header
818 (gnus-simplify-subject
819 (mail-header-subject header) 're-only)))
820 gnus-newsgroup-headers)))"
eec82323
LMI
821 :group 'gnus-group-select
822 :type 'hook)
823
824(defcustom gnus-select-article-hook nil
825 "*A hook called when an article is selected."
826 :group 'gnus-summary-choose
23f87bed 827 :options '(gnus-agent-fetch-selected-article)
eec82323
LMI
828 :type 'hook)
829
830(defcustom gnus-visual-mark-article-hook
831 (list 'gnus-highlight-selected-summary)
832 "*Hook run after selecting an article in the summary buffer.
833It is meant to be used for highlighting the article in some way. It
834is not run if `gnus-visual' is nil."
835 :group 'gnus-summary-visual
836 :type 'hook)
837
16409b0b 838(defcustom gnus-parse-headers-hook nil
eec82323
LMI
839 "*A hook called before parsing the headers."
840 :group 'gnus-various
841 :type 'hook)
842
843(defcustom gnus-exit-group-hook nil
16409b0b
GM
844 "*A hook called when exiting summary mode.
845This hook is not called from the non-updating exit commands like `Q'."
eec82323
LMI
846 :group 'gnus-various
847 :type 'hook)
848
849(defcustom gnus-summary-update-hook
850 (list 'gnus-summary-highlight-line)
851 "*A hook called when a summary line is changed.
852The hook will not be called if `gnus-visual' is nil.
853
854The default function `gnus-summary-highlight-line' will
855highlight the line according to the `gnus-summary-highlight'
856variable."
857 :group 'gnus-summary-visual
858 :type 'hook)
859
860(defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
861 "*A hook called when an article is selected for the first time.
862The hook is intended to mark an article as read (or unread)
863automatically when it is selected."
864 :group 'gnus-summary-choose
865 :type 'hook)
866
867(defcustom gnus-group-no-more-groups-hook nil
868 "*A hook run when returning to group mode having no more (unread) groups."
869 :group 'gnus-group-select
870 :type 'hook)
871
872(defcustom gnus-ps-print-hook nil
873 "*A hook run before ps-printing something from Gnus."
874 :group 'gnus-summary
875 :type 'hook)
876
23f87bed
MB
877(defcustom gnus-summary-article-move-hook nil
878 "*A hook called after an article is moved, copied, respooled, or crossposted."
879 :group 'gnus-summary
880 :type 'hook)
881
882(defcustom gnus-summary-article-delete-hook nil
883 "*A hook called after an article is deleted."
884 :group 'gnus-summary
885 :type 'hook)
886
887(defcustom gnus-summary-article-expire-hook nil
888 "*A hook called after an article is expired."
889 :group 'gnus-summary
890 :type 'hook)
891
892(defcustom gnus-summary-display-arrow
893 (and (fboundp 'display-graphic-p)
894 (display-graphic-p))
895 "*If non-nil, display an arrow highlighting the current article."
896 :version "21.1"
897 :group 'gnus-summary
898 :type 'boolean)
899
eec82323
LMI
900(defcustom gnus-summary-selected-face 'gnus-summary-selected-face
901 "Face used for highlighting the current article in the summary buffer."
902 :group 'gnus-summary-visual
903 :type 'face)
904
23f87bed
MB
905(defvar gnus-tmp-downloaded nil)
906
eec82323 907(defcustom gnus-summary-highlight
23f87bed 908 '(((eq mark gnus-canceled-mark)
eec82323 909 . gnus-summary-cancelled-face)
23f87bed
MB
910 ((and uncached (> score default-high))
911 . gnus-summary-high-undownloaded-face)
912 ((and uncached (< score default-low))
913 . gnus-summary-low-undownloaded-face)
914 (uncached
915 . gnus-summary-normal-undownloaded-face)
916 ((and (> score default-high)
917 (or (eq mark gnus-dormant-mark)
918 (eq mark gnus-ticked-mark)))
eec82323 919 . gnus-summary-high-ticked-face)
23f87bed
MB
920 ((and (< score default-low)
921 (or (eq mark gnus-dormant-mark)
922 (eq mark gnus-ticked-mark)))
eec82323 923 . gnus-summary-low-ticked-face)
23f87bed
MB
924 ((or (eq mark gnus-dormant-mark)
925 (eq mark gnus-ticked-mark))
eec82323 926 . gnus-summary-normal-ticked-face)
23f87bed 927 ((and (> score default-high) (eq mark gnus-ancient-mark))
eec82323 928 . gnus-summary-high-ancient-face)
23f87bed 929 ((and (< score default-low) (eq mark gnus-ancient-mark))
eec82323 930 . gnus-summary-low-ancient-face)
23f87bed 931 ((eq mark gnus-ancient-mark)
eec82323 932 . gnus-summary-normal-ancient-face)
23f87bed 933 ((and (> score default-high) (eq mark gnus-unread-mark))
eec82323 934 . gnus-summary-high-unread-face)
23f87bed 935 ((and (< score default-low) (eq mark gnus-unread-mark))
eec82323 936 . gnus-summary-low-unread-face)
23f87bed 937 ((eq mark gnus-unread-mark)
6748645f 938 . gnus-summary-normal-unread-face)
23f87bed 939 ((> score default-high)
eec82323 940 . gnus-summary-high-read-face)
23f87bed 941 ((< score default-low)
eec82323
LMI
942 . gnus-summary-low-read-face)
943 (t
944 . gnus-summary-normal-read-face))
6748645f 945 "*Controls the highlighting of summary buffer lines.
eec82323 946
23f87bed
MB
947A list of (FORM . FACE) pairs. When deciding how a a particular
948summary line should be displayed, each form is evaluated. The content
949of the face field after the first true form is used. You can change
950how those summary lines are displayed, by editing the face field.
eec82323
LMI
951
952You can use the following variables in the FORM field.
953
23f87bed
MB
954score: The article's score
955default: The default article score.
956default-high: The default score for high scored articles.
957default-low: The default score for low scored articles.
958below: The score below which articles are automatically marked as read.
959mark: The article's mark.
960uncached: Non-nil if the article is uncached."
eec82323
LMI
961 :group 'gnus-summary-visual
962 :type '(repeat (cons (sexp :tag "Form" nil)
963 face)))
964
6748645f
LMI
965(defcustom gnus-alter-header-function nil
966 "Function called to allow alteration of article header structures.
967The function is called with one parameter, the article header vector,
0ab0f2d3
SZ
968which it may alter in any way."
969 :type '(choice (const :tag "None" nil)
970 function)
971 :group 'gnus-summary)
eec82323 972
16409b0b
GM
973(defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
974 "Variable that says which function should be used to decode a string with encoded words.")
975
23f87bed 976(defcustom gnus-extra-headers '(To Newsgroups)
16409b0b 977 "*Extra headers to parse."
58e39d05 978 :version "21.1"
16409b0b
GM
979 :group 'gnus-summary
980 :type '(repeat symbol))
981
982(defcustom gnus-ignored-from-addresses
983 (and user-mail-address (regexp-quote user-mail-address))
984 "*Regexp of From headers that may be suppressed in favor of To headers."
58e39d05 985 :version "21.1"
16409b0b
GM
986 :group 'gnus-summary
987 :type 'regexp)
988
16409b0b
GM
989(defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
990 "List of charsets that should be ignored.
991When these charsets are used in the \"charset\" parameter, the
992default charset will be used instead."
58e39d05 993 :version "21.1"
16409b0b
GM
994 :type '(repeat symbol)
995 :group 'gnus-charset)
996
23f87bed
MB
997(gnus-define-group-parameter
998 ignored-charsets
999 :type list
1000 :function-document
1001 "Return the ignored charsets of GROUP."
1002 :variable gnus-group-ignored-charsets-alist
1003 :variable-default
1004 '(("alt\\.chinese\\.text" iso-8859-1))
1005 :variable-document
1006 "Alist of regexps (to match group names) and charsets that should be ignored.
16409b0b
GM
1007When these charsets are used in the \"charset\" parameter, the
1008default charset will be used instead."
23f87bed
MB
1009 :variable-group gnus-charset
1010 :variable-type '(repeat (cons (regexp :tag "Group")
1011 (repeat symbol)))
1012 :parameter-type '(choice :tag "Ignored charsets"
1013 :value nil
1014 (repeat (symbol)))
1015 :parameter-document "\
1016List of charsets that should be ignored.
1017
1018When these charsets are used in the \"charset\" parameter, the
1019default charset will be used instead.")
16409b0b
GM
1020
1021(defcustom gnus-group-highlight-words-alist nil
1022 "Alist of group regexps and highlight regexps.
1023This variable uses the same syntax as `gnus-emphasis-alist'."
58e39d05 1024 :version "21.1"
16409b0b
GM
1025 :type '(repeat (cons (regexp :tag "Group")
1026 (repeat (list (regexp :tag "Highlight regexp")
1027 (number :tag "Group for entire word" 0)
1028 (number :tag "Group for displayed part" 0)
1029 (symbol :tag "Face"
1030 gnus-emphasis-highlight-words)))))
1031 :group 'gnus-summary-visual)
1032
1033(defcustom gnus-summary-show-article-charset-alist
1034 nil
1035 "Alist of number and charset.
1036The article will be shown with the charset corresponding to the
1037numbered argument.
1038For example: ((1 . cn-gb-2312) (2 . big5))."
58e39d05 1039 :version "21.1"
16409b0b
GM
1040 :type '(repeat (cons (number :tag "Argument" 1)
1041 (symbol :tag "Charset")))
1042 :group 'gnus-charset)
1043
1044(defcustom gnus-preserve-marks t
1045 "Whether marks are preserved when moving, copying and respooling messages."
58e39d05 1046 :version "21.1"
16409b0b
GM
1047 :type 'boolean
1048 :group 'gnus-summary-marks)
1049
1050(defcustom gnus-alter-articles-to-read-function nil
1051 "Function to be called to alter the list of articles to be selected."
8fc7a9a1 1052 :type '(choice (const nil) function)
16409b0b
GM
1053 :group 'gnus-summary)
1054
1055(defcustom gnus-orphan-score nil
1056 "*All orphans get this score added. Set in the score file."
1057 :group 'gnus-score-default
1058 :type '(choice (const nil)
1059 integer))
1060
8b93df01 1061(defcustom gnus-summary-save-parts-default-mime "image/.*"
23f87bed
MB
1062 "*A regexp to match MIME parts when saving multiple parts of a
1063message with `gnus-summary-save-parts' (\\<gnus-summary-mode-map>\\[gnus-summary-save-parts]).
1064This regexp will be used by default when prompting the user for which
1065type of files to save."
8b93df01
DL
1066 :group 'gnus-summary
1067 :type 'regexp)
1068
23f87bed
MB
1069(defcustom gnus-read-all-available-headers nil
1070 "Whether Gnus should parse all headers made available to it.
1071This is mostly relevant for slow back ends where the user may
1072wish to widen the summary buffer to include all headers
1073that were fetched. Say, for nnultimate groups."
1074 :group 'gnus-summary
1075 :type '(choice boolean regexp))
1076
1077(defcustom gnus-summary-muttprint-program "muttprint"
1078 "Command (and optional arguments) used to run Muttprint."
1079 :version "21.3"
1080 :group 'gnus-summary
1081 :type 'string)
1082
1083(defcustom gnus-article-loose-mime nil
1084 "If non-nil, don't require MIME-Version header.
1085Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
1086supply the MIME-Version header or deliberately strip it From the mail.
1087Set it to non-nil, Gnus will treat some articles as MIME even if
1088the MIME-Version header is missed."
1089 :version "21.3"
1090 :type 'boolean
1091 :group 'gnus-article-mime)
1092
1093(defcustom gnus-article-emulate-mime t
1094 "If non-nil, use MIME emulation for uuencode and the like.
1095This means that Gnus will search message bodies for text that look
1096like uuencoded bits, yEncoded bits, and so on, and present that using
1097the normal Gnus MIME machinery."
1098 :type 'boolean
1099 :group 'gnus-article-mime)
8b93df01 1100
eec82323
LMI
1101;;; Internal variables
1102
23f87bed 1103(defvar gnus-summary-display-cache nil)
16409b0b
GM
1104(defvar gnus-article-mime-handles nil)
1105(defvar gnus-article-decoded-p nil)
23f87bed
MB
1106(defvar gnus-article-charset nil)
1107(defvar gnus-article-ignored-charsets nil)
eec82323
LMI
1108(defvar gnus-scores-exclude-files nil)
1109(defvar gnus-page-broken nil)
1110
1111(defvar gnus-original-article nil)
1112(defvar gnus-article-internal-prepare-hook nil)
1113(defvar gnus-newsgroup-process-stack nil)
1114
1115(defvar gnus-thread-indent-array nil)
1116(defvar gnus-thread-indent-array-level gnus-thread-indent-level)
16409b0b
GM
1117(defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
1118 "Function called to sort the articles within a thread after it has been gathered together.")
eec82323 1119
8b93df01 1120(defvar gnus-summary-save-parts-type-history nil)
23f87bed 1121(defvar gnus-summary-save-parts-last-directory mm-default-directory)
8b93df01 1122
eec82323
LMI
1123;; Avoid highlighting in kill files.
1124(defvar gnus-summary-inhibit-highlight nil)
1125(defvar gnus-newsgroup-selected-overlay nil)
1126(defvar gnus-inhibit-limiting nil)
1127(defvar gnus-newsgroup-adaptive-score-file nil)
1128(defvar gnus-current-score-file nil)
1129(defvar gnus-current-move-group nil)
1130(defvar gnus-current-copy-group nil)
1131(defvar gnus-current-crosspost-group nil)
23f87bed 1132(defvar gnus-newsgroup-display nil)
eec82323
LMI
1133
1134(defvar gnus-newsgroup-dependencies nil)
1135(defvar gnus-newsgroup-adaptive nil)
1136(defvar gnus-summary-display-article-function nil)
1137(defvar gnus-summary-highlight-line-function nil
1138 "Function called after highlighting a summary line.")
1139
1140(defvar gnus-summary-line-format-alist
1141 `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
1142 (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
1143 (?s gnus-tmp-subject-or-nil ?s)
1144 (?n gnus-tmp-name ?s)
1145 (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
1146 ?s)
1147 (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
1148 gnus-tmp-from) ?s)
1149 (?F gnus-tmp-from ?s)
1150 (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
1151 (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
1152 (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
6748645f 1153 (?o (gnus-date-iso8601 (mail-header-date gnus-tmp-header)) ?s)
eec82323
LMI
1154 (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
1155 (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
1156 (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
23f87bed
MB
1157 (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
1158 (?L gnus-tmp-lines ?s)
1159 (?O gnus-tmp-downloaded ?c)
eec82323
LMI
1160 (?I gnus-tmp-indentation ?s)
1161 (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
1162 (?R gnus-tmp-replied ?c)
1163 (?\[ gnus-tmp-opening-bracket ?c)
1164 (?\] gnus-tmp-closing-bracket ?c)
1165 (?\> (make-string gnus-tmp-level ? ) ?s)
1166 (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
1167 (?i gnus-tmp-score ?d)
1168 (?z gnus-tmp-score-char ?c)
1169 (?l (bbb-grouplens-score gnus-tmp-header) ?s)
1170 (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
1171 (?U gnus-tmp-unread ?c)
23f87bed
MB
1172 (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header gnus-tmp-from)
1173 ?s)
eec82323
LMI
1174 (?t (gnus-summary-number-of-articles-in-thread
1175 (and (boundp 'thread) (car thread)) gnus-tmp-level)
1176 ?d)
1177 (?e (gnus-summary-number-of-articles-in-thread
1178 (and (boundp 'thread) (car thread)) gnus-tmp-level t)
1179 ?c)
1180 (?u gnus-tmp-user-defined ?s)
23f87bed
MB
1181 (?P (gnus-pick-line-number) ?d)
1182 (?B gnus-tmp-thread-tree-header-string ?s)
1183 (user-date (gnus-user-date
1184 ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
16409b0b
GM
1185 "An alist of format specifications that can appear in summary lines.
1186These are paired with what variables they correspond with, along with
1187the type of the variable (string, integer, character, etc).")
eec82323
LMI
1188
1189(defvar gnus-summary-dummy-line-format-alist
1190 `((?S gnus-tmp-subject ?s)
1191 (?N gnus-tmp-number ?d)
1192 (?u gnus-tmp-user-defined ?s)))
1193
1194(defvar gnus-summary-mode-line-format-alist
1195 `((?G gnus-tmp-group-name ?s)
1196 (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
1197 (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
1198 (?A gnus-tmp-article-number ?d)
1199 (?Z gnus-tmp-unread-and-unselected ?s)
1200 (?V gnus-version ?s)
1201 (?U gnus-tmp-unread-and-unticked ?d)
1202 (?S gnus-tmp-subject ?s)
1203 (?e gnus-tmp-unselected ?d)
1204 (?u gnus-tmp-user-defined ?s)
1205 (?d (length gnus-newsgroup-dormant) ?d)
1206 (?t (length gnus-newsgroup-marked) ?d)
23f87bed 1207 (?h (length gnus-newsgroup-spam-marked) ?d)
eec82323 1208 (?r (length gnus-newsgroup-reads) ?d)
6748645f 1209 (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
eec82323
LMI
1210 (?E gnus-newsgroup-expunged-tally ?d)
1211 (?s (gnus-current-score-file-nondirectory) ?s)))
1212
1213(defvar gnus-last-search-regexp nil
1214 "Default regexp for article search command.")
1215
1216(defvar gnus-last-shell-command nil
1217 "Default shell command on article.")
1218
23f87bed
MB
1219(defvar gnus-newsgroup-agentized nil
1220 "Locally bound in each summary buffer to indicate whether the server has been agentized.")
eec82323
LMI
1221(defvar gnus-newsgroup-begin nil)
1222(defvar gnus-newsgroup-end nil)
1223(defvar gnus-newsgroup-last-rmail nil)
1224(defvar gnus-newsgroup-last-mail nil)
1225(defvar gnus-newsgroup-last-folder nil)
1226(defvar gnus-newsgroup-last-file nil)
1227(defvar gnus-newsgroup-auto-expire nil)
1228(defvar gnus-newsgroup-active nil)
1229
1230(defvar gnus-newsgroup-data nil)
1231(defvar gnus-newsgroup-data-reverse nil)
1232(defvar gnus-newsgroup-limit nil)
1233(defvar gnus-newsgroup-limits nil)
23f87bed 1234(defvar gnus-summary-use-undownloaded-faces nil)
eec82323
LMI
1235
1236(defvar gnus-newsgroup-unreads nil
23f87bed 1237 "Sorted list of unread articles in the current newsgroup.")
eec82323
LMI
1238
1239(defvar gnus-newsgroup-unselected nil
23f87bed 1240 "Sorted list of unselected unread articles in the current newsgroup.")
eec82323
LMI
1241
1242(defvar gnus-newsgroup-reads nil
1243 "Alist of read articles and article marks in the current newsgroup.")
1244
1245(defvar gnus-newsgroup-expunged-tally nil)
1246
1247(defvar gnus-newsgroup-marked nil
23f87bed
MB
1248 "Sorted list of ticked articles in the current newsgroup (a subset of unread art).")
1249
1250(defvar gnus-newsgroup-spam-marked nil
1251 "List of ranges of articles that have been marked as spam.")
eec82323
LMI
1252
1253(defvar gnus-newsgroup-killed nil
1254 "List of ranges of articles that have been through the scoring process.")
1255
1256(defvar gnus-newsgroup-cached nil
23f87bed 1257 "Sorted list of articles that come from the article cache.")
eec82323
LMI
1258
1259(defvar gnus-newsgroup-saved nil
1260 "List of articles that have been saved.")
1261
1262(defvar gnus-newsgroup-kill-headers nil)
1263
1264(defvar gnus-newsgroup-replied nil
1265 "List of articles that have been replied to in the current newsgroup.")
1266
23f87bed
MB
1267(defvar gnus-newsgroup-forwarded nil
1268 "List of articles that have been forwarded in the current newsgroup.")
1269
1270(defvar gnus-newsgroup-recent nil
1271 "List of articles that have are recent in the current newsgroup.")
1272
eec82323 1273(defvar gnus-newsgroup-expirable nil
23f87bed 1274 "Sorted list of articles in the current newsgroup that can be expired.")
eec82323
LMI
1275
1276(defvar gnus-newsgroup-processable nil
1277 "List of articles in the current newsgroup that can be processed.")
1278
6748645f 1279(defvar gnus-newsgroup-downloadable nil
23f87bed
MB
1280 "Sorted list of articles in the current newsgroup that can be processed.")
1281
1282(defvar gnus-newsgroup-unfetched nil
1283 "Sorted list of articles in the current newsgroup whose headers have
1284not been fetched into the agent.
1285
1286This list will always be a subset of gnus-newsgroup-undownloaded.")
6748645f
LMI
1287
1288(defvar gnus-newsgroup-undownloaded nil
23f87bed 1289 "List of articles in the current newsgroup that haven't been downloaded.")
6748645f
LMI
1290
1291(defvar gnus-newsgroup-unsendable nil
1292 "List of articles in the current newsgroup that won't be sent.")
1293
eec82323
LMI
1294(defvar gnus-newsgroup-bookmarks nil
1295 "List of articles in the current newsgroup that have bookmarks.")
1296
1297(defvar gnus-newsgroup-dormant nil
23f87bed
MB
1298 "Sorted list of dormant articles in the current newsgroup.")
1299
1300(defvar gnus-newsgroup-unseen nil
1301 "List of unseen articles in the current newsgroup.")
1302
1303(defvar gnus-newsgroup-seen nil
1304 "Range of seen articles in the current newsgroup.")
1305
1306(defvar gnus-newsgroup-articles nil
1307 "List of articles in the current newsgroup.")
eec82323
LMI
1308
1309(defvar gnus-newsgroup-scored nil
1310 "List of scored articles in the current newsgroup.")
1311
1312(defvar gnus-newsgroup-headers nil
1313 "List of article headers in the current newsgroup.")
1314
1315(defvar gnus-newsgroup-threads nil)
1316
1317(defvar gnus-newsgroup-prepared nil
1318 "Whether the current group has been prepared properly.")
1319
1320(defvar gnus-newsgroup-ancient nil
1321 "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
1322
1323(defvar gnus-newsgroup-sparse nil)
1324
1325(defvar gnus-current-article nil)
1326(defvar gnus-article-current nil)
1327(defvar gnus-current-headers nil)
1328(defvar gnus-have-all-headers nil)
1329(defvar gnus-last-article nil)
1330(defvar gnus-newsgroup-history nil)
16409b0b
GM
1331(defvar gnus-newsgroup-charset nil)
1332(defvar gnus-newsgroup-ephemeral-charset nil)
1333(defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
eec82323 1334
23f87bed
MB
1335(defvar gnus-article-before-search nil)
1336
1337(defvar gnus-summary-local-variables
eec82323
LMI
1338 '(gnus-newsgroup-name
1339 gnus-newsgroup-begin gnus-newsgroup-end
1340 gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
1341 gnus-newsgroup-last-folder gnus-newsgroup-last-file
1342 gnus-newsgroup-auto-expire gnus-newsgroup-unreads
1343 gnus-newsgroup-unselected gnus-newsgroup-marked
23f87bed 1344 gnus-newsgroup-spam-marked
eec82323 1345 gnus-newsgroup-reads gnus-newsgroup-saved
23f87bed
MB
1346 gnus-newsgroup-replied gnus-newsgroup-forwarded
1347 gnus-newsgroup-recent
1348 gnus-newsgroup-expirable
eec82323 1349 gnus-newsgroup-processable gnus-newsgroup-killed
6748645f 1350 gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
23f87bed
MB
1351 gnus-newsgroup-unfetched
1352 gnus-newsgroup-unsendable gnus-newsgroup-unseen
1353 gnus-newsgroup-seen gnus-newsgroup-articles
eec82323
LMI
1354 gnus-newsgroup-bookmarks gnus-newsgroup-dormant
1355 gnus-newsgroup-headers gnus-newsgroup-threads
1356 gnus-newsgroup-prepared gnus-summary-highlight-line-function
1357 gnus-current-article gnus-current-headers gnus-have-all-headers
1358 gnus-last-article gnus-article-internal-prepare-hook
1359 gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1360 gnus-newsgroup-scored gnus-newsgroup-kill-headers
1361 gnus-thread-expunge-below
16409b0b
GM
1362 gnus-score-alist gnus-current-score-file
1363 (gnus-summary-expunge-below . global)
eec82323 1364 (gnus-summary-mark-below . global)
16409b0b 1365 (gnus-orphan-score . global)
eec82323
LMI
1366 gnus-newsgroup-active gnus-scores-exclude-files
1367 gnus-newsgroup-history gnus-newsgroup-ancient
1368 gnus-newsgroup-sparse gnus-newsgroup-process-stack
1369 (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
1370 gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
1371 (gnus-newsgroup-expunged-tally . 0)
1372 gnus-cache-removable-articles gnus-newsgroup-cached
1373 gnus-newsgroup-data gnus-newsgroup-data-reverse
16409b0b 1374 gnus-newsgroup-limit gnus-newsgroup-limits
23f87bed
MB
1375 gnus-newsgroup-charset gnus-newsgroup-display
1376 gnus-summary-use-undownloaded-faces)
eec82323
LMI
1377 "Variables that are buffer-local to the summary buffers.")
1378
23f87bed
MB
1379(defvar gnus-newsgroup-variables nil
1380 "A list of variables that have separate values in different newsgroups.
1381A list of newsgroup (summary buffer) local variables, or cons of
1382variables and their default expressions to be evalled (when the default
1383values are not nil), that should be made global while the summary buffer
1384is active.
1385
1386Note: The default expressions will be evaluated (using function `eval')
1387before assignment to the local variable rather than just assigned to it.
1388If the default expression is the symbol `global', that symbol will not
1389be evaluated but the global value of the local variable will be used
1390instead.
1391
1392These variables can be used to set variables in the group parameters
1393while still allowing them to affect operations done in other buffers.
1394For example:
1395
1396\(setq gnus-newsgroup-variables
1397 '(message-use-followup-to
1398 (gnus-visible-headers .
1399 \"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
1400")
1401
eec82323 1402;; Byte-compiler warning.
23f87bed
MB
1403(eval-when-compile
1404 ;; Bind features so that require will believe that gnus-sum has
1405 ;; already been loaded (avoids infinite recursion)
1406 (let ((features (cons 'gnus-sum features)))
1407 ;; Several of the declarations in gnus-sum are needed to load the
1408 ;; following files. Right now, these definitions have been
1409 ;; compiled but not defined (evaluated). We could either do a
1410 ;; eval-and-compile about all of the declarations or evaluate the
1411 ;; source file.
1412 (if (boundp 'gnus-newsgroup-variables)
1413 nil
1414 (load "gnus-sum.el" t t t))
1415 (require 'gnus)
1416 (require 'gnus-agent)
1417 (require 'gnus-art)))
eec82323 1418
16409b0b
GM
1419;; MIME stuff.
1420
1421(defvar gnus-decode-encoded-word-methods
1422 '(mail-decode-encoded-word-string)
1423 "List of methods used to decode encoded words.
1424
23f87bed
MB
1425This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item
1426is FUNCTION, FUNCTION will be apply to all newsgroups. If item is a
1427\(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
16409b0b
GM
1428whose names match REGEXP.
1429
1430For example:
23f87bed 1431\((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
16409b0b
GM
1432 mail-decode-encoded-word-string
1433 (\"chinese\" . rfc1843-decode-string))")
1434
1435(defvar gnus-decode-encoded-word-methods-cache nil)
1436
1437(defun gnus-multi-decode-encoded-word-string (string)
1438 "Apply the functions from `gnus-encoded-word-methods' that match."
1439 (unless (and gnus-decode-encoded-word-methods-cache
1440 (eq gnus-newsgroup-name
1441 (car gnus-decode-encoded-word-methods-cache)))
1442 (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
1443 (mapcar (lambda (x)
1444 (if (symbolp x)
1445 (nconc gnus-decode-encoded-word-methods-cache (list x))
1446 (if (and gnus-newsgroup-name
1447 (string-match (car x) gnus-newsgroup-name))
1448 (nconc gnus-decode-encoded-word-methods-cache
1449 (list (cdr x))))))
23f87bed 1450 gnus-decode-encoded-word-methods))
16409b0b
GM
1451 (let ((xlist gnus-decode-encoded-word-methods-cache))
1452 (pop xlist)
1453 (while xlist
1454 (setq string (funcall (pop xlist) string))))
1455 string)
1456
eec82323
LMI
1457;; Subject simplification.
1458
6748645f 1459(defun gnus-simplify-whitespace (str)
16409b0b 1460 "Remove excessive whitespace from STR."
23f87bed
MB
1461 ;; Multiple spaces.
1462 (while (string-match "[ \t][ \t]+" str)
1463 (setq str (concat (substring str 0 (match-beginning 0))
1464 " "
1465 (substring str (match-end 0)))))
1466 ;; Leading spaces.
1467 (when (string-match "^[ \t]+" str)
1468 (setq str (substring str (match-end 0))))
1469 ;; Trailing spaces.
1470 (when (string-match "[ \t]+$" str)
1471 (setq str (substring str 0 (match-beginning 0))))
1472 str)
1473
1474(defun gnus-simplify-all-whitespace (str)
1475 "Remove all whitespace from STR."
1476 (while (string-match "[ \t\n]+" str)
1477 (setq str (replace-match "" nil nil str)))
1478 str)
6748645f 1479
eec82323
LMI
1480(defsubst gnus-simplify-subject-re (subject)
1481 "Remove \"Re:\" from subject lines."
23f87bed 1482 (if (string-match message-subject-re-regexp subject)
eec82323
LMI
1483 (substring subject (match-end 0))
1484 subject))
1485
1486(defun gnus-simplify-subject (subject &optional re-only)
1487 "Remove `Re:' and words in parentheses.
1488If RE-ONLY is non-nil, strip leading `Re:'s only."
1489 (let ((case-fold-search t)) ;Ignore case.
1490 ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
1491 (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
1492 (setq subject (substring subject (match-end 0))))
1493 ;; Remove uninteresting prefixes.
1494 (when (and (not re-only)
1495 gnus-simplify-ignored-prefixes
1496 (string-match gnus-simplify-ignored-prefixes subject))
1497 (setq subject (substring subject (match-end 0))))
1498 ;; Remove words in parentheses from end.
1499 (unless re-only
1500 (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
1501 (setq subject (substring subject 0 (match-beginning 0)))))
1502 ;; Return subject string.
1503 subject))
1504
1505;; Remove any leading "re:"s, any trailing paren phrases, and simplify
1506;; all whitespace.
1507(defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
1508 (goto-char (point-min))
1509 (while (re-search-forward regexp nil t)
16409b0b 1510 (replace-match (or newtext ""))))
eec82323
LMI
1511
1512(defun gnus-simplify-buffer-fuzzy ()
1513 "Simplify string in the buffer fuzzily.
1514The string in the accessible portion of the current buffer is simplified.
1515It is assumed to be a single-line subject.
1516Whitespace is generally cleaned up, and miscellaneous leading/trailing
1517matter is removed. Additional things can be deleted by setting
16409b0b 1518`gnus-simplify-subject-fuzzy-regexp'."
eec82323
LMI
1519 (let ((case-fold-search t)
1520 (modified-tick))
1521 (gnus-simplify-buffer-fuzzy-step "\t" " ")
1522
1523 (while (not (eq modified-tick (buffer-modified-tick)))
1524 (setq modified-tick (buffer-modified-tick))
1525 (cond
1526 ((listp gnus-simplify-subject-fuzzy-regexp)
1527 (mapcar 'gnus-simplify-buffer-fuzzy-step
1528 gnus-simplify-subject-fuzzy-regexp))
1529 (gnus-simplify-subject-fuzzy-regexp
1530 (gnus-simplify-buffer-fuzzy-step gnus-simplify-subject-fuzzy-regexp)))
1531 (gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
1532 (gnus-simplify-buffer-fuzzy-step
1533 "^ *\\(re\\|fw\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
1534 (gnus-simplify-buffer-fuzzy-step "^[[].*:\\( .*\\)[]]$" "\\1"))
1535
1536 (gnus-simplify-buffer-fuzzy-step " *[[{(][^()\n]*[]})] *$")
1537 (gnus-simplify-buffer-fuzzy-step " +" " ")
1538 (gnus-simplify-buffer-fuzzy-step " $")
1539 (gnus-simplify-buffer-fuzzy-step "^ +")))
1540
1541(defun gnus-simplify-subject-fuzzy (subject)
1542 "Simplify a subject string fuzzily.
6748645f 1543See `gnus-simplify-buffer-fuzzy' for details."
eec82323
LMI
1544 (save-excursion
1545 (gnus-set-work-buffer)
1546 (let ((case-fold-search t))
6748645f
LMI
1547 ;; Remove uninteresting prefixes.
1548 (when (and gnus-simplify-ignored-prefixes
1549 (string-match gnus-simplify-ignored-prefixes subject))
1550 (setq subject (substring subject (match-end 0))))
eec82323
LMI
1551 (insert subject)
1552 (inline (gnus-simplify-buffer-fuzzy))
1553 (buffer-string))))
1554
1555(defsubst gnus-simplify-subject-fully (subject)
23f87bed 1556 "Simplify a subject string according to `gnus-summary-gather-subject-limit'."
eec82323 1557 (cond
6748645f
LMI
1558 (gnus-simplify-subject-functions
1559 (gnus-map-function gnus-simplify-subject-functions subject))
eec82323
LMI
1560 ((null gnus-summary-gather-subject-limit)
1561 (gnus-simplify-subject-re subject))
1562 ((eq gnus-summary-gather-subject-limit 'fuzzy)
1563 (gnus-simplify-subject-fuzzy subject))
1564 ((numberp gnus-summary-gather-subject-limit)
1565 (gnus-limit-string (gnus-simplify-subject-re subject)
1566 gnus-summary-gather-subject-limit))
1567 (t
1568 subject)))
1569
1570(defsubst gnus-subject-equal (s1 s2 &optional simple-first)
6748645f 1571 "Check whether two subjects are equal.
23f87bed 1572If optional argument SIMPLE-FIRST is t, first argument is already
6748645f 1573simplified."
eec82323
LMI
1574 (cond
1575 ((null simple-first)
1576 (equal (gnus-simplify-subject-fully s1)
1577 (gnus-simplify-subject-fully s2)))
1578 (t
1579 (equal s1
1580 (gnus-simplify-subject-fully s2)))))
1581
1582(defun gnus-summary-bubble-group ()
1583 "Increase the score of the current group.
1584This is a handy function to add to `gnus-summary-exit-hook' to
1585increase the score of each group you read."
1586 (gnus-group-add-score gnus-newsgroup-name))
1587
1588\f
1589;;;
1590;;; Gnus summary mode
1591;;;
1592
1593(put 'gnus-summary-mode 'mode-class 'special)
1594
1653df0f
SZ
1595(defvar gnus-article-commands-menu)
1596
23f87bed
MB
1597;; Non-orthogonal keys
1598
1599(gnus-define-keys gnus-summary-mode-map
1600 " " gnus-summary-next-page
1601 "\177" gnus-summary-prev-page
1602 [delete] gnus-summary-prev-page
1603 [backspace] gnus-summary-prev-page
1604 "\r" gnus-summary-scroll-up
1605 "\M-\r" gnus-summary-scroll-down
1606 "n" gnus-summary-next-unread-article
1607 "p" gnus-summary-prev-unread-article
1608 "N" gnus-summary-next-article
1609 "P" gnus-summary-prev-article
1610 "\M-\C-n" gnus-summary-next-same-subject
1611 "\M-\C-p" gnus-summary-prev-same-subject
1612 "\M-n" gnus-summary-next-unread-subject
1613 "\M-p" gnus-summary-prev-unread-subject
1614 "." gnus-summary-first-unread-article
1615 "," gnus-summary-best-unread-article
1616 "\M-s" gnus-summary-search-article-forward
1617 "\M-r" gnus-summary-search-article-backward
1618 "<" gnus-summary-beginning-of-article
1619 ">" gnus-summary-end-of-article
1620 "j" gnus-summary-goto-article
1621 "^" gnus-summary-refer-parent-article
1622 "\M-^" gnus-summary-refer-article
1623 "u" gnus-summary-tick-article-forward
1624 "!" gnus-summary-tick-article-forward
1625 "U" gnus-summary-tick-article-backward
1626 "d" gnus-summary-mark-as-read-forward
1627 "D" gnus-summary-mark-as-read-backward
1628 "E" gnus-summary-mark-as-expirable
1629 "\M-u" gnus-summary-clear-mark-forward
1630 "\M-U" gnus-summary-clear-mark-backward
1631 "k" gnus-summary-kill-same-subject-and-select
1632 "\C-k" gnus-summary-kill-same-subject
1633 "\M-\C-k" gnus-summary-kill-thread
1634 "\M-\C-l" gnus-summary-lower-thread
1635 "e" gnus-summary-edit-article
1636 "#" gnus-summary-mark-as-processable
1637 "\M-#" gnus-summary-unmark-as-processable
1638 "\M-\C-t" gnus-summary-toggle-threads
1639 "\M-\C-s" gnus-summary-show-thread
1640 "\M-\C-h" gnus-summary-hide-thread
1641 "\M-\C-f" gnus-summary-next-thread
1642 "\M-\C-b" gnus-summary-prev-thread
1643 [(meta down)] gnus-summary-next-thread
1644 [(meta up)] gnus-summary-prev-thread
1645 "\M-\C-u" gnus-summary-up-thread
1646 "\M-\C-d" gnus-summary-down-thread
1647 "&" gnus-summary-execute-command
1648 "c" gnus-summary-catchup-and-exit
1649 "\C-w" gnus-summary-mark-region-as-read
1650 "\C-t" gnus-summary-toggle-truncation
1651 "?" gnus-summary-mark-as-dormant
1652 "\C-c\M-\C-s" gnus-summary-limit-include-expunged
1653 "\C-c\C-s\C-n" gnus-summary-sort-by-number
1654 "\C-c\C-s\C-l" gnus-summary-sort-by-lines
1655 "\C-c\C-s\C-c" gnus-summary-sort-by-chars
1656 "\C-c\C-s\C-a" gnus-summary-sort-by-author
1657 "\C-c\C-s\C-s" gnus-summary-sort-by-subject
1658 "\C-c\C-s\C-d" gnus-summary-sort-by-date
1659 "\C-c\C-s\C-i" gnus-summary-sort-by-score
1660 "\C-c\C-s\C-o" gnus-summary-sort-by-original
1661 "\C-c\C-s\C-r" gnus-summary-sort-by-random
1662 "=" gnus-summary-expand-window
1663 "\C-x\C-s" gnus-summary-reselect-current-group
1664 "\M-g" gnus-summary-rescan-group
1665 "w" gnus-summary-stop-page-breaking
1666 "\C-c\C-r" gnus-summary-caesar-message
1667 "f" gnus-summary-followup
1668 "F" gnus-summary-followup-with-original
1669 "C" gnus-summary-cancel-article
1670 "r" gnus-summary-reply
1671 "R" gnus-summary-reply-with-original
1672 "\C-c\C-f" gnus-summary-mail-forward
1673 "o" gnus-summary-save-article
1674 "\C-o" gnus-summary-save-article-mail
1675 "|" gnus-summary-pipe-output
1676 "\M-k" gnus-summary-edit-local-kill
1677 "\M-K" gnus-summary-edit-global-kill
1678 ;; "V" gnus-version
1679 "\C-c\C-d" gnus-summary-describe-group
1680 "q" gnus-summary-exit
1681 "Q" gnus-summary-exit-no-update
1682 "\C-c\C-i" gnus-info-find-node
1683 gnus-mouse-2 gnus-mouse-pick-article
1684 "m" gnus-summary-mail-other-window
1685 "a" gnus-summary-post-news
1686 "i" gnus-summary-news-other-window
1687 "x" gnus-summary-limit-to-unread
1688 "s" gnus-summary-isearch-article
1689 "t" gnus-summary-toggle-header
1690 "g" gnus-summary-show-article
1691 "l" gnus-summary-goto-last-article
1692 "\C-c\C-v\C-v" gnus-uu-decode-uu-view
1693 "\C-d" gnus-summary-enter-digest-group
1694 "\M-\C-d" gnus-summary-read-document
1695 "\M-\C-e" gnus-summary-edit-parameters
1696 "\M-\C-a" gnus-summary-customize-parameters
1697 "\C-c\C-b" gnus-bug
1698 "*" gnus-cache-enter-article
1699 "\M-*" gnus-cache-remove-article
1700 "\M-&" gnus-summary-universal-argument
1701 "\C-l" gnus-recenter
1702 "I" gnus-summary-increase-score
1703 "L" gnus-summary-lower-score
1704 "\M-i" gnus-symbolic-argument
1705 "h" gnus-summary-select-article-buffer
1706
1707 "b" gnus-article-view-part
1708 "\M-t" gnus-summary-toggle-display-buttonized
1709
1710 "V" gnus-summary-score-map
1711 "X" gnus-uu-extract-map
1712 "S" gnus-summary-send-map)
1713
1714;; Sort of orthogonal keymap
1715(gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
1716 "t" gnus-summary-tick-article-forward
1717 "!" gnus-summary-tick-article-forward
1718 "d" gnus-summary-mark-as-read-forward
1719 "r" gnus-summary-mark-as-read-forward
1720 "c" gnus-summary-clear-mark-forward
1721 " " gnus-summary-clear-mark-forward
1722 "e" gnus-summary-mark-as-expirable
1723 "x" gnus-summary-mark-as-expirable
1724 "?" gnus-summary-mark-as-dormant
1725 "b" gnus-summary-set-bookmark
1726 "B" gnus-summary-remove-bookmark
1727 "#" gnus-summary-mark-as-processable
1728 "\M-#" gnus-summary-unmark-as-processable
1729 "S" gnus-summary-limit-include-expunged
1730 "C" gnus-summary-catchup
1731 "H" gnus-summary-catchup-to-here
1732 "h" gnus-summary-catchup-from-here
1733 "\C-c" gnus-summary-catchup-all
1734 "k" gnus-summary-kill-same-subject-and-select
1735 "K" gnus-summary-kill-same-subject
1736 "P" gnus-uu-mark-map)
1737
1738(gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
1739 "c" gnus-summary-clear-above
1740 "u" gnus-summary-tick-above
1741 "m" gnus-summary-mark-above
1742 "k" gnus-summary-kill-below)
1743
1744(gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
1745 "/" gnus-summary-limit-to-subject
1746 "n" gnus-summary-limit-to-articles
1747 "w" gnus-summary-pop-limit
1748 "s" gnus-summary-limit-to-subject
1749 "a" gnus-summary-limit-to-author
1750 "u" gnus-summary-limit-to-unread
1751 "m" gnus-summary-limit-to-marks
1752 "M" gnus-summary-limit-exclude-marks
1753 "v" gnus-summary-limit-to-score
1754 "*" gnus-summary-limit-include-cached
1755 "D" gnus-summary-limit-include-dormant
1756 "T" gnus-summary-limit-include-thread
1757 "d" gnus-summary-limit-exclude-dormant
1758 "t" gnus-summary-limit-to-age
1759 "." gnus-summary-limit-to-unseen
1760 "x" gnus-summary-limit-to-extra
1761 "p" gnus-summary-limit-to-display-predicate
1762 "E" gnus-summary-limit-include-expunged
1763 "c" gnus-summary-limit-exclude-childless-dormant
1764 "C" gnus-summary-limit-mark-excluded-as-read
1765 "o" gnus-summary-insert-old-articles
1766 "N" gnus-summary-insert-new-articles)
1767
1768(gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
1769 "n" gnus-summary-next-unread-article
1770 "p" gnus-summary-prev-unread-article
1771 "N" gnus-summary-next-article
1772 "P" gnus-summary-prev-article
1773 "\C-n" gnus-summary-next-same-subject
1774 "\C-p" gnus-summary-prev-same-subject
1775 "\M-n" gnus-summary-next-unread-subject
1776 "\M-p" gnus-summary-prev-unread-subject
1777 "f" gnus-summary-first-unread-article
1778 "b" gnus-summary-best-unread-article
1779 "j" gnus-summary-goto-article
1780 "g" gnus-summary-goto-subject
1781 "l" gnus-summary-goto-last-article
1782 "o" gnus-summary-pop-article)
1783
1784(gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
1785 "k" gnus-summary-kill-thread
1786 "l" gnus-summary-lower-thread
1787 "i" gnus-summary-raise-thread
1788 "T" gnus-summary-toggle-threads
1789 "t" gnus-summary-rethread-current
1790 "^" gnus-summary-reparent-thread
1791 "s" gnus-summary-show-thread
1792 "S" gnus-summary-show-all-threads
1793 "h" gnus-summary-hide-thread
1794 "H" gnus-summary-hide-all-threads
1795 "n" gnus-summary-next-thread
1796 "p" gnus-summary-prev-thread
1797 "u" gnus-summary-up-thread
1798 "o" gnus-summary-top-thread
1799 "d" gnus-summary-down-thread
1800 "#" gnus-uu-mark-thread
1801 "\M-#" gnus-uu-unmark-thread)
1802
1803(gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
1804 "g" gnus-summary-prepare
1805 "c" gnus-summary-insert-cached-articles
1806 "d" gnus-summary-insert-dormant-articles)
1807
1808(gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
1809 "c" gnus-summary-catchup-and-exit
1810 "C" gnus-summary-catchup-all-and-exit
1811 "E" gnus-summary-exit-no-update
1812 "Q" gnus-summary-exit
1813 "Z" gnus-summary-exit
1814 "n" gnus-summary-catchup-and-goto-next-group
1815 "R" gnus-summary-reselect-current-group
1816 "G" gnus-summary-rescan-group
1817 "N" gnus-summary-next-group
1818 "s" gnus-summary-save-newsrc
1819 "P" gnus-summary-prev-group)
1820
1821(gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
1822 " " gnus-summary-next-page
1823 "n" gnus-summary-next-page
1824 "\177" gnus-summary-prev-page
1825 [delete] gnus-summary-prev-page
1826 "p" gnus-summary-prev-page
1827 "\r" gnus-summary-scroll-up
1828 "\M-\r" gnus-summary-scroll-down
1829 "<" gnus-summary-beginning-of-article
1830 ">" gnus-summary-end-of-article
1831 "b" gnus-summary-beginning-of-article
1832 "e" gnus-summary-end-of-article
1833 "^" gnus-summary-refer-parent-article
1834 "r" gnus-summary-refer-parent-article
1835 "D" gnus-summary-enter-digest-group
1836 "R" gnus-summary-refer-references
1837 "T" gnus-summary-refer-thread
1838 "g" gnus-summary-show-article
1839 "s" gnus-summary-isearch-article
1840 "P" gnus-summary-print-article
1841 "M" gnus-mailing-list-insinuate
1842 "t" gnus-article-babel)
1843
1844(gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
1845 "b" gnus-article-add-buttons
1846 "B" gnus-article-add-buttons-to-head
1847 "o" gnus-article-treat-overstrike
1848 "e" gnus-article-emphasize
1849 "w" gnus-article-fill-cited-article
1850 "Q" gnus-article-fill-long-lines
1851 "C" gnus-article-capitalize-sentences
1852 "c" gnus-article-remove-cr
1853 "q" gnus-article-de-quoted-unreadable
1854 "6" gnus-article-de-base64-unreadable
1855 "Z" gnus-article-decode-HZ
1856 "h" gnus-article-wash-html
1857 "u" gnus-article-unsplit-urls
1858 "s" gnus-summary-force-verify-and-decrypt
1859 "f" gnus-article-display-x-face
1860 "l" gnus-summary-stop-page-breaking
1861 "r" gnus-summary-caesar-message
1862 "m" gnus-summary-morse-message
1863 "t" gnus-summary-toggle-header
1864 "g" gnus-treat-smiley
1865 "v" gnus-summary-verbose-headers
1866 "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
1867 "p" gnus-article-verify-x-pgp-sig
1868 "d" gnus-article-treat-dumbquotes)
1869
1870(gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
1871 ;; mnemonic: deuglif*Y*
1872 "u" gnus-article-outlook-unwrap-lines
1873 "a" gnus-article-outlook-repair-attribution
1874 "c" gnus-article-outlook-rearrange-citation
1875 "f" gnus-article-outlook-deuglify-article) ;; mnemonic: full deuglify
1876
1877(gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
1878 "a" gnus-article-hide
1879 "h" gnus-article-hide-headers
1880 "b" gnus-article-hide-boring-headers
1881 "s" gnus-article-hide-signature
1882 "c" gnus-article-hide-citation
1883 "C" gnus-article-hide-citation-in-followups
1884 "l" gnus-article-hide-list-identifiers
1885 "B" gnus-article-strip-banner
1886 "P" gnus-article-hide-pem
1887 "\C-c" gnus-article-hide-citation-maybe)
1888
1889(gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
1890 "a" gnus-article-highlight
1891 "h" gnus-article-highlight-headers
1892 "c" gnus-article-highlight-citation
1893 "s" gnus-article-highlight-signature)
1894
1895(gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
1896 "f" gnus-article-treat-fold-headers
1897 "u" gnus-article-treat-unfold-headers
1898 "n" gnus-article-treat-fold-newsgroups)
1899
1900(gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
1901 "x" gnus-article-display-x-face
1902 "d" gnus-article-display-face
1903 "s" gnus-treat-smiley
1904 "D" gnus-article-remove-images
1905 "f" gnus-treat-from-picon
1906 "m" gnus-treat-mail-picon
1907 "n" gnus-treat-newsgroups-picon)
1908
1909(gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
1910 "w" gnus-article-decode-mime-words
1911 "c" gnus-article-decode-charset
1912 "v" gnus-mime-view-all-parts
1913 "b" gnus-article-view-part)
1914
1915(gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
1916 "z" gnus-article-date-ut
1917 "u" gnus-article-date-ut
1918 "l" gnus-article-date-local
1919 "p" gnus-article-date-english
1920 "e" gnus-article-date-lapsed
1921 "o" gnus-article-date-original
1922 "i" gnus-article-date-iso8601
1923 "s" gnus-article-date-user)
1924
1925(gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
1926 "t" gnus-article-remove-trailing-blank-lines
1927 "l" gnus-article-strip-leading-blank-lines
1928 "m" gnus-article-strip-multiple-blank-lines
1929 "a" gnus-article-strip-blank-lines
1930 "A" gnus-article-strip-all-blank-lines
1931 "s" gnus-article-strip-leading-space
1932 "e" gnus-article-strip-trailing-space
1933 "w" gnus-article-remove-leading-whitespace)
1934
1935(gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
1936 "v" gnus-version
1937 "f" gnus-summary-fetch-faq
1938 "d" gnus-summary-describe-group
1939 "h" gnus-summary-describe-briefly
1940 "i" gnus-info-find-node
1941 "c" gnus-group-fetch-charter
1942 "C" gnus-group-fetch-control)
1943
1944(gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
1945 "e" gnus-summary-expire-articles
1946 "\M-\C-e" gnus-summary-expire-articles-now
1947 "\177" gnus-summary-delete-article
1948 [delete] gnus-summary-delete-article
1949 [backspace] gnus-summary-delete-article
1950 "m" gnus-summary-move-article
1951 "r" gnus-summary-respool-article
1952 "w" gnus-summary-edit-article
1953 "c" gnus-summary-copy-article
1954 "B" gnus-summary-crosspost-article
1955 "q" gnus-summary-respool-query
1956 "t" gnus-summary-respool-trace
1957 "i" gnus-summary-import-article
1958 "I" gnus-summary-create-article
1959 "p" gnus-summary-article-posted-p)
1960
1961(gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
1962 "o" gnus-summary-save-article
1963 "m" gnus-summary-save-article-mail
1964 "F" gnus-summary-write-article-file
1965 "r" gnus-summary-save-article-rmail
1966 "f" gnus-summary-save-article-file
1967 "b" gnus-summary-save-article-body-file
1968 "h" gnus-summary-save-article-folder
1969 "v" gnus-summary-save-article-vm
1970 "p" gnus-summary-pipe-output
1971 "P" gnus-summary-muttprint
1972 "s" gnus-soup-add-article)
1973
1974(gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
1975 "b" gnus-summary-display-buttonized
1976 "m" gnus-summary-repair-multipart
1977 "v" gnus-article-view-part
1978 "o" gnus-article-save-part
1979 "c" gnus-article-copy-part
1980 "C" gnus-article-view-part-as-charset
1981 "e" gnus-article-view-part-externally
1982 "E" gnus-article-encrypt-body
1983 "i" gnus-article-inline-part
1984 "|" gnus-article-pipe-part)
1985
1986(gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
1987 "p" gnus-summary-mark-as-processable
1988 "u" gnus-summary-unmark-as-processable
1989 "U" gnus-summary-unmark-all-processable
1990 "v" gnus-uu-mark-over
1991 "s" gnus-uu-mark-series
1992 "r" gnus-uu-mark-region
1993 "g" gnus-uu-unmark-region
1994 "R" gnus-uu-mark-by-regexp
1995 "G" gnus-uu-unmark-by-regexp
1996 "t" gnus-uu-mark-thread
1997 "T" gnus-uu-unmark-thread
1998 "a" gnus-uu-mark-all
1999 "b" gnus-uu-mark-buffer
2000 "S" gnus-uu-mark-sparse
2001 "k" gnus-summary-kill-process-mark
2002 "y" gnus-summary-yank-process-mark
2003 "w" gnus-summary-save-process-mark
2004 "i" gnus-uu-invert-processable)
2005
2006(gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
2007 ;;"x" gnus-uu-extract-any
2008 "m" gnus-summary-save-parts
2009 "u" gnus-uu-decode-uu
2010 "U" gnus-uu-decode-uu-and-save
2011 "s" gnus-uu-decode-unshar
2012 "S" gnus-uu-decode-unshar-and-save
2013 "o" gnus-uu-decode-save
2014 "O" gnus-uu-decode-save
2015 "b" gnus-uu-decode-binhex
2016 "B" gnus-uu-decode-binhex
2017 "p" gnus-uu-decode-postscript
2018 "P" gnus-uu-decode-postscript-and-save)
2019
2020(gnus-define-keys
2021 (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
2022 "u" gnus-uu-decode-uu-view
2023 "U" gnus-uu-decode-uu-and-save-view
2024 "s" gnus-uu-decode-unshar-view
2025 "S" gnus-uu-decode-unshar-and-save-view
2026 "o" gnus-uu-decode-save-view
2027 "O" gnus-uu-decode-save-view
2028 "b" gnus-uu-decode-binhex-view
2029 "B" gnus-uu-decode-binhex-view
2030 "p" gnus-uu-decode-postscript-view
2031 "P" gnus-uu-decode-postscript-and-save-view)
2032
2033(defvar gnus-article-post-menu nil)
2034
2035(defconst gnus-summary-menu-maxlen 20)
2036
2037(defun gnus-summary-menu-split (menu)
2038 ;; If we have lots of elements, divide them into groups of 20
2039 ;; and make a pane (or submenu) for each one.
2040 (if (> (length menu) (/ (* gnus-summary-menu-maxlen 3) 2))
2041 (let ((menu menu) sublists next
2042 (i 1))
2043 (while menu
2044 ;; Pull off the next gnus-summary-menu-maxlen elements
2045 ;; and make them the next element of sublist.
2046 (setq next (nthcdr gnus-summary-menu-maxlen menu))
2047 (if next
2048 (setcdr (nthcdr (1- gnus-summary-menu-maxlen) menu)
2049 nil))
2050 (setq sublists (cons (cons (format "%s ... %s" (aref (car menu) 0)
2051 (aref (car (last menu)) 0)) menu)
2052 sublists))
2053 (setq i (1+ i))
2054 (setq menu next))
2055 (nreverse sublists))
2056 ;; Few elements--put them all in one pane.
2057 menu))
eec82323
LMI
2058
2059(defun gnus-summary-make-menu-bar ()
2060 (gnus-turn-off-edit-menu 'summary)
2061
2062 (unless (boundp 'gnus-summary-misc-menu)
2063
2064 (easy-menu-define
23f87bed
MB
2065 gnus-summary-kill-menu gnus-summary-mode-map ""
2066 (cons
2067 "Score"
2068 (nconc
2069 (list
2070 ["Customize" gnus-score-customize t])
2071 (gnus-make-score-map 'increase)
2072 (gnus-make-score-map 'lower)
2073 '(("Mark"
2074 ["Kill below" gnus-summary-kill-below t]
2075 ["Mark above" gnus-summary-mark-above t]
2076 ["Tick above" gnus-summary-tick-above t]
2077 ["Clear above" gnus-summary-clear-above t])
2078 ["Current score" gnus-summary-current-score t]
2079 ["Set score" gnus-summary-set-score t]
2080 ["Switch current score file..." gnus-score-change-score-file t]
2081 ["Set mark below..." gnus-score-set-mark-below t]
2082 ["Set expunge below..." gnus-score-set-expunge-below t]
2083 ["Edit current score file" gnus-score-edit-current-scores t]
2084 ["Edit score file" gnus-score-edit-file t]
2085 ["Trace score" gnus-score-find-trace t]
2086 ["Find words" gnus-score-find-favourite-words t]
2087 ["Rescore buffer" gnus-summary-rescore t]
2088 ["Increase score..." gnus-summary-increase-score t]
2089 ["Lower score..." gnus-summary-lower-score t]))))
2090
2091 ;; Define both the Article menu in the summary buffer and the
2092 ;; equivalent Commands menu in the article buffer here for
2093 ;; consistency.
6748645f 2094 (let ((innards
23f87bed
MB
2095 `(("Hide"
2096 ["All" gnus-article-hide t]
2097 ["Headers" gnus-article-hide-headers t]
2098 ["Signature" gnus-article-hide-signature t]
2099 ["Citation" gnus-article-hide-citation t]
16409b0b 2100 ["List identifiers" gnus-article-hide-list-identifiers t]
16409b0b 2101 ["Banner" gnus-article-strip-banner t]
23f87bed
MB
2102 ["Boring headers" gnus-article-hide-boring-headers t])
2103 ("Highlight"
2104 ["All" gnus-article-highlight t]
2105 ["Headers" gnus-article-highlight-headers t]
2106 ["Signature" gnus-article-highlight-signature t]
2107 ["Citation" gnus-article-highlight-citation t])
16409b0b
GM
2108 ("MIME"
2109 ["Words" gnus-article-decode-mime-words t]
2110 ["Charset" gnus-article-decode-charset t]
2111 ["QP" gnus-article-de-quoted-unreadable t]
2112 ["Base64" gnus-article-de-base64-unreadable t]
23f87bed
MB
2113 ["View MIME buttons" gnus-summary-display-buttonized t]
2114 ["View all" gnus-mime-view-all-parts t]
2115 ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
2116 ["Encrypt body" gnus-article-encrypt-body
2117 :active (not (gnus-group-read-only-p))
2118 ,@(if (featurep 'xemacs) nil
2119 '(:help "Encrypt the message body on disk"))]
2120 ["Extract all parts..." gnus-summary-save-parts t]
2121 ("Multipart"
2122 ["Repair multipart" gnus-summary-repair-multipart t]
2123 ["Pipe part..." gnus-article-pipe-part t]
2124 ["Inline part" gnus-article-inline-part t]
2125 ["Encrypt body" gnus-article-encrypt-body
2126 :active (not (gnus-group-read-only-p))
2127 ,@(if (featurep 'xemacs) nil
2128 '(:help "Encrypt the message body on disk"))]
2129 ["View part externally" gnus-article-view-part-externally t]
2130 ["View part with charset..." gnus-article-view-part-as-charset t]
2131 ["Copy part" gnus-article-copy-part t]
2132 ["Save part..." gnus-article-save-part t]
2133 ["View part" gnus-article-view-part t]))
2134 ("Date"
2135 ["Local" gnus-article-date-local t]
2136 ["ISO8601" gnus-article-date-iso8601 t]
2137 ["UT" gnus-article-date-ut t]
2138 ["Original" gnus-article-date-original t]
2139 ["Lapsed" gnus-article-date-lapsed t]
2140 ["User-defined" gnus-article-date-user t])
2141 ("Display"
2142 ["Remove images" gnus-article-remove-images t]
2143 ["Toggle smiley" gnus-treat-smiley t]
2144 ["Show X-Face" gnus-article-display-x-face t]
2145 ["Show picons in From" gnus-treat-from-picon t]
2146 ["Show picons in mail headers" gnus-treat-mail-picon t]
2147 ["Show picons in news headers" gnus-treat-newsgroups-picon t]
2148 ("View as different encoding"
2149 ,@(gnus-summary-menu-split
2150 (mapcar
2151 (lambda (cs)
2152 ;; Since easymenu under Emacs doesn't allow
2153 ;; lambda forms for menu commands, we should
2154 ;; provide intern'ed function symbols.
2155 (let ((command (intern (format "\
2156gnus-summary-show-article-from-menu-as-charset-%s" cs))))
2157 (fset command
2158 `(lambda ()
2159 (interactive)
2160 (let ((gnus-summary-show-article-charset-alist
2161 '((1 . ,cs))))
2162 (gnus-summary-show-article 1))))
2163 `[,(symbol-name cs) ,command t]))
2164 (sort (if (fboundp 'coding-system-list)
2165 (coding-system-list)
2166 (mapcar 'car mm-mime-mule-charset-alist))
2167 'string<)))))
2168 ("Washing"
2169 ("Remove Blanks"
2170 ["Leading" gnus-article-strip-leading-blank-lines t]
2171 ["Multiple" gnus-article-strip-multiple-blank-lines t]
2172 ["Trailing" gnus-article-remove-trailing-blank-lines t]
2173 ["All of the above" gnus-article-strip-blank-lines t]
2174 ["All" gnus-article-strip-all-blank-lines t]
2175 ["Leading space" gnus-article-strip-leading-space t]
2176 ["Trailing space" gnus-article-strip-trailing-space t]
2177 ["Leading space in headers"
2178 gnus-article-remove-leading-whitespace t])
2179 ["Overstrike" gnus-article-treat-overstrike t]
2180 ["Dumb quotes" gnus-article-treat-dumbquotes t]
2181 ["Emphasis" gnus-article-emphasize t]
2182 ["Word wrap" gnus-article-fill-cited-article t]
16409b0b
GM
2183 ["Fill long lines" gnus-article-fill-long-lines t]
2184 ["Capitalize sentences" gnus-article-capitalize-sentences t]
23f87bed
MB
2185 ["Remove CR" gnus-article-remove-cr t]
2186 ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
2187 ["Base64" gnus-article-de-base64-unreadable t]
2188 ["Rot 13" gnus-summary-caesar-message
2189 ,@(if (featurep 'xemacs) '(t)
2190 '(:help "\"Caesar rotate\" article by 13"))]
2191 ["Morse decode" gnus-summary-morse-message t]
2192 ["Unix pipe..." gnus-summary-pipe-message t]
2193 ["Add buttons" gnus-article-add-buttons t]
2194 ["Add buttons to head" gnus-article-add-buttons-to-head t]
2195 ["Stop page breaking" gnus-summary-stop-page-breaking t]
2196 ["Verbose header" gnus-summary-verbose-headers t]
2197 ["Toggle header" gnus-summary-toggle-header t]
2198 ["Unfold headers" gnus-article-treat-unfold-headers t]
2199 ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
16409b0b 2200 ["Html" gnus-article-wash-html t]
23f87bed
MB
2201 ["Unsplit URLs" gnus-article-unsplit-urls t]
2202 ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
2203 ["Decode HZ" gnus-article-decode-HZ t]
2204 ("(Outlook) Deuglify"
2205 ["Unwrap lines" gnus-article-outlook-unwrap-lines t]
2206 ["Repair attribution" gnus-article-outlook-repair-attribution t]
2207 ["Rearrange citation" gnus-article-outlook-rearrange-citation t]
2208 ["Full (Outlook) deuglify"
2209 gnus-article-outlook-deuglify-article t])
2210 )
2211 ("Output"
2212 ["Save in default format..." gnus-summary-save-article
2213 ,@(if (featurep 'xemacs) '(t)
2214 '(:help "Save article using default method"))]
2215 ["Save in file..." gnus-summary-save-article-file
2216 ,@(if (featurep 'xemacs) '(t)
2217 '(:help "Save article in file"))]
2218 ["Save in Unix mail format..." gnus-summary-save-article-mail t]
2219 ["Save in MH folder..." gnus-summary-save-article-folder t]
2220 ["Save in VM folder..." gnus-summary-save-article-vm t]
2221 ["Save in RMAIL mbox..." gnus-summary-save-article-rmail t]
2222 ["Save body in file..." gnus-summary-save-article-body-file t]
2223 ["Pipe through a filter..." gnus-summary-pipe-output t]
2224 ["Add to SOUP packet" gnus-soup-add-article t]
2225 ["Print with Muttprint..." gnus-summary-muttprint t]
2226 ["Print" gnus-summary-print-article t])
2227 ("Backend"
2228 ["Respool article..." gnus-summary-respool-article t]
2229 ["Move article..." gnus-summary-move-article
2230 (gnus-check-backend-function
2231 'request-move-article gnus-newsgroup-name)]
2232 ["Copy article..." gnus-summary-copy-article t]
2233 ["Crosspost article..." gnus-summary-crosspost-article
2234 (gnus-check-backend-function
2235 'request-replace-article gnus-newsgroup-name)]
2236 ["Import file..." gnus-summary-import-article
2237 (gnus-check-backend-function
2238 'request-accept-article gnus-newsgroup-name)]
2239 ["Create article..." gnus-summary-create-article
2240 (gnus-check-backend-function
2241 'request-accept-article gnus-newsgroup-name)]
2242 ["Check if posted" gnus-summary-article-posted-p t]
2243 ["Edit article" gnus-summary-edit-article
2244 (not (gnus-group-read-only-p))]
2245 ["Delete article" gnus-summary-delete-article
2246 (gnus-check-backend-function
2247 'request-expire-articles gnus-newsgroup-name)]
2248 ["Query respool" gnus-summary-respool-query t]
6748645f 2249 ["Trace respool" gnus-summary-respool-trace t]
23f87bed
MB
2250 ["Delete expirable articles" gnus-summary-expire-articles-now
2251 (gnus-check-backend-function
2252 'request-expire-articles gnus-newsgroup-name)])
2253 ("Extract"
2254 ["Uudecode" gnus-uu-decode-uu
2255 ,@(if (featurep 'xemacs) '(t)
2256 '(:help "Decode uuencoded article(s)"))]
2257 ["Uudecode and save" gnus-uu-decode-uu-and-save t]
2258 ["Unshar" gnus-uu-decode-unshar t]
2259 ["Unshar and save" gnus-uu-decode-unshar-and-save t]
2260 ["Save" gnus-uu-decode-save t]
2261 ["Binhex" gnus-uu-decode-binhex t]
2262 ["Postscript" gnus-uu-decode-postscript t]
2263 ["All MIME parts" gnus-summary-save-parts t])
2264 ("Cache"
2265 ["Enter article" gnus-cache-enter-article t]
2266 ["Remove article" gnus-cache-remove-article t])
16409b0b 2267 ["Translate" gnus-article-babel t]
23f87bed
MB
2268 ["Select article buffer" gnus-summary-select-article-buffer t]
2269 ["Enter digest buffer" gnus-summary-enter-digest-group t]
2270 ["Isearch article..." gnus-summary-isearch-article t]
2271 ["Beginning of the article" gnus-summary-beginning-of-article t]
2272 ["End of the article" gnus-summary-end-of-article t]
2273 ["Fetch parent of article" gnus-summary-refer-parent-article t]
2274 ["Fetch referenced articles" gnus-summary-refer-references t]
2275 ["Fetch current thread" gnus-summary-refer-thread t]
2276 ["Fetch article with id..." gnus-summary-refer-article t]
2277 ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
2278 ["Redisplay" gnus-summary-show-article t]
2279 ["Raw article" gnus-summary-show-raw-article :keys "C-u g"])))
6748645f 2280 (easy-menu-define
23f87bed
MB
2281 gnus-summary-article-menu gnus-summary-mode-map ""
2282 (cons "Article" innards))
6748645f 2283
1653df0f
SZ
2284 (if (not (keymapp gnus-summary-article-menu))
2285 (easy-menu-define
2286 gnus-article-commands-menu gnus-article-mode-map ""
2287 (cons "Commands" innards))
2288 ;; in Emacs, don't share menu.
a1506d29 2289 (setq gnus-article-commands-menu
1653df0f
SZ
2290 (copy-keymap gnus-summary-article-menu))
2291 (define-key gnus-article-mode-map [menu-bar commands]
2292 (cons "Commands" gnus-article-commands-menu))))
eec82323
LMI
2293
2294 (easy-menu-define
23f87bed
MB
2295 gnus-summary-thread-menu gnus-summary-mode-map ""
2296 '("Threads"
2297 ["Find all messages in thread" gnus-summary-refer-thread t]
2298 ["Toggle threading" gnus-summary-toggle-threads t]
2299 ["Hide threads" gnus-summary-hide-all-threads t]
2300 ["Show threads" gnus-summary-show-all-threads t]
2301 ["Hide thread" gnus-summary-hide-thread t]
2302 ["Show thread" gnus-summary-show-thread t]
2303 ["Go to next thread" gnus-summary-next-thread t]
2304 ["Go to previous thread" gnus-summary-prev-thread t]
2305 ["Go down thread" gnus-summary-down-thread t]
2306 ["Go up thread" gnus-summary-up-thread t]
2307 ["Top of thread" gnus-summary-top-thread t]
2308 ["Mark thread as read" gnus-summary-kill-thread t]
2309 ["Lower thread score" gnus-summary-lower-thread t]
2310 ["Raise thread score" gnus-summary-raise-thread t]
2311 ["Rethread current" gnus-summary-rethread-current t]))
eec82323
LMI
2312
2313 (easy-menu-define
23f87bed
MB
2314 gnus-summary-post-menu gnus-summary-mode-map ""
2315 `("Post"
2316 ["Send a message (mail or news)" gnus-summary-post-news
2317 ,@(if (featurep 'xemacs) '(t)
2318 '(:help "Post an article"))]
2319 ["Followup" gnus-summary-followup
2320 ,@(if (featurep 'xemacs) '(t)
2321 '(:help "Post followup to this article"))]
2322 ["Followup and yank" gnus-summary-followup-with-original
2323 ,@(if (featurep 'xemacs) '(t)
2324 '(:help "Post followup to this article, quoting its contents"))]
2325 ["Supersede article" gnus-summary-supersede-article t]
2326 ["Cancel article" gnus-summary-cancel-article
2327 ,@(if (featurep 'xemacs) '(t)
2328 '(:help "Cancel an article you posted"))]
2329 ["Reply" gnus-summary-reply t]
2330 ["Reply and yank" gnus-summary-reply-with-original t]
2331 ["Wide reply" gnus-summary-wide-reply t]
2332 ["Wide reply and yank" gnus-summary-wide-reply-with-original
2333 ,@(if (featurep 'xemacs) '(t)
2334 '(:help "Mail a reply, quoting this article"))]
2335 ["Very wide reply" gnus-summary-very-wide-reply t]
2336 ["Very wide reply and yank" gnus-summary-very-wide-reply-with-original
2337 ,@(if (featurep 'xemacs) '(t)
2338 '(:help "Mail a very wide reply, quoting this article"))]
2339 ["Mail forward" gnus-summary-mail-forward t]
2340 ["Post forward" gnus-summary-post-forward t]
2341 ["Digest and mail" gnus-uu-digest-mail-forward t]
2342 ["Digest and post" gnus-uu-digest-post-forward t]
2343 ["Resend message" gnus-summary-resend-message t]
2344 ["Resend message edit" gnus-summary-resend-message-edit t]
2345 ["Send bounced mail" gnus-summary-resend-bounced-mail t]
2346 ["Send a mail" gnus-summary-mail-other-window t]
2347 ["Create a local message" gnus-summary-news-other-window t]
2348 ["Uuencode and post" gnus-uu-post-news
2349 ,@(if (featurep 'xemacs) '(t)
2350 '(:help "Post a uuencoded article"))]
2351 ["Followup via news" gnus-summary-followup-to-mail t]
2352 ["Followup via news and yank"
2353 gnus-summary-followup-to-mail-with-original t]
2354 ;;("Draft"
2355 ;;["Send" gnus-summary-send-draft t]
2356 ;;["Send bounced" gnus-resend-bounced-mail t])
2357 ))
2358
2359 (cond
2360 ((not (keymapp gnus-summary-post-menu))
2361 (setq gnus-article-post-menu gnus-summary-post-menu))
2362 ((not gnus-article-post-menu)
2363 ;; Don't share post menu.
2364 (setq gnus-article-post-menu
2365 (copy-keymap gnus-summary-post-menu))))
2366 (define-key gnus-article-mode-map [menu-bar post]
2367 (cons "Post" gnus-article-post-menu))
eec82323
LMI
2368
2369 (easy-menu-define
23f87bed
MB
2370 gnus-summary-misc-menu gnus-summary-mode-map ""
2371 `("Gnus"
2372 ("Mark Read"
2373 ["Mark as read" gnus-summary-mark-as-read-forward t]
2374 ["Mark same subject and select"
2375 gnus-summary-kill-same-subject-and-select t]
2376 ["Mark same subject" gnus-summary-kill-same-subject t]
2377 ["Catchup" gnus-summary-catchup
2378 ,@(if (featurep 'xemacs) '(t)
2379 '(:help "Mark unread articles in this group as read"))]
2380 ["Catchup all" gnus-summary-catchup-all t]
2381 ["Catchup to here" gnus-summary-catchup-to-here t]
2382 ["Catchup from here" gnus-summary-catchup-from-here t]
2383 ["Catchup region" gnus-summary-mark-region-as-read
2384 (gnus-mark-active-p)]
2385 ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
2386 ("Mark Various"
2387 ["Tick" gnus-summary-tick-article-forward t]
2388 ["Mark as dormant" gnus-summary-mark-as-dormant t]
2389 ["Remove marks" gnus-summary-clear-mark-forward t]
2390 ["Set expirable mark" gnus-summary-mark-as-expirable t]
2391 ["Set bookmark" gnus-summary-set-bookmark t]
2392 ["Remove bookmark" gnus-summary-remove-bookmark t])
2393 ("Limit to"
2394 ["Marks..." gnus-summary-limit-to-marks t]
2395 ["Subject..." gnus-summary-limit-to-subject t]
2396 ["Author..." gnus-summary-limit-to-author t]
2397 ["Age..." gnus-summary-limit-to-age t]
2398 ["Extra..." gnus-summary-limit-to-extra t]
2399 ["Score..." gnus-summary-limit-to-score t]
2400 ["Display Predicate" gnus-summary-limit-to-display-predicate t]
2401 ["Unread" gnus-summary-limit-to-unread t]
2402 ["Unseen" gnus-summary-limit-to-unseen t]
2403 ["Non-dormant" gnus-summary-limit-exclude-dormant t]
2404 ["Next articles" gnus-summary-limit-to-articles t]
2405 ["Pop limit" gnus-summary-pop-limit t]
2406 ["Show dormant" gnus-summary-limit-include-dormant t]
2407 ["Hide childless dormant"
2408 gnus-summary-limit-exclude-childless-dormant t]
2409 ;;["Hide thread" gnus-summary-limit-exclude-thread t]
2410 ["Hide marked" gnus-summary-limit-exclude-marks t]
2411 ["Show expunged" gnus-summary-limit-include-expunged t])
2412 ("Process Mark"
2413 ["Set mark" gnus-summary-mark-as-processable t]
2414 ["Remove mark" gnus-summary-unmark-as-processable t]
2415 ["Remove all marks" gnus-summary-unmark-all-processable t]
2416 ["Mark above" gnus-uu-mark-over t]
2417 ["Mark series" gnus-uu-mark-series t]
2418 ["Mark region" gnus-uu-mark-region (gnus-mark-active-p)]
2419 ["Unmark region" gnus-uu-unmark-region (gnus-mark-active-p)]
2420 ["Mark by regexp..." gnus-uu-mark-by-regexp t]
2421 ["Unmark by regexp..." gnus-uu-unmark-by-regexp t]
2422 ["Mark all" gnus-uu-mark-all t]
2423 ["Mark buffer" gnus-uu-mark-buffer t]
2424 ["Mark sparse" gnus-uu-mark-sparse t]
2425 ["Mark thread" gnus-uu-mark-thread t]
2426 ["Unmark thread" gnus-uu-unmark-thread t]
2427 ("Process Mark Sets"
2428 ["Kill" gnus-summary-kill-process-mark t]
2429 ["Yank" gnus-summary-yank-process-mark
2430 gnus-newsgroup-process-stack]
2431 ["Save" gnus-summary-save-process-mark t]
2432 ["Run command on marked..." gnus-summary-universal-argument t]))
2433 ("Scroll article"
2434 ["Page forward" gnus-summary-next-page
2435 ,@(if (featurep 'xemacs) '(t)
2436 '(:help "Show next page of article"))]
2437 ["Page backward" gnus-summary-prev-page
2438 ,@(if (featurep 'xemacs) '(t)
2439 '(:help "Show previous page of article"))]
2440 ["Line forward" gnus-summary-scroll-up t])
2441 ("Move"
2442 ["Next unread article" gnus-summary-next-unread-article t]
2443 ["Previous unread article" gnus-summary-prev-unread-article t]
2444 ["Next article" gnus-summary-next-article t]
2445 ["Previous article" gnus-summary-prev-article t]
2446 ["Next unread subject" gnus-summary-next-unread-subject t]
2447 ["Previous unread subject" gnus-summary-prev-unread-subject t]
2448 ["Next article same subject" gnus-summary-next-same-subject t]
2449 ["Previous article same subject" gnus-summary-prev-same-subject t]
2450 ["First unread article" gnus-summary-first-unread-article t]
2451 ["Best unread article" gnus-summary-best-unread-article t]
2452 ["Go to subject number..." gnus-summary-goto-subject t]
2453 ["Go to article number..." gnus-summary-goto-article t]
2454 ["Go to the last article" gnus-summary-goto-last-article t]
2455 ["Pop article off history" gnus-summary-pop-article t])
2456 ("Sort"
2457 ["Sort by number" gnus-summary-sort-by-number t]
2458 ["Sort by author" gnus-summary-sort-by-author t]
2459 ["Sort by subject" gnus-summary-sort-by-subject t]
2460 ["Sort by date" gnus-summary-sort-by-date t]
2461 ["Sort by score" gnus-summary-sort-by-score t]
2462 ["Sort by lines" gnus-summary-sort-by-lines t]
2463 ["Sort by characters" gnus-summary-sort-by-chars t]
2464 ["Randomize" gnus-summary-sort-by-random t]
2465 ["Original sort" gnus-summary-sort-by-original t])
2466 ("Help"
2467 ["Fetch group FAQ" gnus-summary-fetch-faq t]
2468 ["Describe group" gnus-summary-describe-group t]
2469 ["Fetch charter" gnus-group-fetch-charter
2470 ,@(if (featurep 'xemacs) nil
2471 '(:help "Display the charter of the current group"))]
2472 ["Fetch control message" gnus-group-fetch-control
2473 ,@(if (featurep 'xemacs) nil
2474 '(:help "Display the archived control message for the current group"))]
2475 ["Read manual" gnus-info-find-node t])
2476 ("Modes"
2477 ["Pick and read" gnus-pick-mode t]
2478 ["Binary" gnus-binary-mode t])
2479 ("Regeneration"
2480 ["Regenerate" gnus-summary-prepare t]
2481 ["Insert cached articles" gnus-summary-insert-cached-articles t]
2482 ["Insert dormant articles" gnus-summary-insert-dormant-articles t]
2483 ["Toggle threading" gnus-summary-toggle-threads t])
2484 ["See old articles" gnus-summary-insert-old-articles t]
2485 ["See new articles" gnus-summary-insert-new-articles t]
2486 ["Filter articles..." gnus-summary-execute-command t]
2487 ["Run command on articles..." gnus-summary-universal-argument t]
2488 ["Search articles forward..." gnus-summary-search-article-forward t]
2489 ["Search articles backward..." gnus-summary-search-article-backward t]
2490 ["Toggle line truncation" gnus-summary-toggle-truncation t]
2491 ["Expand window" gnus-summary-expand-window t]
2492 ["Expire expirable articles" gnus-summary-expire-articles
2493 (gnus-check-backend-function
2494 'request-expire-articles gnus-newsgroup-name)]
2495 ["Edit local kill file" gnus-summary-edit-local-kill t]
2496 ["Edit main kill file" gnus-summary-edit-global-kill t]
2497 ["Edit group parameters" gnus-summary-edit-parameters t]
2498 ["Customize group parameters" gnus-summary-customize-parameters t]
2499 ["Send a bug report" gnus-bug t]
2500 ("Exit"
2501 ["Catchup and exit" gnus-summary-catchup-and-exit
2502 ,@(if (featurep 'xemacs) '(t)
2503 '(:help "Mark unread articles in this group as read, then exit"))]
2504 ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
2505 ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
2506 ["Exit group" gnus-summary-exit
2507 ,@(if (featurep 'xemacs) '(t)
2508 '(:help "Exit current group, return to group selection mode"))]
2509 ["Exit group without updating" gnus-summary-exit-no-update t]
2510 ["Exit and goto next group" gnus-summary-next-group t]
2511 ["Exit and goto prev group" gnus-summary-prev-group t]
2512 ["Reselect group" gnus-summary-reselect-current-group t]
2513 ["Rescan group" gnus-summary-rescan-group t]
2514 ["Update dribble" gnus-summary-save-newsrc t])))
eec82323 2515
6748645f 2516 (gnus-run-hooks 'gnus-summary-menu-hook)))
eec82323 2517
60bd5589
DL
2518(defvar gnus-summary-tool-bar-map nil)
2519
9a0026a6 2520;; Emacs 21 tool bar. Should be no-op otherwise.
60bd5589 2521(defun gnus-summary-make-tool-bar ()
23f87bed
MB
2522 (if (and (fboundp 'tool-bar-add-item-from-menu)
2523 (default-value 'tool-bar-mode)
2524 (not gnus-summary-tool-bar-map))
60bd5589 2525 (setq gnus-summary-tool-bar-map
23f87bed
MB
2526 (let ((tool-bar-map (make-sparse-keymap))
2527 (load-path (mm-image-load-path)))
60bd5589
DL
2528 (tool-bar-add-item-from-menu
2529 'gnus-summary-prev-unread "prev-ur" gnus-summary-mode-map)
2530 (tool-bar-add-item-from-menu
2531 'gnus-summary-next-unread "next-ur" gnus-summary-mode-map)
2532 (tool-bar-add-item-from-menu
2533 'gnus-summary-post-news "post" gnus-summary-mode-map)
2534 (tool-bar-add-item-from-menu
2535 'gnus-summary-followup-with-original "fuwo" gnus-summary-mode-map)
2536 (tool-bar-add-item-from-menu
2537 'gnus-summary-followup "followup" gnus-summary-mode-map)
2538 (tool-bar-add-item-from-menu
2539 'gnus-summary-reply-with-original "reply-wo" gnus-summary-mode-map)
2540 (tool-bar-add-item-from-menu
2541 'gnus-summary-reply "reply" gnus-summary-mode-map)
2542 (tool-bar-add-item-from-menu
2543 'gnus-summary-caesar-message "rot13" gnus-summary-mode-map)
2544 (tool-bar-add-item-from-menu
2545 'gnus-uu-decode-uu "uu-decode" gnus-summary-mode-map)
2546 (tool-bar-add-item-from-menu
2547 'gnus-summary-save-article-file "save-aif" gnus-summary-mode-map)
2548 (tool-bar-add-item-from-menu
2549 'gnus-summary-save-article "save-art" gnus-summary-mode-map)
2550 (tool-bar-add-item-from-menu
2551 'gnus-uu-post-news "uu-post" gnus-summary-mode-map)
2552 (tool-bar-add-item-from-menu
2553 'gnus-summary-catchup "catchup" gnus-summary-mode-map)
2554 (tool-bar-add-item-from-menu
2555 'gnus-summary-catchup-and-exit "cu-exit" gnus-summary-mode-map)
2556 (tool-bar-add-item-from-menu
2557 'gnus-summary-exit "exit-summ" gnus-summary-mode-map)
2558 tool-bar-map)))
2559 (if gnus-summary-tool-bar-map
2560 (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
2561
eec82323
LMI
2562(defun gnus-score-set-default (var value)
2563 "A version of set that updates the GNU Emacs menu-bar."
2564 (set var value)
2565 ;; It is the message that forces the active status to be updated.
2566 (message ""))
2567
2568(defun gnus-make-score-map (type)
2569 "Make a summary score map of type TYPE."
2570 (if t
2571 nil
2572 (let ((headers '(("author" "from" string)
2573 ("subject" "subject" string)
2574 ("article body" "body" string)
2575 ("article head" "head" string)
2576 ("xref" "xref" string)
16409b0b 2577 ("extra header" "extra" string)
eec82323
LMI
2578 ("lines" "lines" number)
2579 ("followups to author" "followup" string)))
2580 (types '((number ("less than" <)
2581 ("greater than" >)
2582 ("equal" =))
2583 (string ("substring" s)
2584 ("exact string" e)
2585 ("fuzzy string" f)
2586 ("regexp" r))))
2587 (perms '(("temporary" (current-time-string))
2588 ("permanent" nil)
2589 ("immediate" now)))
2590 header)
2591 (list
2592 (apply
2593 'nconc
2594 (list
2595 (if (eq type 'lower)
2596 "Lower score"
2597 "Increase score"))
2598 (let (outh)
2599 (while headers
2600 (setq header (car headers))
2601 (setq outh
2602 (cons
2603 (apply
2604 'nconc
2605 (list (car header))
2606 (let ((ts (cdr (assoc (nth 2 header) types)))
2607 outt)
2608 (while ts
2609 (setq outt
2610 (cons
2611 (apply
2612 'nconc
2613 (list (caar ts))
2614 (let ((ps perms)
2615 outp)
2616 (while ps
2617 (setq outp
2618 (cons
2619 (vector
2620 (caar ps)
2621 (list
2622 'gnus-summary-score-entry
2623 (nth 1 header)
2624 (if (or (string= (nth 1 header)
2625 "head")
2626 (string= (nth 1 header)
2627 "body"))
2628 ""
2629 (list 'gnus-summary-header
2630 (nth 1 header)))
2631 (list 'quote (nth 1 (car ts)))
16409b0b
GM
2632 (list 'gnus-score-delta-default
2633 nil)
eec82323
LMI
2634 (nth 1 (car ps))
2635 t)
2636 t)
2637 outp))
2638 (setq ps (cdr ps)))
2639 (list (nreverse outp))))
2640 outt))
2641 (setq ts (cdr ts)))
2642 (list (nreverse outt))))
2643 outh))
2644 (setq headers (cdr headers)))
2645 (list (nreverse outh))))))))
2646
2647\f
2648
2649(defun gnus-summary-mode (&optional group)
2650 "Major mode for reading articles.
2651
2652All normal editing commands are switched off.
2653\\<gnus-summary-mode-map>
2654Each line in this buffer represents one article. To read an
2655article, you can, for instance, type `\\[gnus-summary-next-page]'. To move forwards
2656and backwards while displaying articles, type `\\[gnus-summary-next-unread-article]' and `\\[gnus-summary-prev-unread-article]',
2657respectively.
2658
2659You can also post articles and send mail from this buffer. To
23f87bed 2660follow up an article, type `\\[gnus-summary-followup]'. To mail a reply to the author
eec82323
LMI
2661of an article, type `\\[gnus-summary-reply]'.
2662
2663There are approx. one gazillion commands you can execute in this
2664buffer; read the info pages for more information (`\\[gnus-info-find-node]').
2665
2666The following commands are available:
2667
2668\\{gnus-summary-mode-map}"
2669 (interactive)
eec82323 2670 (kill-all-local-variables)
60bd5589
DL
2671 (when (gnus-visual-p 'summary-menu 'menu)
2672 (gnus-summary-make-menu-bar)
2673 (gnus-summary-make-tool-bar))
eec82323 2674 (gnus-summary-make-local-variables)
23f87bed
MB
2675 (let ((gnus-summary-local-variables gnus-newsgroup-variables))
2676 (gnus-summary-make-local-variables))
eec82323
LMI
2677 (gnus-make-thread-indent-array)
2678 (gnus-simplify-mode-line)
2679 (setq major-mode 'gnus-summary-mode)
2680 (setq mode-name "Summary")
2681 (make-local-variable 'minor-mode-alist)
2682 (use-local-map gnus-summary-mode-map)
16409b0b 2683 (buffer-disable-undo)
eec82323
LMI
2684 (setq buffer-read-only t) ;Disable modification
2685 (setq truncate-lines t)
2686 (setq selective-display t)
2687 (setq selective-display-ellipses t) ;Display `...'
2688 (gnus-summary-set-display-table)
2689 (gnus-set-default-directory)
2690 (setq gnus-newsgroup-name group)
2691 (make-local-variable 'gnus-summary-line-format)
2692 (make-local-variable 'gnus-summary-line-format-spec)
6748645f
LMI
2693 (make-local-variable 'gnus-summary-dummy-line-format)
2694 (make-local-variable 'gnus-summary-dummy-line-format-spec)
eec82323 2695 (make-local-variable 'gnus-summary-mark-positions)
23f87bed 2696 (gnus-make-local-hook 'pre-command-hook)
6748645f
LMI
2697 (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
2698 (gnus-run-hooks 'gnus-summary-mode-hook)
23f87bed 2699 (turn-on-gnus-mailing-list-mode)
87545352 2700 (mm-enable-multibyte)
eec82323
LMI
2701 (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
2702 (gnus-update-summary-mark-positions))
2703
2704(defun gnus-summary-make-local-variables ()
2705 "Make all the local summary buffer variables."
16409b0b
GM
2706 (let (global)
2707 (dolist (local gnus-summary-local-variables)
eec82323
LMI
2708 (if (consp local)
2709 (progn
2710 (if (eq (cdr local) 'global)
2711 ;; Copy the global value of the variable.
2712 (setq global (symbol-value (car local)))
2713 ;; Use the value from the list.
2714 (setq global (eval (cdr local))))
16409b0b 2715 (set (make-local-variable (car local)) global))
eec82323 2716 ;; Simple nil-valued local variable.
16409b0b 2717 (set (make-local-variable local) nil)))))
eec82323
LMI
2718
2719(defun gnus-summary-clear-local-variables ()
2720 (let ((locals gnus-summary-local-variables))
2721 (while locals
2722 (if (consp (car locals))
2723 (and (vectorp (caar locals))
2724 (set (caar locals) nil))
2725 (and (vectorp (car locals))
2726 (set (car locals) nil)))
2727 (setq locals (cdr locals)))))
2728
2729;; Summary data functions.
2730
2731(defmacro gnus-data-number (data)
2732 `(car ,data))
2733
2734(defmacro gnus-data-set-number (data number)
2735 `(setcar ,data ,number))
2736
2737(defmacro gnus-data-mark (data)
2738 `(nth 1 ,data))
2739
2740(defmacro gnus-data-set-mark (data mark)
2741 `(setcar (nthcdr 1 ,data) ,mark))
2742
2743(defmacro gnus-data-pos (data)
2744 `(nth 2 ,data))
2745
2746(defmacro gnus-data-set-pos (data pos)
2747 `(setcar (nthcdr 2 ,data) ,pos))
2748
2749(defmacro gnus-data-header (data)
2750 `(nth 3 ,data))
2751
2752(defmacro gnus-data-set-header (data header)
2753 `(setf (nth 3 ,data) ,header))
2754
2755(defmacro gnus-data-level (data)
2756 `(nth 4 ,data))
2757
2758(defmacro gnus-data-unread-p (data)
2759 `(= (nth 1 ,data) gnus-unread-mark))
2760
2761(defmacro gnus-data-read-p (data)
2762 `(/= (nth 1 ,data) gnus-unread-mark))
2763
2764(defmacro gnus-data-pseudo-p (data)
2765 `(consp (nth 3 ,data)))
2766
2767(defmacro gnus-data-find (number)
2768 `(assq ,number gnus-newsgroup-data))
2769
2770(defmacro gnus-data-find-list (number &optional data)
2771 `(let ((bdata ,(or data 'gnus-newsgroup-data)))
2772 (memq (assq ,number bdata)
2773 bdata)))
2774
2775(defmacro gnus-data-make (number mark pos header level)
2776 `(list ,number ,mark ,pos ,header ,level))
2777
2778(defun gnus-data-enter (after-article number mark pos header level offset)
2779 (let ((data (gnus-data-find-list after-article)))
2780 (unless data
2781 (error "No such article: %d" after-article))
2782 (setcdr data (cons (gnus-data-make number mark pos header level)
2783 (cdr data)))
2784 (setq gnus-newsgroup-data-reverse nil)
2785 (gnus-data-update-list (cddr data) offset)))
2786
2787(defun gnus-data-enter-list (after-article list &optional offset)
2788 (when list
2789 (let ((data (and after-article (gnus-data-find-list after-article)))
2790 (ilist list))
6748645f
LMI
2791 (if (not (or data
2792 after-article))
2793 (let ((odata gnus-newsgroup-data))
2794 (setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
eec82323 2795 (when offset
6748645f 2796 (gnus-data-update-list odata offset)))
23f87bed 2797 ;; Find the last element in the list to be spliced into the main
6748645f
LMI
2798 ;; list.
2799 (while (cdr list)
2800 (setq list (cdr list)))
2801 (if (not data)
2802 (progn
2803 (setcdr list gnus-newsgroup-data)
2804 (setq gnus-newsgroup-data ilist)
2805 (when offset
2806 (gnus-data-update-list (cdr list) offset)))
2807 (setcdr list (cdr data))
2808 (setcdr data ilist)
2809 (when offset
2810 (gnus-data-update-list (cdr list) offset))))
eec82323
LMI
2811 (setq gnus-newsgroup-data-reverse nil))))
2812
2813(defun gnus-data-remove (article &optional offset)
2814 (let ((data gnus-newsgroup-data))
2815 (if (= (gnus-data-number (car data)) article)
2816 (progn
2817 (setq gnus-newsgroup-data (cdr gnus-newsgroup-data)
2818 gnus-newsgroup-data-reverse nil)
2819 (when offset
2820 (gnus-data-update-list gnus-newsgroup-data offset)))
2821 (while (cdr data)
2822 (when (= (gnus-data-number (cadr data)) article)
2823 (setcdr data (cddr data))
2824 (when offset
2825 (gnus-data-update-list (cdr data) offset))
2826 (setq data nil
2827 gnus-newsgroup-data-reverse nil))
2828 (setq data (cdr data))))))
2829
2830(defmacro gnus-data-list (backward)
2831 `(if ,backward
2832 (or gnus-newsgroup-data-reverse
2833 (setq gnus-newsgroup-data-reverse
2834 (reverse gnus-newsgroup-data)))
2835 gnus-newsgroup-data))
2836
2837(defun gnus-data-update-list (data offset)
2838 "Add OFFSET to the POS of all data entries in DATA."
6748645f 2839 (setq gnus-newsgroup-data-reverse nil)
eec82323
LMI
2840 (while data
2841 (setcar (nthcdr 2 (car data)) (+ offset (nth 2 (car data))))
2842 (setq data (cdr data))))
2843
eec82323
LMI
2844(defun gnus-summary-article-pseudo-p (article)
2845 "Say whether this article is a pseudo article or not."
2846 (not (vectorp (gnus-data-header (gnus-data-find article)))))
2847
2848(defmacro gnus-summary-article-sparse-p (article)
2849 "Say whether this article is a sparse article or not."
a8151ef7 2850 `(memq ,article gnus-newsgroup-sparse))
eec82323
LMI
2851
2852(defmacro gnus-summary-article-ancient-p (article)
2853 "Say whether this article is a sparse article or not."
2854 `(memq ,article gnus-newsgroup-ancient))
2855
2856(defun gnus-article-parent-p (number)
2857 "Say whether this article is a parent or not."
2858 (let ((data (gnus-data-find-list number)))
23f87bed 2859 (and (cdr data) ; There has to be an article after...
eec82323
LMI
2860 (< (gnus-data-level (car data)) ; And it has to have a higher level.
2861 (gnus-data-level (nth 1 data))))))
2862
2863(defun gnus-article-children (number)
2864 "Return a list of all children to NUMBER."
2865 (let* ((data (gnus-data-find-list number))
2866 (level (gnus-data-level (car data)))
2867 children)
2868 (setq data (cdr data))
2869 (while (and data
2870 (= (gnus-data-level (car data)) (1+ level)))
2871 (push (gnus-data-number (car data)) children)
2872 (setq data (cdr data)))
2873 children))
2874
2875(defmacro gnus-summary-skip-intangible ()
2876 "If the current article is intangible, then jump to a different article."
2877 '(let ((to (get-text-property (point) 'gnus-intangible)))
2878 (and to (gnus-summary-goto-subject to))))
2879
2880(defmacro gnus-summary-article-intangible-p ()
2881 "Say whether this article is intangible or not."
2882 '(get-text-property (point) 'gnus-intangible))
2883
2884(defun gnus-article-read-p (article)
2885 "Say whether ARTICLE is read or not."
2886 (not (or (memq article gnus-newsgroup-marked)
23f87bed 2887 (memq article gnus-newsgroup-spam-marked)
eec82323
LMI
2888 (memq article gnus-newsgroup-unreads)
2889 (memq article gnus-newsgroup-unselected)
2890 (memq article gnus-newsgroup-dormant))))
2891
2892;; Some summary mode macros.
2893
2894(defmacro gnus-summary-article-number ()
2895 "The article number of the article on the current line.
8f688cb0 2896If there isn't an article number here, then we return the current
eec82323
LMI
2897article number."
2898 '(progn
2899 (gnus-summary-skip-intangible)
2900 (or (get-text-property (point) 'gnus-number)
2901 (gnus-summary-last-subject))))
2902
2903(defmacro gnus-summary-article-header (&optional number)
6748645f 2904 "Return the header of article NUMBER."
eec82323
LMI
2905 `(gnus-data-header (gnus-data-find
2906 ,(or number '(gnus-summary-article-number)))))
2907
2908(defmacro gnus-summary-thread-level (&optional number)
6748645f 2909 "Return the level of thread that starts with article NUMBER."
eec82323
LMI
2910 `(if (and (eq gnus-summary-make-false-root 'dummy)
2911 (get-text-property (point) 'gnus-intangible))
2912 0
2913 (gnus-data-level (gnus-data-find
2914 ,(or number '(gnus-summary-article-number))))))
2915
2916(defmacro gnus-summary-article-mark (&optional number)
6748645f 2917 "Return the mark of article NUMBER."
eec82323
LMI
2918 `(gnus-data-mark (gnus-data-find
2919 ,(or number '(gnus-summary-article-number)))))
2920
2921(defmacro gnus-summary-article-pos (&optional number)
6748645f 2922 "Return the position of the line of article NUMBER."
eec82323
LMI
2923 `(gnus-data-pos (gnus-data-find
2924 ,(or number '(gnus-summary-article-number)))))
2925
2926(defalias 'gnus-summary-subject-string 'gnus-summary-article-subject)
2927(defmacro gnus-summary-article-subject (&optional number)
2928 "Return current subject string or nil if nothing."
2929 `(let ((headers
2930 ,(if number
2931 `(gnus-data-header (assq ,number gnus-newsgroup-data))
2932 '(gnus-data-header (assq (gnus-summary-article-number)
2933 gnus-newsgroup-data)))))
2934 (and headers
2935 (vectorp headers)
2936 (mail-header-subject headers))))
2937
2938(defmacro gnus-summary-article-score (&optional number)
2939 "Return current article score."
2940 `(or (cdr (assq ,(or number '(gnus-summary-article-number))
2941 gnus-newsgroup-scored))
2942 gnus-summary-default-score 0))
2943
2944(defun gnus-summary-article-children (&optional number)
6748645f 2945 "Return a list of article numbers that are children of article NUMBER."
eec82323
LMI
2946 (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))))
2947 (level (gnus-data-level (car data)))
2948 l children)
2949 (while (and (setq data (cdr data))
2950 (> (setq l (gnus-data-level (car data))) level))
2951 (and (= (1+ level) l)
2952 (push (gnus-data-number (car data))
2953 children)))
2954 (nreverse children)))
2955
2956(defun gnus-summary-article-parent (&optional number)
6748645f 2957 "Return the article number of the parent of article NUMBER."
eec82323
LMI
2958 (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))
2959 (gnus-data-list t)))
2960 (level (gnus-data-level (car data))))
2961 (if (zerop level)
2962 () ; This is a root.
2963 ;; We search until we find an article with a level less than
2964 ;; this one. That function has to be the parent.
2965 (while (and (setq data (cdr data))
2966 (not (< (gnus-data-level (car data)) level))))
2967 (and data (gnus-data-number (car data))))))
2968
2969(defun gnus-unread-mark-p (mark)
2970 "Say whether MARK is the unread mark."
2971 (= mark gnus-unread-mark))
2972
2973(defun gnus-read-mark-p (mark)
2974 "Say whether MARK is one of the marks that mark as read.
2975This is all marks except unread, ticked, dormant, and expirable."
2976 (not (or (= mark gnus-unread-mark)
2977 (= mark gnus-ticked-mark)
23f87bed 2978 (= mark gnus-spam-mark)
eec82323
LMI
2979 (= mark gnus-dormant-mark)
2980 (= mark gnus-expirable-mark))))
2981
2982(defmacro gnus-article-mark (number)
6748645f
LMI
2983 "Return the MARK of article NUMBER.
2984This macro should only be used when computing the mark the \"first\"
2985time; i.e., when generating the summary lines. After that,
2986`gnus-summary-article-mark' should be used to examine the
2987marks of articles."
eec82323 2988 `(cond
6748645f 2989 ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
6748645f 2990 ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
eec82323
LMI
2991 ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
2992 ((memq ,number gnus-newsgroup-marked) gnus-ticked-mark)
23f87bed 2993 ((memq ,number gnus-newsgroup-spam-marked) gnus-spam-mark)
eec82323
LMI
2994 ((memq ,number gnus-newsgroup-dormant) gnus-dormant-mark)
2995 ((memq ,number gnus-newsgroup-expirable) gnus-expirable-mark)
2996 (t (or (cdr (assq ,number gnus-newsgroup-reads))
2997 gnus-ancient-mark))))
2998
2999;; Saving hidden threads.
3000
eec82323
LMI
3001(defmacro gnus-save-hidden-threads (&rest forms)
3002 "Save hidden threads, eval FORMS, and restore the hidden threads."
3003 (let ((config (make-symbol "config")))
3004 `(let ((,config (gnus-hidden-threads-configuration)))
3005 (unwind-protect
3006 (save-excursion
3007 ,@forms)
3008 (gnus-restore-hidden-threads-configuration ,config)))))
23f87bed
MB
3009(put 'gnus-save-hidden-threads 'lisp-indent-function 0)
3010(put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
eec82323 3011
107ecebb
AS
3012(defun gnus-data-compute-positions ()
3013 "Compute the positions of all articles."
3014 (setq gnus-newsgroup-data-reverse nil)
3015 (let ((data gnus-newsgroup-data))
3016 (save-excursion
3017 (gnus-save-hidden-threads
3018 (gnus-summary-show-all-threads)
3019 (goto-char (point-min))
3020 (while data
3021 (while (get-text-property (point) 'gnus-intangible)
3022 (forward-line 1))
3023 (gnus-data-set-pos (car data) (+ (point) 3))
3024 (setq data (cdr data))
3025 (forward-line 1))))))
3026
16409b0b
GM
3027(defun gnus-hidden-threads-configuration ()
3028 "Return the current hidden threads configuration."
3029 (save-excursion
3030 (let (config)
3031 (goto-char (point-min))
3032 (while (search-forward "\r" nil t)
3033 (push (1- (point)) config))
3034 config)))
3035
3036(defun gnus-restore-hidden-threads-configuration (config)
3037 "Restore hidden threads configuration from CONFIG."
3038 (save-excursion
3039 (let (point buffer-read-only)
3040 (while (setq point (pop config))
3041 (when (and (< point (point-max))
3042 (goto-char point)
3043 (eq (char-after) ?\n))
3044 (subst-char-in-region point (1+ point) ?\n ?\r))))))
3045
eec82323
LMI
3046;; Various summary mode internalish functions.
3047
3048(defun gnus-mouse-pick-article (e)
3049 (interactive "e")
3050 (mouse-set-point e)
3051 (gnus-summary-next-page nil t))
3052
3053(defun gnus-summary-set-display-table ()
16409b0b
GM
3054 "Change the display table.
3055Odd characters have a tendency to mess
3056up nicely formatted displays - we make all possible glyphs
3057display only a single character."
eec82323
LMI
3058
3059 ;; We start from the standard display table, if any.
3060 (let ((table (or (copy-sequence standard-display-table)
3061 (make-display-table)))
3062 (i 32))
3063 ;; Nix out all the control chars...
3064 (while (>= (setq i (1- i)) 0)
3065 (aset table i [??]))
23f87bed 3066 ;; ... but not newline and cr, of course. (cr is necessary for the
eec82323
LMI
3067 ;; selective display).
3068 (aset table ?\n nil)
3069 (aset table ?\r nil)
6748645f
LMI
3070 ;; We keep TAB as well.
3071 (aset table ?\t nil)
eec82323
LMI
3072 ;; We nix out any glyphs over 126 that are not set already.
3073 (let ((i 256))
3074 (while (>= (setq i (1- i)) 127)
3075 ;; Only modify if the entry is nil.
3076 (unless (aref table i)
3077 (aset table i [??]))))
3078 (setq buffer-display-table table)))
3079
23f87bed
MB
3080(defun gnus-summary-set-article-display-arrow (pos)
3081 "Update the overlay arrow to point to line at position POS."
3082 (when (and gnus-summary-display-arrow
3083 (boundp 'overlay-arrow-position)
3084 (boundp 'overlay-arrow-string))
3085 (save-excursion
3086 (goto-char pos)
3087 (beginning-of-line)
3088 (unless overlay-arrow-position
3089 (setq overlay-arrow-position (make-marker)))
3090 (setq overlay-arrow-string "=>"
3091 overlay-arrow-position (set-marker overlay-arrow-position
3092 (point)
3093 (current-buffer))))))
3094
eec82323
LMI
3095(defun gnus-summary-setup-buffer (group)
3096 "Initialize summary buffer."
23f87bed
MB
3097 (let ((buffer (gnus-summary-buffer-name group))
3098 (dead-name (concat "*Dead Summary "
3099 (gnus-group-decoded-name group) "*")))
3100 ;; If a dead summary buffer exists, we kill it.
3101 (when (gnus-buffer-live-p dead-name)
3102 (gnus-kill-buffer dead-name))
eec82323
LMI
3103 (if (get-buffer buffer)
3104 (progn
3105 (set-buffer buffer)
3106 (setq gnus-summary-buffer (current-buffer))
3107 (not gnus-newsgroup-prepared))
3108 ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>
6748645f 3109 (setq gnus-summary-buffer (set-buffer (gnus-get-buffer-create buffer)))
eec82323
LMI
3110 (gnus-summary-mode group)
3111 (when gnus-carpal
3112 (gnus-carpal-setup-buffer 'summary))
3113 (unless gnus-single-article-buffer
3114 (make-local-variable 'gnus-article-buffer)
3115 (make-local-variable 'gnus-article-current)
3116 (make-local-variable 'gnus-original-article-buffer))
3117 (setq gnus-newsgroup-name group)
23f87bed
MB
3118 ;; Set any local variables in the group parameters.
3119 (gnus-summary-set-local-parameters gnus-newsgroup-name)
eec82323
LMI
3120 t)))
3121
3122(defun gnus-set-global-variables ()
16409b0b
GM
3123 "Set the global equivalents of the buffer-local variables.
3124They are set to the latest values they had. These reflect the summary
3125buffer that was in action when the last article was fetched."
eec82323
LMI
3126 (when (eq major-mode 'gnus-summary-mode)
3127 (setq gnus-summary-buffer (current-buffer))
3128 (let ((name gnus-newsgroup-name)
3129 (marked gnus-newsgroup-marked)
23f87bed 3130 (spam gnus-newsgroup-spam-marked)
eec82323
LMI
3131 (unread gnus-newsgroup-unreads)
3132 (headers gnus-current-headers)
3133 (data gnus-newsgroup-data)
3134 (summary gnus-summary-buffer)
3135 (article-buffer gnus-article-buffer)
3136 (original gnus-original-article-buffer)
3137 (gac gnus-article-current)
3138 (reffed gnus-reffed-article-number)
16409b0b 3139 (score-file gnus-current-score-file)
23f87bed
MB
3140 (default-charset gnus-newsgroup-charset)
3141 vlist)
3142 (let ((locals gnus-newsgroup-variables))
3143 (while locals
3144 (if (consp (car locals))
3145 (push (eval (caar locals)) vlist)
3146 (push (eval (car locals)) vlist))
3147 (setq locals (cdr locals)))
3148 (setq vlist (nreverse vlist)))
eec82323
LMI
3149 (save-excursion
3150 (set-buffer gnus-group-buffer)
6748645f
LMI
3151 (setq gnus-newsgroup-name name
3152 gnus-newsgroup-marked marked
23f87bed 3153 gnus-newsgroup-spam-marked spam
6748645f
LMI
3154 gnus-newsgroup-unreads unread
3155 gnus-current-headers headers
3156 gnus-newsgroup-data data
3157 gnus-article-current gac
3158 gnus-summary-buffer summary
3159 gnus-article-buffer article-buffer
3160 gnus-original-article-buffer original
3161 gnus-reffed-article-number reffed
16409b0b
GM
3162 gnus-current-score-file score-file
3163 gnus-newsgroup-charset default-charset)
23f87bed
MB
3164 (let ((locals gnus-newsgroup-variables))
3165 (while locals
3166 (if (consp (car locals))
3167 (set (caar locals) (pop vlist))
3168 (set (car locals) (pop vlist)))
3169 (setq locals (cdr locals))))
eec82323
LMI
3170 ;; The article buffer also has local variables.
3171 (when (gnus-buffer-live-p gnus-article-buffer)
3172 (set-buffer gnus-article-buffer)
3173 (setq gnus-summary-buffer summary))))))
3174
3175(defun gnus-summary-article-unread-p (article)
3176 "Say whether ARTICLE is unread or not."
3177 (memq article gnus-newsgroup-unreads))
3178
3179(defun gnus-summary-first-article-p (&optional article)
3180 "Return whether ARTICLE is the first article in the buffer."
3181 (if (not (setq article (or article (gnus-summary-article-number))))
3182 nil
3183 (eq article (caar gnus-newsgroup-data))))
3184
3185(defun gnus-summary-last-article-p (&optional article)
3186 "Return whether ARTICLE is the last article in the buffer."
3187 (if (not (setq article (or article (gnus-summary-article-number))))
16409b0b
GM
3188 ;; All non-existent numbers are the last article. :-)
3189 t
eec82323
LMI
3190 (not (cdr (gnus-data-find-list article)))))
3191
3192(defun gnus-make-thread-indent-array ()
3193 (let ((n 200))
3194 (unless (and gnus-thread-indent-array
3195 (= gnus-thread-indent-level gnus-thread-indent-array-level))
3196 (setq gnus-thread-indent-array (make-vector 201 "")
3197 gnus-thread-indent-array-level gnus-thread-indent-level)
3198 (while (>= n 0)
3199 (aset gnus-thread-indent-array n
3200 (make-string (* n gnus-thread-indent-level) ? ))
3201 (setq n (1- n))))))
3202
3203(defun gnus-update-summary-mark-positions ()
3204 "Compute where the summary marks are to go."
3205 (save-excursion
6748645f 3206 (when (gnus-buffer-exists-p gnus-summary-buffer)
eec82323
LMI
3207 (set-buffer gnus-summary-buffer))
3208 (let ((gnus-replied-mark 129)
3209 (gnus-score-below-mark 130)
3210 (gnus-score-over-mark 130)
23f87bed 3211 (gnus-undownloaded-mark 131)
eec82323 3212 (spec gnus-summary-line-format-spec)
6748645f 3213 gnus-visual pos)
eec82323
LMI
3214 (save-excursion
3215 (gnus-set-work-buffer)
6748645f 3216 (let ((gnus-summary-line-format-spec spec)
23f87bed 3217 (gnus-newsgroup-downloadable '(0)))
eec82323 3218 (gnus-summary-insert-line
23f87bed
MB
3219 [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil]
3220 0 nil t 128 t nil "" nil 1)
eec82323
LMI
3221 (goto-char (point-min))
3222 (setq pos (list (cons 'unread (and (search-forward "\200" nil t)
667e0ba6 3223 (- (point) (point-min) 1)))))
eec82323
LMI
3224 (goto-char (point-min))
3225 (push (cons 'replied (and (search-forward "\201" nil t)
667e0ba6 3226 (- (point) (point-min) 1)))
eec82323
LMI
3227 pos)
3228 (goto-char (point-min))
667e0ba6
SM
3229 (push (cons 'score (and (search-forward "\202" nil t)
3230 (- (point) (point-min) 1)))
6748645f
LMI
3231 pos)
3232 (goto-char (point-min))
3233 (push (cons 'download
667e0ba6
SM
3234 (and (search-forward "\203" nil t)
3235 (- (point) (point-min) 1)))
eec82323
LMI
3236 pos)))
3237 (setq gnus-summary-mark-positions pos))))
3238
3239(defun gnus-summary-insert-dummy-line (gnus-tmp-subject gnus-tmp-number)
3240 "Insert a dummy root in the summary buffer."
3241 (beginning-of-line)
3242 (gnus-add-text-properties
3243 (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
3244 (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
3245
23f87bed
MB
3246(defun gnus-summary-extract-address-component (from)
3247 (or (car (funcall gnus-extract-address-components from))
3248 from))
3249
3250(defun gnus-summary-from-or-to-or-newsgroups (header gnus-tmp-from)
3251 (let ((mail-parse-charset gnus-newsgroup-charset)
3252 ; Is it really necessary to do this next part for each summary line?
3253 ; Luckily, doesn't seem to slow things down much.
16409b0b
GM
3254 (mail-parse-ignored-charsets
3255 (save-excursion (set-buffer gnus-summary-buffer)
3256 gnus-newsgroup-ignored-charsets)))
23f87bed
MB
3257 (or
3258 (and gnus-ignored-from-addresses
3259 (string-match gnus-ignored-from-addresses gnus-tmp-from)
3260 (let ((extra-headers (mail-header-extra header))
3261 to
3262 newsgroups)
3263 (cond
3264 ((setq to (cdr (assq 'To extra-headers)))
3265 (concat "-> "
3266 (inline
3267 (gnus-summary-extract-address-component
3268 (funcall gnus-decode-encoded-word-function to)))))
3269 ((setq newsgroups (cdr (assq 'Newsgroups extra-headers)))
3270 (concat "=> " newsgroups)))))
3271 (inline (gnus-summary-extract-address-component gnus-tmp-from)))))
16409b0b 3272
eec82323
LMI
3273(defun gnus-summary-insert-line (gnus-tmp-header
3274 gnus-tmp-level gnus-tmp-current
23f87bed 3275 undownloaded gnus-tmp-unread gnus-tmp-replied
eec82323
LMI
3276 gnus-tmp-expirable gnus-tmp-subject-or-nil
3277 &optional gnus-tmp-dummy gnus-tmp-score
3278 gnus-tmp-process)
3279 (let* ((gnus-tmp-indentation (aref gnus-thread-indent-array gnus-tmp-level))
3280 (gnus-tmp-lines (mail-header-lines gnus-tmp-header))
3281 (gnus-tmp-score (or gnus-tmp-score gnus-summary-default-score 0))
3282 (gnus-tmp-score-char
3283 (if (or (null gnus-summary-default-score)
3284 (<= (abs (- gnus-tmp-score gnus-summary-default-score))
3285 gnus-summary-zcore-fuzz))
23f87bed 3286 ? ;Whitespace
eec82323
LMI
3287 (if (< gnus-tmp-score gnus-summary-default-score)
3288 gnus-score-below-mark gnus-score-over-mark)))
23f87bed 3289 (gnus-tmp-number (mail-header-number gnus-tmp-header))
eec82323
LMI
3290 (gnus-tmp-replied
3291 (cond (gnus-tmp-process gnus-process-mark)
3292 ((memq gnus-tmp-current gnus-newsgroup-cached)
3293 gnus-cached-mark)
3294 (gnus-tmp-replied gnus-replied-mark)
23f87bed
MB
3295 ((memq gnus-tmp-current gnus-newsgroup-forwarded)
3296 gnus-forwarded-mark)
eec82323
LMI
3297 ((memq gnus-tmp-current gnus-newsgroup-saved)
3298 gnus-saved-mark)
23f87bed
MB
3299 ((memq gnus-tmp-number gnus-newsgroup-recent)
3300 gnus-recent-mark)
3301 ((memq gnus-tmp-number gnus-newsgroup-unseen)
3302 gnus-unseen-mark)
3303 (t gnus-no-mark)))
3304 (gnus-tmp-downloaded
3305 (cond (undownloaded
3306 gnus-undownloaded-mark)
3307 (gnus-newsgroup-agentized
3308 gnus-downloaded-mark)
3309 (t
3310 gnus-no-mark)))
eec82323
LMI
3311 (gnus-tmp-from (mail-header-from gnus-tmp-header))
3312 (gnus-tmp-name
3313 (cond
3314 ((string-match "<[^>]+> *$" gnus-tmp-from)
3315 (let ((beg (match-beginning 0)))
23f87bed
MB
3316 (or (and (string-match "^\".+\"" gnus-tmp-from)
3317 (substring gnus-tmp-from 1 (1- (match-end 0))))
eec82323
LMI
3318 (substring gnus-tmp-from 0 beg))))
3319 ((string-match "(.+)" gnus-tmp-from)
3320 (substring gnus-tmp-from
3321 (1+ (match-beginning 0)) (1- (match-end 0))))
3322 (t gnus-tmp-from)))
3323 (gnus-tmp-subject (mail-header-subject gnus-tmp-header))
eec82323
LMI
3324 (gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
3325 (gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
3326 (buffer-read-only nil))
3327 (when (string= gnus-tmp-name "")
3328 (setq gnus-tmp-name gnus-tmp-from))
3329 (unless (numberp gnus-tmp-lines)
23f87bed
MB
3330 (setq gnus-tmp-lines -1))
3331 (if (= gnus-tmp-lines -1)
3332 (setq gnus-tmp-lines "?")
3333 (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
3334 (gnus-put-text-property
eec82323
LMI
3335 (point)
3336 (progn (eval gnus-summary-line-format-spec) (point))
23f87bed 3337 'gnus-number gnus-tmp-number)
eec82323
LMI
3338 (when (gnus-visual-p 'summary-highlight 'highlight)
3339 (forward-line -1)
6748645f 3340 (gnus-run-hooks 'gnus-summary-update-hook)
eec82323
LMI
3341 (forward-line 1))))
3342
3343(defun gnus-summary-update-line (&optional dont-update)
16409b0b 3344 "Update summary line after change."
eec82323
LMI
3345 (when (and gnus-summary-default-score
3346 (not gnus-summary-inhibit-highlight))
3347 (let* ((gnus-summary-inhibit-highlight t) ; Prevent recursion.
3348 (article (gnus-summary-article-number))
3349 (score (gnus-summary-article-score article)))
3350 (unless dont-update
3351 (if (and gnus-summary-mark-below
3352 (< (gnus-summary-article-score)
3353 gnus-summary-mark-below))
3354 ;; This article has a low score, so we mark it as read.
3355 (when (memq article gnus-newsgroup-unreads)
3356 (gnus-summary-mark-article-as-read gnus-low-score-mark))
3357 (when (eq (gnus-summary-article-mark) gnus-low-score-mark)
3358 ;; This article was previously marked as read on account
3359 ;; of a low score, but now it has risen, so we mark it as
3360 ;; unread.
3361 (gnus-summary-mark-article-as-unread gnus-unread-mark)))
3362 (gnus-summary-update-mark
3363 (if (or (null gnus-summary-default-score)
3364 (<= (abs (- score gnus-summary-default-score))
3365 gnus-summary-zcore-fuzz))
23f87bed 3366 ? ;Whitespace
eec82323
LMI
3367 (if (< score gnus-summary-default-score)
3368 gnus-score-below-mark gnus-score-over-mark))
3369 'score))
3370 ;; Do visual highlighting.
3371 (when (gnus-visual-p 'summary-highlight 'highlight)
6748645f 3372 (gnus-run-hooks 'gnus-summary-update-hook)))))
eec82323
LMI
3373
3374(defvar gnus-tmp-new-adopts nil)
3375
3376(defun gnus-summary-number-of-articles-in-thread (thread &optional level char)
3377 "Return the number of articles in THREAD.
3378This may be 0 in some cases -- if none of the articles in
3379the thread are to be displayed."
3380 (let* ((number
23f87bed 3381 ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
eec82323
LMI
3382 (cond
3383 ((not (listp thread))
3384 1)
3385 ((and (consp thread) (cdr thread))
3386 (apply
3387 '+ 1 (mapcar
3388 'gnus-summary-number-of-articles-in-thread (cdr thread))))
3389 ((null thread)
3390 1)
3391 ((memq (mail-header-number (car thread)) gnus-newsgroup-limit)
3392 1)
3393 (t 0))))
3394 (when (and level (zerop level) gnus-tmp-new-adopts)
3395 (incf number
3396 (apply '+ (mapcar
3397 'gnus-summary-number-of-articles-in-thread
3398 gnus-tmp-new-adopts))))
3399 (if char
3400 (if (> number 1) gnus-not-empty-thread-mark
3401 gnus-empty-thread-mark)
3402 number)))
3403
23f87bed
MB
3404(defsubst gnus-summary-line-message-size (head)
3405 "Return pretty-printed version of message size.
3406This function is intended to be used in
3407`gnus-summary-line-format-alist'."
3408 (let ((c (or (mail-header-chars head) -1)))
3409 (cond ((< c 0) "n/a") ; chars not available
3410 ((< c (* 1000 10)) (format "%1.1fk" (/ c 1024.0)))
3411 ((< c (* 1000 100)) (format "%dk" (/ c 1024.0)))
3412 ((< c (* 1000 10000)) (format "%1.1fM" (/ c (* 1024.0 1024))))
3413 (t (format "%dM" (/ c (* 1024.0 1024)))))))
3414
3415
eec82323
LMI
3416(defun gnus-summary-set-local-parameters (group)
3417 "Go through the local params of GROUP and set all variable specs in that list."
3418 (let ((params (gnus-group-find-parameter group))
23f87bed 3419 (vars '(quit-config)) ; Ignore quit-config.
eec82323
LMI
3420 elem)
3421 (while params
3422 (setq elem (car params)
3423 params (cdr params))
3424 (and (consp elem) ; Has to be a cons.
3425 (consp (cdr elem)) ; The cdr has to be a list.
3426 (symbolp (car elem)) ; Has to be a symbol in there.
23f87bed 3427 (not (memq (car elem) vars))
eec82323 3428 (ignore-errors ; So we set it.
23f87bed 3429 (push (car elem) vars)
eec82323
LMI
3430 (make-local-variable (car elem))
3431 (set (car elem) (eval (nth 1 elem))))))))
3432
3433(defun gnus-summary-read-group (group &optional show-all no-article
6748645f
LMI
3434 kill-buffer no-display backward
3435 select-articles)
eec82323
LMI
3436 "Start reading news in newsgroup GROUP.
3437If SHOW-ALL is non-nil, already read articles are also listed.
3438If NO-ARTICLE is non-nil, no article is selected initially.
3439If NO-DISPLAY, don't generate a summary buffer."
3440 (let (result)
3441 (while (and group
3442 (null (setq result
3443 (let ((gnus-auto-select-next nil))
6748645f
LMI
3444 (or (gnus-summary-read-group-1
3445 group show-all no-article
3446 kill-buffer no-display
3447 select-articles)
3448 (setq show-all nil
16409b0b 3449 select-articles nil)))))
eec82323
LMI
3450 (eq gnus-auto-select-next 'quietly))
3451 (set-buffer gnus-group-buffer)
6748645f
LMI
3452 ;; The entry function called above goes to the next
3453 ;; group automatically, so we go two groups back
3454 ;; if we are searching for the previous group.
3455 (when backward
3456 (gnus-group-prev-unread-group 2))
eec82323
LMI
3457 (if (not (equal group (gnus-group-group-name)))
3458 (setq group (gnus-group-group-name))
3459 (setq group nil)))
3460 result))
3461
3462(defun gnus-summary-read-group-1 (group show-all no-article
6748645f
LMI
3463 kill-buffer no-display
3464 &optional select-articles)
eec82323 3465 ;; Killed foreign groups can't be entered.
23f87bed
MB
3466 ;; (when (and (not (gnus-group-native-p group))
3467 ;; (not (gnus-gethash group gnus-newsrc-hashtb)))
3468 ;; (error "Dead non-native groups can't be entered"))
3469 (gnus-message 5 "Retrieving newsgroup: %s..."
3470 (gnus-group-decoded-name group))
eec82323
LMI
3471 (let* ((new-group (gnus-summary-setup-buffer group))
3472 (quit-config (gnus-group-quit-config group))
6748645f
LMI
3473 (did-select (and new-group (gnus-select-newsgroup
3474 group show-all select-articles))))
eec82323
LMI
3475 (cond
3476 ;; This summary buffer exists already, so we just select it.
3477 ((not new-group)
3478 (gnus-set-global-variables)
3479 (when kill-buffer
3480 (gnus-kill-or-deaden-summary kill-buffer))
3481 (gnus-configure-windows 'summary 'force)
3482 (gnus-set-mode-line 'summary)
3483 (gnus-summary-position-point)
3484 (message "")
3485 t)
3486 ;; We couldn't select this group.
3487 ((null did-select)
3488 (when (and (eq major-mode 'gnus-summary-mode)
3489 (not (equal (current-buffer) kill-buffer)))
3490 (kill-buffer (current-buffer))
3491 (if (not quit-config)
3492 (progn
6748645f
LMI
3493 ;; Update the info -- marks might need to be removed,
3494 ;; for instance.
3495 (gnus-summary-update-info)
eec82323
LMI
3496 (set-buffer gnus-group-buffer)
3497 (gnus-group-jump-to-group group)
3498 (gnus-group-next-unread-group 1))
3499 (gnus-handle-ephemeral-exit quit-config)))
23f87bed
MB
3500 (let ((grpinfo (gnus-get-info group)))
3501 (if (null (gnus-info-read grpinfo))
3502 (gnus-message 3 "Group %s contains no messages"
3503 (gnus-group-decoded-name group))
3504 (gnus-message 3 "Can't select group")))
eec82323
LMI
3505 nil)
3506 ;; The user did a `C-g' while prompting for number of articles,
3507 ;; so we exit this group.
3508 ((eq did-select 'quit)
3509 (and (eq major-mode 'gnus-summary-mode)
3510 (not (equal (current-buffer) kill-buffer))
3511 (kill-buffer (current-buffer)))
3512 (when kill-buffer
3513 (gnus-kill-or-deaden-summary kill-buffer))
3514 (if (not quit-config)
3515 (progn
3516 (set-buffer gnus-group-buffer)
3517 (gnus-group-jump-to-group group)
3518 (gnus-group-next-unread-group 1)
3519 (gnus-configure-windows 'group 'force))
3520 (gnus-handle-ephemeral-exit quit-config))
3521 ;; Finally signal the quit.
3522 (signal 'quit nil))
3523 ;; The group was successfully selected.
3524 (t
3525 (gnus-set-global-variables)
3526 ;; Save the active value in effect when the group was entered.
3527 (setq gnus-newsgroup-active
3528 (gnus-copy-sequence
3529 (gnus-active gnus-newsgroup-name)))
3530 ;; You can change the summary buffer in some way with this hook.
6748645f 3531 (gnus-run-hooks 'gnus-select-group-hook)
eec82323
LMI
3532 (gnus-update-format-specifications
3533 nil 'summary 'summary-mode 'summary-dummy)
16409b0b 3534 (gnus-update-summary-mark-positions)
eec82323
LMI
3535 ;; Do score processing.
3536 (when gnus-use-scoring
3537 (gnus-possibly-score-headers))
3538 ;; Check whether to fill in the gaps in the threads.
3539 (when gnus-build-sparse-threads
3540 (gnus-build-sparse-threads))
3541 ;; Find the initial limit.
3542 (if gnus-show-threads
3543 (if show-all
3544 (let ((gnus-newsgroup-dormant nil))
3545 (gnus-summary-initial-limit show-all))
3546 (gnus-summary-initial-limit show-all))
8f688cb0 3547 ;; When unthreaded, all articles are always shown.
eec82323
LMI
3548 (setq gnus-newsgroup-limit
3549 (mapcar
3550 (lambda (header) (mail-header-number header))
3551 gnus-newsgroup-headers)))
3552 ;; Generate the summary buffer.
3553 (unless no-display
3554 (gnus-summary-prepare))
3555 (when gnus-use-trees
3556 (gnus-tree-open group)
3557 (setq gnus-summary-highlight-line-function
3558 'gnus-tree-highlight-article))
3559 ;; If the summary buffer is empty, but there are some low-scored
3560 ;; articles or some excluded dormants, we include these in the
3561 ;; buffer.
3562 (when (and (zerop (buffer-size))
3563 (not no-display))
3564 (cond (gnus-newsgroup-dormant
3565 (gnus-summary-limit-include-dormant))
3566 ((and gnus-newsgroup-scored show-all)
3567 (gnus-summary-limit-include-expunged t))))
3568 ;; Function `gnus-apply-kill-file' must be called in this hook.
6748645f 3569 (gnus-run-hooks 'gnus-apply-kill-hook)
eec82323
LMI
3570 (if (and (zerop (buffer-size))
3571 (not no-display))
3572 (progn
3573 ;; This newsgroup is empty.
3574 (gnus-summary-catchup-and-exit nil t)
3575 (gnus-message 6 "No unread news")
3576 (when kill-buffer
3577 (gnus-kill-or-deaden-summary kill-buffer))
3578 ;; Return nil from this function.
3579 nil)
3580 ;; Hide conversation thread subtrees. We cannot do this in
3581 ;; gnus-summary-prepare-hook since kill processing may not
3582 ;; work with hidden articles.
23f87bed 3583 (gnus-summary-maybe-hide-threads)
6748645f
LMI
3584 (when kill-buffer
3585 (gnus-kill-or-deaden-summary kill-buffer))
23f87bed 3586 (gnus-summary-auto-select-subject)
eec82323
LMI
3587 ;; Show first unread article if requested.
3588 (if (and (not no-article)
3589 (not no-display)
3590 gnus-newsgroup-unreads
3591 gnus-auto-select-first)
16409b0b
GM
3592 (progn
3593 (gnus-configure-windows 'summary)
23f87bed
MB
3594 (let ((art (gnus-summary-article-number)))
3595 (unless (and (not gnus-plugged)
3596 (or (memq art gnus-newsgroup-undownloaded)
3597 (memq art gnus-newsgroup-downloadable)))
3598 (gnus-summary-goto-article art))))
3599 ;; Don't select any articles.
eec82323 3600 (gnus-summary-position-point)
6748645f
LMI
3601 (gnus-configure-windows 'summary 'force)
3602 (gnus-set-mode-line 'summary))
23f87bed
MB
3603 (when (and gnus-auto-center-group
3604 (get-buffer-window gnus-group-buffer t))
eec82323
LMI
3605 ;; Gotta use windows, because recenter does weird stuff if
3606 ;; the current buffer ain't the displayed window.
3607 (let ((owin (selected-window)))
3608 (select-window (get-buffer-window gnus-group-buffer t))
3609 (when (gnus-group-goto-group group)
3610 (recenter))
3611 (select-window owin)))
3612 ;; Mark this buffer as "prepared".
3613 (setq gnus-newsgroup-prepared t)
6748645f 3614 (gnus-run-hooks 'gnus-summary-prepared-hook)
23f87bed
MB
3615 (unless (gnus-ephemeral-group-p group)
3616 (gnus-group-update-group group))
eec82323
LMI
3617 t)))))
3618
23f87bed
MB
3619(defun gnus-summary-auto-select-subject ()
3620 "Select the subject line on initial group entry."
3621 (goto-char (point-min))
3622 (cond
3623 ((eq gnus-auto-select-subject 'best)
3624 (gnus-summary-best-unread-subject))
3625 ((eq gnus-auto-select-subject 'unread)
3626 (gnus-summary-first-unread-subject))
3627 ((eq gnus-auto-select-subject 'unseen)
3628 (gnus-summary-first-unseen-subject))
3629 ((eq gnus-auto-select-subject 'unseen-or-unread)
3630 (gnus-summary-first-unseen-or-unread-subject))
3631 ((eq gnus-auto-select-subject 'first)
3632 ;; Do nothing.
3633 )
3634 ((functionp gnus-auto-select-subject)
3635 (funcall gnus-auto-select-subject))))
3636
eec82323
LMI
3637(defun gnus-summary-prepare ()
3638 "Generate the summary buffer."
3639 (interactive)
3640 (let ((buffer-read-only nil))
3641 (erase-buffer)
3642 (setq gnus-newsgroup-data nil
3643 gnus-newsgroup-data-reverse nil)
6748645f 3644 (gnus-run-hooks 'gnus-summary-generate-hook)
eec82323
LMI
3645 ;; Generate the buffer, either with threads or without.
3646 (when gnus-newsgroup-headers
3647 (gnus-summary-prepare-threads
3648 (if gnus-show-threads
3649 (gnus-sort-gathered-threads
3650 (funcall gnus-summary-thread-gathering-function
3651 (gnus-sort-threads
3652 (gnus-cut-threads (gnus-make-threads)))))
3653 ;; Unthreaded display.
3654 (gnus-sort-articles gnus-newsgroup-headers))))
3655 (setq gnus-newsgroup-data (nreverse gnus-newsgroup-data))
3656 ;; Call hooks for modifying summary buffer.
3657 (goto-char (point-min))
6748645f 3658 (gnus-run-hooks 'gnus-summary-prepare-hook)))
eec82323
LMI
3659
3660(defsubst gnus-general-simplify-subject (subject)
23f87bed 3661 "Simplify subject by the same rules as `gnus-gather-threads-by-subject'."
eec82323
LMI
3662 (setq subject
3663 (cond
3664 ;; Truncate the subject.
6748645f
LMI
3665 (gnus-simplify-subject-functions
3666 (gnus-map-function gnus-simplify-subject-functions subject))
eec82323
LMI
3667 ((numberp gnus-summary-gather-subject-limit)
3668 (setq subject (gnus-simplify-subject-re subject))
3669 (if (> (length subject) gnus-summary-gather-subject-limit)
3670 (substring subject 0 gnus-summary-gather-subject-limit)
3671 subject))
3672 ;; Fuzzily simplify it.
3673 ((eq 'fuzzy gnus-summary-gather-subject-limit)
3674 (gnus-simplify-subject-fuzzy subject))
3675 ;; Just remove the leading "Re:".
3676 (t
3677 (gnus-simplify-subject-re subject))))
3678
3679 (if (and gnus-summary-gather-exclude-subject
3680 (string-match gnus-summary-gather-exclude-subject subject))
23f87bed 3681 nil ; This article shouldn't be gathered
eec82323
LMI
3682 subject))
3683
3684(defun gnus-summary-simplify-subject-query ()
3685 "Query where the respool algorithm would put this article."
3686 (interactive)
eec82323
LMI
3687 (gnus-summary-select-article)
3688 (message (gnus-general-simplify-subject (gnus-summary-article-subject))))
3689
3690(defun gnus-gather-threads-by-subject (threads)
3691 "Gather threads by looking at Subject headers."
3692 (if (not gnus-summary-make-false-root)
3693 threads
3694 (let ((hashtb (gnus-make-hashtable 1024))
3695 (prev threads)
3696 (result threads)
3697 subject hthread whole-subject)
3698 (while threads
3699 (setq subject (gnus-general-simplify-subject
3700 (setq whole-subject (mail-header-subject
3701 (caar threads)))))
3702 (when subject
3703 (if (setq hthread (gnus-gethash subject hashtb))
3704 (progn
3705 ;; We enter a dummy root into the thread, if we
3706 ;; haven't done that already.
3707 (unless (stringp (caar hthread))
3708 (setcar hthread (list whole-subject (car hthread))))
3709 ;; We add this new gathered thread to this gathered
3710 ;; thread.
3711 (setcdr (car hthread)
3712 (nconc (cdar hthread) (list (car threads))))
3713 ;; Remove it from the list of threads.
3714 (setcdr prev (cdr threads))
3715 (setq threads prev))
3716 ;; Enter this thread into the hash table.
23f87bed
MB
3717 (gnus-sethash subject
3718 (if gnus-summary-make-false-root-always
3719 (progn
3720 ;; If you want a dummy root above all
3721 ;; threads...
3722 (setcar threads (list whole-subject
3723 (car threads)))
3724 threads)
3725 threads)
3726 hashtb)))
eec82323
LMI
3727 (setq prev threads)
3728 (setq threads (cdr threads)))
3729 result)))
3730
3731(defun gnus-gather-threads-by-references (threads)
3732 "Gather threads by looking at References headers."
3733 (let ((idhashtb (gnus-make-hashtable 1024))
3734 (thhashtb (gnus-make-hashtable 1024))
3735 (prev threads)
3736 (result threads)
3737 ids references id gthread gid entered ref)
3738 (while threads
3739 (when (setq references (mail-header-references (caar threads)))
3740 (setq id (mail-header-id (caar threads))
23f87bed 3741 ids (inline (gnus-split-references references))
eec82323
LMI
3742 entered nil)
3743 (while (setq ref (pop ids))
3744 (setq ids (delete ref ids))
3745 (if (not (setq gid (gnus-gethash ref idhashtb)))
3746 (progn
3747 (gnus-sethash ref id idhashtb)
3748 (gnus-sethash id threads thhashtb))
3749 (setq gthread (gnus-gethash gid thhashtb))
3750 (unless entered
3751 ;; We enter a dummy root into the thread, if we
3752 ;; haven't done that already.
3753 (unless (stringp (caar gthread))
3754 (setcar gthread (list (mail-header-subject (caar gthread))
3755 (car gthread))))
3756 ;; We add this new gathered thread to this gathered
3757 ;; thread.
3758 (setcdr (car gthread)
3759 (nconc (cdar gthread) (list (car threads)))))
3760 ;; Add it into the thread hash table.
3761 (gnus-sethash id gthread thhashtb)
3762 (setq entered t)
3763 ;; Remove it from the list of threads.
3764 (setcdr prev (cdr threads))
3765 (setq threads prev))))
3766 (setq prev threads)
3767 (setq threads (cdr threads)))
3768 result))
3769
3770(defun gnus-sort-gathered-threads (threads)
16409b0b 3771 "Sort subtreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
eec82323
LMI
3772 (let ((result threads))
3773 (while threads
3774 (when (stringp (caar threads))
3775 (setcdr (car threads)
16409b0b 3776 (sort (cdar threads) gnus-sort-gathered-threads-function)))
eec82323
LMI
3777 (setq threads (cdr threads)))
3778 result))
3779
3780(defun gnus-thread-loop-p (root thread)
3781 "Say whether ROOT is in THREAD."
3782 (let ((stack (list thread))
3783 (infloop 0)
3784 th)
3785 (while (setq thread (pop stack))
3786 (setq th (cdr thread))
3787 (while (and th
3788 (not (eq (caar th) root)))
3789 (pop th))
3790 (if th
3791 ;; We have found a loop.
3792 (let (ref-dep)
3793 (setcdr thread (delq (car th) (cdr thread)))
3794 (if (boundp (setq ref-dep (intern "none"
3795 gnus-newsgroup-dependencies)))
3796 (setcdr (symbol-value ref-dep)
3797 (nconc (cdr (symbol-value ref-dep))
3798 (list (car th))))
3799 (set ref-dep (list nil (car th))))
3800 (setq infloop 1
3801 stack nil))
3802 ;; Push all the subthreads onto the stack.
3803 (push (cdr thread) stack)))
3804 infloop))
3805
3806(defun gnus-make-threads ()
3807 "Go through the dependency hashtb and find the roots. Return all threads."
3808 (let (threads)
3809 (while (catch 'infloop
3810 (mapatoms
3811 (lambda (refs)
3812 ;; Deal with self-referencing References loops.
3813 (when (and (car (symbol-value refs))
3814 (not (zerop
3815 (apply
3816 '+
3817 (mapcar
3818 (lambda (thread)
3819 (gnus-thread-loop-p
3820 (car (symbol-value refs)) thread))
3821 (cdr (symbol-value refs)))))))
3822 (setq threads nil)
3823 (throw 'infloop t))
3824 (unless (car (symbol-value refs))
23f87bed
MB
3825 ;; These threads do not refer back to any other
3826 ;; articles, so they're roots.
eec82323
LMI
3827 (setq threads (append (cdr (symbol-value refs)) threads))))
3828 gnus-newsgroup-dependencies)))
3829 threads))
3830
6748645f 3831;; Build the thread tree.
16409b0b 3832(defsubst gnus-dependencies-add-header (header dependencies force-new)
6748645f
LMI
3833 "Enter HEADER into the DEPENDENCIES table if it is not already there.
3834
3835If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
3836if it was already present.
3837
3838If `gnus-summary-ignore-duplicates' is nil then duplicate Message-IDs
3839will not be entered in the DEPENDENCIES table. Otherwise duplicate
23f87bed
MB
3840Message-IDs will be renamed to a unique Message-ID before being
3841entered.
6748645f
LMI
3842
3843Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise."
3844 (let* ((id (mail-header-id header))
3845 (id-dep (and id (intern id dependencies)))
23f87bed 3846 parent-id ref ref-dep ref-header replaced)
6748645f
LMI
3847 ;; Enter this `header' in the `dependencies' table.
3848 (cond
3849 ((not id-dep)
3850 (setq header nil))
3851 ;; The first two cases do the normal part: enter a new `header'
3852 ;; in the `dependencies' table.
3853 ((not (boundp id-dep))
3854 (set id-dep (list header)))
3855 ((null (car (symbol-value id-dep)))
3856 (setcar (symbol-value id-dep) header))
3857
3858 ;; From here the `header' was already present in the
3859 ;; `dependencies' table.
3860 (force-new
3861 ;; Overrides an existing entry;
3862 ;; just set the header part of the entry.
23f87bed
MB
3863 (setcar (symbol-value id-dep) header)
3864 (setq replaced t))
6748645f
LMI
3865
3866 ;; Renames the existing `header' to a unique Message-ID.
3867 ((not gnus-summary-ignore-duplicates)
3868 ;; An article with this Message-ID has already been seen.
3869 ;; We rename the Message-ID.
3870 (set (setq id-dep (intern (setq id (nnmail-message-id)) dependencies))
3871 (list header))
3872 (mail-header-set-id header id))
3873
3874 ;; The last case ignores an existing entry, except it adds any
3875 ;; additional Xrefs (in case the two articles came from different
3876 ;; servers.
3877 ;; Also sets `header' to `nil' meaning that the `dependencies'
3878 ;; table was *not* modified.
3879 (t
3880 (mail-header-set-xref
3881 (car (symbol-value id-dep))
3882 (concat (or (mail-header-xref (car (symbol-value id-dep)))
3883 "")
3884 (or (mail-header-xref header) "")))
3885 (setq header nil)))
3886
23f87bed
MB
3887 (when (and header (not replaced))
3888 ;; First check that we are not creating a References loop.
3889 (setq parent-id (gnus-parent-id (mail-header-references header)))
3890 (setq ref parent-id)
6748645f
LMI
3891 (while (and ref
3892 (setq ref-dep (intern-soft ref dependencies))
3893 (boundp ref-dep)
3894 (setq ref-header (car (symbol-value ref-dep))))
3895 (if (string= id ref)
3896 ;; Yuk! This is a reference loop. Make the article be a
3897 ;; root article.
3898 (progn
3899 (mail-header-set-references (car (symbol-value id-dep)) "none")
23f87bed
MB
3900 (setq ref nil)
3901 (setq parent-id nil))
6748645f 3902 (setq ref (gnus-parent-id (mail-header-references ref-header)))))
23f87bed 3903 (setq ref-dep (intern (or parent-id "none") dependencies))
6748645f
LMI
3904 (if (boundp ref-dep)
3905 (setcdr (symbol-value ref-dep)
3906 (nconc (cdr (symbol-value ref-dep))
3907 (list (symbol-value id-dep))))
3908 (set ref-dep (list nil (symbol-value id-dep)))))
3909 header))
3910
23f87bed
MB
3911(defun gnus-extract-message-id-from-in-reply-to (string)
3912 (if (string-match "<[^>]+>" string)
3913 (substring string (match-beginning 0) (match-end 0))
3914 nil))
3915
eec82323
LMI
3916(defun gnus-build-sparse-threads ()
3917 (let ((headers gnus-newsgroup-headers)
16409b0b 3918 (mail-parse-charset gnus-newsgroup-charset)
6748645f 3919 (gnus-summary-ignore-duplicates t)
eec82323 3920 header references generation relations
6748645f 3921 subject child end new-child date)
eec82323
LMI
3922 ;; First we create an alist of generations/relations, where
3923 ;; generations is how much we trust the relation, and the relation
3924 ;; is parent/child.
3925 (gnus-message 7 "Making sparse threads...")
3926 (save-excursion
3927 (nnheader-set-temp-buffer " *gnus sparse threads*")
3928 (while (setq header (pop headers))
3929 (when (and (setq references (mail-header-references header))
3930 (not (string= references "")))
3931 (insert references)
3932 (setq child (mail-header-id header)
6748645f
LMI
3933 subject (mail-header-subject header)
3934 date (mail-header-date header)
3935 generation 0)
eec82323
LMI
3936 (while (search-backward ">" nil t)
3937 (setq end (1+ (point)))
3938 (when (search-backward "<" nil t)
6748645f 3939 (setq new-child (buffer-substring (point) end))
eec82323 3940 (push (list (incf generation)
6748645f
LMI
3941 child (setq child new-child)
3942 subject date)
eec82323 3943 relations)))
6748645f
LMI
3944 (when child
3945 (push (list (1+ generation) child nil subject) relations))
eec82323
LMI
3946 (erase-buffer)))
3947 (kill-buffer (current-buffer)))
3948 ;; Sort over trustworthiness.
6748645f
LMI
3949 (mapcar
3950 (lambda (relation)
3951 (when (gnus-dependencies-add-header
3952 (make-full-mail-header
3953 gnus-reffed-article-number
3954 (nth 3 relation) "" (or (nth 4 relation) "")
3955 (nth 1 relation)
3956 (or (nth 2 relation) "") 0 0 "")
3957 gnus-newsgroup-dependencies nil)
3958 (push gnus-reffed-article-number gnus-newsgroup-limit)
3959 (push gnus-reffed-article-number gnus-newsgroup-sparse)
3960 (push (cons gnus-reffed-article-number gnus-sparse-mark)
3961 gnus-newsgroup-reads)
3962 (decf gnus-reffed-article-number)))
3963 (sort relations 'car-less-than-car))
eec82323
LMI
3964 (gnus-message 7 "Making sparse threads...done")))
3965
3966(defun gnus-build-old-threads ()
3967 ;; Look at all the articles that refer back to old articles, and
3968 ;; fetch the headers for the articles that aren't there. This will
3969 ;; build complete threads - if the roots haven't been expired by the
3970 ;; server, that is.
16409b0b
GM
3971 (let ((mail-parse-charset gnus-newsgroup-charset)
3972 id heads)
eec82323
LMI
3973 (mapatoms
3974 (lambda (refs)
3975 (when (not (car (symbol-value refs)))
3976 (setq heads (cdr (symbol-value refs)))
3977 (while heads
3978 (if (memq (mail-header-number (caar heads))
3979 gnus-newsgroup-dormant)
3980 (setq heads (cdr heads))
3981 (setq id (symbol-name refs))
3982 (while (and (setq id (gnus-build-get-header id))
6748645f 3983 (not (car (gnus-id-to-thread id)))))
eec82323
LMI
3984 (setq heads nil)))))
3985 gnus-newsgroup-dependencies)))
3986
23f87bed
MB
3987(defsubst gnus-remove-odd-characters (string)
3988 "Translate STRING into something that doesn't contain weird characters."
3989 (mm-subst-char-in-string
3990 ?\r ?\-
3991 (mm-subst-char-in-string
3992 ?\n ?\- string)))
3993
6748645f
LMI
3994;; This function has to be called with point after the article number
3995;; on the beginning of the line.
3996(defsubst gnus-nov-parse-line (number dependencies &optional force-new)
3997 (let ((eol (gnus-point-at-eol))
3998 (buffer (current-buffer))
23f87bed 3999 header references in-reply-to)
6748645f
LMI
4000
4001 ;; overview: [num subject from date id refs chars lines misc]
4002 (unwind-protect
23f87bed 4003 (let (x)
6748645f
LMI
4004 (narrow-to-region (point) eol)
4005 (unless (eobp)
4006 (forward-char))
4007
4008 (setq header
4009 (make-full-mail-header
4010 number ; number
23f87bed
MB
4011 (condition-case () ; subject
4012 (gnus-remove-odd-characters
4013 (funcall gnus-decode-encoded-word-function
4014 (setq x (nnheader-nov-field))))
4015 (error x))
4016 (condition-case () ; from
4017 (gnus-remove-odd-characters
4018 (funcall gnus-decode-encoded-word-function
4019 (setq x (nnheader-nov-field))))
4020 (error x))
16409b0b
GM
4021 (nnheader-nov-field) ; date
4022 (nnheader-nov-read-message-id) ; id
23f87bed 4023 (setq references (nnheader-nov-field)) ; refs
16409b0b
GM
4024 (nnheader-nov-read-integer) ; chars
4025 (nnheader-nov-read-integer) ; lines
4026 (unless (eobp)
8b93df01
DL
4027 (if (looking-at "Xref: ")
4028 (goto-char (match-end 0)))
4029 (nnheader-nov-field)) ; Xref
16409b0b 4030 (nnheader-nov-parse-extra)))) ; extra
6748645f
LMI
4031
4032 (widen))
4033
23f87bed
MB
4034 (when (and (string= references "")
4035 (setq in-reply-to (mail-header-extra header))
4036 (setq in-reply-to (cdr (assq 'In-Reply-To in-reply-to))))
4037 (mail-header-set-references
4038 header (gnus-extract-message-id-from-in-reply-to in-reply-to)))
4039
6748645f
LMI
4040 (when gnus-alter-header-function
4041 (funcall gnus-alter-header-function header))
4042 (gnus-dependencies-add-header header dependencies force-new)))
4043
eec82323 4044(defun gnus-build-get-header (id)
16409b0b
GM
4045 "Look through the buffer of NOV lines and find the header to ID.
4046Enter this line into the dependencies hash table, and return
4047the id of the parent article (if any)."
eec82323
LMI
4048 (let ((deps gnus-newsgroup-dependencies)
4049 found header)
4050 (prog1
4051 (save-excursion
4052 (set-buffer nntp-server-buffer)
4053 (let ((case-fold-search nil))
4054 (goto-char (point-min))
4055 (while (and (not found)
4056 (search-forward id nil t))
4057 (beginning-of-line)
4058 (setq found (looking-at
4059 (format "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t%s"
4060 (regexp-quote id))))
4061 (or found (beginning-of-line 2)))
4062 (when found
4063 (beginning-of-line)
4064 (and
4065 (setq header (gnus-nov-parse-line
4066 (read (current-buffer)) deps))
4067 (gnus-parent-id (mail-header-references header))))))
4068 (when header
4069 (let ((number (mail-header-number header)))
4070 (push number gnus-newsgroup-limit)
4071 (push header gnus-newsgroup-headers)
4072 (if (memq number gnus-newsgroup-unselected)
4073 (progn
23f87bed
MB
4074 (setq gnus-newsgroup-unreads
4075 (gnus-add-to-sorted-list gnus-newsgroup-unreads
4076 number))
eec82323
LMI
4077 (setq gnus-newsgroup-unselected
4078 (delq number gnus-newsgroup-unselected)))
4079 (push number gnus-newsgroup-ancient)))))))
4080
6748645f
LMI
4081(defun gnus-build-all-threads ()
4082 "Read all the headers."
4083 (let ((gnus-summary-ignore-duplicates t)
16409b0b 4084 (mail-parse-charset gnus-newsgroup-charset)
6748645f
LMI
4085 (dependencies gnus-newsgroup-dependencies)
4086 header article)
4087 (save-excursion
4088 (set-buffer nntp-server-buffer)
4089 (let ((case-fold-search nil))
4090 (goto-char (point-min))
4091 (while (not (eobp))
4092 (ignore-errors
4093 (setq article (read (current-buffer))
16409b0b 4094 header (gnus-nov-parse-line article dependencies)))
6748645f
LMI
4095 (when header
4096 (save-excursion
4097 (set-buffer gnus-summary-buffer)
4098 (push header gnus-newsgroup-headers)
4099 (if (memq (setq article (mail-header-number header))
4100 gnus-newsgroup-unselected)
4101 (progn
23f87bed
MB
4102 (setq gnus-newsgroup-unreads
4103 (gnus-add-to-sorted-list
4104 gnus-newsgroup-unreads article))
6748645f
LMI
4105 (setq gnus-newsgroup-unselected
4106 (delq article gnus-newsgroup-unselected)))
4107 (push article gnus-newsgroup-ancient)))
4108 (forward-line 1)))))))
4109
eec82323 4110(defun gnus-summary-update-article-line (article header)
23f87bed 4111 "Update the line for ARTICLE using HEADER."
eec82323
LMI
4112 (let* ((id (mail-header-id header))
4113 (thread (gnus-id-to-thread id)))
4114 (unless thread
4115 (error "Article in no thread"))
4116 ;; Update the thread.
4117 (setcar thread header)
4118 (gnus-summary-goto-subject article)
4119 (let* ((datal (gnus-data-find-list article))
4120 (data (car datal))
eec82323
LMI
4121 (buffer-read-only nil)
4122 (level (gnus-summary-thread-level)))
4123 (gnus-delete-line)
23f87bed
MB
4124 (let ((inserted (- (point)
4125 (progn
4126 (gnus-summary-insert-line
4127 header level nil
4128 (memq article gnus-newsgroup-undownloaded)
4129 (gnus-article-mark article)
4130 (memq article gnus-newsgroup-replied)
4131 (memq article gnus-newsgroup-expirable)
4132 ;; Only insert the Subject string when it's different
4133 ;; from the previous Subject string.
4134 (if (and
4135 gnus-show-threads
4136 (gnus-subject-equal
4137 (condition-case ()
4138 (mail-header-subject
4139 (gnus-data-header
4140 (cadr
4141 (gnus-data-find-list
4142 article
4143 (gnus-data-list t)))))
4144 ;; Error on the side of excessive subjects.
4145 (error ""))
4146 (mail-header-subject header)))
4147 ""
4148 (mail-header-subject header))
4149 nil (cdr (assq article gnus-newsgroup-scored))
4150 (memq article gnus-newsgroup-processable))
4151 (point)))))
4152 (when (cdr datal)
4153 (gnus-data-update-list
4154 (cdr datal)
4155 (- (gnus-data-pos data) (gnus-data-pos (cadr datal)) inserted)))))))
eec82323
LMI
4156
4157(defun gnus-summary-update-article (article &optional iheader)
4158 "Update ARTICLE in the summary buffer."
4159 (set-buffer gnus-summary-buffer)
6748645f 4160 (let* ((header (gnus-summary-article-header article))
eec82323
LMI
4161 (id (mail-header-id header))
4162 (data (gnus-data-find article))
4163 (thread (gnus-id-to-thread id))
4164 (references (mail-header-references header))
4165 (parent
4166 (gnus-id-to-thread
4167 (or (gnus-parent-id
4168 (when (and references
4169 (not (equal "" references)))
4170 references))
4171 "none")))
4172 (buffer-read-only nil)
6748645f 4173 (old (car thread)))
eec82323 4174 (when thread
eec82323 4175 (unless iheader
6748645f
LMI
4176 (setcar thread nil)
4177 (when parent
4178 (delq thread parent)))
4179 (if (gnus-summary-insert-subject id header)
eec82323
LMI
4180 ;; Set the (possibly) new article number in the data structure.
4181 (gnus-data-set-number data (gnus-id-to-article id))
4182 (setcar thread old)
4183 nil))))
4184
6748645f
LMI
4185(defun gnus-rebuild-thread (id &optional line)
4186 "Rebuild the thread containing ID.
4187If LINE, insert the rebuilt thread starting on line LINE."
eec82323
LMI
4188 (let ((buffer-read-only nil)
4189 old-pos current thread data)
4190 (if (not gnus-show-threads)
4191 (setq thread (list (car (gnus-id-to-thread id))))
4192 ;; Get the thread this article is part of.
4193 (setq thread (gnus-remove-thread id)))
4194 (setq old-pos (gnus-point-at-bol))
4195 (setq current (save-excursion
94384150 4196 (and (re-search-backward "[\r\n]" nil t)
eec82323
LMI
4197 (gnus-summary-article-number))))
4198 ;; If this is a gathered thread, we have to go some re-gathering.
4199 (when (stringp (car thread))
4200 (let ((subject (car thread))
4201 roots thr)
4202 (setq thread (cdr thread))
4203 (while thread
4204 (unless (memq (setq thr (gnus-id-to-thread
4205 (gnus-root-id
4206 (mail-header-id (caar thread)))))
4207 roots)
4208 (push thr roots))
4209 (setq thread (cdr thread)))
4210 ;; We now have all (unique) roots.
4211 (if (= (length roots) 1)
4212 ;; All the loose roots are now one solid root.
4213 (setq thread (car roots))
4214 (setq thread (cons subject (gnus-sort-threads roots))))))
4215 (let (threads)
4216 ;; We then insert this thread into the summary buffer.
6748645f
LMI
4217 (when line
4218 (goto-char (point-min))
4219 (forward-line (1- line)))
eec82323
LMI
4220 (let (gnus-newsgroup-data gnus-newsgroup-threads)
4221 (if gnus-show-threads
4222 (gnus-summary-prepare-threads (gnus-cut-threads (list thread)))
4223 (gnus-summary-prepare-unthreaded thread))
4224 (setq data (nreverse gnus-newsgroup-data))
4225 (setq threads gnus-newsgroup-threads))
4226 ;; We splice the new data into the data structure.
6748645f
LMI
4227 ;;!!! This is kinda bogus. We assume that in LINE is non-nil,
4228 ;;!!! then we want to insert at the beginning of the buffer.
4229 ;;!!! That happens to be true with Gnus now, but that may
4230 ;;!!! change in the future. Perhaps.
4231 (gnus-data-enter-list
4232 (if line nil current) data (- (point) old-pos))
4233 (setq gnus-newsgroup-threads
4234 (nconc threads gnus-newsgroup-threads))
4235 (gnus-data-compute-positions))))
eec82323
LMI
4236
4237(defun gnus-number-to-header (number)
4238 "Return the header for article NUMBER."
4239 (let ((headers gnus-newsgroup-headers))
4240 (while (and headers
4241 (not (= number (mail-header-number (car headers)))))
4242 (pop headers))
4243 (when headers
4244 (car headers))))
4245
6748645f 4246(defun gnus-parent-headers (in-headers &optional generation)
eec82323
LMI
4247 "Return the headers of the GENERATIONeth parent of HEADERS."
4248 (unless generation
4249 (setq generation 1))
a8151ef7 4250 (let ((parent t)
6748645f 4251 (headers in-headers)
a8151ef7 4252 references)
6748645f
LMI
4253 (while (and parent
4254 (not (zerop generation))
4255 (setq references (mail-header-references headers)))
4256 (setq headers (if (and references
4257 (setq parent (gnus-parent-id references)))
4258 (car (gnus-id-to-thread parent))
4259 nil))
4260 (decf generation))
4261 (and (not (eq headers in-headers))
4262 headers)))
eec82323
LMI
4263
4264(defun gnus-id-to-thread (id)
4265 "Return the (sub-)thread where ID appears."
4266 (gnus-gethash id gnus-newsgroup-dependencies))
4267
4268(defun gnus-id-to-article (id)
4269 "Return the article number of ID."
4270 (let ((thread (gnus-id-to-thread id)))
4271 (when (and thread
4272 (car thread))
4273 (mail-header-number (car thread)))))
4274
4275(defun gnus-id-to-header (id)
4276 "Return the article headers of ID."
4277 (car (gnus-id-to-thread id)))
4278
4279(defun gnus-article-displayed-root-p (article)
4280 "Say whether ARTICLE is a root(ish) article."
4281 (let ((level (gnus-summary-thread-level article))
4282 (refs (mail-header-references (gnus-summary-article-header article)))
4283 particle)
4284 (cond
4285 ((null level) nil)
4286 ((zerop level) t)
4287 ((null refs) t)
4288 ((null (gnus-parent-id refs)) t)
4289 ((and (= 1 level)
4290 (null (setq particle (gnus-id-to-article
4291 (gnus-parent-id refs))))
4292 (null (gnus-summary-thread-level particle)))))))
4293
4294(defun gnus-root-id (id)
4295 "Return the id of the root of the thread where ID appears."
4296 (let (last-id prev)
6748645f 4297 (while (and id (setq prev (car (gnus-id-to-thread id))))
eec82323
LMI
4298 (setq last-id id
4299 id (gnus-parent-id (mail-header-references prev))))
4300 last-id))
4301
6748645f
LMI
4302(defun gnus-articles-in-thread (thread)
4303 "Return the list of articles in THREAD."
4304 (cons (mail-header-number (car thread))
4305 (apply 'nconc (mapcar 'gnus-articles-in-thread (cdr thread)))))
4306
eec82323
LMI
4307(defun gnus-remove-thread (id &optional dont-remove)
4308 "Remove the thread that has ID in it."
6748645f 4309 (let (headers thread last-id)
eec82323 4310 ;; First go up in this thread until we find the root.
6748645f
LMI
4311 (setq last-id (gnus-root-id id)
4312 headers (message-flatten-list (gnus-id-to-thread last-id)))
eec82323
LMI
4313 ;; We have now found the real root of this thread. It might have
4314 ;; been gathered into some loose thread, so we have to search
4315 ;; through the threads to find the thread we wanted.
4316 (let ((threads gnus-newsgroup-threads)
4317 sub)
4318 (while threads
4319 (setq sub (car threads))
4320 (if (stringp (car sub))
4321 ;; This is a gathered thread, so we look at the roots
4322 ;; below it to find whether this article is in this
4323 ;; gathered root.
4324 (progn
4325 (setq sub (cdr sub))
4326 (while sub
4327 (when (member (caar sub) headers)
4328 (setq thread (car threads)
4329 threads nil
4330 sub nil))
4331 (setq sub (cdr sub))))
4332 ;; It's an ordinary thread, so we check it.
4333 (when (eq (car sub) (car headers))
4334 (setq thread sub
4335 threads nil)))
4336 (setq threads (cdr threads)))
4337 ;; If this article is in no thread, then it's a root.
4338 (if thread
4339 (unless dont-remove
4340 (setq gnus-newsgroup-threads (delq thread gnus-newsgroup-threads)))
6748645f 4341 (setq thread (gnus-id-to-thread last-id)))
eec82323
LMI
4342 (when thread
4343 (prog1
4344 thread ; We return this thread.
4345 (unless dont-remove
4346 (if (stringp (car thread))
4347 (progn
4348 ;; If we use dummy roots, then we have to remove the
4349 ;; dummy root as well.
4350 (when (eq gnus-summary-make-false-root 'dummy)
6748645f
LMI
4351 ;; We go to the dummy root by going to
4352 ;; the first sub-"thread", and then one line up.
4353 (gnus-summary-goto-article
4354 (mail-header-number (caadr thread)))
4355 (forward-line -1)
eec82323
LMI
4356 (gnus-delete-line)
4357 (gnus-data-compute-positions))
4358 (setq thread (cdr thread))
4359 (while thread
4360 (gnus-remove-thread-1 (car thread))
4361 (setq thread (cdr thread))))
4362 (gnus-remove-thread-1 thread))))))))
4363
4364(defun gnus-remove-thread-1 (thread)
4365 "Remove the thread THREAD recursively."
4366 (let ((number (mail-header-number (pop thread)))
4367 d)
4368 (setq thread (reverse thread))
4369 (while thread
4370 (gnus-remove-thread-1 (pop thread)))
4371 (when (setq d (gnus-data-find number))
4372 (goto-char (gnus-data-pos d))
16409b0b 4373 (gnus-summary-show-thread)
eec82323
LMI
4374 (gnus-data-remove
4375 number
4376 (- (gnus-point-at-bol)
4377 (prog1
4378 (1+ (gnus-point-at-eol))
4379 (gnus-delete-line)))))))
4380
16409b0b
GM
4381(defun gnus-sort-threads-1 (threads func)
4382 (sort (mapcar (lambda (thread)
4383 (cons (car thread)
4384 (and (cdr thread)
4385 (gnus-sort-threads-1 (cdr thread) func))))
4386 threads) func))
4387
eec82323
LMI
4388(defun gnus-sort-threads (threads)
4389 "Sort THREADS."
4390 (if (not gnus-thread-sort-functions)
4391 threads
6748645f 4392 (gnus-message 8 "Sorting threads...")
23f87bed
MB
4393 (let ((max-lisp-eval-depth 5000))
4394 (prog1 (gnus-sort-threads-1
a1506d29 4395 threads
16409b0b 4396 (gnus-make-sort-function gnus-thread-sort-functions))
23f87bed 4397 (gnus-message 8 "Sorting threads...done")))))
eec82323
LMI
4398
4399(defun gnus-sort-articles (articles)
4400 "Sort ARTICLES."
4401 (when gnus-article-sort-functions
4402 (gnus-message 7 "Sorting articles...")
4403 (prog1
4404 (setq gnus-newsgroup-headers
4405 (sort articles (gnus-make-sort-function
4406 gnus-article-sort-functions)))
4407 (gnus-message 7 "Sorting articles...done"))))
4408
4409;; Written by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
4410(defmacro gnus-thread-header (thread)
16409b0b
GM
4411 "Return header of first article in THREAD.
4412Note that THREAD must never, ever be anything else than a variable -
4413using some other form will lead to serious barfage."
eec82323
LMI
4414 (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread)))
4415 ;; (8% speedup to gnus-summary-prepare, just for fun :-)
16409b0b 4416 (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207"
eec82323
LMI
4417 (vector thread) 2))
4418
4419(defsubst gnus-article-sort-by-number (h1 h2)
4420 "Sort articles by article number."
4421 (< (mail-header-number h1)
4422 (mail-header-number h2)))
4423
4424(defun gnus-thread-sort-by-number (h1 h2)
4425 "Sort threads by root article number."
4426 (gnus-article-sort-by-number
4427 (gnus-thread-header h1) (gnus-thread-header h2)))
4428
23f87bed
MB
4429(defsubst gnus-article-sort-by-random (h1 h2)
4430 "Sort articles by article number."
4431 (zerop (random 2)))
4432
4433(defun gnus-thread-sort-by-random (h1 h2)
4434 "Sort threads by root article number."
4435 (gnus-article-sort-by-random
4436 (gnus-thread-header h1) (gnus-thread-header h2)))
4437
eec82323
LMI
4438(defsubst gnus-article-sort-by-lines (h1 h2)
4439 "Sort articles by article Lines header."
4440 (< (mail-header-lines h1)
4441 (mail-header-lines h2)))
4442
4443(defun gnus-thread-sort-by-lines (h1 h2)
4444 "Sort threads by root article Lines header."
4445 (gnus-article-sort-by-lines
4446 (gnus-thread-header h1) (gnus-thread-header h2)))
4447
16409b0b
GM
4448(defsubst gnus-article-sort-by-chars (h1 h2)
4449 "Sort articles by octet length."
4450 (< (mail-header-chars h1)
4451 (mail-header-chars h2)))
4452
4453(defun gnus-thread-sort-by-chars (h1 h2)
4454 "Sort threads by root article octet length."
4455 (gnus-article-sort-by-chars
4456 (gnus-thread-header h1) (gnus-thread-header h2)))
4457
eec82323
LMI
4458(defsubst gnus-article-sort-by-author (h1 h2)
4459 "Sort articles by root author."
4460 (string-lessp
4461 (let ((extract (funcall
4462 gnus-extract-address-components
4463 (mail-header-from h1))))
4464 (or (car extract) (cadr extract) ""))
4465 (let ((extract (funcall
4466 gnus-extract-address-components
4467 (mail-header-from h2))))
4468 (or (car extract) (cadr extract) ""))))
4469
4470(defun gnus-thread-sort-by-author (h1 h2)
4471 "Sort threads by root author."
4472 (gnus-article-sort-by-author
4473 (gnus-thread-header h1) (gnus-thread-header h2)))
4474
4475(defsubst gnus-article-sort-by-subject (h1 h2)
4476 "Sort articles by root subject."
4477 (string-lessp
4478 (downcase (gnus-simplify-subject-re (mail-header-subject h1)))
4479 (downcase (gnus-simplify-subject-re (mail-header-subject h2)))))
4480
4481(defun gnus-thread-sort-by-subject (h1 h2)
4482 "Sort threads by root subject."
4483 (gnus-article-sort-by-subject
4484 (gnus-thread-header h1) (gnus-thread-header h2)))
4485
4486(defsubst gnus-article-sort-by-date (h1 h2)
4487 "Sort articles by root article date."
16409b0b 4488 (time-less-p
eec82323
LMI
4489 (gnus-date-get-time (mail-header-date h1))
4490 (gnus-date-get-time (mail-header-date h2))))
4491
4492(defun gnus-thread-sort-by-date (h1 h2)
4493 "Sort threads by root article date."
4494 (gnus-article-sort-by-date
4495 (gnus-thread-header h1) (gnus-thread-header h2)))
4496
4497(defsubst gnus-article-sort-by-score (h1 h2)
4498 "Sort articles by root article score.
4499Unscored articles will be counted as having a score of zero."
4500 (> (or (cdr (assq (mail-header-number h1)
4501 gnus-newsgroup-scored))
4502 gnus-summary-default-score 0)
4503 (or (cdr (assq (mail-header-number h2)
4504 gnus-newsgroup-scored))
4505 gnus-summary-default-score 0)))
4506
4507(defun gnus-thread-sort-by-score (h1 h2)
4508 "Sort threads by root article score."
4509 (gnus-article-sort-by-score
4510 (gnus-thread-header h1) (gnus-thread-header h2)))
4511
4512(defun gnus-thread-sort-by-total-score (h1 h2)
4513 "Sort threads by the sum of all scores in the thread.
4514Unscored articles will be counted as having a score of zero."
4515 (> (gnus-thread-total-score h1) (gnus-thread-total-score h2)))
4516
4517(defun gnus-thread-total-score (thread)
16409b0b 4518 ;; This function find the total score of THREAD.
23f87bed
MB
4519 (cond
4520 ((null thread)
4521 0)
4522 ((consp thread)
4523 (if (stringp (car thread))
4524 (apply gnus-thread-score-function 0
4525 (mapcar 'gnus-thread-total-score-1 (cdr thread)))
4526 (gnus-thread-total-score-1 thread)))
4527 (t
4528 (gnus-thread-total-score-1 (list thread)))))
4529
4530(defun gnus-thread-sort-by-most-recent-number (h1 h2)
4531 "Sort threads such that the thread with the most recently arrived article comes first."
4532 (> (gnus-thread-highest-number h1) (gnus-thread-highest-number h2)))
4533
4534(defun gnus-thread-highest-number (thread)
4535 "Return the highest article number in THREAD."
4536 (apply 'max (mapcar (lambda (header)
4537 (mail-header-number header))
4538 (message-flatten-list thread))))
4539
4540(defun gnus-thread-sort-by-most-recent-date (h1 h2)
4541 "Sort threads such that the thread with the most recently dated article comes first."
4542 (> (gnus-thread-latest-date h1) (gnus-thread-latest-date h2)))
4543
4544(defun gnus-thread-latest-date (thread)
4545 "Return the highest article date in THREAD."
4546 (let ((previous-time 0))
4547 (apply 'max
4548 (mapcar
4549 (lambda (header)
4550 (setq previous-time
4551 (condition-case ()
4552 (time-to-seconds (mail-header-parse-date
4553 (mail-header-date header)))
4554 (error previous-time))))
4555 (sort
4556 (message-flatten-list thread)
4557 (lambda (h1 h2)
4558 (< (mail-header-number h1)
4559 (mail-header-number h2))))))))
eec82323
LMI
4560
4561(defun gnus-thread-total-score-1 (root)
4562 ;; This function find the total score of the thread below ROOT.
4563 (setq root (car root))
4564 (apply gnus-thread-score-function
4565 (or (append
4566 (mapcar 'gnus-thread-total-score
6748645f 4567 (cdr (gnus-id-to-thread (mail-header-id root))))
eec82323
LMI
4568 (when (> (mail-header-number root) 0)
4569 (list (or (cdr (assq (mail-header-number root)
4570 gnus-newsgroup-scored))
4571 gnus-summary-default-score 0))))
4572 (list gnus-summary-default-score)
4573 '(0))))
4574
4575;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
4576(defvar gnus-tmp-prev-subject nil)
4577(defvar gnus-tmp-false-parent nil)
4578(defvar gnus-tmp-root-expunged nil)
4579(defvar gnus-tmp-dummy-line nil)
4580
60bd5589 4581(eval-when-compile (defvar gnus-tmp-header))
16409b0b
GM
4582(defun gnus-extra-header (type &optional header)
4583 "Return the extra header of TYPE."
4584 (or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
4585 ""))
4586
23f87bed
MB
4587(defvar gnus-tmp-thread-tree-header-string "")
4588
4589(defcustom gnus-sum-thread-tree-root "> "
4590 "With %B spec, used for the root of a thread.
4591If nil, use subject instead."
4592 :type '(radio (const :format "%v " nil) (string :size 0))
4593 :group 'gnus-thread)
4594(defcustom gnus-sum-thread-tree-false-root "> "
4595 "With %B spec, used for a false root of a thread.
4596If nil, use subject instead."
4597 :type '(radio (const :format "%v " nil) (string :size 0))
4598 :group 'gnus-thread)
4599(defcustom gnus-sum-thread-tree-single-indent ""
4600 "With %B spec, used for a thread with just one message.
4601If nil, use subject instead."
4602 :type '(radio (const :format "%v " nil) (string :size 0))
4603 :group 'gnus-thread)
4604(defcustom gnus-sum-thread-tree-vertical "| "
4605 "With %B spec, used for drawing a vertical line."
4606 :type 'string
4607 :group 'gnus-thread)
4608(defcustom gnus-sum-thread-tree-indent " "
4609 "With %B spec, used for indenting."
4610 :type 'string
4611 :group 'gnus-thread)
4612(defcustom gnus-sum-thread-tree-leaf-with-other "+-> "
4613 "With %B spec, used for a leaf with brothers."
4614 :type 'string
4615 :group 'gnus-thread)
4616(defcustom gnus-sum-thread-tree-single-leaf "\\-> "
4617 "With %B spec, used for a leaf without brothers."
4618 :type 'string
4619 :group 'gnus-thread)
4620
eec82323
LMI
4621(defun gnus-summary-prepare-threads (threads)
4622 "Prepare summary buffer from THREADS and indentation LEVEL.
4623THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
4624or a straight list of headers."
4625 (gnus-message 7 "Generating summary...")
4626
4627 (setq gnus-newsgroup-threads threads)
4628 (beginning-of-line)
4629
4630 (let ((gnus-tmp-level 0)
4631 (default-score (or gnus-summary-default-score 0))
4632 (gnus-visual-p (gnus-visual-p 'summary-highlight 'highlight))
23f87bed
MB
4633 (building-line-count gnus-summary-display-while-building)
4634 (building-count (integerp gnus-summary-display-while-building))
eec82323 4635 thread number subject stack state gnus-tmp-gathered beg-match
23f87bed
MB
4636 new-roots gnus-tmp-new-adopts thread-end simp-subject
4637 gnus-tmp-header gnus-tmp-unread gnus-tmp-downloaded
eec82323
LMI
4638 gnus-tmp-replied gnus-tmp-subject-or-nil
4639 gnus-tmp-dummy gnus-tmp-indentation gnus-tmp-lines gnus-tmp-score
4640 gnus-tmp-score-char gnus-tmp-from gnus-tmp-name
23f87bed
MB
4641 gnus-tmp-number gnus-tmp-opening-bracket gnus-tmp-closing-bracket
4642 tree-stack)
eec82323 4643
23f87bed
MB
4644 (setq gnus-tmp-prev-subject nil
4645 gnus-tmp-thread-tree-header-string "")
eec82323
LMI
4646
4647 (if (vectorp (car threads))
4648 ;; If this is a straight (sic) list of headers, then a
4649 ;; threaded summary display isn't required, so we just create
4650 ;; an unthreaded one.
4651 (gnus-summary-prepare-unthreaded threads)
4652
4653 ;; Do the threaded display.
4654
23f87bed
MB
4655 (if gnus-summary-display-while-building
4656 (switch-to-buffer (buffer-name)))
eec82323
LMI
4657 (while (or threads stack gnus-tmp-new-adopts new-roots)
4658
4659 (if (and (= gnus-tmp-level 0)
eec82323
LMI
4660 (or (not stack)
4661 (= (caar stack) 0))
4662 (not gnus-tmp-false-parent)
4663 (or gnus-tmp-new-adopts new-roots))
4664 (if gnus-tmp-new-adopts
4665 (setq gnus-tmp-level (if gnus-tmp-root-expunged 0 1)
4666 thread (list (car gnus-tmp-new-adopts))
4667 gnus-tmp-header (caar thread)
4668 gnus-tmp-new-adopts (cdr gnus-tmp-new-adopts))
4669 (when new-roots
4670 (setq thread (list (car new-roots))
4671 gnus-tmp-header (caar thread)
4672 new-roots (cdr new-roots))))
4673
4674 (if threads
4675 ;; If there are some threads, we do them before the
4676 ;; threads on the stack.
4677 (setq thread threads
4678 gnus-tmp-header (caar thread))
4679 ;; There were no current threads, so we pop something off
4680 ;; the stack.
4681 (setq state (car stack)
4682 gnus-tmp-level (car state)
23f87bed
MB
4683 tree-stack (cadr state)
4684 thread (caddr state)
eec82323
LMI
4685 stack (cdr stack)
4686 gnus-tmp-header (caar thread))))
4687
4688 (setq gnus-tmp-false-parent nil)
4689 (setq gnus-tmp-root-expunged nil)
4690 (setq thread-end nil)
4691
4692 (if (stringp gnus-tmp-header)
4693 ;; The header is a dummy root.
4694 (cond
4695 ((eq gnus-summary-make-false-root 'adopt)
4696 ;; We let the first article adopt the rest.
4697 (setq gnus-tmp-new-adopts (nconc gnus-tmp-new-adopts
4698 (cddar thread)))
4699 (setq gnus-tmp-gathered
4700 (nconc (mapcar
4701 (lambda (h) (mail-header-number (car h)))
4702 (cddar thread))
4703 gnus-tmp-gathered))
4704 (setq thread (cons (list (caar thread)
4705 (cadar thread))
4706 (cdr thread)))
4707 (setq gnus-tmp-level -1
4708 gnus-tmp-false-parent t))
4709 ((eq gnus-summary-make-false-root 'empty)
4710 ;; We print adopted articles with empty subject fields.
4711 (setq gnus-tmp-gathered
4712 (nconc (mapcar
4713 (lambda (h) (mail-header-number (car h)))
4714 (cddar thread))
4715 gnus-tmp-gathered))
4716 (setq gnus-tmp-level -1))
4717 ((eq gnus-summary-make-false-root 'dummy)
4718 ;; We remember that we probably want to output a dummy
4719 ;; root.
4720 (setq gnus-tmp-dummy-line gnus-tmp-header)
4721 (setq gnus-tmp-prev-subject gnus-tmp-header))
4722 (t
4723 ;; We do not make a root for the gathered
4724 ;; sub-threads at all.
4725 (setq gnus-tmp-level -1)))
4726
4727 (setq number (mail-header-number gnus-tmp-header)
23f87bed
MB
4728 subject (mail-header-subject gnus-tmp-header)
4729 simp-subject (gnus-simplify-subject-fully subject))
eec82323
LMI
4730
4731 (cond
4732 ;; If the thread has changed subject, we might want to make
4733 ;; this subthread into a root.
4734 ((and (null gnus-thread-ignore-subject)
4735 (not (zerop gnus-tmp-level))
4736 gnus-tmp-prev-subject
23f87bed 4737 (not (string= gnus-tmp-prev-subject simp-subject)))
eec82323
LMI
4738 (setq new-roots (nconc new-roots (list (car thread)))
4739 thread-end t
4740 gnus-tmp-header nil))
4741 ;; If the article lies outside the current limit,
4742 ;; then we do not display it.
4743 ((not (memq number gnus-newsgroup-limit))
4744 (setq gnus-tmp-gathered
4745 (nconc (mapcar
4746 (lambda (h) (mail-header-number (car h)))
4747 (cdar thread))
4748 gnus-tmp-gathered))
4749 (setq gnus-tmp-new-adopts (if (cdar thread)
4750 (append gnus-tmp-new-adopts
4751 (cdar thread))
4752 gnus-tmp-new-adopts)
4753 thread-end t
4754 gnus-tmp-header nil)
4755 (when (zerop gnus-tmp-level)
4756 (setq gnus-tmp-root-expunged t)))
4757 ;; Perhaps this article is to be marked as read?
4758 ((and gnus-summary-mark-below
4759 (< (or (cdr (assq number gnus-newsgroup-scored))
4760 default-score)
4761 gnus-summary-mark-below)
4762 ;; Don't touch sparse articles.
4763 (not (gnus-summary-article-sparse-p number))
4764 (not (gnus-summary-article-ancient-p number)))
4765 (setq gnus-newsgroup-unreads
4766 (delq number gnus-newsgroup-unreads))
4767 (if gnus-newsgroup-auto-expire
23f87bed
MB
4768 (setq gnus-newsgroup-expirable
4769 (gnus-add-to-sorted-list
4770 gnus-newsgroup-expirable number))
eec82323
LMI
4771 (push (cons number gnus-low-score-mark)
4772 gnus-newsgroup-reads))))
4773
4774 (when gnus-tmp-header
4775 ;; We may have an old dummy line to output before this
4776 ;; article.
6748645f
LMI
4777 (when (and gnus-tmp-dummy-line
4778 (gnus-subject-equal
4779 gnus-tmp-dummy-line
4780 (mail-header-subject gnus-tmp-header)))
eec82323
LMI
4781 (gnus-summary-insert-dummy-line
4782 gnus-tmp-dummy-line (mail-header-number gnus-tmp-header))
4783 (setq gnus-tmp-dummy-line nil))
4784
4785 ;; Compute the mark.
4786 (setq gnus-tmp-unread (gnus-article-mark number))
4787
4788 (push (gnus-data-make number gnus-tmp-unread (1+ (point))
4789 gnus-tmp-header gnus-tmp-level)
4790 gnus-newsgroup-data)
4791
4792 ;; Actually insert the line.
4793 (setq
4794 gnus-tmp-subject-or-nil
4795 (cond
4796 ((and gnus-thread-ignore-subject
4797 gnus-tmp-prev-subject
23f87bed 4798 (not (string= gnus-tmp-prev-subject simp-subject)))
eec82323
LMI
4799 subject)
4800 ((zerop gnus-tmp-level)
4801 (if (and (eq gnus-summary-make-false-root 'empty)
4802 (memq number gnus-tmp-gathered)
4803 gnus-tmp-prev-subject
23f87bed 4804 (string= gnus-tmp-prev-subject simp-subject))
eec82323
LMI
4805 gnus-summary-same-subject
4806 subject))
4807 (t gnus-summary-same-subject)))
4808 (if (and (eq gnus-summary-make-false-root 'adopt)
4809 (= gnus-tmp-level 1)
4810 (memq number gnus-tmp-gathered))
4811 (setq gnus-tmp-opening-bracket ?\<
4812 gnus-tmp-closing-bracket ?\>)
4813 (setq gnus-tmp-opening-bracket ?\[
4814 gnus-tmp-closing-bracket ?\]))
4815 (setq
4816 gnus-tmp-indentation
4817 (aref gnus-thread-indent-array gnus-tmp-level)
4818 gnus-tmp-lines (mail-header-lines gnus-tmp-header)
4819 gnus-tmp-score (or (cdr (assq number gnus-newsgroup-scored))
4820 gnus-summary-default-score 0)
4821 gnus-tmp-score-char
4822 (if (or (null gnus-summary-default-score)
4823 (<= (abs (- gnus-tmp-score gnus-summary-default-score))
4824 gnus-summary-zcore-fuzz))
23f87bed 4825 ? ;Whitespace
eec82323
LMI
4826 (if (< gnus-tmp-score gnus-summary-default-score)
4827 gnus-score-below-mark gnus-score-over-mark))
4828 gnus-tmp-replied
4829 (cond ((memq number gnus-newsgroup-processable)
4830 gnus-process-mark)
4831 ((memq number gnus-newsgroup-cached)
4832 gnus-cached-mark)
4833 ((memq number gnus-newsgroup-replied)
4834 gnus-replied-mark)
23f87bed
MB
4835 ((memq number gnus-newsgroup-forwarded)
4836 gnus-forwarded-mark)
eec82323
LMI
4837 ((memq number gnus-newsgroup-saved)
4838 gnus-saved-mark)
23f87bed
MB
4839 ((memq number gnus-newsgroup-recent)
4840 gnus-recent-mark)
4841 ((memq number gnus-newsgroup-unseen)
4842 gnus-unseen-mark)
4843 (t gnus-no-mark))
4844 gnus-tmp-downloaded
4845 (cond ((memq number gnus-newsgroup-undownloaded)
4846 gnus-undownloaded-mark)
4847 (gnus-newsgroup-agentized
4848 gnus-downloaded-mark)
4849 (t
4850 gnus-no-mark))
eec82323
LMI
4851 gnus-tmp-from (mail-header-from gnus-tmp-header)
4852 gnus-tmp-name
4853 (cond
4854 ((string-match "<[^>]+> *$" gnus-tmp-from)
4855 (setq beg-match (match-beginning 0))
23f87bed
MB
4856 (or (and (string-match "^\".+\"" gnus-tmp-from)
4857 (substring gnus-tmp-from 1 (1- (match-end 0))))
eec82323
LMI
4858 (substring gnus-tmp-from 0 beg-match)))
4859 ((string-match "(.+)" gnus-tmp-from)
4860 (substring gnus-tmp-from
4861 (1+ (match-beginning 0)) (1- (match-end 0))))
23f87bed
MB
4862 (t gnus-tmp-from))
4863
4864 ;; Do the %B string
4865 gnus-tmp-thread-tree-header-string
4866 (cond
4867 ((not gnus-show-threads) "")
4868 ((zerop gnus-tmp-level)
4869 (cond ((cdar thread)
4870 (or gnus-sum-thread-tree-root subject))
4871 (gnus-tmp-new-adopts
4872 (or gnus-sum-thread-tree-false-root subject))
4873 (t
4874 (or gnus-sum-thread-tree-single-indent subject))))
4875 (t
4876 (concat (apply 'concat
4877 (mapcar (lambda (item)
4878 (if (= item 1)
4879 gnus-sum-thread-tree-vertical
4880 gnus-sum-thread-tree-indent))
4881 (cdr (reverse tree-stack))))
4882 (if (nth 1 thread)
4883 gnus-sum-thread-tree-leaf-with-other
4884 gnus-sum-thread-tree-single-leaf)))))
eec82323
LMI
4885 (when (string= gnus-tmp-name "")
4886 (setq gnus-tmp-name gnus-tmp-from))
4887 (unless (numberp gnus-tmp-lines)
23f87bed
MB
4888 (setq gnus-tmp-lines -1))
4889 (if (= gnus-tmp-lines -1)
4890 (setq gnus-tmp-lines "?")
4891 (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
4892 (gnus-put-text-property
eec82323
LMI
4893 (point)
4894 (progn (eval gnus-summary-line-format-spec) (point))
23f87bed 4895 'gnus-number number)
eec82323
LMI
4896 (when gnus-visual-p
4897 (forward-line -1)
6748645f 4898 (gnus-run-hooks 'gnus-summary-update-hook)
eec82323
LMI
4899 (forward-line 1))
4900
23f87bed 4901 (setq gnus-tmp-prev-subject simp-subject)))
eec82323
LMI
4902
4903 (when (nth 1 thread)
23f87bed
MB
4904 (push (list (max 0 gnus-tmp-level)
4905 (copy-sequence tree-stack)
4906 (nthcdr 1 thread))
4907 stack))
4908 (push (if (nth 1 thread) 1 0) tree-stack)
eec82323
LMI
4909 (incf gnus-tmp-level)
4910 (setq threads (if thread-end nil (cdar thread)))
23f87bed
MB
4911 (if gnus-summary-display-while-building
4912 (if building-count
4913 (progn
4914 ;; use a set frequency
4915 (setq building-line-count (1- building-line-count))
4916 (when (= building-line-count 0)
4917 (sit-for 0)
4918 (setq building-line-count
4919 gnus-summary-display-while-building)))
4920 ;; always
4921 (sit-for 0)))
eec82323
LMI
4922 (unless threads
4923 (setq gnus-tmp-level 0)))))
4924 (gnus-message 7 "Generating summary...done"))
4925
4926(defun gnus-summary-prepare-unthreaded (headers)
4927 "Generate an unthreaded summary buffer based on HEADERS."
4928 (let (header number mark)
4929
4930 (beginning-of-line)
4931
4932 (while headers
4933 ;; We may have to root out some bad articles...
4934 (when (memq (setq number (mail-header-number
4935 (setq header (pop headers))))
4936 gnus-newsgroup-limit)
4937 ;; Mark article as read when it has a low score.
4938 (when (and gnus-summary-mark-below
4939 (< (or (cdr (assq number gnus-newsgroup-scored))
4940 gnus-summary-default-score 0)
4941 gnus-summary-mark-below)
4942 (not (gnus-summary-article-ancient-p number)))
4943 (setq gnus-newsgroup-unreads
4944 (delq number gnus-newsgroup-unreads))
4945 (if gnus-newsgroup-auto-expire
4946 (push number gnus-newsgroup-expirable)
4947 (push (cons number gnus-low-score-mark)
4948 gnus-newsgroup-reads)))
4949
4950 (setq mark (gnus-article-mark number))
4951 (push (gnus-data-make number mark (1+ (point)) header 0)
4952 gnus-newsgroup-data)
4953 (gnus-summary-insert-line
4954 header 0 number
23f87bed 4955 (memq number gnus-newsgroup-undownloaded)
eec82323
LMI
4956 mark (memq number gnus-newsgroup-replied)
4957 (memq number gnus-newsgroup-expirable)
4958 (mail-header-subject header) nil
4959 (cdr (assq number gnus-newsgroup-scored))
4960 (memq number gnus-newsgroup-processable))))))
4961
16409b0b
GM
4962(defun gnus-summary-remove-list-identifiers ()
4963 "Remove list identifiers in `gnus-list-identifiers' from articles in the current group."
23f87bed
MB
4964 (let ((regexp (if (consp gnus-list-identifiers)
4965 (mapconcat 'identity gnus-list-identifiers " *\\|")
4966 gnus-list-identifiers))
4967 changed subject)
4968 (when regexp
4969 (dolist (header gnus-newsgroup-headers)
4970 (setq subject (mail-header-subject header)
4971 changed nil)
4972 (while (string-match
4973 (concat "^\\(R[Ee]: +\\)*\\(" regexp " *\\)")
4974 subject)
4975 (setq subject
4976 (concat (substring subject 0 (match-beginning 2))
4977 (substring subject (match-end 0)))
4978 changed t))
4979 (when (and changed
4980 (string-match
4981 "^\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" subject))
4982 (setq subject
4983 (concat (substring subject 0 (match-beginning 1))
4984 (substring subject (match-end 1)))))
4985 (when changed
4986 (mail-header-set-subject header subject))))))
4987
4988(defun gnus-fetch-headers (articles)
4989 "Fetch headers of ARTICLES."
4990 (let ((name (gnus-group-decoded-name gnus-newsgroup-name)))
4991 (gnus-message 5 "Fetching headers for %s..." name)
4992 (prog1
4993 (if (eq 'nov
4994 (setq gnus-headers-retrieved-by
4995 (gnus-retrieve-headers
4996 articles gnus-newsgroup-name
4997 ;; We might want to fetch old headers, but
4998 ;; not if there is only 1 article.
4999 (and (or (and
5000 (not (eq gnus-fetch-old-headers 'some))
5001 (not (numberp gnus-fetch-old-headers)))
5002 (> (length articles) 1))
5003 gnus-fetch-old-headers))))
5004 (gnus-get-newsgroup-headers-xover
5005 articles nil nil gnus-newsgroup-name t)
5006 (gnus-get-newsgroup-headers))
5007 (gnus-message 5 "Fetching headers for %s...done" name))))
16409b0b 5008
6748645f 5009(defun gnus-select-newsgroup (group &optional read-all select-articles)
eec82323 5010 "Select newsgroup GROUP.
6748645f
LMI
5011If READ-ALL is non-nil, all articles in the group are selected.
5012If SELECT-ARTICLES, only select those articles from GROUP."
eec82323
LMI
5013 (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
5014 ;;!!! Dirty hack; should be removed.
5015 (gnus-summary-ignore-duplicates
23f87bed 5016 (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
eec82323
LMI
5017 t
5018 gnus-summary-ignore-duplicates))
5019 (info (nth 2 entry))
5020 articles fetched-articles cached)
5021
5022 (unless (gnus-check-server
475e0e0c
GM
5023 (set (make-local-variable 'gnus-current-select-method)
5024 (gnus-find-method-for-group group)))
eec82323
LMI
5025 (error "Couldn't open server"))
5026
5027 (or (and entry (not (eq (car entry) t))) ; Either it's active...
5028 (gnus-activate-group group) ; Or we can activate it...
5029 (progn ; Or we bug out.
5030 (when (equal major-mode 'gnus-summary-mode)
23f87bed
MB
5031 (gnus-kill-buffer (current-buffer)))
5032 (error "Couldn't activate group %s: %s"
eec82323
LMI
5033 group (gnus-status-message group))))
5034
5035 (unless (gnus-request-group group t)
5036 (when (equal major-mode 'gnus-summary-mode)
23f87bed 5037 (gnus-kill-buffer (current-buffer)))
eec82323
LMI
5038 (error "Couldn't request group %s: %s"
5039 group (gnus-status-message group)))
5040
23f87bed
MB
5041 (when gnus-agent
5042 ;; The agent may be storing articles that are no longer in the
5043 ;; server's active range. If that is the case, the active range
5044 ;; needs to be expanded such that the agent's articles can be
5045 ;; included in the summary.
5046 (let* ((gnus-command-method (gnus-find-method-for-group group))
5047 (alist (gnus-agent-load-alist group))
5048 (active (gnus-active group)))
5049 (if (and (car alist)
5050 (< (caar alist) (car active)))
5051 (gnus-set-active group (cons (caar alist) (cdr active)))))
5052
5053 (setq gnus-summary-use-undownloaded-faces
5054 (gnus-agent-find-parameter
5055 group
5056 'agent-enable-undownloaded-faces)))
5057
5058 (setq gnus-newsgroup-name group
5059 gnus-newsgroup-unselected nil
5060 gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
5061
5062 (let ((display (gnus-group-find-parameter group 'display)))
5063 (setq gnus-newsgroup-display
5064 (cond
5065 ((not (zerop (or (car-safe read-all) 0)))
5066 ;; The user entered the group with C-u SPC/RET, let's show
5067 ;; all articles.
5068 'gnus-not-ignore)
5069 ((eq display 'all)
5070 'gnus-not-ignore)
5071 ((arrayp display)
5072 (gnus-summary-display-make-predicate (mapcar 'identity display)))
5073 ((numberp display)
5074 ;; The following is probably the "correct" solution, but
5075 ;; it makes Gnus fetch all headers and then limit the
5076 ;; articles (which is slow), so instead we hack the
5077 ;; select-articles parameter instead. -- Simon Josefsson
5078 ;; <jas@kth.se>
5079 ;;
5080 ;; (gnus-byte-compile
5081 ;; `(lambda () (> number ,(- (cdr (gnus-active group))
5082 ;; display)))))
5083 (setq select-articles
5084 (gnus-uncompress-range
5085 (cons (let ((tmp (- (cdr (gnus-active group)) display)))
5086 (if (> tmp 0)
5087 tmp
5088 1))
5089 (cdr (gnus-active group)))))
5090 nil)
5091 (t
5092 nil))))
eec82323 5093
23f87bed 5094 (gnus-summary-setup-default-charset)
eec82323
LMI
5095
5096 ;; Kludge to avoid having cached articles nixed out in virtual groups.
5097 (when (gnus-virtual-group-p group)
5098 (setq cached gnus-newsgroup-cached))
5099
5100 (setq gnus-newsgroup-unreads
23f87bed
MB
5101 (gnus-sorted-ndifference
5102 (gnus-sorted-ndifference gnus-newsgroup-unreads
5103 gnus-newsgroup-marked)
eec82323
LMI
5104 gnus-newsgroup-dormant))
5105
5106 (setq gnus-newsgroup-processable nil)
5107
5108 (gnus-update-read-articles group gnus-newsgroup-unreads)
eec82323 5109
23f87bed
MB
5110 ;; Adjust and set lists of article marks.
5111 (when info
5112 (gnus-adjust-marked-articles info))
6748645f
LMI
5113 (if (setq articles select-articles)
5114 (setq gnus-newsgroup-unselected
23f87bed 5115 (gnus-sorted-difference gnus-newsgroup-unreads articles))
6748645f 5116 (setq articles (gnus-articles-to-read group read-all)))
eec82323
LMI
5117
5118 (cond
5119 ((null articles)
5120 ;;(gnus-message 3 "Couldn't select newsgroup -- no articles to display")
5121 'quit)
5122 ((eq articles 0) nil)
5123 (t
5124 ;; Init the dependencies hash table.
5125 (setq gnus-newsgroup-dependencies
5126 (gnus-make-hashtable (length articles)))
16409b0b 5127 (gnus-set-global-variables)
eec82323 5128 ;; Retrieve the headers and read them in.
23f87bed
MB
5129
5130 (setq gnus-newsgroup-headers (gnus-fetch-headers articles))
eec82323
LMI
5131
5132 ;; Kludge to avoid having cached articles nixed out in virtual groups.
5133 (when cached
5134 (setq gnus-newsgroup-cached cached))
5135
5136 ;; Suppress duplicates?
5137 (when gnus-suppress-duplicates
5138 (gnus-dup-suppress-articles))
5139
5140 ;; Set the initial limit.
5141 (setq gnus-newsgroup-limit (copy-sequence articles))
5142 ;; Remove canceled articles from the list of unread articles.
23f87bed
MB
5143 (setq fetched-articles
5144 (mapcar (lambda (headers) (mail-header-number headers))
5145 gnus-newsgroup-headers))
5146 (setq gnus-newsgroup-articles fetched-articles)
eec82323 5147 (setq gnus-newsgroup-unreads
23f87bed
MB
5148 (gnus-sorted-nintersection
5149 gnus-newsgroup-unreads fetched-articles))
5150 (gnus-compute-unseen-list)
5151
eec82323
LMI
5152 ;; Removed marked articles that do not exist.
5153 (gnus-update-missing-marks
23f87bed 5154 (gnus-sorted-difference articles fetched-articles))
eec82323 5155 ;; We might want to build some more threads first.
6748645f
LMI
5156 (when (and gnus-fetch-old-headers
5157 (eq gnus-headers-retrieved-by 'nov))
5158 (if (eq gnus-fetch-old-headers 'invisible)
5159 (gnus-build-all-threads)
5160 (gnus-build-old-threads)))
5161 ;; Let the Gnus agent mark articles as read.
5162 (when gnus-agent
5163 (gnus-agent-get-undownloaded-list))
16409b0b
GM
5164 ;; Remove list identifiers from subject
5165 (when gnus-list-identifiers
5166 (gnus-summary-remove-list-identifiers))
eec82323
LMI
5167 ;; Check whether auto-expire is to be done in this group.
5168 (setq gnus-newsgroup-auto-expire
5169 (gnus-group-auto-expirable-p group))
5170 ;; Set up the article buffer now, if necessary.
5171 (unless gnus-single-article-buffer
5172 (gnus-article-setup-buffer))
5173 ;; First and last article in this newsgroup.
5174 (when gnus-newsgroup-headers
5175 (setq gnus-newsgroup-begin
5176 (mail-header-number (car gnus-newsgroup-headers))
5177 gnus-newsgroup-end
5178 (mail-header-number
5179 (gnus-last-element gnus-newsgroup-headers))))
5180 ;; GROUP is successfully selected.
5181 (or gnus-newsgroup-headers t)))))
5182
23f87bed
MB
5183(defun gnus-compute-unseen-list ()
5184 ;; The `seen' marks are treated specially.
5185 (if (not gnus-newsgroup-seen)
5186 (setq gnus-newsgroup-unseen gnus-newsgroup-articles)
5187 (setq gnus-newsgroup-unseen
5188 (gnus-inverse-list-range-intersection
5189 gnus-newsgroup-articles gnus-newsgroup-seen))))
5190
5191(defun gnus-summary-display-make-predicate (display)
5192 (require 'gnus-agent)
5193 (when (= (length display) 1)
5194 (setq display (car display)))
5195 (unless gnus-summary-display-cache
5196 (dolist (elem (append '((unread . unread)
5197 (read . read)
5198 (unseen . unseen))
5199 gnus-article-mark-lists))
5200 (push (cons (cdr elem)
5201 (gnus-byte-compile
5202 `(lambda () (gnus-article-marked-p ',(cdr elem)))))
5203 gnus-summary-display-cache)))
5204 (let ((gnus-category-predicate-alist gnus-summary-display-cache)
5205 (gnus-category-predicate-cache gnus-summary-display-cache))
5206 (gnus-get-predicate display)))
5207
5208;; Uses the dynamically bound `number' variable.
5209(eval-when-compile
5210 (defvar number))
5211(defun gnus-article-marked-p (type &optional article)
5212 (let ((article (or article number)))
5213 (cond
5214 ((eq type 'tick)
5215 (memq article gnus-newsgroup-marked))
5216 ((eq type 'spam)
5217 (memq article gnus-newsgroup-spam-marked))
5218 ((eq type 'unsend)
5219 (memq article gnus-newsgroup-unsendable))
5220 ((eq type 'undownload)
5221 (memq article gnus-newsgroup-undownloaded))
5222 ((eq type 'download)
5223 (memq article gnus-newsgroup-downloadable))
5224 ((eq type 'unread)
5225 (memq article gnus-newsgroup-unreads))
5226 ((eq type 'read)
5227 (memq article gnus-newsgroup-reads))
5228 ((eq type 'dormant)
5229 (memq article gnus-newsgroup-dormant) )
5230 ((eq type 'expire)
5231 (memq article gnus-newsgroup-expirable))
5232 ((eq type 'reply)
5233 (memq article gnus-newsgroup-replied))
5234 ((eq type 'killed)
5235 (memq article gnus-newsgroup-killed))
5236 ((eq type 'bookmark)
5237 (assq article gnus-newsgroup-bookmarks))
5238 ((eq type 'score)
5239 (assq article gnus-newsgroup-scored))
5240 ((eq type 'save)
5241 (memq article gnus-newsgroup-saved))
5242 ((eq type 'cache)
5243 (memq article gnus-newsgroup-cached))
5244 ((eq type 'forward)
5245 (memq article gnus-newsgroup-forwarded))
5246 ((eq type 'seen)
5247 (not (memq article gnus-newsgroup-unseen)))
5248 ((eq type 'recent)
5249 (memq article gnus-newsgroup-recent))
5250 (t t))))
5251
eec82323 5252(defun gnus-articles-to-read (group &optional read-all)
16409b0b 5253 "Find out what articles the user wants to read."
23f87bed
MB
5254 (let* ((display (gnus-group-find-parameter group 'display))
5255 (articles
eec82323
LMI
5256 ;; Select all articles if `read-all' is non-nil, or if there
5257 ;; are no unread articles.
5258 (if (or read-all
5259 (and (zerop (length gnus-newsgroup-marked))
5260 (zerop (length gnus-newsgroup-unreads)))
23f87bed
MB
5261 ;; Fetch all if the predicate is non-nil.
5262 gnus-newsgroup-display)
5263 ;; We want to select the headers for all the articles in
5264 ;; the group, so we select either all the active
5265 ;; articles in the group, or (if that's nil), the
5266 ;; articles in the cache.
16409b0b
GM
5267 (or
5268 (gnus-uncompress-range (gnus-active group))
5269 (gnus-cache-articles-in-group group))
23f87bed
MB
5270 ;; Select only the "normal" subset of articles.
5271 (gnus-sorted-nunion
5272 (gnus-sorted-union gnus-newsgroup-dormant gnus-newsgroup-marked)
5273 gnus-newsgroup-unreads)))
eec82323
LMI
5274 (scored-list (gnus-killed-articles gnus-newsgroup-killed articles))
5275 (scored (length scored-list))
5276 (number (length articles))
5277 (marked (+ (length gnus-newsgroup-marked)
5278 (length gnus-newsgroup-dormant)))
5279 (select
5280 (cond
5281 ((numberp read-all)
5282 read-all)
23f87bed
MB
5283 ((numberp gnus-newsgroup-display)
5284 gnus-newsgroup-display)
eec82323
LMI
5285 (t
5286 (condition-case ()
5287 (cond
5288 ((and (or (<= scored marked) (= scored number))
5289 (numberp gnus-large-newsgroup)
5290 (> number gnus-large-newsgroup))
23f87bed
MB
5291 (let* ((cursor-in-echo-area nil)
5292 (initial (gnus-parameter-large-newsgroup-initial
5293 gnus-newsgroup-name))
5294 (input
5295 (read-string
5296 (format
5297 "How many articles from %s (%s %d): "
5298 (gnus-limit-string
5299 (gnus-group-decoded-name gnus-newsgroup-name)
5300 35)
5301 (if initial "max" "default")
5302 number)
5303 (if initial
5304 (cons (number-to-string initial)
5305 0)))))
eec82323
LMI
5306 (if (string-match "^[ \t]*$" input) number input)))
5307 ((and (> scored marked) (< scored number)
5308 (> (- scored number) 20))
5309 (let ((input
5310 (read-string
5311 (format "%s %s (%d scored, %d total): "
5312 "How many articles from"
23f87bed
MB
5313 (gnus-group-decoded-name group)
5314 scored number))))
eec82323
LMI
5315 (if (string-match "^[ \t]*$" input)
5316 number input)))
5317 (t number))
d4dfaa19
DL
5318 (quit
5319 (message "Quit getting the articles to read")
5320 nil))))))
eec82323
LMI
5321 (setq select (if (stringp select) (string-to-number select) select))
5322 (if (or (null select) (zerop select))
5323 select
5324 (if (and (not (zerop scored)) (<= (abs select) scored))
5325 (progn
5326 (setq articles (sort scored-list '<))
5327 (setq number (length articles)))
5328 (setq articles (copy-sequence articles)))
5329
5330 (when (< (abs select) number)
5331 (if (< select 0)
5332 ;; Select the N oldest articles.
5333 (setcdr (nthcdr (1- (abs select)) articles) nil)
5334 ;; Select the N most recent articles.
5335 (setq articles (nthcdr (- number select) articles))))
5336 (setq gnus-newsgroup-unselected
23f87bed 5337 (gnus-sorted-difference gnus-newsgroup-unreads articles))
16409b0b 5338 (when gnus-alter-articles-to-read-function
23f87bed 5339 (setq articles
a1506d29 5340 (sort
16409b0b 5341 (funcall gnus-alter-articles-to-read-function
23f87bed 5342 gnus-newsgroup-name articles)
16409b0b 5343 '<)))
eec82323
LMI
5344 articles)))
5345
5346(defun gnus-killed-articles (killed articles)
5347 (let (out)
5348 (while articles
5349 (when (inline (gnus-member-of-range (car articles) killed))
5350 (push (car articles) out))
5351 (setq articles (cdr articles)))
5352 out))
5353
5354(defun gnus-uncompress-marks (marks)
5355 "Uncompress the mark ranges in MARKS."
5356 (let ((uncompressed '(score bookmark))
5357 out)
5358 (while marks
5359 (if (memq (caar marks) uncompressed)
5360 (push (car marks) out)
5361 (push (cons (caar marks) (gnus-uncompress-range (cdar marks))) out))
5362 (setq marks (cdr marks)))
5363 out))
5364
23f87bed
MB
5365(defun gnus-article-mark-to-type (mark)
5366 "Return the type of MARK."
5367 (or (cadr (assq mark gnus-article-special-mark-lists))
5368 'list))
5369
5370(defun gnus-article-unpropagatable-p (mark)
5371 "Return whether MARK should be propagated to back end."
5372 (memq mark gnus-article-unpropagated-mark-lists))
5373
eec82323 5374(defun gnus-adjust-marked-articles (info)
16409b0b 5375 "Set all article lists and remove all marks that are no longer valid."
eec82323
LMI
5376 (let* ((marked-lists (gnus-info-marks info))
5377 (active (gnus-active (gnus-info-group info)))
5378 (min (car active))
5379 (max (cdr active))
5380 (types gnus-article-mark-lists)
23f87bed 5381 marks var articles article mark mark-type)
eec82323 5382
23f87bed
MB
5383 (dolist (marks marked-lists)
5384 (setq mark (car marks)
5385 mark-type (gnus-article-mark-to-type mark)
5386 var (intern (format "gnus-newsgroup-%s" (car (rassq mark types)))))
eec82323 5387
23f87bed
MB
5388 ;; We set the variable according to the type of the marks list,
5389 ;; and then adjust the marks to a subset of the active articles.
eec82323
LMI
5390 (cond
5391 ;; Adjust "simple" lists.
23f87bed
MB
5392 ((eq mark-type 'list)
5393 (set var (setq articles (gnus-uncompress-range (cdr marks))))
5394 (when (memq mark '(tick dormant expire reply save))
5395 (while articles
5396 (when (or (< (setq article (pop articles)) min) (> article max))
5397 (set var (delq article (symbol-value var)))))))
eec82323 5398 ;; Adjust assocs.
23f87bed
MB
5399 ((eq mark-type 'tuple)
5400 (set var (setq articles (cdr marks)))
a8151ef7
LMI
5401 (when (not (listp (cdr (symbol-value var))))
5402 (set var (list (symbol-value var))))
5403 (when (not (listp (cdr articles)))
5404 (setq articles (list articles)))
eec82323
LMI
5405 (while articles
5406 (when (or (not (consp (setq article (pop articles))))
5407 (< (car article) min)
5408 (> (car article) max))
23f87bed
MB
5409 (set var (delq article (symbol-value var))))))
5410 ;; Adjust ranges (sloppily).
5411 ((eq mark-type 'range)
5412 (cond
5413 ((eq mark 'seen)
5414 ;; Fix the record for `seen' if it looks like (seen NUM1 . NUM2).
5415 ;; It should be (seen (NUM1 . NUM2)).
5416 (when (numberp (cddr marks))
5417 (setcdr marks (list (cdr marks))))
5418 (setq articles (cdr marks))
5419 (while (and articles
5420 (or (and (consp (car articles))
5421 (> min (cdar articles)))
5422 (and (numberp (car articles))
5423 (> min (car articles)))))
5424 (pop articles))
5425 (set var articles))))))))
eec82323
LMI
5426
5427(defun gnus-update-missing-marks (missing)
6748645f 5428 "Go through the list of MISSING articles and remove them from the mark lists."
eec82323 5429 (when missing
23f87bed 5430 (let (var m)
eec82323 5431 ;; Go through all types.
23f87bed
MB
5432 (dolist (elem gnus-article-mark-lists)
5433 (when (eq (gnus-article-mark-to-type (cdr elem)) 'list)
5434 (setq var (intern (format "gnus-newsgroup-%s" (car elem))))
5435 (when (symbol-value var)
5436 ;; This list has articles. So we delete all missing
5437 ;; articles from it.
5438 (setq m missing)
5439 (while m
5440 (set var (delq (pop m) (symbol-value var))))))))))
eec82323
LMI
5441
5442(defun gnus-update-marks ()
5443 "Enter the various lists of marked articles into the newsgroup info list."
5444 (let ((types gnus-article-mark-lists)
5445 (info (gnus-get-info gnus-newsgroup-name))
16409b0b 5446 type list newmarked symbol delta-marks)
eec82323 5447 (when info
16409b0b 5448 ;; Add all marks lists to the list of marks lists.
eec82323 5449 (while (setq type (pop types))
16409b0b
GM
5450 (setq list (symbol-value
5451 (setq symbol
23f87bed 5452 (intern (format "gnus-newsgroup-%s" (car type))))))
eec82323 5453
16409b0b 5454 (when list
eec82323
LMI
5455 ;; Get rid of the entries of the articles that have the
5456 ;; default score.
5457 (when (and (eq (cdr type) 'score)
5458 gnus-save-score
5459 list)
5460 (let* ((arts list)
5461 (prev (cons nil list))
5462 (all prev))
5463 (while arts
5464 (if (or (not (consp (car arts)))
5465 (= (cdar arts) gnus-summary-default-score))
5466 (setcdr prev (cdr arts))
5467 (setq prev arts))
5468 (setq arts (cdr arts)))
16409b0b
GM
5469 (setq list (cdr all)))))
5470
23f87bed
MB
5471 (when (eq (cdr type) 'seen)
5472 (setq list (gnus-range-add list gnus-newsgroup-unseen)))
5473
5474 (when (eq (gnus-article-mark-to-type (cdr type)) 'list)
16409b0b 5475 (setq list (gnus-compress-sequence (set symbol (sort list '<)) t)))
a1506d29 5476
23f87bed
MB
5477 (when (and (gnus-check-backend-function
5478 'request-set-mark gnus-newsgroup-name)
5479 (not (gnus-article-unpropagatable-p (cdr type))))
5480 (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
5481 (del (gnus-remove-from-range (gnus-copy-sequence old) list))
5482 (add (gnus-remove-from-range
5483 (gnus-copy-sequence list) old)))
5484 (when add
5485 (push (list add 'add (list (cdr type))) delta-marks))
5486 (when del
5487 (push (list del 'del (list (cdr type))) delta-marks))))
a1506d29 5488
16409b0b
GM
5489 (when list
5490 (push (cons (cdr type) list) newmarked)))
5491
5492 (when delta-marks
5493 (unless (gnus-check-group gnus-newsgroup-name)
5494 (error "Can't open server for %s" gnus-newsgroup-name))
5495 (gnus-request-set-mark gnus-newsgroup-name delta-marks))
a1506d29 5496
eec82323
LMI
5497 ;; Enter these new marks into the info of the group.
5498 (if (nthcdr 3 info)
5499 (setcar (nthcdr 3 info) newmarked)
5500 ;; Add the marks lists to the end of the info.
5501 (when newmarked
5502 (setcdr (nthcdr 2 info) (list newmarked))))
5503
5504 ;; Cut off the end of the info if there's nothing else there.
5505 (let ((i 5))
5506 (while (and (> i 2)
5507 (not (nth i info)))
5508 (when (nthcdr (decf i) info)
5509 (setcdr (nthcdr i info) nil)))))))
5510
5511(defun gnus-set-mode-line (where)
16409b0b 5512 "Set the mode line of the article or summary buffers.
eec82323
LMI
5513If WHERE is `summary', the summary mode line format will be used."
5514 ;; Is this mode line one we keep updated?
16409b0b
GM
5515 (when (and (memq where gnus-updated-mode-lines)
5516 (symbol-value
5517 (intern (format "gnus-%s-mode-line-format-spec" where))))
eec82323
LMI
5518 (let (mode-string)
5519 (save-excursion
5520 ;; We evaluate this in the summary buffer since these
5521 ;; variables are buffer-local to that buffer.
5522 (set-buffer gnus-summary-buffer)
23f87bed 5523 ;; We bind all these variables that are used in the `eval' form
eec82323
LMI
5524 ;; below.
5525 (let* ((mformat (symbol-value
5526 (intern
5527 (format "gnus-%s-mode-line-format-spec" where))))
23f87bed
MB
5528 (gnus-tmp-group-name (gnus-group-decoded-name
5529 gnus-newsgroup-name))
eec82323
LMI
5530 (gnus-tmp-article-number (or gnus-current-article 0))
5531 (gnus-tmp-unread gnus-newsgroup-unreads)
5532 (gnus-tmp-unread-and-unticked (length gnus-newsgroup-unreads))
5533 (gnus-tmp-unselected (length gnus-newsgroup-unselected))
5534 (gnus-tmp-unread-and-unselected
5535 (cond ((and (zerop gnus-tmp-unread-and-unticked)
5536 (zerop gnus-tmp-unselected))
5537 "")
5538 ((zerop gnus-tmp-unselected)
5539 (format "{%d more}" gnus-tmp-unread-and-unticked))
5540 (t (format "{%d(+%d) more}"
5541 gnus-tmp-unread-and-unticked
5542 gnus-tmp-unselected))))
5543 (gnus-tmp-subject
5544 (if (and gnus-current-headers
5545 (vectorp gnus-current-headers))
5546 (gnus-mode-string-quote
5547 (mail-header-subject gnus-current-headers))
5548 ""))
5549 bufname-length max-len
23f87bed 5550 gnus-tmp-header) ;; passed as argument to any user-format-funcs
eec82323
LMI
5551 (setq mode-string (eval mformat))
5552 (setq bufname-length (if (string-match "%b" mode-string)
5553 (- (length
5554 (buffer-name
5555 (if (eq where 'summary)
5556 nil
5557 (get-buffer gnus-article-buffer))))
5558 2)
5559 0))
5560 (setq max-len (max 4 (if gnus-mode-non-string-length
5561 (- (window-width)
5562 gnus-mode-non-string-length
5563 bufname-length)
5564 (length mode-string))))
5565 ;; We might have to chop a bit of the string off...
5566 (when (> (length mode-string) max-len)
5567 (setq mode-string
16409b0b 5568 (concat (truncate-string-to-width mode-string (- max-len 3))
eec82323
LMI
5569 "...")))
5570 ;; Pad the mode string a bit.
5571 (setq mode-string (format (format "%%-%ds" max-len) mode-string))))
5572 ;; Update the mode line.
5573 (setq mode-line-buffer-identification
5574 (gnus-mode-line-buffer-identification (list mode-string)))
5575 (set-buffer-modified-p t))))
5576
5577(defun gnus-create-xref-hashtb (from-newsgroup headers unreads)
5578 "Go through the HEADERS list and add all Xrefs to a hash table.
5579The resulting hash table is returned, or nil if no Xrefs were found."
5580 (let* ((virtual (gnus-virtual-group-p from-newsgroup))
5581 (prefix (if virtual "" (gnus-group-real-prefix from-newsgroup)))
5582 (xref-hashtb (gnus-make-hashtable))
5583 start group entry number xrefs header)
5584 (while headers
5585 (setq header (pop headers))
5586 (when (and (setq xrefs (mail-header-xref header))
5587 (not (memq (setq number (mail-header-number header))
5588 unreads)))
5589 (setq start 0)
5590 (while (string-match "\\([^ ]+\\)[:/]\\([0-9]+\\)" xrefs start)
5591 (setq start (match-end 0))
5592 (setq group (if prefix
5593 (concat prefix (substring xrefs (match-beginning 1)
5594 (match-end 1)))
5595 (substring xrefs (match-beginning 1) (match-end 1))))
5596 (setq number
5597 (string-to-int (substring xrefs (match-beginning 2)
5598 (match-end 2))))
5599 (if (setq entry (gnus-gethash group xref-hashtb))
5600 (setcdr entry (cons number (cdr entry)))
5601 (gnus-sethash group (cons number nil) xref-hashtb)))))
5602 (and start xref-hashtb)))
5603
5604(defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
5605 "Look through all the headers and mark the Xrefs as read."
5606 (let ((virtual (gnus-virtual-group-p from-newsgroup))
5607 name entry info xref-hashtb idlist method nth4)
5608 (save-excursion
5609 (set-buffer gnus-group-buffer)
5610 (when (setq xref-hashtb
5611 (gnus-create-xref-hashtb from-newsgroup headers unreads))
5612 (mapatoms
5613 (lambda (group)
5614 (unless (string= from-newsgroup (setq name (symbol-name group)))
5615 (setq idlist (symbol-value group))
5616 ;; Dead groups are not updated.
5617 (and (prog1
5618 (setq entry (gnus-gethash name gnus-newsrc-hashtb)
5619 info (nth 2 entry))
5620 (when (stringp (setq nth4 (gnus-info-method info)))
5621 (setq nth4 (gnus-server-to-method nth4))))
5622 ;; Only do the xrefs if the group has the same
5623 ;; select method as the group we have just read.
5624 (or (gnus-methods-equal-p
5625 nth4 (gnus-find-method-for-group from-newsgroup))
5626 virtual
5627 (equal nth4 (setq method (gnus-find-method-for-group
5628 from-newsgroup)))
5629 (and (equal (car nth4) (car method))
5630 (equal (nth 1 nth4) (nth 1 method))))
5631 gnus-use-cross-reference
5632 (or (not (eq gnus-use-cross-reference t))
5633 virtual
5634 ;; Only do cross-references on subscribed
5635 ;; groups, if that is what is wanted.
5636 (<= (gnus-info-level info) gnus-level-subscribed))
5637 (gnus-group-make-articles-read name idlist))))
5638 xref-hashtb)))))
5639
6748645f
LMI
5640(defun gnus-compute-read-articles (group articles)
5641 (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
5642 (info (nth 2 entry))
5643 (active (gnus-active group))
5644 ninfo)
5645 (when entry
16409b0b 5646 ;; First peel off all invalid article numbers.
6748645f
LMI
5647 (when active
5648 (let ((ids articles)
5649 id first)
5650 (while (setq id (pop ids))
5651 (when (and first (> id (cdr active)))
5652 ;; We'll end up in this situation in one particular
5653 ;; obscure situation. If you re-scan a group and get
5654 ;; a new article that is cross-posted to a different
5655 ;; group that has not been re-scanned, you might get
5656 ;; crossposted article that has a higher number than
5657 ;; Gnus believes possible. So we re-activate this
5658 ;; group as well. This might mean doing the
5659 ;; crossposting thingy will *increase* the number
5660 ;; of articles in some groups. Tsk, tsk.
5661 (setq active (or (gnus-activate-group group) active)))
5662 (when (or (> id (cdr active))
5663 (< id (car active)))
5664 (setq articles (delq id articles))))))
5665 ;; If the read list is nil, we init it.
5666 (if (and active
5667 (null (gnus-info-read info))
5668 (> (car active) 1))
5669 (setq ninfo (cons 1 (1- (car active))))
5670 (setq ninfo (gnus-info-read info)))
5671 ;; Then we add the read articles to the range.
5672 (gnus-add-to-range
5673 ninfo (setq articles (sort articles '<))))))
5674
eec82323
LMI
5675(defun gnus-group-make-articles-read (group articles)
5676 "Update the info of GROUP to say that ARTICLES are read."
5677 (let* ((num 0)
5678 (entry (gnus-gethash group gnus-newsrc-hashtb))
5679 (info (nth 2 entry))
5680 (active (gnus-active group))
5681 range)
6748645f
LMI
5682 (when entry
5683 (setq range (gnus-compute-read-articles group articles))
5684 (save-excursion
5685 (set-buffer gnus-group-buffer)
5686 (gnus-undo-register
5687 `(progn
5688 (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
5689 (gnus-info-set-read ',info ',(gnus-info-read info))
5690 (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
23f87bed 5691 (gnus-request-set-mark ,group (list (list ',range 'del '(read))))
6748645f
LMI
5692 (gnus-group-update-group ,group t))))
5693 ;; Add the read articles to the range.
5694 (gnus-info-set-read info range)
23f87bed 5695 (gnus-request-set-mark group (list (list range 'add '(read))))
6748645f
LMI
5696 ;; Then we have to re-compute how many unread
5697 ;; articles there are in this group.
5698 (when active
5699 (cond
5700 ((not range)
5701 (setq num (- (1+ (cdr active)) (car active))))
5702 ((not (listp (cdr range)))
5703 (setq num (- (cdr active) (- (1+ (cdr range))
5704 (car range)))))
5705 (t
5706 (while range
5707 (if (numberp (car range))
5708 (setq num (1+ num))
5709 (setq num (+ num (- (1+ (cdar range)) (caar range)))))
5710 (setq range (cdr range)))
5711 (setq num (- (cdr active) num))))
5712 ;; Update the number of unread articles.
5713 (setcar entry num)
5714 ;; Update the group buffer.
23f87bed
MB
5715 (unless (gnus-ephemeral-group-p group)
5716 (gnus-group-update-group group t))))))
eec82323 5717
eec82323
LMI
5718(defvar gnus-newsgroup-none-id 0)
5719
5720(defun gnus-get-newsgroup-headers (&optional dependencies force-new)
5721 (let ((cur nntp-server-buffer)
5722 (dependencies
5723 (or dependencies
5724 (save-excursion (set-buffer gnus-summary-buffer)
5725 gnus-newsgroup-dependencies)))
16409b0b
GM
5726 headers id end ref
5727 (mail-parse-charset gnus-newsgroup-charset)
5728 (mail-parse-ignored-charsets
5729 (save-excursion (condition-case nil
5730 (set-buffer gnus-summary-buffer)
5731 (error))
5732 gnus-newsgroup-ignored-charsets)))
eec82323
LMI
5733 (save-excursion
5734 (set-buffer nntp-server-buffer)
5735 ;; Translate all TAB characters into SPACE characters.
5736 (subst-char-in-region (point-min) (point-max) ?\t ? t)
16409b0b 5737 (subst-char-in-region (point-min) (point-max) ?\r ? t)
23f87bed 5738 (ietf-drums-unfold-fws)
6748645f 5739 (gnus-run-hooks 'gnus-parse-headers-hook)
eec82323 5740 (let ((case-fold-search t)
6748645f 5741 in-reply-to header p lines chars)
eec82323
LMI
5742 (goto-char (point-min))
5743 ;; Search to the beginning of the next header. Error messages
5744 ;; do not begin with 2 or 3.
5745 (while (re-search-forward "^[23][0-9]+ " nil t)
5746 (setq id nil
5747 ref nil)
5748 ;; This implementation of this function, with nine
5749 ;; search-forwards instead of the one re-search-forward and
5750 ;; a case (which basically was the old function) is actually
5751 ;; about twice as fast, even though it looks messier. You
5752 ;; can't have everything, I guess. Speed and elegance
5753 ;; doesn't always go hand in hand.
5754 (setq
5755 header
5756 (vector
5757 ;; Number.
5758 (prog1
5759 (read cur)
5760 (end-of-line)
5761 (setq p (point))
5762 (narrow-to-region (point)
5763 (or (and (search-forward "\n.\n" nil t)
5764 (- (point) 2))
5765 (point))))
5766 ;; Subject.
5767 (progn
5768 (goto-char p)
23f87bed 5769 (if (search-forward "\nsubject:" nil t)
16409b0b
GM
5770 (funcall gnus-decode-encoded-word-function
5771 (nnheader-header-value))
2bd3dcae 5772 "(none)"))
eec82323
LMI
5773 ;; From.
5774 (progn
5775 (goto-char p)
23f87bed 5776 (if (search-forward "\nfrom:" nil t)
16409b0b
GM
5777 (funcall gnus-decode-encoded-word-function
5778 (nnheader-header-value))
2bd3dcae 5779 "(nobody)"))
eec82323
LMI
5780 ;; Date.
5781 (progn
5782 (goto-char p)
23f87bed 5783 (if (search-forward "\ndate:" nil t)
eec82323
LMI
5784 (nnheader-header-value) ""))
5785 ;; Message-ID.
5786 (progn
5787 (goto-char p)
6748645f
LMI
5788 (setq id (if (re-search-forward
5789 "^message-id: *\\(<[^\n\t> ]+>\\)" nil t)
5790 ;; We do it this way to make sure the Message-ID
5791 ;; is (somewhat) syntactically valid.
5792 (buffer-substring (match-beginning 1)
5793 (match-end 1))
eec82323
LMI
5794 ;; If there was no message-id, we just fake one
5795 ;; to make subsequent routines simpler.
5796 (nnheader-generate-fake-message-id))))
5797 ;; References.
5798 (progn
5799 (goto-char p)
23f87bed 5800 (if (search-forward "\nreferences:" nil t)
eec82323
LMI
5801 (progn
5802 (setq end (point))
5803 (prog1
5804 (nnheader-header-value)
5805 (setq ref
5806 (buffer-substring
5807 (progn
5808 (end-of-line)
5809 (search-backward ">" end t)
5810 (1+ (point)))
5811 (progn
5812 (search-backward "<" end t)
5813 (point))))))
5814 ;; Get the references from the in-reply-to header if there
5815 ;; were no references and the in-reply-to header looks
5816 ;; promising.
23f87bed 5817 (if (and (search-forward "\nin-reply-to:" nil t)
eec82323
LMI
5818 (setq in-reply-to (nnheader-header-value))
5819 (string-match "<[^>]+>" in-reply-to))
6748645f
LMI
5820 (let (ref2)
5821 (setq ref (substring in-reply-to (match-beginning 0)
5822 (match-end 0)))
5823 (while (string-match "<[^>]+>" in-reply-to (match-end 0))
5824 (setq ref2 (substring in-reply-to (match-beginning 0)
5825 (match-end 0)))
5826 (when (> (length ref2) (length ref))
5827 (setq ref ref2)))
5828 ref)
eec82323
LMI
5829 (setq ref nil))))
5830 ;; Chars.
6748645f
LMI
5831 (progn
5832 (goto-char p)
5833 (if (search-forward "\nchars: " nil t)
5834 (if (numberp (setq chars (ignore-errors (read cur))))
23f87bed
MB
5835 chars -1)
5836 -1))
eec82323
LMI
5837 ;; Lines.
5838 (progn
5839 (goto-char p)
5840 (if (search-forward "\nlines: " nil t)
a8151ef7 5841 (if (numberp (setq lines (ignore-errors (read cur))))
23f87bed
MB
5842 lines -1)
5843 -1))
eec82323
LMI
5844 ;; Xref.
5845 (progn
5846 (goto-char p)
23f87bed 5847 (and (search-forward "\nxref:" nil t)
16409b0b
GM
5848 (nnheader-header-value)))
5849 ;; Extra.
5850 (when gnus-extra-headers
5851 (let ((extra gnus-extra-headers)
5852 out)
5853 (while extra
5854 (goto-char p)
5855 (when (search-forward
23f87bed 5856 (concat "\n" (symbol-name (car extra)) ":") nil t)
16409b0b
GM
5857 (push (cons (car extra) (nnheader-header-value))
5858 out))
5859 (pop extra))
5860 out))))
eec82323
LMI
5861 (when (equal id ref)
5862 (setq ref nil))
6748645f
LMI
5863
5864 (when gnus-alter-header-function
5865 (funcall gnus-alter-header-function header)
5866 (setq id (mail-header-id header)
5867 ref (gnus-parent-id (mail-header-references header))))
5868
5869 (when (setq header
5870 (gnus-dependencies-add-header
5871 header dependencies force-new))
eec82323
LMI
5872 (push header headers))
5873 (goto-char (point-max))
5874 (widen))
5875 (nreverse headers)))))
5876
eec82323
LMI
5877;; Goes through the xover lines and returns a list of vectors
5878(defun gnus-get-newsgroup-headers-xover (sequence &optional
5879 force-new dependencies
5880 group also-fetch-heads)
16409b0b
GM
5881 "Parse the news overview data in the server buffer.
5882Return a list of headers that match SEQUENCE (see
5883`nntp-retrieve-headers')."
eec82323
LMI
5884 ;; Get the Xref when the users reads the articles since most/some
5885 ;; NNTP servers do not include Xrefs when using XOVER.
5886 (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
16409b0b
GM
5887 (let ((mail-parse-charset gnus-newsgroup-charset)
5888 (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
5889 (cur nntp-server-buffer)
eec82323 5890 (dependencies (or dependencies gnus-newsgroup-dependencies))
23f87bed
MB
5891 (allp (cond
5892 ((eq gnus-read-all-available-headers t)
5893 t)
5894 ((stringp gnus-read-all-available-headers)
5895 (string-match gnus-read-all-available-headers group))
5896 (t
5897 nil)))
eec82323
LMI
5898 number headers header)
5899 (save-excursion
5900 (set-buffer nntp-server-buffer)
16409b0b 5901 (subst-char-in-region (point-min) (point-max) ?\r ? t)
eec82323 5902 ;; Allow the user to mangle the headers before parsing them.
6748645f 5903 (gnus-run-hooks 'gnus-parse-headers-hook)
eec82323 5904 (goto-char (point-min))
23f87bed
MB
5905 (gnus-parse-without-error
5906 (while (and (or sequence allp)
5907 (not (eobp)))
5908 (setq number (read cur))
5909 (when (not allp)
5910 (while (and sequence
5911 (< (car sequence) number))
5912 (setq sequence (cdr sequence))))
5913 (when (and (or allp
5914 (and sequence
5915 (eq number (car sequence))))
5916 (progn
5917 (setq sequence (cdr sequence))
5918 (setq header (inline
5919 (gnus-nov-parse-line
5920 number dependencies force-new)))))
5921 (push header headers))
5922 (forward-line 1)))
eec82323
LMI
5923 ;; A common bug in inn is that if you have posted an article and
5924 ;; then retrieves the active file, it will answer correctly --
5925 ;; the new article is included. However, a NOV entry for the
5926 ;; article may not have been generated yet, so this may fail.
5927 ;; We work around this problem by retrieving the last few
5928 ;; headers using HEAD.
5929 (if (or (not also-fetch-heads)
5930 (not sequence))
5931 ;; We (probably) got all the headers.
5932 (nreverse headers)
5933 (let ((gnus-nov-is-evil t))
5934 (nconc
5935 (nreverse headers)
23f87bed 5936 (when (eq (gnus-retrieve-headers sequence group) 'headers)
eec82323
LMI
5937 (gnus-get-newsgroup-headers))))))))
5938
5939(defun gnus-article-get-xrefs ()
5940 "Fill in the Xref value in `gnus-current-headers', if necessary.
5941This is meant to be called in `gnus-article-internal-prepare-hook'."
5942 (let ((headers (save-excursion (set-buffer gnus-summary-buffer)
5943 gnus-current-headers)))
5944 (or (not gnus-use-cross-reference)
5945 (not headers)
5946 (and (mail-header-xref headers)
5947 (not (string= (mail-header-xref headers) "")))
5948 (let ((case-fold-search t)
5949 xref)
5950 (save-restriction
5951 (nnheader-narrow-to-headers)
5952 (goto-char (point-min))
16409b0b
GM
5953 (when (or (and (not (eobp))
5954 (eq (downcase (char-after)) ?x)
eec82323
LMI
5955 (looking-at "Xref:"))
5956 (search-forward "\nXref:" nil t))
5957 (goto-char (1+ (match-end 0)))
23f87bed 5958 (setq xref (buffer-substring (point) (gnus-point-at-eol)))
eec82323
LMI
5959 (mail-header-set-xref headers xref)))))))
5960
5961(defun gnus-summary-insert-subject (id &optional old-header use-old-header)
6748645f
LMI
5962 "Find article ID and insert the summary line for that article.
5963OLD-HEADER can either be a header or a line number to insert
5964the subject line on."
5965 (let* ((line (and (numberp old-header) old-header))
5966 (old-header (and (vectorp old-header) old-header))
5967 (header (cond ((and old-header use-old-header)
16409b0b
GM
5968 old-header)
5969 ((and (numberp id)
5970 (gnus-number-to-header id))
5971 (gnus-number-to-header id))
5972 (t
5973 (gnus-read-header id))))
5974 (number (and (numberp id) id))
5975 d)
eec82323
LMI
5976 (when header
5977 ;; Rebuild the thread that this article is part of and go to the
5978 ;; article we have fetched.
5979 (when (and (not gnus-show-threads)
5980 old-header)
6748645f
LMI
5981 (when (and number
5982 (setq d (gnus-data-find (mail-header-number old-header))))
eec82323
LMI
5983 (goto-char (gnus-data-pos d))
5984 (gnus-data-remove
5985 number
5986 (- (gnus-point-at-bol)
5987 (prog1
5988 (1+ (gnus-point-at-eol))
5989 (gnus-delete-line))))))
23f87bed
MB
5990 ;; Remove list identifiers from subject.
5991 (when gnus-list-identifiers
5992 (let ((gnus-newsgroup-headers (list header)))
5993 (gnus-summary-remove-list-identifiers)
5994 (setq header (car gnus-newsgroup-headers))))
eec82323
LMI
5995 (when old-header
5996 (mail-header-set-number header (mail-header-number old-header)))
5997 (setq gnus-newsgroup-sparse
5998 (delq (setq number (mail-header-number header))
5999 gnus-newsgroup-sparse))
6000 (setq gnus-newsgroup-ancient (delq number gnus-newsgroup-ancient))
6748645f
LMI
6001 (push number gnus-newsgroup-limit)
6002 (gnus-rebuild-thread (mail-header-id header) line)
eec82323
LMI
6003 (gnus-summary-goto-subject number nil t))
6004 (when (and (numberp number)
6005 (> number 0))
6006 ;; We have to update the boundaries even if we can't fetch the
6007 ;; article if ID is a number -- so that the next `P' or `N'
6008 ;; command will fetch the previous (or next) article even
6009 ;; if the one we tried to fetch this time has been canceled.
6010 (when (> number gnus-newsgroup-end)
6011 (setq gnus-newsgroup-end number))
6012 (when (< number gnus-newsgroup-begin)
6013 (setq gnus-newsgroup-begin number))
6014 (setq gnus-newsgroup-unselected
6015 (delq number gnus-newsgroup-unselected)))
6016 ;; Report back a success?
6017 (and header (mail-header-number header))))
6018
6019;;; Process/prefix in the summary buffer
6020
6021(defun gnus-summary-work-articles (n)
6748645f
LMI
6022 "Return a list of articles to be worked upon.
6023The prefix argument, the list of process marked articles, and the
6024current article will be taken into consideration."
6025 (save-excursion
6026 (set-buffer gnus-summary-buffer)
6027 (cond
6028 (n
6029 ;; A numerical prefix has been given.
6030 (setq n (prefix-numeric-value n))
6031 (let ((backward (< n 0))
6032 (n (abs (prefix-numeric-value n)))
6033 articles article)
6034 (save-excursion
6035 (while
6036 (and (> n 0)
6037 (push (setq article (gnus-summary-article-number))
6038 articles)
6039 (if backward
6040 (gnus-summary-find-prev nil article)
6041 (gnus-summary-find-next nil article)))
6042 (decf n)))
6043 (nreverse articles)))
6044 ((and (gnus-region-active-p) (mark))
6045 (message "region active")
6046 ;; Work on the region between point and mark.
6047 (let ((max (max (point) (mark)))
6048 articles article)
6049 (save-excursion
6050 (goto-char (min (min (point) (mark))))
6051 (while
6052 (and
6053 (push (setq article (gnus-summary-article-number)) articles)
6054 (gnus-summary-find-next nil article)
6055 (< (point) max)))
6056 (nreverse articles))))
6057 (gnus-newsgroup-processable
6058 ;; There are process-marked articles present.
6059 ;; Save current state.
6060 (gnus-summary-save-process-mark)
6061 ;; Return the list.
6062 (reverse gnus-newsgroup-processable))
6063 (t
6064 ;; Just return the current article.
6065 (list (gnus-summary-article-number))))))
6066
6067(defmacro gnus-summary-iterate (arg &rest forms)
6068 "Iterate over the process/prefixed articles and do FORMS.
6069ARG is the interactive prefix given to the command. FORMS will be
6070executed with point over the summary line of the articles."
6071 (let ((articles (make-symbol "gnus-summary-iterate-articles")))
6072 `(let ((,articles (gnus-summary-work-articles ,arg)))
6073 (while ,articles
6074 (gnus-summary-goto-subject (car ,articles))
16409b0b
GM
6075 ,@forms
6076 (pop ,articles)))))
6748645f
LMI
6077
6078(put 'gnus-summary-iterate 'lisp-indent-function 1)
6079(put 'gnus-summary-iterate 'edebug-form-spec '(form body))
eec82323
LMI
6080
6081(defun gnus-summary-save-process-mark ()
6082 "Push the current set of process marked articles on the stack."
6083 (interactive)
6084 (push (copy-sequence gnus-newsgroup-processable)
6085 gnus-newsgroup-process-stack))
6086
6087(defun gnus-summary-kill-process-mark ()
6088 "Push the current set of process marked articles on the stack and unmark."
6089 (interactive)
6090 (gnus-summary-save-process-mark)
6091 (gnus-summary-unmark-all-processable))
6092
6093(defun gnus-summary-yank-process-mark ()
6094 "Pop the last process mark state off the stack and restore it."
6095 (interactive)
6096 (unless gnus-newsgroup-process-stack
6097 (error "Empty mark stack"))
6098 (gnus-summary-process-mark-set (pop gnus-newsgroup-process-stack)))
6099
6100(defun gnus-summary-process-mark-set (set)
6101 "Make SET into the current process marked articles."
6102 (gnus-summary-unmark-all-processable)
6103 (while set
6104 (gnus-summary-set-process-mark (pop set))))
6105
6106;;; Searching and stuff
6107
6108(defun gnus-summary-search-group (&optional backward use-level)
6109 "Search for next unread newsgroup.
6110If optional argument BACKWARD is non-nil, search backward instead."
6111 (save-excursion
6112 (set-buffer gnus-group-buffer)
6113 (when (gnus-group-search-forward
6114 backward nil (if use-level (gnus-group-group-level) nil))
6115 (gnus-group-group-name))))
6116
6117(defun gnus-summary-best-group (&optional exclude-group)
6118 "Find the name of the best unread group.
6119If EXCLUDE-GROUP, do not go to this group."
6120 (save-excursion
6121 (set-buffer gnus-group-buffer)
6122 (save-excursion
6123 (gnus-group-best-unread-group exclude-group))))
6124
23f87bed
MB
6125(defun gnus-summary-find-next (&optional unread article backward)
6126 (if backward
6127 (gnus-summary-find-prev unread article)
eec82323
LMI
6128 (let* ((dummy (gnus-summary-article-intangible-p))
6129 (article (or article (gnus-summary-article-number)))
23f87bed 6130 (data (gnus-data-find-list article))
eec82323
LMI
6131 result)
6132 (when (and (not dummy)
6133 (or (not gnus-summary-check-current)
6134 (not unread)
23f87bed
MB
6135 (not (gnus-data-unread-p (car data)))))
6136 (setq data (cdr data)))
eec82323
LMI
6137 (when (setq result
6138 (if unread
6139 (progn
23f87bed
MB
6140 (while data
6141 (unless (memq (gnus-data-number (car data))
6142 (cond
6143 ((eq gnus-auto-goto-ignores
6144 'always-undownloaded)
6145 gnus-newsgroup-undownloaded)
6146 (gnus-plugged
6147 nil)
6148 ((eq gnus-auto-goto-ignores
6149 'unfetched)
6150 gnus-newsgroup-unfetched)
6151 ((eq gnus-auto-goto-ignores
6152 'undownloaded)
6153 gnus-newsgroup-undownloaded)))
6154 (when (gnus-data-unread-p (car data))
6155 (setq result (car data)
6156 data nil)))
6157 (setq data (cdr data)))
eec82323 6158 result)
23f87bed 6159 (car data)))
eec82323
LMI
6160 (goto-char (gnus-data-pos result))
6161 (gnus-data-number result)))))
6162
6163(defun gnus-summary-find-prev (&optional unread article)
6164 (let* ((eobp (eobp))
6165 (article (or article (gnus-summary-article-number)))
23f87bed 6166 (data (gnus-data-find-list article (gnus-data-list 'rev)))
eec82323
LMI
6167 result)
6168 (when (and (not eobp)
6169 (or (not gnus-summary-check-current)
6170 (not unread)
23f87bed
MB
6171 (not (gnus-data-unread-p (car data)))))
6172 (setq data (cdr data)))
eec82323
LMI
6173 (when (setq result
6174 (if unread
6175 (progn
23f87bed
MB
6176 (while data
6177 (unless (memq (gnus-data-number (car data))
6178 (cond
6179 ((eq gnus-auto-goto-ignores
6180 'always-undownloaded)
6181 gnus-newsgroup-undownloaded)
6182 (gnus-plugged
6183 nil)
6184 ((eq gnus-auto-goto-ignores
6185 'unfetched)
6186 gnus-newsgroup-unfetched)
6187 ((eq gnus-auto-goto-ignores
6188 'undownloaded)
6189 gnus-newsgroup-undownloaded)))
6190 (when (gnus-data-unread-p (car data))
6191 (setq result (car data)
6192 data nil)))
6193 (setq data (cdr data)))
eec82323 6194 result)
23f87bed 6195 (car data)))
eec82323
LMI
6196 (goto-char (gnus-data-pos result))
6197 (gnus-data-number result))))
6198
6199(defun gnus-summary-find-subject (subject &optional unread backward article)
6200 (let* ((simp-subject (gnus-simplify-subject-fully subject))
6201 (article (or article (gnus-summary-article-number)))
6202 (articles (gnus-data-list backward))
6203 (arts (gnus-data-find-list article articles))
6204 result)
6205 (when (or (not gnus-summary-check-current)
6206 (not unread)
6207 (not (gnus-data-unread-p (car arts))))
6208 (setq arts (cdr arts)))
6209 (while arts
6210 (and (or (not unread)
6211 (gnus-data-unread-p (car arts)))
6212 (vectorp (gnus-data-header (car arts)))
6213 (gnus-subject-equal
6214 simp-subject (mail-header-subject (gnus-data-header (car arts))) t)
6215 (setq result (car arts)
6216 arts nil))
6217 (setq arts (cdr arts)))
6218 (and result
6219 (goto-char (gnus-data-pos result))
6220 (gnus-data-number result))))
6221
6222(defun gnus-summary-search-forward (&optional unread subject backward)
6223 "Search forward for an article.
6224If UNREAD, look for unread articles. If SUBJECT, look for
6225articles with that subject. If BACKWARD, search backward instead."
6226 (cond (subject (gnus-summary-find-subject subject unread backward))
6227 (backward (gnus-summary-find-prev unread))
6228 (t (gnus-summary-find-next unread))))
6229
6230(defun gnus-recenter (&optional n)
6231 "Center point in window and redisplay frame.
6232Also do horizontal recentering."
6233 (interactive "P")
6234 (when (and gnus-auto-center-summary
6235 (not (eq gnus-auto-center-summary 'vertical)))
6236 (gnus-horizontal-recenter))
6237 (recenter n))
6238
6239(defun gnus-summary-recenter ()
6240 "Center point in the summary window.
6241If `gnus-auto-center-summary' is nil, or the article buffer isn't
6242displayed, no centering will be performed."
6243 ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
6244 ;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu.
16409b0b 6245 (interactive)
23f87bed
MB
6246 ;; The user has to want it.
6247 (when gnus-auto-center-summary
6248 (let* ((top (cond ((< (window-height) 4) 0)
6249 ((< (window-height) 7) 1)
6250 (t (if (numberp gnus-auto-center-summary)
6251 gnus-auto-center-summary
6252 2))))
6253 (height (1- (window-height)))
6254 (bottom (save-excursion (goto-char (point-max))
6255 (forward-line (- height))
6256 (point)))
6257 (window (get-buffer-window (current-buffer))))
eec82323
LMI
6258 (when (get-buffer-window gnus-article-buffer)
6259 ;; Only do recentering when the article buffer is displayed,
6260 ;; Set the window start to either `bottom', which is the biggest
6261 ;; possible valid number, or the second line from the top,
6262 ;; whichever is the least.
db7ebd73
MB
6263 (let ((top-pos (save-excursion (forward-line (- top)) (point))))
6264 (if (> bottom top-pos)
6265 ;; Keep the second line from the top visible
6266 (set-window-start window top-pos t)
6267 ;; Try to keep the bottom line visible; if it's partially
6268 ;; obscured, either scroll one more line to make it fully
6269 ;; visible, or revert to using TOP-POS.
6270 (save-excursion
6271 (goto-char (point-max))
6272 (forward-line -1)
6273 (let ((last-line-start (point)))
6274 (goto-char bottom)
6275 (set-window-start window (point) t)
6276 (when (not (pos-visible-in-window-p last-line-start window))
6277 (forward-line 1)
6278 (set-window-start window (min (point) top-pos) t)))))))
eec82323
LMI
6279 ;; Do horizontal recentering while we're at it.
6280 (when (and (get-buffer-window (current-buffer) t)
6281 (not (eq gnus-auto-center-summary 'vertical)))
6282 (let ((selected (selected-window)))
6283 (select-window (get-buffer-window (current-buffer) t))
6284 (gnus-summary-position-point)
6285 (gnus-horizontal-recenter)
6286 (select-window selected))))))
6287
6288(defun gnus-summary-jump-to-group (newsgroup)
6289 "Move point to NEWSGROUP in group mode buffer."
6290 ;; Keep update point of group mode buffer if visible.
6291 (if (eq (current-buffer) (get-buffer gnus-group-buffer))
6292 (save-window-excursion
6293 ;; Take care of tree window mode.
6294 (when (get-buffer-window gnus-group-buffer)
6295 (pop-to-buffer gnus-group-buffer))
6296 (gnus-group-jump-to-group newsgroup))
6297 (save-excursion
6298 ;; Take care of tree window mode.
6299 (if (get-buffer-window gnus-group-buffer)
6300 (pop-to-buffer gnus-group-buffer)
6301 (set-buffer gnus-group-buffer))
6302 (gnus-group-jump-to-group newsgroup))))
6303
6304;; This function returns a list of article numbers based on the
6305;; difference between the ranges of read articles in this group and
6306;; the range of active articles.
6307(defun gnus-list-of-unread-articles (group)
6308 (let* ((read (gnus-info-read (gnus-get-info group)))
6309 (active (or (gnus-active group) (gnus-activate-group group)))
6310 (last (cdr active))
6311 first nlast unread)
6312 ;; If none are read, then all are unread.
6313 (if (not read)
6314 (setq first (car active))
6315 ;; If the range of read articles is a single range, then the
6316 ;; first unread article is the article after the last read
6317 ;; article. Sounds logical, doesn't it?
16409b0b
GM
6318 (if (and (not (listp (cdr read)))
6319 (or (< (car read) (car active))
6320 (progn (setq read (list read))
6321 nil)))
6748645f 6322 (setq first (max (car active) (1+ (cdr read))))
eec82323
LMI
6323 ;; `read' is a list of ranges.
6324 (when (/= (setq nlast (or (and (numberp (car read)) (car read))
6325 (caar read)))
6326 1)
6748645f 6327 (setq first (car active)))
eec82323
LMI
6328 (while read
6329 (when first
6330 (while (< first nlast)
6331 (push first unread)
6332 (setq first (1+ first))))
6333 (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
6334 (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
6335 (setq read (cdr read)))))
6336 ;; And add the last unread articles.
6337 (while (<= first last)
6338 (push first unread)
6339 (setq first (1+ first)))
6340 ;; Return the list of unread articles.
6748645f 6341 (delq 0 (nreverse unread))))
eec82323
LMI
6342
6343(defun gnus-list-of-read-articles (group)
6344 "Return a list of unread, unticked and non-dormant articles."
6345 (let* ((info (gnus-get-info group))
6346 (marked (gnus-info-marks info))
6347 (active (gnus-active group)))
6348 (and info active
23f87bed
MB
6349 (gnus-list-range-difference
6350 (gnus-list-range-difference
6351 (gnus-sorted-complement
6352 (gnus-uncompress-range active)
6353 (gnus-list-of-unread-articles group))
6354 (cdr (assq 'dormant marked)))
6355 (cdr (assq 'tick marked))))))
eec82323
LMI
6356
6357;; Various summary commands
6358
6748645f
LMI
6359(defun gnus-summary-select-article-buffer ()
6360 "Reconfigure windows to show article buffer."
6361 (interactive)
6362 (if (not (gnus-buffer-live-p gnus-article-buffer))
6363 (error "There is no article buffer for this summary buffer")
6364 (gnus-configure-windows 'article)
6365 (select-window (get-buffer-window gnus-article-buffer))))
6366
eec82323
LMI
6367(defun gnus-summary-universal-argument (arg)
6368 "Perform any operation on all articles that are process/prefixed."
6369 (interactive "P")
eec82323
LMI
6370 (let ((articles (gnus-summary-work-articles arg))
6371 func article)
6372 (if (eq
6373 (setq
6374 func
6375 (key-binding
6376 (read-key-sequence
6377 (substitute-command-keys
16409b0b 6378 "\\<gnus-summary-mode-map>\\[gnus-summary-universal-argument]"))))
eec82323
LMI
6379 'undefined)
6380 (gnus-error 1 "Undefined key")
6381 (save-excursion
6382 (while articles
6383 (gnus-summary-goto-subject (setq article (pop articles)))
6384 (let (gnus-newsgroup-processable)
6385 (command-execute func))
6386 (gnus-summary-remove-process-mark article)))))
6387 (gnus-summary-position-point))
6388
6389(defun gnus-summary-toggle-truncation (&optional arg)
6390 "Toggle truncation of summary lines.
23f87bed 6391With ARG, turn line truncation on if ARG is positive."
eec82323
LMI
6392 (interactive "P")
6393 (setq truncate-lines
6394 (if (null arg) (not truncate-lines)
6395 (> (prefix-numeric-value arg) 0)))
6396 (redraw-display))
6397
23f87bed
MB
6398(defun gnus-summary-find-for-reselect ()
6399 "Return the number of an article to stay on across a reselect.
6400The current article is considered, then following articles, then previous
6401articles. An article is sought which is not cancelled and isn't a temporary
6402insertion from another group. If there's no such then return a dummy 0."
6403 (let (found)
6404 (dolist (rev '(nil t))
6405 (unless found ; don't demand the reverse list if we don't need it
6406 (let ((data (gnus-data-find-list
6407 (gnus-summary-article-number) (gnus-data-list rev))))
6408 (while (and data (not found))
6409 (if (and (< 0 (gnus-data-number (car data)))
6410 (not (eq gnus-canceled-mark (gnus-data-mark (car data)))))
6411 (setq found (gnus-data-number (car data))))
6412 (setq data (cdr data))))))
6413 (or found 0)))
6414
eec82323
LMI
6415(defun gnus-summary-reselect-current-group (&optional all rescan)
6416 "Exit and then reselect the current newsgroup.
6417The prefix argument ALL means to select all articles."
6418 (interactive "P")
eec82323
LMI
6419 (when (gnus-ephemeral-group-p gnus-newsgroup-name)
6420 (error "Ephemeral groups can't be reselected"))
23f87bed 6421 (let ((current-subject (gnus-summary-find-for-reselect))
eec82323
LMI
6422 (group gnus-newsgroup-name))
6423 (setq gnus-newsgroup-begin nil)
23f87bed 6424 (gnus-summary-exit nil 'leave-hidden)
eec82323
LMI
6425 ;; We have to adjust the point of group mode buffer because
6426 ;; point was moved to the next unread newsgroup by exiting.
6427 (gnus-summary-jump-to-group group)
6428 (when rescan
6429 (save-excursion
6430 (gnus-group-get-new-news-this-group 1)))
6431 (gnus-group-read-group all t)
6432 (gnus-summary-goto-subject current-subject nil t)))
6433
6434(defun gnus-summary-rescan-group (&optional all)
6435 "Exit the newsgroup, ask for new articles, and select the newsgroup."
6436 (interactive "P")
6437 (gnus-summary-reselect-current-group all t))
6438
6439(defun gnus-summary-update-info (&optional non-destructive)
6440 (save-excursion
6441 (let ((group gnus-newsgroup-name))
6748645f
LMI
6442 (when group
6443 (when gnus-newsgroup-kill-headers
6444 (setq gnus-newsgroup-killed
6445 (gnus-compress-sequence
23f87bed
MB
6446 (gnus-sorted-union
6447 (gnus-list-range-intersection
6448 gnus-newsgroup-unselected gnus-newsgroup-killed)
6449 gnus-newsgroup-unreads)
6748645f
LMI
6450 t)))
6451 (unless (listp (cdr gnus-newsgroup-killed))
6452 (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
6453 (let ((headers gnus-newsgroup-headers))
6454 ;; Set the new ranges of read articles.
6455 (save-excursion
6456 (set-buffer gnus-group-buffer)
6457 (gnus-undo-force-boundary))
6458 (gnus-update-read-articles
23f87bed
MB
6459 group (gnus-sorted-union
6460 gnus-newsgroup-unreads gnus-newsgroup-unselected))
6748645f
LMI
6461 ;; Set the current article marks.
6462 (let ((gnus-newsgroup-scored
6463 (if (and (not gnus-save-score)
6464 (not non-destructive))
6465 nil
6466 gnus-newsgroup-scored)))
6467 (save-excursion
6468 (gnus-update-marks)))
6469 ;; Do the cross-ref thing.
6470 (when gnus-use-cross-reference
6471 (gnus-mark-xrefs-as-read group headers gnus-newsgroup-unreads))
6472 ;; Do not switch windows but change the buffer to work.
a8151ef7 6473 (set-buffer gnus-group-buffer)
6748645f
LMI
6474 (unless (gnus-ephemeral-group-p group)
6475 (gnus-group-update-group group)))))))
eec82323
LMI
6476
6477(defun gnus-summary-save-newsrc (&optional force)
6478 "Save the current number of read/marked articles in the dribble buffer.
6479The dribble buffer will then be saved.
6480If FORCE (the prefix), also save the .newsrc file(s)."
6481 (interactive "P")
6482 (gnus-summary-update-info t)
6483 (if force
6484 (gnus-save-newsrc-file)
6485 (gnus-dribble-save)))
6486
23f87bed 6487(defun gnus-summary-exit (&optional temporary leave-hidden)
eec82323 6488 "Exit reading current newsgroup, and then return to group selection mode.
16409b0b 6489`gnus-exit-group-hook' is called with no arguments if that value is non-nil."
eec82323
LMI
6490 (interactive)
6491 (gnus-set-global-variables)
16409b0b
GM
6492 (when (gnus-buffer-live-p gnus-article-buffer)
6493 (save-excursion
6494 (set-buffer gnus-article-buffer)
6495 (mm-destroy-parts gnus-article-mime-handles)
6496 ;; Set it to nil for safety reason.
6497 (setq gnus-article-mime-handle-alist nil)
6498 (setq gnus-article-mime-handles nil)))
eec82323 6499 (gnus-kill-save-kill-buffer)
6748645f 6500 (gnus-async-halt-prefetch)
eec82323
LMI
6501 (let* ((group gnus-newsgroup-name)
6502 (quit-config (gnus-group-quit-config gnus-newsgroup-name))
23f87bed 6503 (gnus-group-is-exiting-p t)
eec82323 6504 (mode major-mode)
23f87bed 6505 (group-point nil)
eec82323 6506 (buf (current-buffer)))
16409b0b
GM
6507 (unless quit-config
6508 ;; Do adaptive scoring, and possibly save score files.
6509 (when gnus-newsgroup-adaptive
6510 (gnus-score-adaptive))
6511 (when gnus-use-scoring
6512 (gnus-score-save)))
6748645f 6513 (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
eec82323
LMI
6514 ;; If we have several article buffers, we kill them at exit.
6515 (unless gnus-single-article-buffer
6516 (gnus-kill-buffer gnus-original-article-buffer)
6517 (setq gnus-article-current nil))
6518 (when gnus-use-cache
6519 (gnus-cache-possibly-remove-articles)
6520 (gnus-cache-save-buffers))
6521 (gnus-async-prefetch-remove-group group)
6522 (when gnus-suppress-duplicates
6523 (gnus-dup-enter-articles))
6524 (when gnus-use-trees
6525 (gnus-tree-close group))
16409b0b
GM
6526 (when gnus-use-cache
6527 (gnus-cache-write-active))
6748645f
LMI
6528 ;; Remove entries for this group.
6529 (nnmail-purge-split-history (gnus-group-real-name group))
eec82323
LMI
6530 ;; Make all changes in this group permanent.
6531 (unless quit-config
6748645f 6532 (gnus-run-hooks 'gnus-exit-group-hook)
16409b0b 6533 (gnus-summary-update-info))
eec82323
LMI
6534 (gnus-close-group group)
6535 ;; Make sure where we were, and go to next newsgroup.
6536 (set-buffer gnus-group-buffer)
6537 (unless quit-config
6538 (gnus-group-jump-to-group group))
6748645f
LMI
6539 (gnus-run-hooks 'gnus-summary-exit-hook)
6540 (unless (or quit-config
6541 ;; If this group has disappeared from the summary
6542 ;; buffer, don't skip forwards.
6543 (not (string= group (gnus-group-group-name))))
eec82323 6544 (gnus-group-next-unread-group 1))
a8151ef7 6545 (setq group-point (point))
eec82323
LMI
6546 (if temporary
6547 nil ;Nothing to do.
6548 ;; If we have several article buffers, we kill them at exit.
6549 (unless gnus-single-article-buffer
6550 (gnus-kill-buffer gnus-article-buffer)
6551 (gnus-kill-buffer gnus-original-article-buffer)
6552 (setq gnus-article-current nil))
6553 (set-buffer buf)
6554 (if (not gnus-kill-summary-on-exit)
23f87bed
MB
6555 (progn
6556 (gnus-deaden-summary)
6557 (setq mode nil))
eec82323
LMI
6558 ;; We set all buffer-local variables to nil. It is unclear why
6559 ;; this is needed, but if we don't, buffer-local variables are
6560 ;; not garbage-collected, it seems. This would the lead to en
6561 ;; ever-growing Emacs.
6562 (gnus-summary-clear-local-variables)
23f87bed
MB
6563 (let ((gnus-summary-local-variables gnus-newsgroup-variables))
6564 (gnus-summary-clear-local-variables))
eec82323
LMI
6565 (when (get-buffer gnus-article-buffer)
6566 (bury-buffer gnus-article-buffer))
6567 ;; We clear the global counterparts of the buffer-local
6568 ;; variables as well, just to be on the safe side.
6569 (set-buffer gnus-group-buffer)
6570 (gnus-summary-clear-local-variables)
23f87bed
MB
6571 (let ((gnus-summary-local-variables gnus-newsgroup-variables))
6572 (gnus-summary-clear-local-variables))
eec82323
LMI
6573 ;; Return to group mode buffer.
6574 (when (eq mode 'gnus-summary-mode)
6575 (gnus-kill-buffer buf)))
6576 (setq gnus-current-select-method gnus-select-method)
23f87bed
MB
6577 (if leave-hidden
6578 (set-buffer gnus-group-buffer)
6579 (pop-to-buffer gnus-group-buffer))
eec82323
LMI
6580 (if (not quit-config)
6581 (progn
a8151ef7 6582 (goto-char group-point)
23f87bed
MB
6583 (unless leave-hidden
6584 (gnus-configure-windows 'group 'force)))
eec82323 6585 (gnus-handle-ephemeral-exit quit-config))
6748645f 6586 ;; Clear the current group name.
eec82323
LMI
6587 (unless quit-config
6588 (setq gnus-newsgroup-name nil)))))
6589
6590(defalias 'gnus-summary-quit 'gnus-summary-exit-no-update)
6591(defun gnus-summary-exit-no-update (&optional no-questions)
6592 "Quit reading current newsgroup without updating read article info."
6593 (interactive)
eec82323 6594 (let* ((group gnus-newsgroup-name)
23f87bed
MB
6595 (gnus-group-is-exiting-p t)
6596 (gnus-group-is-exiting-without-update-p t)
eec82323
LMI
6597 (quit-config (gnus-group-quit-config group)))
6598 (when (or no-questions
6599 gnus-expert-user
6600 (gnus-y-or-n-p "Discard changes to this group and exit? "))
6748645f 6601 (gnus-async-halt-prefetch)
23f87bed 6602 (run-hooks 'gnus-summary-prepare-exit-hook)
16409b0b
GM
6603 (when (gnus-buffer-live-p gnus-article-buffer)
6604 (save-excursion
6605 (set-buffer gnus-article-buffer)
6606 (mm-destroy-parts gnus-article-mime-handles)
6607 ;; Set it to nil for safety reason.
6608 (setq gnus-article-mime-handle-alist nil)
6609 (setq gnus-article-mime-handles nil)))
eec82323
LMI
6610 ;; If we have several article buffers, we kill them at exit.
6611 (unless gnus-single-article-buffer
6612 (gnus-kill-buffer gnus-article-buffer)
6613 (gnus-kill-buffer gnus-original-article-buffer)
6614 (setq gnus-article-current nil))
6615 (if (not gnus-kill-summary-on-exit)
6616 (gnus-deaden-summary)
6617 (gnus-close-group group)
6618 (gnus-summary-clear-local-variables)
23f87bed
MB
6619 (let ((gnus-summary-local-variables gnus-newsgroup-variables))
6620 (gnus-summary-clear-local-variables))
eec82323
LMI
6621 (set-buffer gnus-group-buffer)
6622 (gnus-summary-clear-local-variables)
23f87bed
MB
6623 (let ((gnus-summary-local-variables gnus-newsgroup-variables))
6624 (gnus-summary-clear-local-variables))
6625 (gnus-kill-buffer gnus-summary-buffer))
eec82323
LMI
6626 (unless gnus-single-article-buffer
6627 (setq gnus-article-current nil))
6628 (when gnus-use-trees
6629 (gnus-tree-close group))
6630 (gnus-async-prefetch-remove-group group)
6631 (when (get-buffer gnus-article-buffer)
6632 (bury-buffer gnus-article-buffer))
6633 ;; Return to the group buffer.
6634 (gnus-configure-windows 'group 'force)
6635 ;; Clear the current group name.
6636 (setq gnus-newsgroup-name nil)
23f87bed
MB
6637 (unless (gnus-ephemeral-group-p group)
6638 (gnus-group-update-group group))
eec82323
LMI
6639 (when (equal (gnus-group-group-name) group)
6640 (gnus-group-next-unread-group 1))
6641 (when quit-config
23f87bed 6642 (gnus-handle-ephemeral-exit quit-config)))))
eec82323
LMI
6643
6644(defun gnus-handle-ephemeral-exit (quit-config)
6748645f
LMI
6645 "Handle movement when leaving an ephemeral group.
6646The state which existed when entering the ephemeral is reset."
eec82323
LMI
6647 (if (not (buffer-name (car quit-config)))
6648 (gnus-configure-windows 'group 'force)
6649 (set-buffer (car quit-config))
6650 (cond ((eq major-mode 'gnus-summary-mode)
23f87bed
MB
6651 (gnus-set-global-variables))
6652 ((eq major-mode 'gnus-article-mode)
6653 (save-excursion
6654 ;; The `gnus-summary-buffer' variable may point
6655 ;; to the old summary buffer when using a single
6656 ;; article buffer.
6657 (unless (gnus-buffer-live-p gnus-summary-buffer)
6658 (set-buffer gnus-group-buffer))
6659 (set-buffer gnus-summary-buffer)
6660 (gnus-set-global-variables))))
eec82323 6661 (if (or (eq (cdr quit-config) 'article)
23f87bed
MB
6662 (eq (cdr quit-config) 'pick))
6663 (progn
6664 ;; The current article may be from the ephemeral group
6665 ;; thus it is best that we reload this article
6666 ;;
6667 ;; If we're exiting from a large digest, this can be
6668 ;; extremely slow. So, it's better not to reload it. -- jh.
6669 ;;(gnus-summary-show-article)
6670 (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
6671 (gnus-configure-windows 'pick 'force)
6672 (gnus-configure-windows (cdr quit-config) 'force)))
eec82323
LMI
6673 (gnus-configure-windows (cdr quit-config) 'force))
6674 (when (eq major-mode 'gnus-summary-mode)
6675 (gnus-summary-next-subject 1 nil t)
6676 (gnus-summary-recenter)
6677 (gnus-summary-position-point))))
6678
6679;;; Dead summaries.
6680
6681(defvar gnus-dead-summary-mode-map nil)
6682
6683(unless gnus-dead-summary-mode-map
6684 (setq gnus-dead-summary-mode-map (make-keymap))
6685 (suppress-keymap gnus-dead-summary-mode-map)
6686 (substitute-key-definition
6687 'undefined 'gnus-summary-wake-up-the-dead gnus-dead-summary-mode-map)
23f87bed
MB
6688 (dolist (key '("\C-d" "\r" "\177" [delete]))
6689 (define-key gnus-dead-summary-mode-map
6690 key 'gnus-summary-wake-up-the-dead))
6691 (dolist (key '("q" "Q"))
6692 (define-key gnus-dead-summary-mode-map key 'bury-buffer)))
eec82323
LMI
6693
6694(defvar gnus-dead-summary-mode nil
6695 "Minor mode for Gnus summary buffers.")
6696
6697(defun gnus-dead-summary-mode (&optional arg)
6698 "Minor mode for Gnus summary buffers."
6699 (interactive "P")
6700 (when (eq major-mode 'gnus-summary-mode)
6701 (make-local-variable 'gnus-dead-summary-mode)
6702 (setq gnus-dead-summary-mode
6703 (if (null arg) (not gnus-dead-summary-mode)
6704 (> (prefix-numeric-value arg) 0)))
6705 (when gnus-dead-summary-mode
a8151ef7
LMI
6706 (gnus-add-minor-mode
6707 'gnus-dead-summary-mode " Dead" gnus-dead-summary-mode-map))))
eec82323
LMI
6708
6709(defun gnus-deaden-summary ()
6710 "Make the current summary buffer into a dead summary buffer."
6711 ;; Kill any previous dead summary buffer.
6712 (when (and gnus-dead-summary
6713 (buffer-name gnus-dead-summary))
6714 (save-excursion
6715 (set-buffer gnus-dead-summary)
6716 (when gnus-dead-summary-mode
6717 (kill-buffer (current-buffer)))))
6718 ;; Make this the current dead summary.
6719 (setq gnus-dead-summary (current-buffer))
6720 (gnus-dead-summary-mode 1)
6721 (let ((name (buffer-name)))
6722 (when (string-match "Summary" name)
6723 (rename-buffer
6724 (concat (substring name 0 (match-beginning 0)) "Dead "
6725 (substring name (match-beginning 0)))
16409b0b
GM
6726 t)
6727 (bury-buffer))))
eec82323
LMI
6728
6729(defun gnus-kill-or-deaden-summary (buffer)
6730 "Kill or deaden the summary BUFFER."
6748645f
LMI
6731 (save-excursion
6732 (when (and (buffer-name buffer)
6733 (not gnus-single-article-buffer))
6734 (save-excursion
6735 (set-buffer buffer)
6736 (gnus-kill-buffer gnus-article-buffer)
6737 (gnus-kill-buffer gnus-original-article-buffer)))
23f87bed
MB
6738 (cond
6739 ;; Kill the buffer.
6740 (gnus-kill-summary-on-exit
6741 (when (and gnus-use-trees
6742 (gnus-buffer-exists-p buffer))
6743 (save-excursion
6744 (set-buffer buffer)
6745 (gnus-tree-close gnus-newsgroup-name)))
6746 (gnus-kill-buffer buffer))
6747 ;; Deaden the buffer.
6748 ((gnus-buffer-exists-p buffer)
6749 (save-excursion
6750 (set-buffer buffer)
6751 (gnus-deaden-summary))))))
eec82323
LMI
6752
6753(defun gnus-summary-wake-up-the-dead (&rest args)
6754 "Wake up the dead summary buffer."
6755 (interactive)
6756 (gnus-dead-summary-mode -1)
6757 (let ((name (buffer-name)))
6758 (when (string-match "Dead " name)
6759 (rename-buffer
6760 (concat (substring name 0 (match-beginning 0))
6761 (substring name (match-end 0)))
6762 t)))
6763 (gnus-message 3 "This dead summary is now alive again"))
6764
6765;; Suggested by Andrew Eskilsson <pi92ae@pt.hk-r.se>.
6766(defun gnus-summary-fetch-faq (&optional faq-dir)
6767 "Fetch the FAQ for the current group.
6768If FAQ-DIR (the prefix), prompt for a directory to search for the faq
6769in."
6770 (interactive
6771 (list
6772 (when current-prefix-arg
6773 (completing-read
8f688cb0 6774 "FAQ dir: " (and (listp gnus-group-faq-directory)
a8151ef7
LMI
6775 (mapcar (lambda (file) (list file))
6776 gnus-group-faq-directory))))))
eec82323
LMI
6777 (let (gnus-faq-buffer)
6778 (when (setq gnus-faq-buffer
6779 (gnus-group-fetch-faq gnus-newsgroup-name faq-dir))
6780 (gnus-configure-windows 'summary-faq))))
6781
6782;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
6783(defun gnus-summary-describe-group (&optional force)
6784 "Describe the current newsgroup."
6785 (interactive "P")
6786 (gnus-group-describe-group force gnus-newsgroup-name))
6787
6788(defun gnus-summary-describe-briefly ()
6789 "Describe summary mode commands briefly."
6790 (interactive)
16409b0b 6791 (gnus-message 6 (substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select \\[gnus-summary-next-unread-article]:Forward \\[gnus-summary-prev-unread-article]:Backward \\[gnus-summary-exit]:Exit \\[gnus-info-find-node]:Run Info \\[gnus-summary-describe-briefly]:This help")))
eec82323
LMI
6792
6793;; Walking around group mode buffer from summary mode.
6794
6795(defun gnus-summary-next-group (&optional no-article target-group backward)
6796 "Exit current newsgroup and then select next unread newsgroup.
6797If prefix argument NO-ARTICLE is non-nil, no article is selected
23f87bed 6798initially. If TARGET-GROUP, go to this group. If BACKWARD, go to
eec82323
LMI
6799previous group instead."
6800 (interactive "P")
eec82323
LMI
6801 ;; Stop pre-fetching.
6802 (gnus-async-halt-prefetch)
6803 (let ((current-group gnus-newsgroup-name)
6804 (current-buffer (current-buffer))
6805 entered)
6806 ;; First we semi-exit this group to update Xrefs and all variables.
6807 ;; We can't do a real exit, because the window conf must remain
6808 ;; the same in case the user is prompted for info, and we don't
6809 ;; want the window conf to change before that...
6810 (gnus-summary-exit t)
6811 (while (not entered)
6812 ;; Then we find what group we are supposed to enter.
6813 (set-buffer gnus-group-buffer)
6814 (gnus-group-jump-to-group current-group)
6815 (setq target-group
6816 (or target-group
6817 (if (eq gnus-keep-same-level 'best)
6818 (gnus-summary-best-group gnus-newsgroup-name)
6819 (gnus-summary-search-group backward gnus-keep-same-level))))
6820 (if (not target-group)
6821 ;; There are no further groups, so we return to the group
6822 ;; buffer.
6823 (progn
6824 (gnus-message 5 "Returning to the group buffer")
6825 (setq entered t)
6826 (when (gnus-buffer-live-p current-buffer)
6827 (set-buffer current-buffer)
6828 (gnus-summary-exit))
6748645f 6829 (gnus-run-hooks 'gnus-group-no-more-groups-hook))
eec82323
LMI
6830 ;; We try to enter the target group.
6831 (gnus-group-jump-to-group target-group)
6832 (let ((unreads (gnus-group-group-unread)))
6833 (if (and (or (eq t unreads)
6834 (and unreads (not (zerop unreads))))
23f87bed
MB
6835 (gnus-summary-read-group
6836 target-group nil no-article
6837 (and (buffer-name current-buffer) current-buffer)
6838 nil backward))
eec82323
LMI
6839 (setq entered t)
6840 (setq current-group target-group
6841 target-group nil)))))))
6842
6843(defun gnus-summary-prev-group (&optional no-article)
6844 "Exit current newsgroup and then select previous unread newsgroup.
6845If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
6846 (interactive "P")
6847 (gnus-summary-next-group no-article nil t))
6848
6849;; Walking around summary lines.
6850
23f87bed
MB
6851(defun gnus-summary-first-subject (&optional unread undownloaded unseen)
6852 "Go to the first subject satisfying any non-nil constraint.
6853If UNREAD is non-nil, the article should be unread.
6854If UNDOWNLOADED is non-nil, the article should be undownloaded.
6855If UNSEEN is non-nil, the article should be unseen.
6856Returns the article selected or nil if there are no matching articles."
eec82323 6857 (interactive "P")
23f87bed
MB
6858 (cond
6859 ;; Empty summary.
6860 ((null gnus-newsgroup-data)
6861 (gnus-message 3 "No articles in the group")
6862 nil)
6863 ;; Pick the first article.
6864 ((not (or unread undownloaded unseen))
6865 (goto-char (gnus-data-pos (car gnus-newsgroup-data)))
6866 (gnus-data-number (car gnus-newsgroup-data)))
6867 ;; Find the first unread article.
6868 (t
6869 (let ((data gnus-newsgroup-data))
6870 (while (and data
6871 (let ((num (gnus-data-number (car data))))
6872 (or (memq num gnus-newsgroup-unfetched)
6873 (not (or (and unread
6874 (memq num gnus-newsgroup-unreads))
6875 (and undownloaded
6876 (memq num gnus-newsgroup-undownloaded))
6877 (and unseen
6878 (memq num gnus-newsgroup-unseen)))))))
6879 (setq data (cdr data)))
6880 (prog1
6881 (if data
6882 (progn
6883 (goto-char (gnus-data-pos (car data)))
6884 (gnus-data-number (car data)))
6885 (gnus-message 3 "No more%s articles"
6886 (let* ((r (when unread " unread"))
6887 (d (when undownloaded " undownloaded"))
6888 (s (when unseen " unseen"))
6889 (l (delq nil (list r d s))))
6890 (cond ((= 3 (length l))
6891 (concat r "," d ", or" s))
6892 ((= 2 (length l))
6893 (concat (car l) ", or" (cadr l)))
6894 ((= 1 (length l))
6895 (car l))
6896 (t
6897 ""))))
6898 nil
6899 )
6900 (gnus-summary-position-point))))))
eec82323
LMI
6901
6902(defun gnus-summary-next-subject (n &optional unread dont-display)
6903 "Go to next N'th summary line.
6904If N is negative, go to the previous N'th subject line.
6905If UNREAD is non-nil, only unread articles are selected.
6906The difference between N and the actual number of steps taken is
6907returned."
6908 (interactive "p")
6909 (let ((backward (< n 0))
6910 (n (abs n)))
6911 (while (and (> n 0)
6912 (if backward
6913 (gnus-summary-find-prev unread)
6914 (gnus-summary-find-next unread)))
16409b0b
GM
6915 (unless (zerop (setq n (1- n)))
6916 (gnus-summary-show-thread)))
eec82323
LMI
6917 (when (/= 0 n)
6918 (gnus-message 7 "No more%s articles"
6919 (if unread " unread" "")))
6920 (unless dont-display
6921 (gnus-summary-recenter)
6922 (gnus-summary-position-point))
6923 n))
6924
6925(defun gnus-summary-next-unread-subject (n)
6926 "Go to next N'th unread summary line."
6927 (interactive "p")
6928 (gnus-summary-next-subject n t))
6929
6930(defun gnus-summary-prev-subject (n &optional unread)
6931 "Go to previous N'th summary line.
6932If optional argument UNREAD is non-nil, only unread article is selected."
6933 (interactive "p")
6934 (gnus-summary-next-subject (- n) unread))
6935
6936(defun gnus-summary-prev-unread-subject (n)
6937 "Go to previous N'th unread summary line."
6938 (interactive "p")
6939 (gnus-summary-next-subject (- n) t))
6940
23f87bed
MB
6941(defun gnus-summary-goto-subjects (articles)
6942 "Insert the subject header for ARTICLES in the current buffer."
6943 (save-excursion
6944 (dolist (article articles)
6945 (gnus-summary-goto-subject article t)))
6946 (gnus-summary-limit (append articles gnus-newsgroup-limit))
6947 (gnus-summary-position-point))
6948
eec82323
LMI
6949(defun gnus-summary-goto-subject (article &optional force silent)
6950 "Go the subject line of ARTICLE.
6951If FORCE, also allow jumping to articles not currently shown."
6952 (interactive "nArticle number: ")
23f87bed
MB
6953 (unless (numberp article)
6954 (error "Article %s is not a number" article))
eec82323
LMI
6955 (let ((b (point))
6956 (data (gnus-data-find article)))
6957 ;; We read in the article if we have to.
6958 (and (not data)
6959 force
6748645f
LMI
6960 (gnus-summary-insert-subject
6961 article
6962 (if (or (numberp force) (vectorp force)) force)
6963 t)
eec82323
LMI
6964 (setq data (gnus-data-find article)))
6965 (goto-char b)
6966 (if (not data)
6967 (progn
6968 (unless silent
6969 (gnus-message 3 "Can't find article %d" article))
6970 nil)
23f87bed
MB
6971 (let ((pt (gnus-data-pos data)))
6972 (goto-char pt)
6973 (gnus-summary-set-article-display-arrow pt))
6748645f 6974 (gnus-summary-position-point)
eec82323
LMI
6975 article)))
6976
6977;; Walking around summary lines with displaying articles.
6978
6979(defun gnus-summary-expand-window (&optional arg)
6980 "Make the summary buffer take up the entire Emacs frame.
6981Given a prefix, will force an `article' buffer configuration."
6982 (interactive "P")
eec82323
LMI
6983 (if arg
6984 (gnus-configure-windows 'article 'force)
6985 (gnus-configure-windows 'summary 'force)))
6986
6987(defun gnus-summary-display-article (article &optional all-header)
6988 "Display ARTICLE in article buffer."
d4dfaa19
DL
6989 (when (gnus-buffer-live-p gnus-article-buffer)
6990 (with-current-buffer gnus-article-buffer
87545352 6991 (mm-enable-multibyte)))
eec82323 6992 (gnus-set-global-variables)
23f87bed
MB
6993 (when (gnus-buffer-live-p gnus-article-buffer)
6994 (with-current-buffer gnus-article-buffer
6995 (setq gnus-article-charset gnus-newsgroup-charset)
6996 (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
6997 (mm-enable-multibyte)))
eec82323
LMI
6998 (if (null article)
6999 nil
7000 (prog1
7001 (if gnus-summary-display-article-function
7002 (funcall gnus-summary-display-article-function article all-header)
7003 (gnus-article-prepare article all-header))
6748645f 7004 (gnus-run-hooks 'gnus-select-article-hook)
eec82323
LMI
7005 (when (and gnus-current-article
7006 (not (zerop gnus-current-article)))
7007 (gnus-summary-goto-subject gnus-current-article))
7008 (gnus-summary-recenter)
7009 (when (and gnus-use-trees gnus-show-threads)
7010 (gnus-possibly-generate-tree article)
7011 (gnus-highlight-selected-tree article))
7012 ;; Successfully display article.
7013 (gnus-article-set-window-start
7014 (cdr (assq article gnus-newsgroup-bookmarks))))))
7015
7016(defun gnus-summary-select-article (&optional all-headers force pseudo article)
7017 "Select the current article.
7018If ALL-HEADERS is non-nil, show all header fields. If FORCE is
7019non-nil, the article will be re-fetched even if it already present in
7020the article buffer. If PSEUDO is non-nil, pseudo-articles will also
7021be displayed."
7022 ;; Make sure we are in the summary buffer to work around bbdb bug.
7023 (unless (eq major-mode 'gnus-summary-mode)
7024 (set-buffer gnus-summary-buffer))
7025 (let ((article (or article (gnus-summary-article-number)))
f0529b5b 7026 (all-headers (not (not all-headers))) ;Must be t or nil.
16409b0b 7027 gnus-summary-display-article-function)
eec82323
LMI
7028 (and (not pseudo)
7029 (gnus-summary-article-pseudo-p article)
a8151ef7 7030 (error "This is a pseudo-article"))
16409b0b
GM
7031 (save-excursion
7032 (set-buffer gnus-summary-buffer)
7033 (if (or (and gnus-single-article-buffer
7034 (or (null gnus-current-article)
7035 (null gnus-article-current)
7036 (null (get-buffer gnus-article-buffer))
7037 (not (eq article (cdr gnus-article-current)))
7038 (not (equal (car gnus-article-current)
7039 gnus-newsgroup-name))))
7040 (and (not gnus-single-article-buffer)
7041 (or (null gnus-current-article)
7042 (not (eq gnus-current-article article))))
7043 force)
7044 ;; The requested article is different from the current article.
7045 (progn
16409b0b
GM
7046 (gnus-summary-display-article article all-headers)
7047 (when (gnus-buffer-live-p gnus-article-buffer)
23f87bed 7048 (with-current-buffer gnus-article-buffer
16409b0b 7049 (if (not gnus-article-decoded-p) ;; a local variable
87545352 7050 (mm-disable-multibyte))))
16409b0b
GM
7051 (gnus-article-set-window-start
7052 (cdr (assq article gnus-newsgroup-bookmarks)))
7053 article)
16409b0b 7054 'old))))
eec82323 7055
23f87bed
MB
7056(defun gnus-summary-force-verify-and-decrypt ()
7057 "Display buttons for signed/encrypted parts and verify/decrypt them."
7058 (interactive)
7059 (let ((mm-verify-option 'known)
7060 (mm-decrypt-option 'known)
7061 (gnus-article-emulate-mime t)
7062 (gnus-buttonized-mime-types (append (list "multipart/signed"
7063 "multipart/encrypted")
7064 gnus-buttonized-mime-types)))
7065 (gnus-summary-select-article nil 'force)))
7066
eec82323
LMI
7067(defun gnus-summary-set-current-mark (&optional current-mark)
7068 "Obsolete function."
7069 nil)
7070
7071(defun gnus-summary-next-article (&optional unread subject backward push)
7072 "Select the next article.
7073If UNREAD, only unread articles are selected.
7074If SUBJECT, only articles with SUBJECT are selected.
7075If BACKWARD, the previous article is selected instead of the next."
7076 (interactive "P")
eec82323
LMI
7077 (cond
7078 ;; Is there such an article?
7079 ((and (gnus-summary-search-forward unread subject backward)
7080 (or (gnus-summary-display-article (gnus-summary-article-number))
7081 (eq (gnus-summary-article-mark) gnus-canceled-mark)))
7082 (gnus-summary-position-point))
7083 ;; If not, we try the first unread, if that is wanted.
7084 ((and subject
7085 gnus-auto-select-same
7086 (gnus-summary-first-unread-article))
7087 (gnus-summary-position-point)
7088 (gnus-message 6 "Wrapped"))
7089 ;; Try to get next/previous article not displayed in this group.
7090 ((and gnus-auto-extend-newsgroup
7091 (not unread) (not subject))
7092 (gnus-summary-goto-article
7093 (if backward (1- gnus-newsgroup-begin) (1+ gnus-newsgroup-end))
6748645f 7094 nil (count-lines (point-min) (point))))
eec82323
LMI
7095 ;; Go to next/previous group.
7096 (t
7097 (unless (gnus-ephemeral-group-p gnus-newsgroup-name)
7098 (gnus-summary-jump-to-group gnus-newsgroup-name))
7099 (let ((cmd last-command-char)
7100 (point
7101 (save-excursion
7102 (set-buffer gnus-group-buffer)
7103 (point)))
7104 (group
7105 (if (eq gnus-keep-same-level 'best)
7106 (gnus-summary-best-group gnus-newsgroup-name)
7107 (gnus-summary-search-group backward gnus-keep-same-level))))
7108 ;; For some reason, the group window gets selected. We change
7109 ;; it back.
7110 (select-window (get-buffer-window (current-buffer)))
7111 ;; Select next unread newsgroup automagically.
7112 (cond
7113 ((or (not gnus-auto-select-next)
7114 (not cmd))
7115 (gnus-message 7 "No more%s articles" (if unread " unread" "")))
7116 ((or (eq gnus-auto-select-next 'quietly)
7117 (and (eq gnus-auto-select-next 'slightly-quietly)
7118 push)
7119 (and (eq gnus-auto-select-next 'almost-quietly)
7120 (gnus-summary-last-article-p)))
7121 ;; Select quietly.
7122 (if (gnus-ephemeral-group-p gnus-newsgroup-name)
7123 (gnus-summary-exit)
7124 (gnus-message 7 "No more%s articles (%s)..."
7125 (if unread " unread" "")
7126 (if group (concat "selecting " group)
7127 "exiting"))
7128 (gnus-summary-next-group nil group backward)))
7129 (t
7130 (when (gnus-key-press-event-p last-input-event)
7131 (gnus-summary-walk-group-buffer
7132 gnus-newsgroup-name cmd unread backward point))))))))
7133
7134(defun gnus-summary-walk-group-buffer (from-group cmd unread backward start)
7135 (let ((keystrokes '((?\C-n (gnus-group-next-unread-group 1))
7136 (?\C-p (gnus-group-prev-unread-group 1))))
7137 (cursor-in-echo-area t)
23f87bed 7138 keve key group ended prompt)
eec82323
LMI
7139 (save-excursion
7140 (set-buffer gnus-group-buffer)
7141 (goto-char start)
7142 (setq group
7143 (if (eq gnus-keep-same-level 'best)
7144 (gnus-summary-best-group gnus-newsgroup-name)
7145 (gnus-summary-search-group backward gnus-keep-same-level))))
7146 (while (not ended)
23f87bed
MB
7147 (setq prompt
7148 (format
7149 "No more%s articles%s " (if unread " unread" "")
7150 (if (and group
7151 (not (gnus-ephemeral-group-p gnus-newsgroup-name)))
7152 (format " (Type %s for %s [%s])"
7153 (single-key-description cmd) group
7154 (car (gnus-gethash group gnus-newsrc-hashtb)))
7155 (format " (Type %s to exit %s)"
7156 (single-key-description cmd)
7157 gnus-newsgroup-name))))
eec82323 7158 ;; Confirm auto selection.
23f87bed
MB
7159 (setq key (car (setq keve (gnus-read-event-char prompt)))
7160 ended t)
eec82323
LMI
7161 (cond
7162 ((assq key keystrokes)
7163 (let ((obuf (current-buffer)))
7164 (switch-to-buffer gnus-group-buffer)
7165 (when group
7166 (gnus-group-jump-to-group group))
7167 (eval (cadr (assq key keystrokes)))
7168 (setq group (gnus-group-group-name))
7169 (switch-to-buffer obuf))
7170 (setq ended nil))
7171 ((equal key cmd)
7172 (if (or (not group)
7173 (gnus-ephemeral-group-p gnus-newsgroup-name))
7174 (gnus-summary-exit)
7175 (gnus-summary-next-group nil group backward)))
7176 (t
7177 (push (cdr keve) unread-command-events))))))
7178
7179(defun gnus-summary-next-unread-article ()
7180 "Select unread article after current one."
7181 (interactive)
7182 (gnus-summary-next-article
7183 (or (not (eq gnus-summary-goto-unread 'never))
7184 (gnus-summary-last-article-p (gnus-summary-article-number)))
7185 (and gnus-auto-select-same
7186 (gnus-summary-article-subject))))
7187
7188(defun gnus-summary-prev-article (&optional unread subject)
7189 "Select the article after the current one.
7190If UNREAD is non-nil, only unread articles are selected."
7191 (interactive "P")
7192 (gnus-summary-next-article unread subject t))
7193
7194(defun gnus-summary-prev-unread-article ()
7195 "Select unread article before current one."
7196 (interactive)
7197 (gnus-summary-prev-article
7198 (or (not (eq gnus-summary-goto-unread 'never))
7199 (gnus-summary-first-article-p (gnus-summary-article-number)))
7200 (and gnus-auto-select-same
7201 (gnus-summary-article-subject))))
7202
23f87bed 7203(defun gnus-summary-next-page (&optional lines circular stop)
eec82323
LMI
7204 "Show next page of the selected article.
7205If at the end of the current article, select the next article.
7206LINES says how many lines should be scrolled up.
7207
7208If CIRCULAR is non-nil, go to the start of the article instead of
7209selecting the next article when reaching the end of the current
23f87bed
MB
7210article.
7211
7212If STOP is non-nil, just stop when reaching the end of the message.
7213
7214Also see the variable `gnus-article-skip-boring'."
eec82323
LMI
7215 (interactive "P")
7216 (setq gnus-summary-buffer (current-buffer))
7217 (gnus-set-global-variables)
7218 (let ((article (gnus-summary-article-number))
7219 (article-window (get-buffer-window gnus-article-buffer t))
7220 endp)
6748645f
LMI
7221 ;; If the buffer is empty, we have no article.
7222 (unless article
7223 (error "No article to select"))
eec82323
LMI
7224 (gnus-configure-windows 'article)
7225 (if (eq (cdr (assq article gnus-newsgroup-reads)) gnus-canceled-mark)
7226 (if (and (eq gnus-summary-goto-unread 'never)
7227 (not (gnus-summary-last-article-p article)))
7228 (gnus-summary-next-article)
7229 (gnus-summary-next-unread-article))
7230 (if (or (null gnus-current-article)
7231 (null gnus-article-current)
7232 (/= article (cdr gnus-article-current))
7233 (not (equal (car gnus-article-current) gnus-newsgroup-name)))
7234 ;; Selected subject is different from current article's.
7235 (gnus-summary-display-article article)
7236 (when article-window
7237 (gnus-eval-in-buffer-window gnus-article-buffer
23f87bed
MB
7238 (setq endp (or (gnus-article-next-page lines)
7239 (gnus-article-only-boring-p))))
eec82323 7240 (when endp
23f87bed
MB
7241 (cond (stop
7242 (gnus-message 3 "End of message"))
7243 (circular
eec82323
LMI
7244 (gnus-summary-beginning-of-article))
7245 (lines
7246 (gnus-message 3 "End of message"))
7247 ((null lines)
7248 (if (and (eq gnus-summary-goto-unread 'never)
7249 (not (gnus-summary-last-article-p article)))
7250 (gnus-summary-next-article)
7251 (gnus-summary-next-unread-article))))))))
7252 (gnus-summary-recenter)
7253 (gnus-summary-position-point)))
7254
7255(defun gnus-summary-prev-page (&optional lines move)
7256 "Show previous page of selected article.
7257Argument LINES specifies lines to be scrolled down.
7258If MOVE, move to the previous unread article if point is at
7259the beginning of the buffer."
7260 (interactive "P")
eec82323
LMI
7261 (let ((article (gnus-summary-article-number))
7262 (article-window (get-buffer-window gnus-article-buffer t))
7263 endp)
7264 (gnus-configure-windows 'article)
7265 (if (or (null gnus-current-article)
7266 (null gnus-article-current)
7267 (/= article (cdr gnus-article-current))
7268 (not (equal (car gnus-article-current) gnus-newsgroup-name)))
7269 ;; Selected subject is different from current article's.
7270 (gnus-summary-display-article article)
7271 (gnus-summary-recenter)
7272 (when article-window
7273 (gnus-eval-in-buffer-window gnus-article-buffer
7274 (setq endp (gnus-article-prev-page lines)))
7275 (when (and move endp)
7276 (cond (lines
7277 (gnus-message 3 "Beginning of message"))
7278 ((null lines)
7279 (if (and (eq gnus-summary-goto-unread 'never)
7280 (not (gnus-summary-first-article-p article)))
7281 (gnus-summary-prev-article)
7282 (gnus-summary-prev-unread-article))))))))
7283 (gnus-summary-position-point))
7284
7285(defun gnus-summary-prev-page-or-article (&optional lines)
7286 "Show previous page of selected article.
7287Argument LINES specifies lines to be scrolled down.
7288If at the beginning of the article, go to the next article."
7289 (interactive "P")
7290 (gnus-summary-prev-page lines t))
7291
7292(defun gnus-summary-scroll-up (lines)
7293 "Scroll up (or down) one line current article.
7294Argument LINES specifies lines to be scrolled up (or down if negative)."
7295 (interactive "p")
eec82323
LMI
7296 (gnus-configure-windows 'article)
7297 (gnus-summary-show-thread)
7298 (when (eq (gnus-summary-select-article nil nil 'pseudo) 'old)
7299 (gnus-eval-in-buffer-window gnus-article-buffer
7300 (cond ((> lines 0)
7301 (when (gnus-article-next-page lines)
7302 (gnus-message 3 "End of message")))
7303 ((< lines 0)
7304 (gnus-article-prev-page (- lines))))))
7305 (gnus-summary-recenter)
7306 (gnus-summary-position-point))
7307
6748645f
LMI
7308(defun gnus-summary-scroll-down (lines)
7309 "Scroll down (or up) one line current article.
7310Argument LINES specifies lines to be scrolled down (or up if negative)."
7311 (interactive "p")
7312 (gnus-summary-scroll-up (- lines)))
7313
eec82323
LMI
7314(defun gnus-summary-next-same-subject ()
7315 "Select next article which has the same subject as current one."
7316 (interactive)
eec82323
LMI
7317 (gnus-summary-next-article nil (gnus-summary-article-subject)))
7318
7319(defun gnus-summary-prev-same-subject ()
7320 "Select previous article which has the same subject as current one."
7321 (interactive)
eec82323
LMI
7322 (gnus-summary-prev-article nil (gnus-summary-article-subject)))
7323
7324(defun gnus-summary-next-unread-same-subject ()
7325 "Select next unread article which has the same subject as current one."
7326 (interactive)
eec82323
LMI
7327 (gnus-summary-next-article t (gnus-summary-article-subject)))
7328
7329(defun gnus-summary-prev-unread-same-subject ()
7330 "Select previous unread article which has the same subject as current one."
7331 (interactive)
eec82323
LMI
7332 (gnus-summary-prev-article t (gnus-summary-article-subject)))
7333
7334(defun gnus-summary-first-unread-article ()
7335 "Select the first unread article.
7336Return nil if there are no unread articles."
7337 (interactive)
eec82323
LMI
7338 (prog1
7339 (when (gnus-summary-first-subject t)
7340 (gnus-summary-show-thread)
7341 (gnus-summary-first-subject t)
7342 (gnus-summary-display-article (gnus-summary-article-number)))
7343 (gnus-summary-position-point)))
7344
16409b0b
GM
7345(defun gnus-summary-first-unread-subject ()
7346 "Place the point on the subject line of the first unread article.
7347Return nil if there are no unread articles."
7348 (interactive)
7349 (prog1
7350 (when (gnus-summary-first-subject t)
7351 (gnus-summary-show-thread)
7352 (gnus-summary-first-subject t))
7353 (gnus-summary-position-point)))
7354
23f87bed
MB
7355(defun gnus-summary-first-unseen-subject ()
7356 "Place the point on the subject line of the first unseen article.
7357Return nil if there are no unseen articles."
7358 (interactive)
7359 (prog1
7360 (when (gnus-summary-first-subject nil nil t)
7361 (gnus-summary-show-thread)
7362 (gnus-summary-first-subject nil nil t))
7363 (gnus-summary-position-point)))
7364
7365(defun gnus-summary-first-unseen-or-unread-subject ()
7366 "Place the point on the subject line of the first unseen article or,
7367if all article have been seen, on the subject line of the first unread
7368article."
7369 (interactive)
7370 (prog1
7371 (unless (when (gnus-summary-first-subject nil nil t)
7372 (gnus-summary-show-thread)
7373 (gnus-summary-first-subject nil nil t))
7374 (when (gnus-summary-first-subject t)
7375 (gnus-summary-show-thread)
7376 (gnus-summary-first-subject t)))
7377 (gnus-summary-position-point)))
7378
eec82323
LMI
7379(defun gnus-summary-first-article ()
7380 "Select the first article.
7381Return nil if there are no articles."
7382 (interactive)
eec82323
LMI
7383 (prog1
7384 (when (gnus-summary-first-subject)
16409b0b
GM
7385 (gnus-summary-show-thread)
7386 (gnus-summary-first-subject)
7387 (gnus-summary-display-article (gnus-summary-article-number)))
eec82323
LMI
7388 (gnus-summary-position-point)))
7389
23f87bed
MB
7390(defun gnus-summary-best-unread-article (&optional arg)
7391 "Select the unread article with the highest score.
7392If given a prefix argument, select the next unread article that has a
7393score higher than the default score."
7394 (interactive "P")
7395 (let ((article (if arg
7396 (gnus-summary-better-unread-subject)
7397 (gnus-summary-best-unread-subject))))
7398 (if article
7399 (gnus-summary-goto-article article)
7400 (error "No unread articles"))))
7401
7402(defun gnus-summary-best-unread-subject ()
7403 "Select the unread subject with the highest score."
eec82323 7404 (interactive)
eec82323
LMI
7405 (let ((best -1000000)
7406 (data gnus-newsgroup-data)
7407 article score)
7408 (while data
7409 (and (gnus-data-unread-p (car data))
7410 (> (setq score
7411 (gnus-summary-article-score (gnus-data-number (car data))))
7412 best)
7413 (setq best score
7414 article (gnus-data-number (car data))))
7415 (setq data (cdr data)))
23f87bed
MB
7416 (when article
7417 (gnus-summary-goto-subject article))
7418 (gnus-summary-position-point)
7419 article))
7420
7421(defun gnus-summary-better-unread-subject ()
7422 "Select the first unread subject that has a score over the default score."
7423 (interactive)
7424 (let ((data gnus-newsgroup-data)
7425 article score)
7426 (while (and (setq article (gnus-data-number (car data)))
7427 (or (gnus-data-read-p (car data))
7428 (not (> (gnus-summary-article-score article)
7429 gnus-summary-default-score))))
7430 (setq data (cdr data)))
7431 (when article
7432 (gnus-summary-goto-subject article))
7433 (gnus-summary-position-point)
7434 article))
eec82323
LMI
7435
7436(defun gnus-summary-last-subject ()
7437 "Go to the last displayed subject line in the group."
7438 (let ((article (gnus-data-number (car (gnus-data-list t)))))
7439 (when article
7440 (gnus-summary-goto-subject article))))
7441
7442(defun gnus-summary-goto-article (article &optional all-headers force)
6748645f
LMI
7443 "Fetch ARTICLE (article number or Message-ID) and display it if it exists.
7444If ALL-HEADERS is non-nil, no header lines are hidden.
7445If FORCE, go to the article even if it isn't displayed. If FORCE
7446is a number, it is the line the article is to be displayed on."
eec82323
LMI
7447 (interactive
7448 (list
6748645f
LMI
7449 (completing-read
7450 "Article number or Message-ID: "
7451 (mapcar (lambda (number) (list (int-to-string number)))
7452 gnus-newsgroup-limit))
eec82323
LMI
7453 current-prefix-arg
7454 t))
7455 (prog1
6748645f 7456 (if (and (stringp article)
23f87bed 7457 (string-match "@\\|%40" article))
6748645f
LMI
7458 (gnus-summary-refer-article article)
7459 (when (stringp article)
7460 (setq article (string-to-number article)))
7461 (if (gnus-summary-goto-subject article force)
7462 (gnus-summary-display-article article all-headers)
7463 (gnus-message 4 "Couldn't go to article %s" article) nil))
eec82323
LMI
7464 (gnus-summary-position-point)))
7465
7466(defun gnus-summary-goto-last-article ()
7467 "Go to the previously read article."
7468 (interactive)
7469 (prog1
7470 (when gnus-last-article
6748645f 7471 (gnus-summary-goto-article gnus-last-article nil t))
eec82323
LMI
7472 (gnus-summary-position-point)))
7473
7474(defun gnus-summary-pop-article (number)
7475 "Pop one article off the history and go to the previous.
7476NUMBER articles will be popped off."
7477 (interactive "p")
7478 (let (to)
7479 (setq gnus-newsgroup-history
7480 (cdr (setq to (nthcdr number gnus-newsgroup-history))))
7481 (if to
6748645f 7482 (gnus-summary-goto-article (car to) nil t)
eec82323
LMI
7483 (error "Article history empty")))
7484 (gnus-summary-position-point))
7485
7486;; Summary commands and functions for limiting the summary buffer.
7487
7488(defun gnus-summary-limit-to-articles (n)
7489 "Limit the summary buffer to the next N articles.
7490If not given a prefix, use the process marked articles instead."
7491 (interactive "P")
eec82323
LMI
7492 (prog1
7493 (let ((articles (gnus-summary-work-articles n)))
7494 (setq gnus-newsgroup-processable nil)
7495 (gnus-summary-limit articles))
7496 (gnus-summary-position-point)))
7497
7498(defun gnus-summary-pop-limit (&optional total)
7499 "Restore the previous limit.
7500If given a prefix, remove all limits."
7501 (interactive "P")
eec82323
LMI
7502 (when total
7503 (setq gnus-newsgroup-limits
7504 (list (mapcar (lambda (h) (mail-header-number h))
7505 gnus-newsgroup-headers))))
7506 (unless gnus-newsgroup-limits
7507 (error "No limit to pop"))
7508 (prog1
7509 (gnus-summary-limit nil 'pop)
7510 (gnus-summary-position-point)))
7511
47b63dfa
SZ
7512(defun gnus-summary-limit-to-subject (subject &optional header not-matching)
7513 "Limit the summary buffer to articles that have subjects that match a regexp.
7514If NOT-MATCHING, excluding articles that have subjects that match a regexp."
a1506d29 7515 (interactive
47b63dfa
SZ
7516 (list (read-string (if current-prefix-arg
7517 "Exclude subject (regexp): "
a1506d29 7518 "Limit to subject (regexp): "))
47b63dfa 7519 nil current-prefix-arg))
eec82323
LMI
7520 (unless header
7521 (setq header "subject"))
7522 (when (not (equal "" subject))
7523 (prog1
7524 (let ((articles (gnus-summary-find-matching
a1506d29 7525 (or header "subject") subject 'all nil nil
47b63dfa 7526 not-matching)))
eec82323
LMI
7527 (unless articles
7528 (error "Found no matches for \"%s\"" subject))
7529 (gnus-summary-limit articles))
7530 (gnus-summary-position-point))))
7531
ef6e0ec7 7532(defun gnus-summary-limit-to-author (from &optional not-matching)
47b63dfa
SZ
7533 "Limit the summary buffer to articles that have authors that match a regexp.
7534If NOT-MATCHING, excluding articles that have authors that match a regexp."
a1506d29 7535 (interactive
47b63dfa
SZ
7536 (list (read-string (if current-prefix-arg
7537 "Exclude author (regexp): "
a1506d29 7538 "Limit to author (regexp): "))
ef6e0ec7
SZ
7539 current-prefix-arg))
7540 (gnus-summary-limit-to-subject from "from" not-matching))
eec82323
LMI
7541
7542(defun gnus-summary-limit-to-age (age &optional younger-p)
7543 "Limit the summary buffer to articles that are older than (or equal) AGE days.
7544If YOUNGER-P (the prefix) is non-nil, limit the summary buffer to
7545articles that are younger than AGE days."
16409b0b
GM
7546 (interactive
7547 (let ((younger current-prefix-arg)
7548 (days-got nil)
7549 days)
7550 (while (not days-got)
7551 (setq days (if younger
23f87bed
MB
7552 (read-string "Limit to articles younger than (in days, older when negative): ")
7553 (read-string
7554 "Limit to articles older than (in days, younger when negative): ")))
16409b0b
GM
7555 (when (> (length days) 0)
7556 (setq days (read days)))
7557 (if (numberp days)
23f87bed
MB
7558 (progn
7559 (setq days-got t)
7560 (if (< days 0)
7561 (progn
7562 (setq younger (not younger))
7563 (setq days (* days -1)))))
16409b0b
GM
7564 (message "Please enter a number.")
7565 (sleep-for 1)))
7566 (list days younger)))
eec82323
LMI
7567 (prog1
7568 (let ((data gnus-newsgroup-data)
16409b0b 7569 (cutoff (days-to-time age))
eec82323
LMI
7570 articles d date is-younger)
7571 (while (setq d (pop data))
7572 (when (and (vectorp (gnus-data-header d))
7573 (setq date (mail-header-date (gnus-data-header d))))
16409b0b
GM
7574 (setq is-younger (time-less-p
7575 (time-since (condition-case ()
7576 (date-to-time date)
7577 (error '(0 0))))
eec82323 7578 cutoff))
6748645f
LMI
7579 (when (if younger-p
7580 is-younger
7581 (not is-younger))
eec82323
LMI
7582 (push (gnus-data-number d) articles))))
7583 (gnus-summary-limit (nreverse articles)))
7584 (gnus-summary-position-point)))
7585
47b63dfa 7586(defun gnus-summary-limit-to-extra (header regexp &optional not-matching)
16409b0b
GM
7587 "Limit the summary buffer to articles that match an 'extra' header."
7588 (interactive
7589 (let ((header
7590 (intern
23f87bed 7591 (gnus-completing-read-with-default
16409b0b 7592 (symbol-name (car gnus-extra-headers))
47b63dfa
SZ
7593 (if current-prefix-arg
7594 "Exclude extra header:"
7595 "Limit extra header:")
16409b0b
GM
7596 (mapcar (lambda (x)
7597 (cons (symbol-name x) x))
7598 gnus-extra-headers)
7599 nil
7600 t))))
7601 (list header
a1506d29 7602 (read-string (format "%s header %s (regexp): "
47b63dfa
SZ
7603 (if current-prefix-arg "Exclude" "Limit to")
7604 header))
7605 current-prefix-arg)))
16409b0b
GM
7606 (when (not (equal "" regexp))
7607 (prog1
7608 (let ((articles (gnus-summary-find-matching
a1506d29 7609 (cons 'extra header) regexp 'all nil nil
47b63dfa 7610 not-matching)))
16409b0b
GM
7611 (unless articles
7612 (error "Found no matches for \"%s\"" regexp))
7613 (gnus-summary-limit articles))
7614 (gnus-summary-position-point))))
7615
23f87bed
MB
7616(defun gnus-summary-limit-to-display-predicate ()
7617 "Limit the summary buffer to the predicated in the `display' group parameter."
7618 (interactive)
7619 (unless gnus-newsgroup-display
7620 (error "There is no `display' group parameter"))
7621 (let (articles)
7622 (dolist (number gnus-newsgroup-articles)
7623 (when (funcall gnus-newsgroup-display)
7624 (push number articles)))
7625 (gnus-summary-limit articles))
7626 (gnus-summary-position-point))
7627
eec82323
LMI
7628(defalias 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
7629(make-obsolete
7630 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread)
7631
7632(defun gnus-summary-limit-to-unread (&optional all)
7633 "Limit the summary buffer to articles that are not marked as read.
7634If ALL is non-nil, limit strictly to unread articles."
7635 (interactive "P")
7636 (if all
7637 (gnus-summary-limit-to-marks (char-to-string gnus-unread-mark))
7638 (gnus-summary-limit-to-marks
7639 ;; Concat all the marks that say that an article is read and have
7640 ;; those removed.
7641 (list gnus-del-mark gnus-read-mark gnus-ancient-mark
23f87bed 7642 gnus-killed-mark gnus-spam-mark gnus-kill-file-mark
eec82323
LMI
7643 gnus-low-score-mark gnus-expirable-mark
7644 gnus-canceled-mark gnus-catchup-mark gnus-sparse-mark
7645 gnus-duplicate-mark gnus-souped-mark)
7646 'reverse)))
7647
7648(defalias 'gnus-summary-delete-marked-with 'gnus-summary-limit-exclude-marks)
7649(make-obsolete 'gnus-summary-delete-marked-with
81ceefe2 7650 'gnus-summary-limit-exclude-marks)
eec82323
LMI
7651
7652(defun gnus-summary-limit-exclude-marks (marks &optional reverse)
7653 "Exclude articles that are marked with MARKS (e.g. \"DK\").
7654If REVERSE, limit the summary buffer to articles that are marked
7655with MARKS. MARKS can either be a string of marks or a list of marks.
7656Returns how many articles were removed."
7657 (interactive "sMarks: ")
7658 (gnus-summary-limit-to-marks marks t))
7659
7660(defun gnus-summary-limit-to-marks (marks &optional reverse)
7661 "Limit the summary buffer to articles that are marked with MARKS (e.g. \"DK\").
7662If REVERSE (the prefix), limit the summary buffer to articles that are
7663not marked with MARKS. MARKS can either be a string of marks or a
7664list of marks.
7665Returns how many articles were removed."
6748645f 7666 (interactive "sMarks: \nP")
eec82323
LMI
7667 (prog1
7668 (let ((data gnus-newsgroup-data)
7669 (marks (if (listp marks) marks
7670 (append marks nil))) ; Transform to list.
7671 articles)
7672 (while data
7673 (when (if reverse (not (memq (gnus-data-mark (car data)) marks))
7674 (memq (gnus-data-mark (car data)) marks))
7675 (push (gnus-data-number (car data)) articles))
7676 (setq data (cdr data)))
7677 (gnus-summary-limit articles))
7678 (gnus-summary-position-point)))
7679
23f87bed 7680(defun gnus-summary-limit-to-score (score)
eec82323 7681 "Limit to articles with score at or above SCORE."
23f87bed 7682 (interactive "NLimit to articles with score of at least: ")
eec82323
LMI
7683 (let ((data gnus-newsgroup-data)
7684 articles)
7685 (while data
7686 (when (>= (gnus-summary-article-score (gnus-data-number (car data)))
7687 score)
7688 (push (gnus-data-number (car data)) articles))
7689 (setq data (cdr data)))
7690 (prog1
7691 (gnus-summary-limit articles)
7692 (gnus-summary-position-point))))
7693
23f87bed
MB
7694(defun gnus-summary-limit-to-unseen ()
7695 "Limit to unseen articles."
7696 (interactive)
7697 (prog1
7698 (gnus-summary-limit gnus-newsgroup-unseen)
7699 (gnus-summary-position-point)))
7700
6748645f 7701(defun gnus-summary-limit-include-thread (id)
23f87bed
MB
7702 "Display all the hidden articles that is in the thread with ID in it.
7703When called interactively, ID is the Message-ID of the current
7704article."
6748645f
LMI
7705 (interactive (list (mail-header-id (gnus-summary-article-header))))
7706 (let ((articles (gnus-articles-in-thread
7707 (gnus-id-to-thread (gnus-root-id id)))))
7708 (prog1
7709 (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
23f87bed
MB
7710 (gnus-summary-limit-include-matching-articles
7711 "subject"
7712 (regexp-quote (gnus-simplify-subject-re
7713 (mail-header-subject (gnus-id-to-header id)))))
6748645f
LMI
7714 (gnus-summary-position-point))))
7715
23f87bed
MB
7716(defun gnus-summary-limit-include-matching-articles (header regexp)
7717 "Display all the hidden articles that have HEADERs that match REGEXP."
7718 (interactive (list (read-string "Match on header: ")
7719 (read-string "Regexp: ")))
7720 (let ((articles (gnus-find-matching-articles header regexp)))
7721 (prog1
7722 (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
7723 (gnus-summary-position-point))))
7724
7725(defun gnus-summary-insert-dormant-articles ()
7726 "Insert all the dormant articles for this group into the current buffer."
7727 (interactive)
7728 (let ((gnus-verbose (max 6 gnus-verbose)))
7729 (if (not gnus-newsgroup-dormant)
7730 (gnus-message 3 "No cached articles for this group")
7731 (gnus-summary-goto-subjects gnus-newsgroup-dormant))))
7732
eec82323 7733(defun gnus-summary-limit-include-dormant ()
6748645f
LMI
7734 "Display all the hidden articles that are marked as dormant.
7735Note that this command only works on a subset of the articles currently
7736fetched for this group."
eec82323 7737 (interactive)
eec82323
LMI
7738 (unless gnus-newsgroup-dormant
7739 (error "There are no dormant articles in this group"))
7740 (prog1
7741 (gnus-summary-limit (append gnus-newsgroup-dormant gnus-newsgroup-limit))
7742 (gnus-summary-position-point)))
7743
7744(defun gnus-summary-limit-exclude-dormant ()
7745 "Hide all dormant articles."
7746 (interactive)
eec82323
LMI
7747 (prog1
7748 (gnus-summary-limit-to-marks (list gnus-dormant-mark) 'reverse)
7749 (gnus-summary-position-point)))
7750
7751(defun gnus-summary-limit-exclude-childless-dormant ()
7752 "Hide all dormant articles that have no children."
7753 (interactive)
eec82323
LMI
7754 (let ((data (gnus-data-list t))
7755 articles d children)
7756 ;; Find all articles that are either not dormant or have
7757 ;; children.
7758 (while (setq d (pop data))
7759 (when (or (not (= (gnus-data-mark d) gnus-dormant-mark))
7760 (and (setq children
7761 (gnus-article-children (gnus-data-number d)))
7762 (let (found)
7763 (while children
7764 (when (memq (car children) articles)
7765 (setq children nil
7766 found t))
7767 (pop children))
7768 found)))
7769 (push (gnus-data-number d) articles)))
7770 ;; Do the limiting.
7771 (prog1
7772 (gnus-summary-limit articles)
7773 (gnus-summary-position-point))))
7774
7775(defun gnus-summary-limit-mark-excluded-as-read (&optional all)
7776 "Mark all unread excluded articles as read.
7777If ALL, mark even excluded ticked and dormants as read."
7778 (interactive "P")
23f87bed
MB
7779 (setq gnus-newsgroup-limit (sort gnus-newsgroup-limit '<))
7780 (let ((articles (gnus-sorted-ndifference
eec82323
LMI
7781 (sort
7782 (mapcar (lambda (h) (mail-header-number h))
7783 gnus-newsgroup-headers)
7784 '<)
23f87bed 7785 gnus-newsgroup-limit))
eec82323 7786 article)
6748645f 7787 (setq gnus-newsgroup-unreads
23f87bed
MB
7788 (gnus-sorted-intersection gnus-newsgroup-unreads
7789 gnus-newsgroup-limit))
eec82323
LMI
7790 (if all
7791 (setq gnus-newsgroup-dormant nil
7792 gnus-newsgroup-marked nil
7793 gnus-newsgroup-reads
7794 (nconc
7795 (mapcar (lambda (n) (cons n gnus-catchup-mark)) articles)
7796 gnus-newsgroup-reads))
7797 (while (setq article (pop articles))
7798 (unless (or (memq article gnus-newsgroup-dormant)
7799 (memq article gnus-newsgroup-marked))
7800 (push (cons article gnus-catchup-mark) gnus-newsgroup-reads))))))
7801
7802(defun gnus-summary-limit (articles &optional pop)
7803 (if pop
7804 ;; We pop the previous limit off the stack and use that.
7805 (setq articles (car gnus-newsgroup-limits)
7806 gnus-newsgroup-limits (cdr gnus-newsgroup-limits))
7807 ;; We use the new limit, so we push the old limit on the stack.
7808 (push gnus-newsgroup-limit gnus-newsgroup-limits))
7809 ;; Set the limit.
7810 (setq gnus-newsgroup-limit articles)
7811 (let ((total (length gnus-newsgroup-data))
7812 (data (gnus-data-find-list (gnus-summary-article-number)))
7813 (gnus-summary-mark-below nil) ; Inhibit this.
7814 found)
7815 ;; This will do all the work of generating the new summary buffer
7816 ;; according to the new limit.
7817 (gnus-summary-prepare)
7818 ;; Hide any threads, possibly.
23f87bed 7819 (gnus-summary-maybe-hide-threads)
eec82323
LMI
7820 ;; Try to return to the article you were at, or one in the
7821 ;; neighborhood.
7822 (when data
7823 ;; We try to find some article after the current one.
7824 (while data
7825 (when (gnus-summary-goto-subject (gnus-data-number (car data)) nil t)
7826 (setq data nil
7827 found t))
7828 (setq data (cdr data))))
7829 (unless found
7830 ;; If there is no data, that means that we were after the last
7831 ;; article. The same goes when we can't find any articles
7832 ;; after the current one.
7833 (goto-char (point-max))
7834 (gnus-summary-find-prev))
6748645f 7835 (gnus-set-mode-line 'summary)
eec82323
LMI
7836 ;; We return how many articles were removed from the summary
7837 ;; buffer as a result of the new limit.
7838 (- total (length gnus-newsgroup-data))))
7839
7840(defsubst gnus-invisible-cut-children (threads)
7841 (let ((num 0))
7842 (while threads
7843 (when (memq (mail-header-number (caar threads)) gnus-newsgroup-limit)
7844 (incf num))
7845 (pop threads))
7846 (< num 2)))
7847
7848(defsubst gnus-cut-thread (thread)
7849 "Go forwards in the thread until we find an article that we want to display."
7850 (when (or (eq gnus-fetch-old-headers 'some)
6748645f 7851 (eq gnus-fetch-old-headers 'invisible)
16409b0b 7852 (numberp gnus-fetch-old-headers)
eec82323
LMI
7853 (eq gnus-build-sparse-threads 'some)
7854 (eq gnus-build-sparse-threads 'more))
7855 ;; Deal with old-fetched headers and sparse threads.
7856 (while (and
7857 thread
7858 (or
7859 (gnus-summary-article-sparse-p (mail-header-number (car thread)))
7860 (gnus-summary-article-ancient-p
7861 (mail-header-number (car thread))))
6748645f
LMI
7862 (if (or (<= (length (cdr thread)) 1)
7863 (eq gnus-fetch-old-headers 'invisible))
7864 (setq gnus-newsgroup-limit
7865 (delq (mail-header-number (car thread))
7866 gnus-newsgroup-limit)
7867 thread (cadr thread))
7868 (when (gnus-invisible-cut-children (cdr thread))
7869 (let ((th (cdr thread)))
7870 (while th
7871 (if (memq (mail-header-number (caar th))
a8151ef7 7872 gnus-newsgroup-limit)
6748645f
LMI
7873 (setq thread (car th)
7874 th nil)
7875 (setq th (cdr th))))))))))
eec82323
LMI
7876 thread)
7877
7878(defun gnus-cut-threads (threads)
23f87bed 7879 "Cut off all uninteresting articles from the beginning of THREADS."
eec82323 7880 (when (or (eq gnus-fetch-old-headers 'some)
6748645f 7881 (eq gnus-fetch-old-headers 'invisible)
16409b0b 7882 (numberp gnus-fetch-old-headers)
eec82323
LMI
7883 (eq gnus-build-sparse-threads 'some)
7884 (eq gnus-build-sparse-threads 'more))
7885 (let ((th threads))
7886 (while th
7887 (setcar th (gnus-cut-thread (car th)))
7888 (setq th (cdr th)))))
7889 ;; Remove nixed out threads.
7890 (delq nil threads))
7891
7892(defun gnus-summary-initial-limit (&optional show-if-empty)
7893 "Figure out what the initial limit is supposed to be on group entry.
7894This entails weeding out unwanted dormants, low-scored articles,
7895fetch-old-headers verbiage, and so on."
7896 ;; Most groups have nothing to remove.
7897 (if (or gnus-inhibit-limiting
7898 (and (null gnus-newsgroup-dormant)
23f87bed 7899 (eq gnus-newsgroup-display 'gnus-not-ignore)
eec82323 7900 (not (eq gnus-fetch-old-headers 'some))
16409b0b 7901 (not (numberp gnus-fetch-old-headers))
6748645f 7902 (not (eq gnus-fetch-old-headers 'invisible))
eec82323
LMI
7903 (null gnus-summary-expunge-below)
7904 (not (eq gnus-build-sparse-threads 'some))
7905 (not (eq gnus-build-sparse-threads 'more))
7906 (null gnus-thread-expunge-below)
7907 (not gnus-use-nocem)))
7908 () ; Do nothing.
7909 (push gnus-newsgroup-limit gnus-newsgroup-limits)
7910 (setq gnus-newsgroup-limit nil)
7911 (mapatoms
7912 (lambda (node)
7913 (unless (car (symbol-value node))
7914 ;; These threads have no parents -- they are roots.
7915 (let ((nodes (cdr (symbol-value node)))
7916 thread)
7917 (while nodes
7918 (if (and gnus-thread-expunge-below
7919 (< (gnus-thread-total-score (car nodes))
7920 gnus-thread-expunge-below))
7921 (gnus-expunge-thread (pop nodes))
7922 (setq thread (pop nodes))
7923 (gnus-summary-limit-children thread))))))
7924 gnus-newsgroup-dependencies)
7925 ;; If this limitation resulted in an empty group, we might
7926 ;; pop the previous limit and use it instead.
7927 (when (and (not gnus-newsgroup-limit)
7928 show-if-empty)
7929 (setq gnus-newsgroup-limit (pop gnus-newsgroup-limits)))
7930 gnus-newsgroup-limit))
7931
7932(defun gnus-summary-limit-children (thread)
7933 "Return 1 if this subthread is visible and 0 if it is not."
7934 ;; First we get the number of visible children to this thread. This
7935 ;; is done by recursing down the thread using this function, so this
7936 ;; will really go down to a leaf article first, before slowly
7937 ;; working its way up towards the root.
7938 (when thread
23f87bed
MB
7939 (let* ((max-lisp-eval-depth 5000)
7940 (children
eec82323
LMI
7941 (if (cdr thread)
7942 (apply '+ (mapcar 'gnus-summary-limit-children
7943 (cdr thread)))
7944 0))
7945 (number (mail-header-number (car thread)))
7946 score)
7947 (if (and
7948 (not (memq number gnus-newsgroup-marked))
7949 (or
7950 ;; If this article is dormant and has absolutely no visible
7951 ;; children, then this article isn't visible.
7952 (and (memq number gnus-newsgroup-dormant)
7953 (zerop children))
7954 ;; If this is "fetch-old-headered" and there is no
7955 ;; visible children, then we don't want this article.
16409b0b
GM
7956 (and (or (eq gnus-fetch-old-headers 'some)
7957 (numberp gnus-fetch-old-headers))
eec82323
LMI
7958 (gnus-summary-article-ancient-p number)
7959 (zerop children))
6748645f
LMI
7960 ;; If this is "fetch-old-headered" and `invisible', then
7961 ;; we don't want this article.
7962 (and (eq gnus-fetch-old-headers 'invisible)
7963 (gnus-summary-article-ancient-p number))
eec82323
LMI
7964 ;; If this is a sparsely inserted article with no children,
7965 ;; we don't want it.
7966 (and (eq gnus-build-sparse-threads 'some)
7967 (gnus-summary-article-sparse-p number)
7968 (zerop children))
7969 ;; If we use expunging, and this article is really
7970 ;; low-scored, then we don't want this article.
7971 (when (and gnus-summary-expunge-below
7972 (< (setq score
7973 (or (cdr (assq number gnus-newsgroup-scored))
7974 gnus-summary-default-score))
7975 gnus-summary-expunge-below))
7976 ;; We increase the expunge-tally here, but that has
7977 ;; nothing to do with the limits, really.
7978 (incf gnus-newsgroup-expunged-tally)
7979 ;; We also mark as read here, if that's wanted.
7980 (when (and gnus-summary-mark-below
7981 (< score gnus-summary-mark-below))
7982 (setq gnus-newsgroup-unreads
7983 (delq number gnus-newsgroup-unreads))
7984 (if gnus-newsgroup-auto-expire
7985 (push number gnus-newsgroup-expirable)
7986 (push (cons number gnus-low-score-mark)
7987 gnus-newsgroup-reads)))
7988 t)
23f87bed
MB
7989 ;; Do the `display' group parameter.
7990 (and gnus-newsgroup-display
7991 (not (funcall gnus-newsgroup-display)))
eec82323
LMI
7992 ;; Check NoCeM things.
7993 (if (and gnus-use-nocem
7994 (gnus-nocem-unwanted-article-p
7995 (mail-header-id (car thread))))
7996 (progn
a8151ef7 7997 (setq gnus-newsgroup-unreads
eec82323
LMI
7998 (delq number gnus-newsgroup-unreads))
7999 t))))
8000 ;; Nope, invisible article.
8001 0
8002 ;; Ok, this article is to be visible, so we add it to the limit
8003 ;; and return 1.
8004 (push number gnus-newsgroup-limit)
8005 1))))
8006
8007(defun gnus-expunge-thread (thread)
8008 "Mark all articles in THREAD as read."
8009 (let* ((number (mail-header-number (car thread))))
8010 (incf gnus-newsgroup-expunged-tally)
8011 ;; We also mark as read here, if that's wanted.
8012 (setq gnus-newsgroup-unreads
8013 (delq number gnus-newsgroup-unreads))
8014 (if gnus-newsgroup-auto-expire
8015 (push number gnus-newsgroup-expirable)
8016 (push (cons number gnus-low-score-mark)
8017 gnus-newsgroup-reads)))
8018 ;; Go recursively through all subthreads.
8019 (mapcar 'gnus-expunge-thread (cdr thread)))
8020
8021;; Summary article oriented commands
8022
8023(defun gnus-summary-refer-parent-article (n)
8024 "Refer parent article N times.
8025If N is negative, go to ancestor -N instead.
8026The difference between N and the number of articles fetched is returned."
8027 (interactive "p")
eec82323
LMI
8028 (let ((skip 1)
8029 error header ref)
8030 (when (not (natnump n))
8031 (setq skip (abs n)
8032 n 1))
8033 (while (and (> n 0)
8034 (not error))
8035 (setq header (gnus-summary-article-header))
8036 (if (and (eq (mail-header-number header)
8037 (cdr gnus-article-current))
8038 (equal gnus-newsgroup-name
8039 (car gnus-article-current)))
8040 ;; If we try to find the parent of the currently
8041 ;; displayed article, then we take a look at the actual
8042 ;; References header, since this is slightly more
8043 ;; reliable than the References field we got from the
8044 ;; server.
8045 (save-excursion
8046 (set-buffer gnus-original-article-buffer)
8047 (nnheader-narrow-to-headers)
8048 (unless (setq ref (message-fetch-field "references"))
23f87bed
MB
8049 (when (setq ref (message-fetch-field "in-reply-to"))
8050 (setq ref (gnus-extract-message-id-from-in-reply-to ref))))
eec82323
LMI
8051 (widen))
8052 (setq ref
8053 ;; It's not the current article, so we take a bet on
8054 ;; the value we got from the server.
8055 (mail-header-references header)))
8056 (if (and ref
8057 (not (equal ref "")))
8058 (unless (gnus-summary-refer-article (gnus-parent-id ref skip))
8059 (gnus-message 1 "Couldn't find parent"))
8060 (gnus-message 1 "No references in article %d"
8061 (gnus-summary-article-number))
8062 (setq error t))
8063 (decf n))
8064 (gnus-summary-position-point)
8065 n))
8066
8067(defun gnus-summary-refer-references ()
8068 "Fetch all articles mentioned in the References header.
6748645f 8069Return the number of articles fetched."
eec82323 8070 (interactive)
eec82323
LMI
8071 (let ((ref (mail-header-references (gnus-summary-article-header)))
8072 (current (gnus-summary-article-number))
8073 (n 0))
8074 (if (or (not ref)
8075 (equal ref ""))
8076 (error "No References in the current article")
8077 ;; For each Message-ID in the References header...
8078 (while (string-match "<[^>]*>" ref)
8079 (incf n)
8080 ;; ... fetch that article.
8081 (gnus-summary-refer-article
8082 (prog1 (match-string 0 ref)
8083 (setq ref (substring ref (match-end 0))))))
8084 (gnus-summary-goto-subject current)
8085 (gnus-summary-position-point)
8086 n)))
8087
6748645f
LMI
8088(defun gnus-summary-refer-thread (&optional limit)
8089 "Fetch all articles in the current thread.
8090If LIMIT (the numerical prefix), fetch that many old headers instead
8091of what's specified by the `gnus-refer-thread-limit' variable."
8092 (interactive "P")
8093 (let ((id (mail-header-id (gnus-summary-article-header)))
8094 (limit (if limit (prefix-numeric-value limit)
8095 gnus-refer-thread-limit)))
6748645f
LMI
8096 (unless (eq gnus-fetch-old-headers 'invisible)
8097 (gnus-message 5 "Fetching headers for %s..." gnus-newsgroup-name)
8098 ;; Retrieve the headers and read them in.
23f87bed
MB
8099 (if (eq (if (numberp limit)
8100 (gnus-retrieve-headers
8101 (list (min
8102 (+ (mail-header-number
8103 (gnus-summary-article-header))
8104 limit)
8105 gnus-newsgroup-end))
8106 gnus-newsgroup-name (* limit 2))
8107 ;; gnus-refer-thread-limit is t, i.e. fetch _all_
8108 ;; headers.
8109 (gnus-retrieve-headers (list gnus-newsgroup-end)
8110 gnus-newsgroup-name limit))
6748645f
LMI
8111 'nov)
8112 (gnus-build-all-threads)
23f87bed 8113 (error "Can't fetch thread from back ends that don't support NOV"))
6748645f
LMI
8114 (gnus-message 5 "Fetching headers for %s...done" gnus-newsgroup-name))
8115 (gnus-summary-limit-include-thread id)))
8116
16409b0b
GM
8117(defun gnus-summary-refer-article (message-id)
8118 "Fetch an article specified by MESSAGE-ID."
8119 (interactive "sMessage-ID: ")
eec82323
LMI
8120 (when (and (stringp message-id)
8121 (not (zerop (length message-id))))
23f87bed 8122 (setq message-id (gnus-replace-in-string message-id " " ""))
eec82323
LMI
8123 ;; Construct the correct Message-ID if necessary.
8124 ;; Suggested by tale@pawl.rpi.edu.
8125 (unless (string-match "^<" message-id)
8126 (setq message-id (concat "<" message-id)))
8127 (unless (string-match ">$" message-id)
8128 (setq message-id (concat message-id ">")))
23f87bed
MB
8129 ;; People often post MIDs from URLs, so unhex it:
8130 (unless (string-match "@" message-id)
8131 (setq message-id (gnus-url-unhex-string message-id)))
eec82323
LMI
8132 (let* ((header (gnus-id-to-header message-id))
8133 (sparse (and header
8134 (gnus-summary-article-sparse-p
a8151ef7
LMI
8135 (mail-header-number header))
8136 (memq (mail-header-number header)
16409b0b
GM
8137 gnus-newsgroup-limit)))
8138 number)
6748645f
LMI
8139 (cond
8140 ;; If the article is present in the buffer we just go to it.
8141 ((and header
8142 (or (not (gnus-summary-article-sparse-p
8143 (mail-header-number header)))
8144 sparse))
8145 (prog1
8146 (gnus-summary-goto-article
8147 (mail-header-number header) nil t)
8148 (when sparse
8149 (gnus-summary-update-article (mail-header-number header)))))
8150 (t
16409b0b
GM
8151 ;; We fetch the article.
8152 (catch 'found
8153 (dolist (gnus-override-method (gnus-refer-article-methods))
23f87bed
MB
8154 (when (and (gnus-check-server gnus-override-method)
8155 ;; Fetch the header,
8156 (setq number (gnus-summary-insert-subject message-id)))
8157 ;; and display the article.
eec82323 8158 (gnus-summary-select-article nil nil nil number)
16409b0b
GM
8159 (throw 'found t)))
8160 (gnus-message 3 "Couldn't fetch article %s" message-id)))))))
8161
8162(defun gnus-refer-article-methods ()
8f688cb0 8163 "Return a list of referable methods."
16409b0b
GM
8164 (cond
8165 ;; No method, so we default to current and native.
8166 ((null gnus-refer-article-method)
8167 (list gnus-current-select-method gnus-select-method))
8168 ;; Current.
8169 ((eq 'current gnus-refer-article-method)
8170 (list gnus-current-select-method))
8171 ;; List of select methods.
d4dfaa19
DL
8172 ((not (and (symbolp (car gnus-refer-article-method))
8173 (assq (car gnus-refer-article-method) nnoo-definition-alist)))
16409b0b
GM
8174 (let (out)
8175 (dolist (method gnus-refer-article-method)
8176 (push (if (eq 'current method)
8177 gnus-current-select-method
8178 method)
8179 out))
8180 (nreverse out)))
8181 ;; One single select method.
8182 (t
8183 (list gnus-refer-article-method))))
6748645f
LMI
8184
8185(defun gnus-summary-edit-parameters ()
8186 "Edit the group parameters of the current group."
8187 (interactive)
8188 (gnus-group-edit-group gnus-newsgroup-name 'params))
eec82323 8189
16409b0b
GM
8190(defun gnus-summary-customize-parameters ()
8191 "Customize the group parameters of the current group."
8192 (interactive)
8193 (gnus-group-customize gnus-newsgroup-name))
8194
eec82323
LMI
8195(defun gnus-summary-enter-digest-group (&optional force)
8196 "Enter an nndoc group based on the current article.
8197If FORCE, force a digest interpretation. If not, try
8198to guess what the document format is."
8199 (interactive "P")
eec82323 8200 (let ((conf gnus-current-window-configuration))
23f87bed
MB
8201 (save-window-excursion
8202 (save-excursion
8203 (let (gnus-article-prepare-hook
8204 gnus-display-mime-function
8205 gnus-break-pages)
8206 (gnus-summary-select-article))))
eec82323
LMI
8207 (setq gnus-current-window-configuration conf)
8208 (let* ((name (format "%s-%d"
8209 (gnus-group-prefixed-name
8210 gnus-newsgroup-name (list 'nndoc ""))
8211 (save-excursion
8212 (set-buffer gnus-summary-buffer)
8213 gnus-current-article)))
8214 (ogroup gnus-newsgroup-name)
8215 (params (append (gnus-info-params (gnus-get-info ogroup))
8216 (list (cons 'to-group ogroup))
23f87bed 8217 (list (cons 'parent-group ogroup))
eec82323
LMI
8218 (list (cons 'save-article-group ogroup))))
8219 (case-fold-search t)
8220 (buf (current-buffer))
16409b0b 8221 dig to-address)
eec82323 8222 (save-excursion
16409b0b
GM
8223 (set-buffer gnus-original-article-buffer)
8224 ;; Have the digest group inherit the main mail address of
8225 ;; the parent article.
23f87bed
MB
8226 (when (setq to-address (or (gnus-fetch-field "reply-to")
8227 (gnus-fetch-field "from")))
a1506d29
JB
8228 (setq params (append
8229 (list (cons 'to-address
d4dfaa19
DL
8230 (funcall gnus-decode-encoded-word-function
8231 to-address))))))
eec82323
LMI
8232 (setq dig (nnheader-set-temp-buffer " *gnus digest buffer*"))
8233 (insert-buffer-substring gnus-original-article-buffer)
8234 ;; Remove lines that may lead nndoc to misinterpret the
8235 ;; document type.
8236 (narrow-to-region
8237 (goto-char (point-min))
8238 (or (search-forward "\n\n" nil t) (point)))
8239 (goto-char (point-min))
16409b0b 8240 (delete-matching-lines "^Path:\\|^From ")
eec82323
LMI
8241 (widen))
8242 (unwind-protect
23f87bed 8243 (if (let ((gnus-newsgroup-ephemeral-charset gnus-newsgroup-charset)
16409b0b
GM
8244 (gnus-newsgroup-ephemeral-ignored-charsets
8245 gnus-newsgroup-ignored-charsets))
8246 (gnus-group-read-ephemeral-group
8247 name `(nndoc ,name (nndoc-address ,(get-buffer dig))
8248 (nndoc-article-type
23f87bed
MB
8249 ,(if force 'mbox 'guess)))
8250 t nil nil nil
8251 `((adapt-file . ,(gnus-score-file-name gnus-newsgroup-name
8252 "ADAPT")))))
16409b0b 8253 ;; Make all postings to this group go to the parent group.
23f87bed
MB
8254 (nconc (gnus-info-params (gnus-get-info name))
8255 params)
8256 ;; Couldn't select this doc group.
8257 (switch-to-buffer buf)
8258 (gnus-set-global-variables)
8259 (gnus-configure-windows 'summary)
8260 (gnus-message 3 "Article couldn't be entered?"))
eec82323
LMI
8261 (kill-buffer dig)))))
8262
8263(defun gnus-summary-read-document (n)
8264 "Open a new group based on the current article(s).
8265This will allow you to read digests and other similar
8266documents as newsgroups.
8267Obeys the standard process/prefix convention."
8268 (interactive "P")
8269 (let* ((articles (gnus-summary-work-articles n))
8270 (ogroup gnus-newsgroup-name)
8271 (params (append (gnus-info-params (gnus-get-info ogroup))
8272 (list (cons 'to-group ogroup))))
8273 article group egroup groups vgroup)
8274 (while (setq article (pop articles))
8275 (setq group (format "%s-%d" gnus-newsgroup-name article))
8276 (gnus-summary-remove-process-mark article)
8277 (when (gnus-summary-display-article article)
8278 (save-excursion
16409b0b 8279 (with-temp-buffer
eec82323
LMI
8280 (insert-buffer-substring gnus-original-article-buffer)
8281 ;; Remove some headers that may lead nndoc to make
8282 ;; the wrong guess.
8283 (message-narrow-to-head)
8284 (goto-char (point-min))
8285 (delete-matching-lines "^\\(Path\\):\\|^From ")
8286 (widen)
8287 (if (setq egroup
8288 (gnus-group-read-ephemeral-group
8289 group `(nndoc ,group (nndoc-address ,(current-buffer))
8290 (nndoc-article-type guess))
8291 t nil t))
8292 (progn
23f87bed 8293 ;; Make all postings to this group go to the parent group.
eec82323
LMI
8294 (nconc (gnus-info-params (gnus-get-info egroup))
8295 params)
8296 (push egroup groups))
8297 ;; Couldn't select this doc group.
8298 (gnus-error 3 "Article couldn't be entered"))))))
8299 ;; Now we have selected all the documents.
8300 (cond
8301 ((not groups)
8302 (error "None of the articles could be interpreted as documents"))
8303 ((gnus-group-read-ephemeral-group
8304 (setq vgroup (format
8305 "nnvirtual:%s-%s" gnus-newsgroup-name
8306 (format-time-string "%Y%m%dT%H%M%S" (current-time))))
8307 `(nnvirtual ,vgroup (nnvirtual-component-groups ,groups))
8308 t
8309 (cons (current-buffer) 'summary)))
8310 (t
8311 (error "Couldn't select virtual nndoc group")))))
8312
8313(defun gnus-summary-isearch-article (&optional regexp-p)
8314 "Do incremental search forward on the current article.
8315If REGEXP-P (the prefix) is non-nil, do regexp isearch."
8316 (interactive "P")
eec82323
LMI
8317 (gnus-summary-select-article)
8318 (gnus-configure-windows 'article)
8319 (gnus-eval-in-buffer-window gnus-article-buffer
6748645f
LMI
8320 (save-restriction
8321 (widen)
8322 (isearch-forward regexp-p))))
eec82323
LMI
8323
8324(defun gnus-summary-search-article-forward (regexp &optional backward)
8325 "Search for an article containing REGEXP forward.
8326If BACKWARD, search backward instead."
8327 (interactive
8328 (list (read-string
8329 (format "Search article %s (regexp%s): "
8330 (if current-prefix-arg "backward" "forward")
8331 (if gnus-last-search-regexp
8332 (concat ", default " gnus-last-search-regexp)
8333 "")))
8334 current-prefix-arg))
eec82323
LMI
8335 (if (string-equal regexp "")
8336 (setq regexp (or gnus-last-search-regexp ""))
23f87bed
MB
8337 (setq gnus-last-search-regexp regexp)
8338 (setq gnus-article-before-search gnus-current-article))
8339 ;; Intentionally set gnus-last-article.
8340 (setq gnus-last-article gnus-article-before-search)
8341 (let ((gnus-last-article gnus-last-article))
8342 (if (gnus-summary-search-article regexp backward)
8343 (gnus-summary-show-thread)
abc40aab 8344 (signal 'search-failed (list regexp)))))
eec82323
LMI
8345
8346(defun gnus-summary-search-article-backward (regexp)
8347 "Search for an article containing REGEXP backward."
8348 (interactive
8349 (list (read-string
8350 (format "Search article backward (regexp%s): "
8351 (if gnus-last-search-regexp
8352 (concat ", default " gnus-last-search-regexp)
8353 "")))))
8354 (gnus-summary-search-article-forward regexp 'backward))
8355
8356(defun gnus-summary-search-article (regexp &optional backward)
8357 "Search for an article containing REGEXP.
8358Optional argument BACKWARD means do search for backward.
8359`gnus-select-article-hook' is not called during the search."
a8151ef7
LMI
8360 ;; We have to require this here to make sure that the following
8361 ;; dynamic binding isn't shadowed by autoloading.
8362 (require 'gnus-async)
16409b0b 8363 (require 'gnus-art)
eec82323 8364 (let ((gnus-select-article-hook nil) ;Disable hook.
16409b0b 8365 (gnus-article-prepare-hook nil)
eec82323
LMI
8366 (gnus-mark-article-hook nil) ;Inhibit marking as read.
8367 (gnus-use-article-prefetch nil)
8368 (gnus-xmas-force-redisplay nil) ;Inhibit XEmacs redisplay.
a8151ef7 8369 (gnus-use-trees nil) ;Inhibit updating tree buffer.
23f87bed
MB
8370 (gnus-visual nil)
8371 (gnus-keep-backlog nil)
8372 (gnus-break-pages nil)
8373 (gnus-summary-display-arrow nil)
8374 (gnus-updated-mode-lines nil)
8375 (gnus-auto-center-summary nil)
eec82323 8376 (sum (current-buffer))
16409b0b 8377 (gnus-display-mime-function nil)
eec82323
LMI
8378 (found nil)
8379 point)
8380 (gnus-save-hidden-threads
8381 (gnus-summary-select-article)
8382 (set-buffer gnus-article-buffer)
16409b0b 8383 (goto-char (window-point (get-buffer-window (current-buffer))))
eec82323
LMI
8384 (when backward
8385 (forward-line -1))
8386 (while (not found)
8387 (gnus-message 7 "Searching article: %d..." (cdr gnus-article-current))
8388 (if (if backward
8389 (re-search-backward regexp nil t)
8390 (re-search-forward regexp nil t))
8391 ;; We found the regexp.
8392 (progn
8393 (setq found 'found)
8394 (beginning-of-line)
8395 (set-window-start
8396 (get-buffer-window (current-buffer))
8397 (point))
8398 (forward-line 1)
16409b0b
GM
8399 (set-window-point
8400 (get-buffer-window (current-buffer))
8401 (point))
eec82323
LMI
8402 (set-buffer sum)
8403 (setq point (point)))
8404 ;; We didn't find it, so we go to the next article.
8405 (set-buffer sum)
8406 (setq found 'not)
8407 (while (eq found 'not)
8408 (if (not (if backward (gnus-summary-find-prev)
8409 (gnus-summary-find-next)))
8410 ;; No more articles.
8411 (setq found t)
8412 ;; Select the next article and adjust point.
8413 (unless (gnus-summary-article-sparse-p
8414 (gnus-summary-article-number))
8415 (setq found nil)
8416 (gnus-summary-select-article)
8417 (set-buffer gnus-article-buffer)
8418 (widen)
8419 (goto-char (if backward (point-max) (point-min))))))))
8420 (gnus-message 7 ""))
8421 ;; Return whether we found the regexp.
8422 (when (eq found 'found)
8423 (goto-char point)
8424 (gnus-summary-show-thread)
8425 (gnus-summary-goto-subject gnus-current-article)
8426 (gnus-summary-position-point)
8427 t)))
8428
23f87bed
MB
8429(defun gnus-find-matching-articles (header regexp)
8430 "Return a list of all articles that match REGEXP on HEADER.
8431This search includes all articles in the current group that Gnus has
8432fetched headers for, whether they are displayed or not."
8433 (let ((articles nil)
8434 (func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
8435 (case-fold-search t))
8436 (dolist (header gnus-newsgroup-headers)
8437 (when (string-match regexp (funcall func header))
8438 (push (mail-header-number header) articles)))
8439 (nreverse articles)))
8440
eec82323 8441(defun gnus-summary-find-matching (header regexp &optional backward unread
47b63dfa 8442 not-case-fold not-matching)
eec82323
LMI
8443 "Return a list of all articles that match REGEXP on HEADER.
8444The search stars on the current article and goes forwards unless
8445BACKWARD is non-nil. If BACKWARD is `all', do all articles.
8446If UNREAD is non-nil, only unread articles will
8447be taken into consideration. If NOT-CASE-FOLD, case won't be folded
a1506d29 8448in the comparisons. If NOT-MATCHING, return a list of all articles that
47b63dfa
SZ
8449not match REGEXP on HEADER."
8450 (let ((case-fold-search (not not-case-fold))
16409b0b
GM
8451 articles d func)
8452 (if (consp header)
8453 (if (eq (car header) 'extra)
8454 (setq func
8455 `(lambda (h)
8456 (or (cdr (assq ',(cdr header) (mail-header-extra h)))
8457 "")))
8458 (error "%s is an invalid header" header))
8459 (unless (fboundp (intern (concat "mail-header-" header)))
8460 (error "%s is not a valid header" header))
8461 (setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h))))
47b63dfa
SZ
8462 (dolist (d (if (eq backward 'all)
8463 gnus-newsgroup-data
8464 (gnus-data-find-list
8465 (gnus-summary-article-number)
8466 (gnus-data-list backward))))
8467 (when (and (or (not unread) ; We want all articles...
8468 (gnus-data-unread-p d)) ; Or just unreads.
8469 (vectorp (gnus-data-header d)) ; It's not a pseudo.
8470 (if not-matching
a1506d29 8471 (not (string-match
47b63dfa
SZ
8472 regexp
8473 (funcall func (gnus-data-header d))))
8474 (string-match regexp
8475 (funcall func (gnus-data-header d)))))
8476 (push (gnus-data-number d) articles))) ; Success!
eec82323
LMI
8477 (nreverse articles)))
8478
8479(defun gnus-summary-execute-command (header regexp command &optional backward)
8480 "Search forward for an article whose HEADER matches REGEXP and execute COMMAND.
8481If HEADER is an empty string (or nil), the match is done on the entire
8482article. If BACKWARD (the prefix) is non-nil, search backward instead."
8483 (interactive
8484 (list (let ((completion-ignore-case t))
8485 (completing-read
8486 "Header name: "
23f87bed
MB
8487 (mapcar (lambda (header) (list (format "%s" header)))
8488 (append
8489 '("Number" "Subject" "From" "Lines" "Date"
8490 "Message-ID" "Xref" "References" "Body")
8491 gnus-extra-headers))
eec82323
LMI
8492 nil 'require-match))
8493 (read-string "Regexp: ")
8494 (read-key-sequence "Command: ")
8495 current-prefix-arg))
8496 (when (equal header "Body")
8497 (setq header ""))
eec82323
LMI
8498 ;; Hidden thread subtrees must be searched as well.
8499 (gnus-summary-show-all-threads)
8500 ;; We don't want to change current point nor window configuration.
8501 (save-excursion
8502 (save-window-excursion
23f87bed
MB
8503 (let (gnus-visual
8504 gnus-treat-strip-trailing-blank-lines
8505 gnus-treat-strip-leading-blank-lines
8506 gnus-treat-strip-multiple-blank-lines
8507 gnus-treat-hide-boring-headers
8508 gnus-treat-fold-newsgroups
8509 gnus-article-prepare-hook)
8510 (gnus-message 6 "Executing %s..." (key-description command))
8511 ;; We'd like to execute COMMAND interactively so as to give arguments.
8512 (gnus-execute header regexp
8513 `(call-interactively ',(key-binding command))
8514 backward)
8515 (gnus-message 6 "Executing %s...done" (key-description command))))))
eec82323
LMI
8516
8517(defun gnus-summary-beginning-of-article ()
8518 "Scroll the article back to the beginning."
8519 (interactive)
eec82323
LMI
8520 (gnus-summary-select-article)
8521 (gnus-configure-windows 'article)
8522 (gnus-eval-in-buffer-window gnus-article-buffer
8523 (widen)
8524 (goto-char (point-min))
23f87bed 8525 (when gnus-break-pages
eec82323
LMI
8526 (gnus-narrow-to-page))))
8527
8528(defun gnus-summary-end-of-article ()
8529 "Scroll to the end of the article."
8530 (interactive)
eec82323
LMI
8531 (gnus-summary-select-article)
8532 (gnus-configure-windows 'article)
8533 (gnus-eval-in-buffer-window gnus-article-buffer
8534 (widen)
8535 (goto-char (point-max))
8536 (recenter -3)
23f87bed
MB
8537 (when gnus-break-pages
8538 (when (re-search-backward page-delimiter nil t)
8539 (narrow-to-region (match-end 0) (point-max)))
eec82323
LMI
8540 (gnus-narrow-to-page))))
8541
23f87bed
MB
8542(defun gnus-summary-print-truncate-and-quote (string &optional len)
8543 "Truncate to LEN and quote all \"(\"'s in STRING."
8544 (gnus-replace-in-string (if (and len (> (length string) len))
8545 (substring string 0 len)
8546 string)
8547 "[()]" "\\\\\\&"))
8548
6748645f 8549(defun gnus-summary-print-article (&optional filename n)
23f87bed
MB
8550 "Generate and print a PostScript image of the process-marked (mail) articles.
8551
8552If used interactively, print the current article if none are
8553process-marked. With prefix arg, prompt the user for the name of the
8554file to save in.
6748645f 8555
23f87bed
MB
8556When used from Lisp, accept two optional args FILENAME and N. N means
8557to print the next N articles. If N is negative, print the N previous
8558articles. If N is nil and articles have been marked with the process
8559mark, print these instead.
eec82323 8560
16409b0b 8561If the optional first argument FILENAME is nil, send the image to the
6748645f
LMI
8562printer. If FILENAME is a string, save the PostScript image in a file with
8563that name. If FILENAME is a number, prompt the user for the name of the file
eec82323 8564to save in."
676a7cc9 8565 (interactive (list (ps-print-preprint current-prefix-arg)))
6748645f
LMI
8566 (dolist (article (gnus-summary-work-articles n))
8567 (gnus-summary-select-article nil nil 'pseudo article)
8568 (gnus-eval-in-buffer-window gnus-article-buffer
23f87bed 8569 (gnus-print-buffer))
676a7cc9
SZ
8570 (gnus-summary-remove-process-mark article))
8571 (ps-despool filename))
eec82323 8572
23f87bed
MB
8573(defun gnus-print-buffer ()
8574 (let ((buffer (generate-new-buffer " *print*")))
8575 (unwind-protect
8576 (progn
8577 (copy-to-buffer buffer (point-min) (point-max))
8578 (set-buffer buffer)
8579 (gnus-remove-text-with-property 'gnus-decoration)
8580 (when (gnus-visual-p 'article-highlight 'highlight)
8581 ;; Copy-to-buffer doesn't copy overlay. So redo
8582 ;; highlight.
8583 (let ((gnus-article-buffer buffer))
8584 (gnus-article-highlight-citation t)
8585 (gnus-article-highlight-signature)
8586 (gnus-article-emphasize)
8587 (gnus-article-delete-invisible-text)))
8588 (let ((ps-left-header
8589 (list
8590 (concat "("
8591 (gnus-summary-print-truncate-and-quote
8592 (mail-header-subject gnus-current-headers)
8593 66) ")")
8594 (concat "("
8595 (gnus-summary-print-truncate-and-quote
8596 (mail-header-from gnus-current-headers)
8597 45) ")")))
8598 (ps-right-header
8599 (list
8600 "/pagenumberstring load"
8601 (concat "("
8602 (mail-header-date gnus-current-headers) ")"))))
8603 (gnus-run-hooks 'gnus-ps-print-hook)
8604 (save-excursion
8605 (if window-system
8606 (ps-spool-buffer-with-faces)
8607 (ps-spool-buffer)))))
8608 (kill-buffer buffer))))
8609
eec82323 8610(defun gnus-summary-show-article (&optional arg)
23f87bed 8611 "Force redisplaying of the current article.
16409b0b
GM
8612If ARG (the prefix) is a number, show the article with the charset
8613defined in `gnus-summary-show-article-charset-alist', or the charset
23f87bed 8614input.
16409b0b 8615If ARG (the prefix) is non-nil and not a number, show the raw article
23f87bed
MB
8616without any article massaging functions being run. Normally, the key
8617strokes are `C-u g'."
eec82323 8618 (interactive "P")
16409b0b
GM
8619 (cond
8620 ((numberp arg)
23f87bed 8621 (gnus-summary-show-article t)
16409b0b
GM
8622 (let ((gnus-newsgroup-charset
8623 (or (cdr (assq arg gnus-summary-show-article-charset-alist))
23f87bed
MB
8624 (mm-read-coding-system
8625 "View as charset: " ;; actually it is coding system.
8626 (save-excursion
8627 (set-buffer gnus-article-buffer)
8628 (mm-detect-coding-region (point) (point-max))))))
16409b0b 8629 (gnus-newsgroup-ignored-charsets 'gnus-all))
23f87bed
MB
8630 (gnus-summary-select-article nil 'force)
8631 (let ((deps gnus-newsgroup-dependencies)
8632 head header lines)
8633 (save-excursion
8634 (set-buffer gnus-original-article-buffer)
8635 (save-restriction
8636 (message-narrow-to-head)
8637 (setq head (buffer-string))
8638 (goto-char (point-min))
8639 (unless (re-search-forward "^lines:[ \t]\\([0-9]+\\)" nil t)
8640 (goto-char (point-max))
8641 (widen)
8642 (setq lines (1- (count-lines (point) (point-max))))))
8643 (with-temp-buffer
8644 (insert (format "211 %d Article retrieved.\n"
8645 (cdr gnus-article-current)))
8646 (insert head)
8647 (if lines (insert (format "Lines: %d\n" lines)))
8648 (insert ".\n")
8649 (let ((nntp-server-buffer (current-buffer)))
8650 (setq header (car (gnus-get-newsgroup-headers deps t))))))
8651 (gnus-data-set-header
8652 (gnus-data-find (cdr gnus-article-current))
8653 header)
8654 (gnus-summary-update-article-line
8655 (cdr gnus-article-current) header)
8656 (when (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
8657 (gnus-summary-update-secondary-mark (cdr gnus-article-current))))))
16409b0b
GM
8658 ((not arg)
8659 ;; Select the article the normal way.
8660 (gnus-summary-select-article nil 'force))
8661 (t
8662 ;; We have to require this here to make sure that the following
8663 ;; dynamic binding isn't shadowed by autoloading.
8664 (require 'gnus-async)
8665 (require 'gnus-art)
eec82323
LMI
8666 ;; Bind the article treatment functions to nil.
8667 (let ((gnus-have-all-headers t)
eec82323 8668 gnus-article-prepare-hook
16409b0b
GM
8669 gnus-article-decode-hook
8670 gnus-display-mime-function
8671 gnus-break-pages)
8672 ;; Destroy any MIME parts.
8673 (when (gnus-buffer-live-p gnus-article-buffer)
8674 (save-excursion
8675 (set-buffer gnus-article-buffer)
8676 (mm-destroy-parts gnus-article-mime-handles)
8677 ;; Set it to nil for safety reason.
8678 (setq gnus-article-mime-handle-alist nil)
8679 (setq gnus-article-mime-handles nil)))
8680 (gnus-summary-select-article nil 'force))))
eec82323
LMI
8681 (gnus-summary-goto-subject gnus-current-article)
8682 (gnus-summary-position-point))
8683
23f87bed
MB
8684(defun gnus-summary-show-raw-article ()
8685 "Show the raw article without any article massaging functions being run."
8686 (interactive)
8687 (gnus-summary-show-article t))
8688
eec82323
LMI
8689(defun gnus-summary-verbose-headers (&optional arg)
8690 "Toggle permanent full header display.
8691If ARG is a positive number, turn header display on.
8692If ARG is a negative number, turn header display off."
8693 (interactive "P")
eec82323
LMI
8694 (setq gnus-show-all-headers
8695 (cond ((or (not (numberp arg))
8696 (zerop arg))
8697 (not gnus-show-all-headers))
8698 ((natnump arg)
8699 t)))
8700 (gnus-summary-show-article))
8701
8702(defun gnus-summary-toggle-header (&optional arg)
8703 "Show the headers if they are hidden, or hide them if they are shown.
8704If ARG is a positive number, show the entire header.
8705If ARG is a negative number, hide the unwanted header lines."
8706 (interactive "P")
23f87bed
MB
8707 (let ((window (and (gnus-buffer-live-p gnus-article-buffer)
8708 (get-buffer-window gnus-article-buffer t))))
8709 (with-current-buffer gnus-article-buffer
8710 (widen)
8711 (article-narrow-to-head)
16409b0b
GM
8712 (let* ((buffer-read-only nil)
8713 (inhibit-point-motion-hooks t)
23f87bed
MB
8714 (hidden (if (numberp arg)
8715 (>= arg 0)
8716 (gnus-article-hidden-text-p 'headers)))
8717 s e)
8718 (delete-region (point-min) (point-max))
667e0ba6
SM
8719 (with-current-buffer gnus-original-article-buffer
8720 (goto-char (setq s (point-min)))
23f87bed
MB
8721 (setq e (if (search-forward "\n\n" nil t)
8722 (1- (point))
8723 (point-max))))
667e0ba6 8724 (insert-buffer-substring gnus-original-article-buffer s e)
23f87bed
MB
8725 (run-hooks 'gnus-article-decode-hook)
8726 (if hidden
8727 (let ((gnus-treat-hide-headers nil)
8728 (gnus-treat-hide-boring-headers nil))
8729 (gnus-delete-wash-type 'headers)
8730 (gnus-treat-article 'head))
8731 (gnus-treat-article 'head))
8732 (widen)
8733 (if window
8734 (set-window-start window (goto-char (point-min))))
8735 (if gnus-break-pages
8736 (gnus-narrow-to-page)
8737 (when (gnus-visual-p 'page-marker)
8738 (let ((buffer-read-only nil))
8739 (gnus-remove-text-with-property 'gnus-prev)
8740 (gnus-remove-text-with-property 'gnus-next))))
16409b0b 8741 (gnus-set-mode-line 'article)))))
eec82323
LMI
8742
8743(defun gnus-summary-show-all-headers ()
8744 "Make all header lines visible."
8745 (interactive)
23f87bed 8746 (gnus-summary-toggle-header 1))
eec82323 8747
eec82323
LMI
8748(defun gnus-summary-caesar-message (&optional arg)
8749 "Caesar rotate the current article by 13.
8750The numerical prefix specifies how many places to rotate each letter
8751forward."
8752 (interactive "P")
eec82323
LMI
8753 (gnus-summary-select-article)
8754 (let ((mail-header-separator ""))
8755 (gnus-eval-in-buffer-window gnus-article-buffer
8756 (save-restriction
8757 (widen)
8758 (let ((start (window-start))
8759 buffer-read-only)
8760 (message-caesar-buffer-body arg)
8761 (set-window-start (get-buffer-window (current-buffer)) start))))))
8762
23f87bed
MB
8763(autoload 'unmorse-region "morse"
8764 "Convert morse coded text in region to ordinary ASCII text."
8765 t)
8766
8767(defun gnus-summary-morse-message (&optional arg)
8768 "Morse decode the current article."
8769 (interactive "P")
8770 (gnus-summary-select-article)
8771 (let ((mail-header-separator ""))
8772 (gnus-eval-in-buffer-window gnus-article-buffer
8773 (save-excursion
8774 (save-restriction
8775 (widen)
8776 (let ((pos (window-start))
8777 buffer-read-only)
8778 (goto-char (point-min))
8779 (when (message-goto-body)
8780 (gnus-narrow-to-body))
8781 (goto-char (point-min))
8782