X-Git-Url: http://cgit.sxemacs.org/?p=gnus;a=blobdiff_plain;f=lisp%2Fgnus-sum.el;h=7d239f568a8d334742635b421baa103e506ba1e0;hp=77b9bd3ea62441eb9f406d411d0dcd36a907761b;hb=178fc161c59aebf50ba3042c6aecb56888cb4d49;hpb=9a26e97c41ef82c089dd31764693badcaf498bfe;ds=sidebyside diff --git a/lisp/gnus-sum.el b/lisp/gnus-sum.el index 77b9bd3ea..7d239f568 100644 --- a/lisp/gnus-sum.el +++ b/lisp/gnus-sum.el @@ -1,5 +1,6 @@ ;;; gnus-sum.el --- summary mode commands for Gnus -;; Copyright (C) 1996,97,98 Free Software Foundation, Inc. +;; Copyright (C) 1996, 1997, 1998, 1999, 2000 +;; Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Keywords: news @@ -168,10 +169,15 @@ This variable will only be used if the value of :type 'string) (defcustom gnus-summary-goto-unread t - "*If t, marking commands will go to the next unread article. -If `never', commands that usually go to the next unread article, will -go to the next article, whether it is read or not. -If nil, only the marking commands will go to the next (un)read article." + "*If t, many commands will go to the next unread article. +This applies to marking commands as well as other commands that +\"naturally\" select the next article, like, for instance, `SPC' at +the end of an article. + +If nil, the marking commands do NOT go to the next unread article +(they go to the next article instead). If `never', commands that +usually go to the next unread article, will go to the next article, +whether it is read or not." :group 'gnus-summary-marks :link '(custom-manual "(gnus)Setting Marks") :type '(choice (const :tag "off" nil) @@ -256,8 +262,8 @@ If this variable is `best', select the highest-scored unread article in the group. If t, select the first unread article. This variable can also be a function to place point on a likely -subject line. Useful values include `gnus-summary-first-unread-subject', -`gnus-summary-first-unread-article' and +subject line. Useful values include `gnus-summary-first-unread-subject', +`gnus-summary-first-unread-article' and `gnus-summary-best-unread-article'. If you want to prevent automatic selection of the first unread article @@ -345,7 +351,7 @@ It uses the same syntax as the `gnus-split-methods' variable." (cons :value ("" "") regexp (repeat string)) (sexp :value nil)))) -(defcustom gnus-unread-mark ? +(defcustom gnus-unread-mark ? ;Whitespace "*Mark used for unread articles." :group 'gnus-summary-marks :type 'character) @@ -460,7 +466,7 @@ It uses the same syntax as the `gnus-split-methods' variable." :group 'gnus-summary-marks :type 'character) -(defcustom gnus-empty-thread-mark ? +(defcustom gnus-empty-thread-mark ? ;Whitespace "*There is no thread under the article." :group 'gnus-summary-marks :type 'character) @@ -542,6 +548,15 @@ with some simple extensions: :group 'gnus-summary-format :type 'string) +(defcustom gnus-list-identifiers nil + "Regexp that matches list identifiers to be removed from subject. +This can also be a list of regexps." + :group 'gnus-summary-format + :group 'gnus-article-hiding + :type '(choice (const :tag "none" nil) + (regexp :value ".*") + (repeat :value (".*") regexp))) + (defcustom gnus-summary-mark-below 0 "*Mark all articles with a score below this variable as read. This variable is local to each summary buffer and usually set by the @@ -606,7 +621,7 @@ See `gnus-thread-score-function' for en explanation of what a \"thread score\" is. This variable is local to the summary buffers." - :group 'gnus-treading + :group 'gnus-threading :group 'gnus-score-default :type '(choice (const :tag "off" nil) integer)) @@ -684,7 +699,8 @@ is not run if `gnus-visual' is nil." :type 'hook) (defcustom gnus-exit-group-hook nil - "*A hook called when exiting (not quitting) summary mode." + "*A hook called when exiting summary mode. +This hook is not called from the non-updating exit commands like `Q'." :group 'gnus-various :type 'hook) @@ -797,25 +813,71 @@ which it may alter in any way.") :group 'gnus-summary :type 'regexp) -(defcustom gnus-default-charset 'iso-8859-1 - "Default charset assumed to be used when viewing non-ASCII characters. -This variable is used only in non-Mule Emacsen.") +(defcustom gnus-group-charset-alist + '(("^hk\\>\\|^tw\\>\\|\\" cn-big5) + ("^cn\\>\\|\\" cn-gb-2312) + ("^fj\\>\\|^japan\\>" iso-2022-jp-2) + ("^tnn\\>\\|^pin\\>\\|^sci.lang.japan" iso-2022-7bit) + ("^relcom\\>" koi8-r) + ("^fido7\\>" koi8-r) + ("^\\(cz\\|hun\\|pl\\|sk\\|hr\\)\\>" iso-8859-2) + ("^israel\\>" iso-8859-1) + ("^han\\>" euc-kr) + ("^alt.chinese.text.big5\\>" chinese-big5) + ("^soc.culture.vietnamese\\>" vietnamese-viqr) + ("^\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1) + (".*" iso-8859-1)) + "Alist of regexps (to match group names) and default charsets to be used when reading." + :type '(repeat (list (regexp :tag "Group") + (symbol :tag "Charset"))) + :group 'gnus-charset) + +(defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown) + "List of charsets that should be ignored. +When these charsets are used in the \"charset\" parameter, the +default charset will be used instead." + :type '(repeat symbol) + :group 'gnus-charset) + +(defcustom gnus-group-ignored-charsets-alist + '(("alt\\.chinese\\.text" iso-8859-1)) + "Alist of regexps (to match group names) and charsets that should be ignored. +When these charsets are used in the \"charset\" parameter, the +default charset will be used instead." + :type '(repeat (cons (regexp :tag "Group") + (repeat symbol))) + :group 'gnus-charset) -(defcustom gnus-newsgroup-default-charset-alist - '(("^hk\\>\\|^tw\\>\\|\\" . cn-big5) - ("^cn\\>\\|\\" . cn-gb-2312) - ("^fj\\>\\|^japan\\>" . iso-2022-jp-2) - ("^relcom\\>" . koi8-r)) - "Alist of Regexps (to match group names) and default charsets to be applied." +(defcustom gnus-group-highlight-words-alist nil + "Alist of group regexps and highlight regexps. +This variable uses the same syntax as `gnus-emphasis-alist'." :type '(repeat (cons (regexp :tag "Group") + (repeat (list (regexp :tag "Highlight regexp") + (number :tag "Group for entire word" 0) + (number :tag "Group for displayed part" 0) + (symbol :tag "Face" + gnus-emphasis-highlight-words))))) + :group 'gnus-summary-visual) + +(defcustom gnus-summary-show-article-charset-alist + nil + "Alist of number and charset. +The article will be shown with the charset corresponding to the +numbered argument. +For example: ((1 . cn-gb-2312) (2 . big5))." + :type '(repeat (cons (number :tag "Argument" 1) (symbol :tag "Charset"))) - :group 'gnus) + :group 'gnus-charset) + +(defcustom gnus-preserve-marks t + "Whether marks are preserved when moving, copying and respooling messages." + :type 'boolean + :group 'gnus-summary-marks) -(defcustom gnus-newsgroup-iso-8859-1-forced-regexp - "^tw\\>\\|^hk\\>\\|^cn\\>\\|\\" - "Regexp of newsgroup in which ISO-8859-1 is forced to other charset." - :type 'regexp - :group 'gnus) +(defcustom gnus-alter-articles-to-read-function nil + "Function to be called to alter the list of articles to be selected." + :type 'function + :group 'gnus-summary) ;;; Internal variables @@ -831,6 +893,8 @@ This variable is used only in non-Mule Emacsen.") (defvar gnus-thread-indent-array nil) (defvar gnus-thread-indent-array-level gnus-thread-indent-level) +(defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number + "Function called to sort the articles within a thread after it has been gathered together.") ;; Avoid highlighting in kill files. (defvar gnus-summary-inhibit-highlight nil) @@ -1005,9 +1069,9 @@ variable (string, integer, character, etc).") (defvar gnus-have-all-headers nil) (defvar gnus-last-article nil) (defvar gnus-newsgroup-history nil) - -(defvar gnus-newsgroup-default-charset gnus-default-charset) -(defvar gnus-newsgroup-iso-8859-1-forced nil) +(defvar gnus-newsgroup-charset nil) +(defvar gnus-newsgroup-ephemeral-charset nil) +(defvar gnus-newsgroup-ephemeral-ignored-charsets nil) (defconst gnus-summary-local-variables '(gnus-newsgroup-name @@ -1029,7 +1093,8 @@ variable (string, integer, character, etc).") gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay gnus-newsgroup-scored gnus-newsgroup-kill-headers gnus-thread-expunge-below - gnus-score-alist gnus-current-score-file gnus-summary-expunge-below + gnus-score-alist gnus-current-score-file + (gnus-summary-expunge-below . global) (gnus-summary-mark-below . global) gnus-newsgroup-active gnus-scores-exclude-files gnus-newsgroup-history gnus-newsgroup-ancient @@ -1040,7 +1105,7 @@ variable (string, integer, character, etc).") gnus-cache-removable-articles gnus-newsgroup-cached gnus-newsgroup-data gnus-newsgroup-data-reverse gnus-newsgroup-limit gnus-newsgroup-limits - gnus-newsgroup-default-charset gnus-newsgroup-iso-8859-1-forced) + gnus-newsgroup-charset) "Variables that are buffer-local to the summary buffers.") ;; Byte-compiler warning. @@ -1052,14 +1117,14 @@ variable (string, integer, character, etc).") '(mail-decode-encoded-word-string) "List of methods used to decode encoded words. -This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item is -FUNCTION, FUNCTION will be apply to all newsgroups. If item is a +This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item is +FUNCTION, FUNCTION will be apply to all newsgroups. If item is a (REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups whose names match REGEXP. -For example: +For example: ((\"chinese\" . gnus-decode-encoded-word-string-by-guess) - mail-decode-encoded-word-string + mail-decode-encoded-word-string (\"chinese\" . rfc1843-decode-string)) ") @@ -1068,16 +1133,16 @@ For example: (defun gnus-multi-decode-encoded-word-string (string) "Apply the functions from `gnus-encoded-word-methods' that match." (unless (and gnus-decode-encoded-word-methods-cache - (eq gnus-newsgroup-name + (eq gnus-newsgroup-name (car gnus-decode-encoded-word-methods-cache))) (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name)) - (mapc '(lambda (x) - (if (symbolp x) - (nconc gnus-decode-encoded-word-methods-cache (list x)) - (if (and gnus-newsgroup-name - (string-match (car x) gnus-newsgroup-name)) - (nconc gnus-decode-encoded-word-methods-cache - (list (cdr x)))))) + (mapcar (lambda (x) + (if (symbolp x) + (nconc gnus-decode-encoded-word-methods-cache (list x)) + (if (and gnus-newsgroup-name + (string-match (car x) gnus-newsgroup-name)) + (nconc gnus-decode-encoded-word-methods-cache + (list (cdr x)))))) gnus-decode-encoded-word-methods)) (let ((xlist gnus-decode-encoded-word-methods-cache)) (pop xlist) @@ -1133,7 +1198,7 @@ If RE-ONLY is non-nil, strip leading `Re:'s only." (defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext) (goto-char (point-min)) (while (re-search-forward regexp nil t) - (replace-match (or newtext "")))) + (replace-match (or newtext "")))) (defun gnus-simplify-buffer-fuzzy () "Simplify string in the buffer fuzzily. @@ -1265,6 +1330,8 @@ increase the score of each group you read." "\M-\C-h" gnus-summary-hide-thread "\M-\C-f" gnus-summary-next-thread "\M-\C-b" gnus-summary-prev-thread + [(meta down)] gnus-summary-next-thread + [(meta up)] gnus-summary-prev-thread "\M-\C-u" gnus-summary-up-thread "\M-\C-d" gnus-summary-down-thread "&" gnus-summary-execute-command @@ -1275,6 +1342,7 @@ increase the score of each group you read." "\C-c\M-\C-s" gnus-summary-limit-include-expunged "\C-c\C-s\C-n" gnus-summary-sort-by-number "\C-c\C-s\C-l" gnus-summary-sort-by-lines + "\C-c\C-s\C-c" gnus-summary-sort-by-chars "\C-c\C-s\C-a" gnus-summary-sort-by-author "\C-c\C-s\C-s" gnus-summary-sort-by-subject "\C-c\C-s\C-d" gnus-summary-sort-by-date @@ -1305,14 +1373,14 @@ increase the score of each group you read." "a" gnus-summary-post-news "x" gnus-summary-limit-to-unread "s" gnus-summary-isearch-article - "t" gnus-article-hide-headers + "t" gnus-summary-toggle-header "g" gnus-summary-show-article "l" gnus-summary-goto-last-article "\C-c\C-v\C-v" gnus-uu-decode-uu-view "\C-d" gnus-summary-enter-digest-group "\M-\C-d" gnus-summary-read-document "\M-\C-e" gnus-summary-edit-parameters - "\M-\C-g" gnus-summary-customize-parameters + "\M-\C-a" gnus-summary-customize-parameters "\C-c\C-b" gnus-bug "*" gnus-cache-enter-article "\M-*" gnus-cache-remove-article @@ -1325,7 +1393,7 @@ increase the score of each group you read." "b" gnus-article-view-part "\M-t" gnus-summary-toggle-display-buttonized - + "V" gnus-summary-score-map "X" gnus-uu-extract-map "S" gnus-summary-send-map) @@ -1367,12 +1435,14 @@ increase the score of each group you read." "a" gnus-summary-limit-to-author "u" gnus-summary-limit-to-unread "m" gnus-summary-limit-to-marks + "M" gnus-summary-limit-exclude-marks "v" gnus-summary-limit-to-score "*" gnus-summary-limit-include-cached "D" gnus-summary-limit-include-dormant "T" gnus-summary-limit-include-thread "d" gnus-summary-limit-exclude-dormant "t" gnus-summary-limit-to-age + "x" gnus-summary-limit-to-extra "E" gnus-summary-limit-include-expunged "c" gnus-summary-limit-exclude-childless-dormant "C" gnus-summary-limit-mark-excluded-as-read) @@ -1443,11 +1513,13 @@ increase the score of each group you read." "e" gnus-summary-end-of-article "^" gnus-summary-refer-parent-article "r" gnus-summary-refer-parent-article + "D" gnus-summary-enter-digest-group "R" gnus-summary-refer-references "T" gnus-summary-refer-thread "g" gnus-summary-show-article "s" gnus-summary-isearch-article - "P" gnus-summary-print-article) + "P" gnus-summary-print-article + "t" gnus-article-babel) (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map) "b" gnus-article-add-buttons @@ -1455,6 +1527,8 @@ increase the score of each group you read." "o" gnus-article-treat-overstrike "e" gnus-article-emphasize "w" gnus-article-fill-cited-article + "Q" gnus-article-fill-long-lines + "C" gnus-article-capitalize-sentences "c" gnus-article-remove-cr "q" gnus-article-de-quoted-unreadable "f" gnus-article-display-x-face @@ -1462,7 +1536,7 @@ increase the score of each group you read." "r" gnus-summary-caesar-message "t" gnus-article-hide-headers "v" gnus-summary-verbose-headers - "h" gnus-article-treat-html + "H" gnus-article-strip-headers-in-body "d" gnus-article-treat-dumbquotes) (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map) @@ -1472,7 +1546,9 @@ increase the score of each group you read." "s" gnus-article-hide-signature "c" gnus-article-hide-citation "C" gnus-article-hide-citation-in-followups + "l" gnus-article-hide-list-identifiers "p" gnus-article-hide-pgp + "B" gnus-article-strip-banner "P" gnus-article-hide-pem "\C-c" gnus-article-hide-citation-maybe) @@ -1518,6 +1594,7 @@ increase the score of each group you read." "\M-\C-e" gnus-summary-expire-articles-now "\177" gnus-summary-delete-article [delete] gnus-summary-delete-article + [backspace] gnus-summary-delete-article "m" gnus-summary-move-article "r" gnus-summary-respool-article "w" gnus-summary-edit-article @@ -1547,8 +1624,8 @@ increase the score of each group you read." "o" gnus-article-save-part "c" gnus-article-copy-part "e" gnus-article-externalize-part - "|" gnus-article-pipe-part) - ) + "i" gnus-article-inline-part + "|" gnus-article-pipe-part)) (defun gnus-summary-make-menu-bar () (gnus-turn-off-edit-menu 'summary) @@ -1591,7 +1668,9 @@ increase the score of each group you read." ["Headers" gnus-article-hide-headers t] ["Signature" gnus-article-hide-signature t] ["Citation" gnus-article-hide-citation t] + ["List identifiers" gnus-article-hide-list-identifiers t] ["PGP" gnus-article-hide-pgp t] + ["Banner" gnus-article-strip-banner t] ["Boring headers" gnus-article-hide-boring-headers t]) ("Highlight" ["All" gnus-article-highlight t] @@ -1623,17 +1702,19 @@ increase the score of each group you read." ["Dumb quotes" gnus-article-treat-dumbquotes t] ["Emphasis" gnus-article-emphasize t] ["Word wrap" gnus-article-fill-cited-article t] + ["Fill long lines" gnus-article-fill-long-lines t] + ["Capitalize sentences" gnus-article-capitalize-sentences t] ["CR" gnus-article-remove-cr t] ["Show X-Face" gnus-article-display-x-face t] ["Quoted-Printable" gnus-article-de-quoted-unreadable t] - ["UnHTMLize" gnus-article-treat-html t] ["Rot 13" gnus-summary-caesar-message t] ["Unix pipe" gnus-summary-pipe-message t] ["Add buttons" gnus-article-add-buttons t] ["Add buttons to head" gnus-article-add-buttons-to-head t] ["Stop page breaking" gnus-summary-stop-page-breaking t] ["Verbose header" gnus-summary-verbose-headers t] - ["Toggle header" gnus-summary-toggle-header t]) + ["Toggle header" gnus-summary-toggle-header t] + ["HZ" gnus-article-decode-HZ t]) ("Output" ["Save in default format" gnus-summary-save-article t] ["Save in file" gnus-summary-save-article-file t] @@ -1677,6 +1758,7 @@ increase the score of each group you read." ("Cache" ["Enter article" gnus-cache-enter-article t] ["Remove article" gnus-cache-remove-article t]) + ["Translate" gnus-article-babel t] ["Select article buffer" gnus-summary-select-article-buffer t] ["Enter digest buffer" gnus-summary-enter-digest-group t] ["Isearch article..." gnus-summary-isearch-article t] @@ -1711,8 +1793,7 @@ increase the score of each group you read." ["Mark thread as read" gnus-summary-kill-thread t] ["Lower thread score" gnus-summary-lower-thread t] ["Raise thread score" gnus-summary-raise-thread t] - ["Rethread current" gnus-summary-rethread-current t] - )) + ["Rethread current" gnus-summary-rethread-current t])) (easy-menu-define gnus-summary-post-menu gnus-summary-mode-map "" @@ -1767,6 +1848,7 @@ increase the score of each group you read." ["Subject..." gnus-summary-limit-to-subject t] ["Author..." gnus-summary-limit-to-author t] ["Age..." gnus-summary-limit-to-age t] + ["Extra..." gnus-summary-limit-to-extra t] ["Score" gnus-summary-limit-to-score t] ["Unread" gnus-summary-limit-to-unread t] ["Non-dormant" gnus-summary-limit-exclude-dormant t] @@ -1776,6 +1858,7 @@ increase the score of each group you read." ["Hide childless dormant" gnus-summary-limit-exclude-childless-dormant t] ;;["Hide thread" gnus-summary-limit-exclude-thread t] + ["Hide marked" gnus-summary-limit-exclude-marks t] ["Show expunged" gnus-summary-show-all-expunged t]) ("Process Mark" ["Set mark" gnus-summary-mark-as-processable t] @@ -1822,7 +1905,8 @@ increase the score of each group you read." ["Sort by subject" gnus-summary-sort-by-subject t] ["Sort by date" gnus-summary-sort-by-date t] ["Sort by score" gnus-summary-sort-by-score t] - ["Sort by lines" gnus-summary-sort-by-lines t]) + ["Sort by lines" gnus-summary-sort-by-lines t] + ["Sort by characters" gnus-summary-sort-by-chars t]) ("Help" ["Fetch group FAQ" gnus-summary-fetch-faq t] ["Describe group" gnus-summary-describe-group t] @@ -1932,7 +2016,8 @@ increase the score of each group you read." (list 'gnus-summary-header (nth 1 header))) (list 'quote (nth 1 (car ts))) - (list 'gnus-score-default nil) + (list 'gnus-score-delta-default + nil) (nth 1 (car ps)) t) t) @@ -1992,8 +2077,6 @@ The following commands are available: (make-local-variable 'gnus-summary-dummy-line-format) (make-local-variable 'gnus-summary-dummy-line-format-spec) (make-local-variable 'gnus-summary-mark-positions) - (make-local-hook 'post-command-hook) - (add-hook 'post-command-hook 'gnus-clear-inboxes-moved nil t) (make-local-hook 'pre-command-hook) (add-hook 'pre-command-hook 'gnus-set-global-variables nil t) (gnus-run-hooks 'gnus-summary-mode-hook) @@ -2003,9 +2086,8 @@ The following commands are available: (defun gnus-summary-make-local-variables () "Make all the local summary buffer variables." - (let ((locals gnus-summary-local-variables) - global local) - (while (setq local (pop locals)) + (let (global) + (dolist (local gnus-summary-local-variables) (if (consp local) (progn (if (eq (cdr local) 'global) @@ -2013,11 +2095,9 @@ The following commands are available: (setq global (symbol-value (car local))) ;; Use the value from the list. (setq global (eval (cdr local)))) - (make-local-variable (car local)) - (set (car local) global)) + (set (make-local-variable (car local)) global)) ;; Simple nil-valued local variable. - (make-local-variable local) - (set local nil))))) + (set (make-local-variable local) nil))))) (defun gnus-summary-clear-local-variables () (let ((locals gnus-summary-local-variables)) @@ -2414,8 +2494,7 @@ marks of articles." (gac gnus-article-current) (reffed gnus-reffed-article-number) (score-file gnus-current-score-file) - (default-charset gnus-newsgroup-default-charset) - (iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced)) + (default-charset gnus-newsgroup-charset)) (save-excursion (set-buffer gnus-group-buffer) (setq gnus-newsgroup-name name @@ -2429,8 +2508,7 @@ marks of articles." gnus-original-article-buffer original gnus-reffed-article-number reffed gnus-current-score-file score-file - gnus-newsgroup-default-charset default-charset - gnus-newsgroup-iso-8859-1-forced iso-8859-1-forced) + gnus-newsgroup-charset default-charset) ;; The article buffer also has local variables. (when (gnus-buffer-live-p gnus-article-buffer) (set-buffer gnus-article-buffer) @@ -2449,7 +2527,8 @@ marks of articles." (defun gnus-summary-last-article-p (&optional article) "Return whether ARTICLE is the last article in the buffer." (if (not (setq article (or article (gnus-summary-article-number)))) - t ; All non-existent numbers are the last article. :-) + ;; All non-existent numbers are the last article. :-) + t (not (cdr (gnus-data-find-list article))))) (defun gnus-make-thread-indent-array () @@ -2506,8 +2585,10 @@ marks of articles." (defun gnus-summary-from-or-to-or-newsgroups (header) (let ((to (cdr (assq 'To (mail-header-extra header)))) (newsgroups (cdr (assq 'Newsgroups (mail-header-extra header)))) - (rfc2047-default-charset gnus-newsgroup-default-charset) - (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced)) + (mail-parse-charset gnus-newsgroup-charset) + (mail-parse-ignored-charsets + (save-excursion (set-buffer gnus-summary-buffer) + gnus-newsgroup-ignored-charsets))) (cond ((and to gnus-ignored-from-addresses @@ -2541,7 +2622,7 @@ marks of articles." (if (or (null gnus-summary-default-score) (<= (abs (- gnus-tmp-score gnus-summary-default-score)) gnus-summary-zcore-fuzz)) - ? + ? ;Whitespace (if (< gnus-tmp-score gnus-summary-default-score) gnus-score-below-mark gnus-score-over-mark))) (gnus-tmp-replied @@ -2606,7 +2687,7 @@ marks of articles." (if (or (null gnus-summary-default-score) (<= (abs (- score gnus-summary-default-score)) gnus-summary-zcore-fuzz)) - ? + ? ;Whitespace (if (< score gnus-summary-default-score) gnus-score-below-mark gnus-score-over-mark)) 'score)) @@ -2757,6 +2838,7 @@ If NO-DISPLAY, don't generate a summary buffer." (gnus-summary-set-local-parameters gnus-newsgroup-name) (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy) + (gnus-update-summary-mark-positions) ;; Do score processing. (when gnus-use-scoring (gnus-possibly-score-headers)) @@ -2769,6 +2851,7 @@ If NO-DISPLAY, don't generate a summary buffer." (let ((gnus-newsgroup-dormant nil)) (gnus-summary-initial-limit show-all)) (gnus-summary-initial-limit show-all)) + ;; When untreaded, all articles are always shown. (setq gnus-newsgroup-limit (mapcar (lambda (header) (mail-header-number header)) @@ -2972,7 +3055,7 @@ If NO-DISPLAY, don't generate a summary buffer." (while threads (when (stringp (caar threads)) (setcdr (car threads) - (sort (cdar threads) 'gnus-thread-sort-by-number))) + (sort (cdar threads) gnus-sort-gathered-threads-function))) (setq threads (cdr threads))) result)) @@ -3107,6 +3190,7 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (defun gnus-build-sparse-threads () (let ((headers gnus-newsgroup-headers) + (mail-parse-charset gnus-newsgroup-charset) (gnus-summary-ignore-duplicates t) header references generation relations subject child end new-child date) @@ -3159,7 +3243,8 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." ;; fetch the headers for the articles that aren't there. This will ;; build complete threads - if the roots haven't been expired by the ;; server, that is. - (let (id heads) + (let ((mail-parse-charset gnus-newsgroup-charset) + id heads) (mapatoms (lambda (refs) (when (not (car (symbol-value refs))) @@ -3174,31 +3259,6 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (setq heads nil))))) gnus-newsgroup-dependencies))) -(defmacro gnus-nov-read-integer () - '(prog1 - (if (eq (char-after) ?\t) - 0 - (let ((num (ignore-errors (read buffer)))) - (if (numberp num) num 0))) - (unless (eobp) - (search-forward "\t" eol 'move)))) - -(defmacro gnus-nov-skip-field () - '(search-forward "\t" eol 'move)) - -(defmacro gnus-nov-field () - '(buffer-substring (point) (if (gnus-nov-skip-field) (1- (point)) eol))) - -(defmacro gnus-nov-parse-extra () - '(let (out string) - (while (not (memq (char-after) '(?\n nil))) - (setq string (gnus-nov-field)) - (when (string-match "^\\([^ :]+\\): " string) - (push (cons (intern (match-string 1 string)) - (substring string (match-end 0))) - out))) - out)) - ;; This function has to be called with point after the article number ;; on the beginning of the line. (defsubst gnus-nov-parse-line (number dependencies &optional force-new) @@ -3217,18 +3277,17 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (make-full-mail-header number ; number (funcall gnus-decode-encoded-word-function - (gnus-nov-field)) ; subject + (nnheader-nov-field)) ; subject (funcall gnus-decode-encoded-word-function - (gnus-nov-field)) ; from - (gnus-nov-field) ; date - (or (gnus-nov-field) - (nnheader-generate-fake-message-id)) ; id - (gnus-nov-field) ; refs - (gnus-nov-read-integer) ; chars - (gnus-nov-read-integer) ; lines - (unless (eq (char-after) ?\n) - (gnus-nov-field)) ; misc - (gnus-nov-parse-extra)))) ; extra + (nnheader-nov-field)) ; from + (nnheader-nov-field) ; date + (nnheader-nov-read-message-id) ; id + (nnheader-nov-field) ; refs + (nnheader-nov-read-integer) ; chars + (nnheader-nov-read-integer) ; lines + (unless (eobp) + (nnheader-nov-field)) ; misc + (nnheader-nov-parse-extra)))) ; extra (widen)) @@ -3274,6 +3333,7 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (defun gnus-build-all-threads () "Read all the headers." (let ((gnus-summary-ignore-duplicates t) + (mail-parse-charset gnus-newsgroup-charset) (dependencies gnus-newsgroup-dependencies) header article) (save-excursion @@ -3283,8 +3343,7 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (while (not (eobp)) (ignore-errors (setq article (read (current-buffer)) - header (gnus-nov-parse-line - article dependencies))) + header (gnus-nov-parse-line article dependencies))) (when header (save-excursion (set-buffer gnus-summary-buffer) @@ -3321,17 +3380,19 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (memq article gnus-newsgroup-expirable) ;; Only insert the Subject string when it's different ;; from the previous Subject string. - (if (gnus-subject-equal - (condition-case () - (mail-header-subject - (gnus-data-header - (cadr - (gnus-data-find-list - article - (gnus-data-list t))))) - ;; Error on the side of excessive subjects. - (error "")) - (mail-header-subject header)) + (if (and + gnus-show-threads + (gnus-subject-equal + (condition-case () + (mail-header-subject + (gnus-data-header + (cadr + (gnus-data-find-list + article + (gnus-data-list t))))) + ;; Error on the side of excessive subjects. + (error "")) + (mail-header-subject header))) "" (mail-header-subject header)) nil (cdr (assq article gnus-newsgroup-scored)) @@ -3545,7 +3606,6 @@ If LINE, insert the rebuilt thread starting on line LINE." (while thread (gnus-remove-thread-1 (car thread)) (setq thread (cdr thread)))) - (gnus-summary-show-all-threads) (gnus-remove-thread-1 thread)))))))) (defun gnus-remove-thread-1 (thread) @@ -3557,6 +3617,7 @@ If LINE, insert the rebuilt thread starting on line LINE." (gnus-remove-thread-1 (pop thread))) (when (setq d (gnus-data-find number)) (goto-char (gnus-data-pos d)) + (gnus-summary-show-thread) (gnus-data-remove number (- (gnus-point-at-bol) @@ -3590,7 +3651,7 @@ If LINE, insert the rebuilt thread starting on line LINE." ;; using some other form will lead to serious barfage. (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread))) ;; (8% speedup to gnus-summary-prepare, just for fun :-) - (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207" ; + (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207" (vector thread) 2)) (defsubst gnus-article-sort-by-number (h1 h2) @@ -3613,6 +3674,16 @@ If LINE, insert the rebuilt thread starting on line LINE." (gnus-article-sort-by-lines (gnus-thread-header h1) (gnus-thread-header h2))) +(defsubst gnus-article-sort-by-chars (h1 h2) + "Sort articles by octet length." + (< (mail-header-chars h1) + (mail-header-chars h2))) + +(defun gnus-thread-sort-by-chars (h1 h2) + "Sort threads by root article octet length." + (gnus-article-sort-by-chars + (gnus-thread-header h1) (gnus-thread-header h2))) + (defsubst gnus-article-sort-by-author (h1 h2) "Sort articles by root author." (string-lessp @@ -3673,7 +3744,7 @@ Unscored articles will be counted as having a score of zero." (> (gnus-thread-total-score h1) (gnus-thread-total-score h2))) (defun gnus-thread-total-score (thread) - ;; This function find the total score of THREAD. + ;; This function find the total score of THREAD. (cond ((null thread) 0) ((consp thread) @@ -3907,7 +3978,7 @@ or a straight list of headers." (if (or (null gnus-summary-default-score) (<= (abs (- gnus-tmp-score gnus-summary-default-score)) gnus-summary-zcore-fuzz)) - ? + ? ;Whitespace (if (< gnus-tmp-score gnus-summary-default-score) gnus-score-below-mark gnus-score-over-mark)) gnus-tmp-replied @@ -3991,6 +4062,20 @@ or a straight list of headers." (cdr (assq number gnus-newsgroup-scored)) (memq number gnus-newsgroup-processable)))))) +(defun gnus-summary-remove-list-identifiers () + "Remove list identifiers in `gnus-list-identifiers' from articles in the current group." + (let ((regexp (if (stringp gnus-list-identifiers) + gnus-list-identifiers + (mapconcat 'identity gnus-list-identifiers " *\\|")))) + (dolist (header gnus-newsgroup-headers) + (when (string-match (concat "\\(Re: +\\)?\\(" regexp " *\\)") + (mail-header-subject header)) + (mail-header-set-subject + header (concat (substring (mail-header-subject header) + 0 (match-beginning 2)) + (substring (mail-header-subject header) + (match-end 2)))))))) + (defun gnus-select-newsgroup (group &optional read-all select-articles) "Select newsgroup GROUP. If READ-ALL is non-nil, all articles in the group are selected. @@ -4026,7 +4111,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." (setq gnus-newsgroup-name group) (setq gnus-newsgroup-unselected nil) (setq gnus-newsgroup-unreads (gnus-list-of-unread-articles group)) - (gnus-newsgroup-setup-default-charset) + (gnus-summary-setup-default-charset) ;; Adjust and set lists of article marks. (when info @@ -4110,6 +4195,9 @@ If SELECT-ARTICLES, only select those articles from GROUP." ;; Let the Gnus agent mark articles as read. (when gnus-agent (gnus-agent-get-undownloaded-list)) + ;; Remove list identifiers from subject + (when gnus-list-identifiers + (gnus-summary-remove-list-identifiers)) ;; Check whether auto-expire is to be done in this group. (setq gnus-newsgroup-auto-expire (gnus-group-auto-expirable-p group)) @@ -4136,7 +4224,9 @@ If SELECT-ARTICLES, only select those articles from GROUP." (zerop (length gnus-newsgroup-unreads))) (eq (gnus-group-find-parameter group 'display) 'all)) - (gnus-uncompress-range (gnus-active group)) + (or + (gnus-uncompress-range (gnus-active group)) + (gnus-cache-articles-in-group group)) (sort (append gnus-newsgroup-dormant gnus-newsgroup-marked (copy-sequence gnus-newsgroup-unreads)) '<))) @@ -4192,6 +4282,12 @@ If SELECT-ARTICLES, only select those articles from GROUP." (gnus-sorted-intersection gnus-newsgroup-unreads (gnus-sorted-complement gnus-newsgroup-unreads articles))) + (when gnus-alter-articles-to-read-function + (setq gnus-newsgroup-unreads + (sort + (funcall gnus-alter-articles-to-read-function + gnus-newsgroup-name gnus-newsgroup-unreads) + '<))) articles))) (defun gnus-killed-articles (killed articles) @@ -4214,7 +4310,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." out)) (defun gnus-adjust-marked-articles (info) - "Set all article lists and remove all marks that are no longer legal." + "Set all article lists and remove all marks that are no longer valid." (let* ((marked-lists (gnus-info-marks info)) (active (gnus-active (gnus-info-group info))) (min (car active)) @@ -4274,13 +4370,14 @@ If SELECT-ARTICLES, only select those articles from GROUP." (uncompressed '(score bookmark killed)) type list newmarked symbol delta-marks) (when info - ;; Add all marks lists that are non-nil to the list of marks lists. + ;; Add all marks lists to the list of marks lists. (while (setq type (pop types)) - (when (setq list (symbol-value - (setq symbol - (intern (format "gnus-newsgroup-%s" - (car type)))))) + (setq list (symbol-value + (setq symbol + (intern (format "gnus-newsgroup-%s" + (car type)))))) + (when list ;; Get rid of the entries of the articles that have the ;; default score. (when (and (eq (cdr type) 'score) @@ -4295,14 +4392,33 @@ If SELECT-ARTICLES, only select those articles from GROUP." (setcdr prev (cdr arts)) (setq prev arts)) (setq arts (cdr arts))) - (setq list (cdr all)))) - - (push (cons (cdr type) - (if (memq (cdr type) uncompressed) list - (gnus-compress-sequence - (set symbol (sort list '<)) t))) - newmarked))) - + (setq list (cdr all))))) + + (unless (memq (cdr type) uncompressed) + (setq list (gnus-compress-sequence (set symbol (sort list '<)) t))) + + (when (gnus-check-backend-function + 'request-set-mark gnus-newsgroup-name) + ;; uncompressed:s are not proper flags (they are cons cells) + ;; cache is a internal gnus flag + (unless (memq (cdr type) (cons 'cache uncompressed)) + (let* ((old (cdr (assq (cdr type) (gnus-info-marks info)))) + (del (gnus-remove-from-range (gnus-copy-sequence old) list)) + (add (gnus-remove-from-range + (gnus-copy-sequence list) old))) + (when add + (push (list add 'add (list (cdr type))) delta-marks)) + (when del + (push (list del 'del (list (cdr type))) delta-marks))))) + + (when list + (push (cons (cdr type) list) newmarked))) + + (when delta-marks + (unless (gnus-check-group gnus-newsgroup-name) + (error "Can't open server for %s" gnus-newsgroup-name)) + (gnus-request-set-mark gnus-newsgroup-name delta-marks)) + ;; Enter these new marks into the info of the group. (if (nthcdr 3 info) (setcar (nthcdr 3 info) newmarked) @@ -4451,7 +4567,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." (active (gnus-active group)) ninfo) (when entry - ;; First peel off all illegal article numbers. + ;; First peel off all invalid article numbers. (when active (let ((ids articles) id first) @@ -4520,15 +4636,6 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; Update the group buffer. (gnus-group-update-group group t))))) -(defun gnus-methods-equal-p (m1 m2) - (let ((m1 (or m1 gnus-select-method)) - (m2 (or m2 gnus-select-method))) - (or (equal m1 m2) - (and (eq (car m1) (car m2)) - (or (not (memq 'address (assoc (symbol-name (car m1)) - gnus-valid-select-methods))) - (equal (nth 1 m1) (nth 1 m2))))))) - (defvar gnus-newsgroup-none-id 0) (defun gnus-get-newsgroup-headers (&optional dependencies force-new) @@ -4538,8 +4645,12 @@ The resulting hash table is returned, or nil if no Xrefs were found." (save-excursion (set-buffer gnus-summary-buffer) gnus-newsgroup-dependencies))) headers id end ref - (rfc2047-default-charset gnus-newsgroup-default-charset) - (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced)) + (mail-parse-charset gnus-newsgroup-charset) + (mail-parse-ignored-charsets + (save-excursion (condition-case nil + (set-buffer gnus-summary-buffer) + (error)) + gnus-newsgroup-ignored-charsets))) (save-excursion (set-buffer nntp-server-buffer) ;; Translate all TAB characters into SPACE characters. @@ -4692,8 +4803,8 @@ list of headers that match SEQUENCE (see `nntp-retrieve-headers')." ;; Get the Xref when the users reads the articles since most/some ;; NNTP servers do not include Xrefs when using XOVER. (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs)) - (let ((rfc2047-default-charset gnus-newsgroup-default-charset) - (mm-charset-iso-8859-1-forced gnus-newsgroup-iso-8859-1-forced) + (let ((mail-parse-charset gnus-newsgroup-charset) + (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets) (cur nntp-server-buffer) (dependencies (or dependencies gnus-newsgroup-dependencies)) number headers header) @@ -4753,7 +4864,8 @@ This is meant to be called in `gnus-article-internal-prepare-hook'." (save-restriction (nnheader-narrow-to-headers) (goto-char (point-min)) - (when (or (and (eq (downcase (char-after)) ?x) + (when (or (and (not (eobp)) + (eq (downcase (char-after)) ?x) (looking-at "Xref:")) (search-forward "\nXref:" nil t)) (goto-char (1+ (match-end 0))) @@ -4870,7 +4982,8 @@ executed with point over the summary line of the articles." `(let ((,articles (gnus-summary-work-articles ,arg))) (while ,articles (gnus-summary-goto-subject (car ,articles)) - ,@forms)))) + ,@forms + (pop ,articles))))) (put 'gnus-summary-iterate 'lisp-indent-function 1) (put 'gnus-summary-iterate 'edebug-form-spec '(form body)) @@ -5004,7 +5117,8 @@ articles with that subject. If BACKWARD, search backward instead." "Center point in window and redisplay frame. Also do horizontal recentering." (interactive "P") - (when (and gnus-auto-center-summary + (when (and nil + gnus-auto-center-summary (not (eq gnus-auto-center-summary 'vertical))) (gnus-horizontal-recenter)) (recenter n)) @@ -5015,6 +5129,7 @@ If `gnus-auto-center-summary' is nil, or the article buffer isn't displayed, no centering will be performed." ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle). ;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu. + (interactive) (let* ((top (cond ((< (window-height) 4) 0) ((< (window-height) 7) 1) (t (if (numberp gnus-auto-center-summary) @@ -5034,7 +5149,8 @@ displayed, no centering will be performed." ;; whichever is the least. (set-window-start window (min bottom (save-excursion - (forward-line (- top)) (point))))) + (forward-line (- top)) (point))) + t)) ;; Do horizontal recentering while we're at it. (when (and (get-buffer-window (current-buffer) t) (not (eq gnus-auto-center-summary 'vertical))) @@ -5074,7 +5190,10 @@ displayed, no centering will be performed." ;; If the range of read articles is a single range, then the ;; first unread article is the article after the last read ;; article. Sounds logical, doesn't it? - (if (not (listp (cdr read))) + (if (and (not (listp (cdr read))) + (or (< (car read) (car active)) + (progn (setq read (list read)) + nil))) (setq first (max (car active) (1+ (cdr read)))) ;; `read' is a list of ranges. (when (/= (setq nlast (or (and (numberp (car read)) (car read)) @@ -5131,8 +5250,7 @@ displayed, no centering will be performed." (key-binding (read-key-sequence (substitute-command-keys - "\\\\[gnus-summary-universal-argument]" - )))) + "\\\\[gnus-summary-universal-argument]")))) 'undefined) (gnus-error 1 "Undefined key") (save-excursion @@ -5228,9 +5346,13 @@ If FORCE (the prefix), also save the .newsrc file(s)." (defun gnus-summary-exit (&optional temporary) "Exit reading current newsgroup, and then return to group selection mode. -gnus-exit-group-hook is called with no arguments if that value is non-nil." +`gnus-exit-group-hook' is called with no arguments if that value is non-nil." (interactive) (gnus-set-global-variables) + (when (gnus-buffer-live-p gnus-article-buffer) + (save-excursion + (set-buffer gnus-article-buffer) + (mm-destroy-parts gnus-article-mime-handles))) (gnus-kill-save-kill-buffer) (gnus-async-halt-prefetch) (let* ((group gnus-newsgroup-name) @@ -5238,6 +5360,12 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." (mode major-mode) (group-point nil) (buf (current-buffer))) + (unless quit-config + ;; Do adaptive scoring, and possibly save score files. + (when gnus-newsgroup-adaptive + (gnus-score-adaptive)) + (when gnus-use-scoring + (gnus-score-save))) (gnus-run-hooks 'gnus-summary-prepare-exit-hook) ;; If we have several article buffers, we kill them at exit. (unless gnus-single-article-buffer @@ -5251,17 +5379,14 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." (gnus-dup-enter-articles)) (when gnus-use-trees (gnus-tree-close group)) + (when gnus-use-cache + (gnus-cache-write-active)) ;; Remove entries for this group. (nnmail-purge-split-history (gnus-group-real-name group)) ;; Make all changes in this group permanent. (unless quit-config (gnus-run-hooks 'gnus-exit-group-hook) - (gnus-summary-update-info) - ;; Do adaptive scoring, and possibly save score files. - (when gnus-newsgroup-adaptive - (gnus-score-adaptive)) - (when gnus-use-scoring - (gnus-score-save))) + (gnus-summary-update-info)) (gnus-close-group group) ;; Make sure where we were, and go to next newsgroup. (set-buffer gnus-group-buffer) @@ -5276,10 +5401,6 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." (setq group-point (point)) (if temporary nil ;Nothing to do. - (when (gnus-buffer-live-p gnus-article-buffer) - (save-excursion - (set-buffer gnus-article-buffer) - (mm-destroy-parts gnus-article-mime-handles))) ;; If we have several article buffers, we kill them at exit. (unless gnus-single-article-buffer (gnus-kill-buffer gnus-article-buffer) @@ -5323,8 +5444,9 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil." gnus-expert-user (gnus-y-or-n-p "Discard changes to this group and exit? ")) (gnus-async-halt-prefetch) - (gnus-run-hooks (delq 'gnus-summary-expire-articles - (copy-list gnus-summary-prepare-exit-hook))) + (mapcar 'funcall + (delq 'gnus-summary-expire-articles + (copy-sequence gnus-summary-prepare-exit-hook))) (when (gnus-buffer-live-p gnus-article-buffer) (save-excursion (set-buffer gnus-article-buffer) @@ -5436,7 +5558,8 @@ The state which existed when entering the ephemeral is reset." (rename-buffer (concat (substring name 0 (match-beginning 0)) "Dead " (substring name (match-beginning 0))) - t)))) + t) + (bury-buffer)))) (defun gnus-kill-or-deaden-summary (buffer) "Kill or deaden the summary BUFFER." @@ -5497,8 +5620,7 @@ in." (defun gnus-summary-describe-briefly () "Describe summary mode commands briefly." (interactive) - (gnus-message 6 - (substitute-command-keys "\\\\[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"))) + (gnus-message 6 (substitute-command-keys "\\\\[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"))) ;; Walking around group mode buffer from summary mode. @@ -5604,8 +5726,8 @@ returned." (if backward (gnus-summary-find-prev unread) (gnus-summary-find-next unread))) - (gnus-summary-show-thread) - (setq n (1- n))) + (unless (zerop (setq n (1- n))) + (gnus-summary-show-thread))) (when (/= 0 n) (gnus-message 7 "No more%s articles" (if unread " unread" ""))) @@ -5696,35 +5818,34 @@ be displayed." (set-buffer gnus-summary-buffer)) (let ((article (or article (gnus-summary-article-number))) (all-headers (not (not all-headers))) ;Must be T or NIL. - gnus-summary-display-article-function - did) + gnus-summary-display-article-function) (and (not pseudo) (gnus-summary-article-pseudo-p article) (error "This is a pseudo-article")) - (prog1 - (save-excursion - (set-buffer gnus-summary-buffer) - (if (or (and gnus-single-article-buffer - (or (null gnus-current-article) - (null gnus-article-current) - (null (get-buffer gnus-article-buffer)) - (not (eq article (cdr gnus-article-current))) - (not (equal (car gnus-article-current) - gnus-newsgroup-name)))) - (and (not gnus-single-article-buffer) - (or (null gnus-current-article) - (not (eq gnus-current-article article)))) - force) - ;; The requested article is different from the current article. - (prog1 - (gnus-summary-display-article article all-headers) - (setq did article)) + (save-excursion + (set-buffer gnus-summary-buffer) + (if (or (and gnus-single-article-buffer + (or (null gnus-current-article) + (null gnus-article-current) + (null (get-buffer gnus-article-buffer)) + (not (eq article (cdr gnus-article-current))) + (not (equal (car gnus-article-current) + gnus-newsgroup-name)))) + (and (not gnus-single-article-buffer) + (or (null gnus-current-article) + (not (eq gnus-current-article article)))) + force) + ;; The requested article is different from the current article. + (progn + (gnus-summary-display-article article all-headers) (when (or all-headers gnus-show-all-headers) (gnus-article-show-all-headers)) - 'old)) - (when did - (gnus-article-set-window-start - (cdr (assq article gnus-newsgroup-bookmarks))))))) + (gnus-article-set-window-start + (cdr (assq article gnus-newsgroup-bookmarks))) + article) + (when (or all-headers gnus-show-all-headers) + (gnus-article-show-all-headers)) + 'old)))) (defun gnus-summary-set-current-mark (&optional current-mark) "Obsolete function." @@ -6136,7 +6257,21 @@ If given a prefix, remove all limits." "Limit the summary buffer to articles that are older than (or equal) AGE days. If YOUNGER-P (the prefix) is non-nil, limit the summary buffer to articles that are younger than AGE days." - (interactive "nTime in days: \nP") + (interactive + (let ((younger current-prefix-arg) + (days-got nil) + days) + (while (not days-got) + (setq days (if younger + (read-string "Limit to articles within (in days): ") + (read-string "Limit to articles old than (in days): "))) + (when (> (length days) 0) + (setq days (read days))) + (if (numberp days) + (setq days-got t) + (message "Please enter a number.") + (sleep-for 1))) + (list days younger))) (prog1 (let ((data gnus-newsgroup-data) (cutoff (days-to-time age)) @@ -6145,7 +6280,9 @@ articles that are younger than AGE days." (when (and (vectorp (gnus-data-header d)) (setq date (mail-header-date (gnus-data-header d)))) (setq is-younger (time-less-p - (time-since (date-to-time date)) + (time-since (condition-case () + (date-to-time date) + (error '(0 0)))) cutoff)) (when (if younger-p is-younger @@ -6154,6 +6291,30 @@ articles that are younger than AGE days." (gnus-summary-limit (nreverse articles))) (gnus-summary-position-point))) +(defun gnus-summary-limit-to-extra (header regexp) + "Limit the summary buffer to articles that match an 'extra' header." + (interactive + (let ((header + (intern + (gnus-completing-read + (symbol-name (car gnus-extra-headers)) + "Limit extra header:" + (mapcar (lambda (x) + (cons (symbol-name x) x)) + gnus-extra-headers) + nil + t)))) + (list header + (read-string (format "Limit to header %s (regexp): " header))))) + (when (not (equal "" regexp)) + (prog1 + (let ((articles (gnus-summary-find-matching + (cons 'extra header) regexp 'all))) + (unless articles + (error "Found no matches for \"%s\"" regexp)) + (gnus-summary-limit articles)) + (gnus-summary-position-point)))) + (defalias 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread) (make-obsolete 'gnus-summary-delete-marked-as-read 'gnus-summary-limit-to-unread) @@ -6351,6 +6512,7 @@ If ALL, mark even excluded ticked and dormants as read." "Go forwards in the thread until we find an article that we want to display." (when (or (eq gnus-fetch-old-headers 'some) (eq gnus-fetch-old-headers 'invisible) + (numberp gnus-fetch-old-headers) (eq gnus-build-sparse-threads 'some) (eq gnus-build-sparse-threads 'more)) ;; Deal with old-fetched headers and sparse threads. @@ -6380,6 +6542,7 @@ If ALL, mark even excluded ticked and dormants as read." "Cut off all uninteresting articles from the beginning of threads." (when (or (eq gnus-fetch-old-headers 'some) (eq gnus-fetch-old-headers 'invisible) + (numberp gnus-fetch-old-headers) (eq gnus-build-sparse-threads 'some) (eq gnus-build-sparse-threads 'more)) (let ((th threads)) @@ -6397,6 +6560,7 @@ fetch-old-headers verbiage, and so on." (if (or gnus-inhibit-limiting (and (null gnus-newsgroup-dormant) (not (eq gnus-fetch-old-headers 'some)) + (not (numberp gnus-fetch-old-headers)) (not (eq gnus-fetch-old-headers 'invisible)) (null gnus-summary-expunge-below) (not (eq gnus-build-sparse-threads 'some)) @@ -6450,7 +6614,8 @@ fetch-old-headers verbiage, and so on." (zerop children)) ;; If this is "fetch-old-headered" and there is no ;; visible children, then we don't want this article. - (and (eq gnus-fetch-old-headers 'some) + (and (or (eq gnus-fetch-old-headers 'some) + (numberp gnus-fetch-old-headers)) (gnus-summary-article-ancient-p number) (zerop children)) ;; If this is "fetch-old-headered" and `invisible', then @@ -6601,11 +6766,9 @@ of what's specified by the `gnus-refer-thread-limit' variable." (gnus-message 5 "Fetching headers for %s...done" gnus-newsgroup-name)) (gnus-summary-limit-include-thread id))) -(defun gnus-summary-refer-article (message-id &optional arg) - "Fetch an article specified by MESSAGE-ID. -If ARG (the prefix), fetch the article using `gnus-refer-article-method' -or `gnus-select-method', no matter what backend the article comes from." - (interactive "sMessage-ID: \nP") +(defun gnus-summary-refer-article (message-id) + "Fetch an article specified by MESSAGE-ID." + (interactive "sMessage-ID: ") (when (and (stringp message-id) (not (zerop (length message-id)))) ;; Construct the correct Message-ID if necessary. @@ -6619,7 +6782,8 @@ or `gnus-select-method', no matter what backend the article comes from." (gnus-summary-article-sparse-p (mail-header-number header)) (memq (mail-header-number header) - gnus-newsgroup-limit)))) + gnus-newsgroup-limit))) + number) (cond ;; If the article is present in the buffer we just go to it. ((and header @@ -6632,22 +6796,37 @@ or `gnus-select-method', no matter what backend the article comes from." (when sparse (gnus-summary-update-article (mail-header-number header))))) (t - ;; We fetch the article - (let ((gnus-override-method - (cond ((gnus-news-group-p gnus-newsgroup-name) - gnus-refer-article-method) - (arg - (or gnus-refer-article-method gnus-select-method)) - (t nil))) - number) - ;; Start the special refer-article method, if necessary. - (when (and gnus-refer-article-method - (gnus-news-group-p gnus-newsgroup-name)) - (gnus-check-server gnus-refer-article-method)) - ;; Fetch the header, and display the article. - (if (setq number (gnus-summary-insert-subject message-id)) + ;; We fetch the article. + (catch 'found + (dolist (gnus-override-method (gnus-refer-article-methods)) + (gnus-check-server gnus-override-method) + ;; Fetch the header, and display the article. + (when (setq number (gnus-summary-insert-subject message-id)) (gnus-summary-select-article nil nil nil number) - (gnus-message 3 "Couldn't fetch article %s" message-id)))))))) + (throw 'found t))) + (gnus-message 3 "Couldn't fetch article %s" message-id))))))) + +(defun gnus-refer-article-methods () + "Return a list of referrable methods." + (cond + ;; No method, so we default to current and native. + ((null gnus-refer-article-method) + (list gnus-current-select-method gnus-select-method)) + ;; Current. + ((eq 'current gnus-refer-article-method) + (list gnus-current-select-method)) + ;; List of select methods. + ((not (stringp (cadr gnus-refer-article-method))) + (let (out) + (dolist (method gnus-refer-article-method) + (push (if (eq 'current method) + gnus-current-select-method + method) + out)) + (nreverse out))) + ;; One single select method. + (t + (list gnus-refer-article-method)))) (defun gnus-summary-edit-parameters () "Edit the group parameters of the current group." @@ -6680,8 +6859,14 @@ to guess what the document format is." (list (cons 'save-article-group ogroup)))) (case-fold-search t) (buf (current-buffer)) - dig) + dig to-address) (save-excursion + (set-buffer gnus-original-article-buffer) + ;; Have the digest group inherit the main mail address of + ;; the parent article. + (when (setq to-address (or (message-fetch-field "reply-to") + (message-fetch-field "from"))) + (setq params (append (list (cons 'to-address to-address))))) (setq dig (nnheader-set-temp-buffer " *gnus digest buffer*")) (insert-buffer-substring gnus-original-article-buffer) ;; Remove lines that may lead nndoc to misinterpret the @@ -6690,14 +6875,17 @@ to guess what the document format is." (goto-char (point-min)) (or (search-forward "\n\n" nil t) (point))) (goto-char (point-min)) - (delete-matching-lines "^\\(Path\\):\\|^From ") + (delete-matching-lines "^Path:\\|^From ") (widen)) (unwind-protect - (if (gnus-group-read-ephemeral-group - name `(nndoc ,name (nndoc-address ,(get-buffer dig)) - (nndoc-article-type - ,(if force 'digest 'guess))) t) - ;; Make all postings to this group go to the parent group. + (if (let ((gnus-newsgroup-ephemeral-charset gnus-newsgroup-charset) + (gnus-newsgroup-ephemeral-ignored-charsets + gnus-newsgroup-ignored-charsets)) + (gnus-group-read-ephemeral-group + name `(nndoc ,name (nndoc-address ,(get-buffer dig)) + (nndoc-article-type + ,(if force 'mbox 'guess))) t)) + ;; Make all postings to this group go to the parent group. (nconc (gnus-info-params (gnus-get-info name)) params) ;; Couldn't select this doc group. @@ -6805,7 +6993,7 @@ Optional argument BACKWARD means do search for backward. (require 'gnus-async) (require 'gnus-art) (let ((gnus-select-article-hook nil) ;Disable hook. - (gnus-article-display-hook nil) + (gnus-article-prepare-hook nil) (gnus-mark-article-hook nil) ;Inhibit marking as read. (gnus-use-article-prefetch nil) (gnus-xmas-force-redisplay nil) ;Inhibit XEmacs redisplay. @@ -6817,6 +7005,7 @@ Optional argument BACKWARD means do search for backward. (gnus-save-hidden-threads (gnus-summary-select-article) (set-buffer gnus-article-buffer) + (goto-char (window-point (get-buffer-window (current-buffer)))) (when backward (forward-line -1)) (while (not found) @@ -6832,6 +7021,9 @@ Optional argument BACKWARD means do search for backward. (get-buffer-window (current-buffer)) (point)) (forward-line 1) + (set-window-point + (get-buffer-window (current-buffer)) + (point)) (set-buffer sum) (setq point (point))) ;; We didn't find it, so we go to the next article. @@ -6870,11 +7062,18 @@ in the comparisons." (let ((data (if (eq backward 'all) gnus-newsgroup-data (gnus-data-find-list (gnus-summary-article-number) (gnus-data-list backward)))) - (func `(lambda (h) (,(intern (concat "mail-header-" header)) h))) (case-fold-search (not not-case-fold)) - articles d) - (unless (fboundp (intern (concat "mail-header-" header))) - (error "%s is not a valid header" header)) + articles d func) + (if (consp header) + (if (eq (car header) 'extra) + (setq func + `(lambda (h) + (or (cdr (assq ',(cdr header) (mail-header-extra h))) + ""))) + (error "%s is an invalid header" header)) + (unless (fboundp (intern (concat "mail-header-" header))) + (error "%s is not a valid header" header)) + (setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))) (while data (setq d (car data)) (and (or (not unread) ; We want all articles... @@ -6943,7 +7142,7 @@ article. If BACKWARD (the prefix) is non-nil, search backward instead." If N is negative, print the N previous articles. If N is nil and articles have been marked with the process mark, print these instead. -If the optional second argument FILENAME is nil, send the image to the +If the optional first argument FILENAME is nil, send the image to the printer. If FILENAME is a string, save the PostScript image in a file with that name. If FILENAME is a number, prompt the user for the name of the file to save in." @@ -6976,25 +7175,39 @@ to save in." (defun gnus-summary-show-article (&optional arg) "Force re-fetching of the current article. -If ARG (the prefix) is non-nil, show the raw article without any -article massaging functions being run." +If ARG (the prefix) is a number, show the article with the charset +defined in `gnus-summary-show-article-charset-alist', or the charset +inputed. +If ARG (the prefix) is non-nil and not a number, show the raw article +without any article massaging functions being run." (interactive "P") - (if (not arg) - ;; Select the article the normal way. - (gnus-summary-select-article nil 'force) + (cond + ((numberp arg) + (let ((gnus-newsgroup-charset + (or (cdr (assq arg gnus-summary-show-article-charset-alist)) + (read-coding-system "Charset: "))) + (gnus-newsgroup-ignored-charsets 'gnus-all)) + (gnus-summary-select-article nil 'force))) + ((not arg) + ;; Select the article the normal way. + (gnus-summary-select-article nil 'force)) + (t ;; We have to require this here to make sure that the following ;; dynamic binding isn't shadowed by autoloading. (require 'gnus-async) (require 'gnus-art) ;; Bind the article treatment functions to nil. (let ((gnus-have-all-headers t) - gnus-article-display-hook gnus-article-prepare-hook gnus-article-decode-hook gnus-display-mime-function - gnus-break-pages - gnus-visual) - (gnus-summary-select-article nil 'force))) + gnus-break-pages) + ;; Destroy any MIME parts. + (when (gnus-buffer-live-p gnus-article-buffer) + (save-excursion + (set-buffer gnus-article-buffer) + (mm-destroy-parts gnus-article-mime-handles))) + (gnus-summary-select-article nil 'force)))) (gnus-summary-goto-subject gnus-current-article) (gnus-summary-position-point)) @@ -7018,25 +7231,36 @@ If ARG is a negative number, hide the unwanted header lines." (interactive "P") (save-excursion (set-buffer gnus-article-buffer) - (let* ((buffer-read-only nil) - (inhibit-point-motion-hooks t) - (hidden (text-property-any - (goto-char (point-min)) (search-forward "\n\n") - 'invisible t)) - e) - (goto-char (point-min)) - (when (search-forward "\n\n" nil t) - (delete-region (point-min) (1- (point)))) - (goto-char (point-min)) - (save-excursion - (set-buffer gnus-original-article-buffer) + (save-restriction + (let* ((buffer-read-only nil) + (inhibit-point-motion-hooks t) + hidden e) + (setq hidden + (if (numberp arg) + (>= arg 0) + (save-restriction + (article-narrow-to-head) + (gnus-article-hidden-text-p 'headers)))) (goto-char (point-min)) - (setq e (1- (or (search-forward "\n\n" nil t) (point-max))))) - (insert-buffer-substring gnus-original-article-buffer 1 e) - (let ((article-inhibit-hiding t)) - (gnus-run-hooks 'gnus-article-display-hook)) - (when (or (not hidden) (and (numberp arg) (< arg 0))) - (gnus-article-hide-headers))))) + (when (search-forward "\n\n" nil t) + (delete-region (point-min) (1- (point)))) + (goto-char (point-min)) + (save-excursion + (set-buffer gnus-original-article-buffer) + (goto-char (point-min)) + (setq e (1- (or (search-forward "\n\n" nil t) (point-max))))) + (insert-buffer-substring gnus-original-article-buffer 1 e) + (save-restriction + (narrow-to-region (point-min) (point)) + (article-decode-encoded-words) + (if hidden + (let ((gnus-treat-hide-headers nil) + (gnus-treat-hide-boring-headers nil)) + (setq gnus-article-wash-types + (delq 'headers gnus-article-wash-types)) + (gnus-treat-article 'head)) + (gnus-treat-article 'head))) + (gnus-set-mode-line 'article))))) (defun gnus-summary-show-all-headers () "Make all header lines visible." @@ -7083,7 +7307,9 @@ re-spool using this method. For this function to work, both the current newsgroup and the newsgroup that you want to move to have to support the `request-move' -and `request-accept' functions." +and `request-accept' functions. + +ACTION can be either `move' (the default), `crosspost' or `copy'." (interactive "P") (unless action (setq action 'move)) @@ -7101,7 +7327,10 @@ and `request-accept' functions." 'request-replace-article gnus-newsgroup-name))) (error "The current group does not support article editing"))) (let ((articles (gnus-summary-work-articles n)) - (prefix (gnus-group-real-prefix gnus-newsgroup-name)) + (prefix (if (gnus-check-backend-function + 'request-move-article gnus-newsgroup-name) + (gnus-group-real-prefix gnus-newsgroup-name) + "")) (names '((move "Move" "Moving") (copy "Copy" "Copying") (crosspost "Crosspost" "Crossposting"))) @@ -7120,7 +7349,8 @@ and `request-accept' functions." articles prefix)) (set (intern (format "gnus-current-%s-group" action)) to-newsgroup)) (setq to-method (or select-method - (gnus-group-name-to-method to-newsgroup))) + (gnus-server-to-method + (gnus-group-method to-newsgroup)))) ;; Check the method we are to move this article to... (unless (gnus-check-backend-function 'request-accept-article (car to-method)) @@ -7146,7 +7376,7 @@ and `request-accept' functions." gnus-newsgroup-name)) ; Server (list 'gnus-request-accept-article to-newsgroup (list 'quote select-method) - (not articles) t) ; Accept form + (not articles) t) ; Accept form (not articles))) ; Only save nov last time ;; Copy the article. ((eq action 'copy) @@ -7187,19 +7417,21 @@ and `request-accept' functions." art-group)))))) (cond ((not art-group) - (gnus-message 1 "Couldn't %s article %s" - (cadr (assq action names)) article)) - ((and (eq art-group 'junk) - (eq action 'move)) - (gnus-summary-mark-article article gnus-canceled-mark) - (gnus-message 4 "Deleted article %s" article)) + (gnus-message 1 "Couldn't %s article %s: %s" + (cadr (assq action names)) article + (nnheader-get-report (car to-method)))) + ((eq art-group 'junk) + (when (eq action 'move) + (gnus-summary-mark-article article gnus-canceled-mark) + (gnus-message 4 "Deleted article %s" article))) (t (let* ((pto-group (gnus-group-prefixed-name (car art-group) to-method)) (entry (gnus-gethash pto-group gnus-newsrc-hashtb)) (info (nth 2 entry)) - (to-group (gnus-info-group info))) + (to-group (gnus-info-group info)) + to-marks) ;; Update the group that has been moved to. (when (and info (memq action '(move copy))) @@ -7207,49 +7439,54 @@ and `request-accept' functions." (push to-group to-groups)) (unless (memq article gnus-newsgroup-unreads) + (push 'read to-marks) (gnus-info-set-read info (gnus-add-to-range (gnus-info-read info) (list (cdr art-group))))) - ;; Copy any marks over to the new group. + ;; See whether the article is to be put in the cache. (let ((marks gnus-article-mark-lists) (to-article (cdr art-group))) - ;; See whether the article is to be put in the cache. + ;; Enter the article into the cache in the new group, + ;; if that is required. (when gnus-use-cache (gnus-cache-possibly-enter-article to-group to-article - (let ((header (copy-sequence - (gnus-summary-article-header article)))) - (mail-header-set-number header to-article) - header) (memq article gnus-newsgroup-marked) (memq article gnus-newsgroup-dormant) (memq article gnus-newsgroup-unreads))) - (when (and (equal to-group gnus-newsgroup-name) - (not (memq article gnus-newsgroup-unreads))) - ;; Mark this article as read in this group. - (push (cons to-article gnus-read-mark) gnus-newsgroup-reads) - (setcdr (gnus-active to-group) to-article) - (setcdr gnus-newsgroup-active to-article)) - - (while marks - (when (memq article (symbol-value - (intern (format "gnus-newsgroup-%s" - (caar marks))))) - ;; If the other group is the same as this group, - ;; then we have to add the mark to the list. - (when (equal to-group gnus-newsgroup-name) - (set (intern (format "gnus-newsgroup-%s" (caar marks))) - (cons to-article - (symbol-value - (intern (format "gnus-newsgroup-%s" - (caar marks))))))) - ;; Copy the marks to other group. - (gnus-add-marked-articles - to-group (cdar marks) (list to-article) info)) - (setq marks (cdr marks))) + (when gnus-preserve-marks + ;; Copy any marks over to the new group. + (when (and (equal to-group gnus-newsgroup-name) + (not (memq article gnus-newsgroup-unreads))) + ;; Mark this article as read in this group. + (push (cons to-article gnus-read-mark) gnus-newsgroup-reads) + (setcdr (gnus-active to-group) to-article) + (setcdr gnus-newsgroup-active to-article)) + + (while marks + (when (memq article (symbol-value + (intern (format "gnus-newsgroup-%s" + (caar marks))))) + (push (cdar marks) to-marks) + ;; If the other group is the same as this group, + ;; then we have to add the mark to the list. + (when (equal to-group gnus-newsgroup-name) + (set (intern (format "gnus-newsgroup-%s" (caar marks))) + (cons to-article + (symbol-value + (intern (format "gnus-newsgroup-%s" + (caar marks))))))) + ;; Copy the marks to other group. + (gnus-add-marked-articles + to-group (cdar marks) (list to-article) info)) + (setq marks (cdr marks))) + + (gnus-request-set-mark to-group (list (list (list to-article) + 'set + to-marks)))) (gnus-dribble-enter (concat "(gnus-group-set-info '" @@ -7380,12 +7617,11 @@ latter case, they will be copied into the relevant groups." (kill-buffer (current-buffer))))) (defun gnus-summary-article-posted-p () - "Say whether the current (mail) article is available from `gnus-select-method' as well. + "Say whether the current (mail) article is available from news as well. This will be the case if the article has both been mailed and posted." (interactive) (let ((id (mail-header-references (gnus-summary-article-header))) - (gnus-override-method - (or gnus-refer-article-method gnus-select-method))) + (gnus-override-method (car (gnus-refer-article-methods)))) (if (gnus-request-head id "") (gnus-message 2 "The current message was found on %s" gnus-override-method) @@ -7418,6 +7654,8 @@ This will be the case if the article has both been mailed and posted." ;; There are expirable articles in this group, so we run them ;; through the expiry process. (gnus-message 6 "Expiring articles...") + (unless (gnus-check-group gnus-newsgroup-name) + (error "Can't open server for %s" gnus-newsgroup-name)) ;; The list of articles that weren't expired is returned. (save-excursion (if expiry-wait @@ -7499,20 +7737,23 @@ groups." (interactive "P") (save-excursion (set-buffer gnus-summary-buffer) - (gnus-set-global-variables) - (when (and (not force) - (gnus-group-read-only-p)) - (error "The current newsgroup does not support article editing")) - ;; Select article if needed. - (unless (eq (gnus-summary-article-number) - gnus-current-article) - (gnus-summary-select-article t)) - (gnus-article-date-original) - (gnus-article-edit-article - `(lambda (no-highlight) - (gnus-summary-edit-article-done - ,(or (mail-header-references gnus-current-headers) "") - ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))) + (let ((mail-parse-charset gnus-newsgroup-charset) + (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)) + (gnus-set-global-variables) + (when (and (not force) + (gnus-group-read-only-p)) + (error "The current newsgroup does not support article editing")) + (gnus-summary-show-article t) + (gnus-article-edit-article + 'mime-to-mml + `(lambda (no-highlight) + (let ((mail-parse-charset ',gnus-newsgroup-charset) + (mail-parse-ignored-charsets + ',gnus-newsgroup-ignored-charsets)) + (mml-to-mime) + (gnus-summary-edit-article-done + ,(or (mail-header-references gnus-current-headers) "") + ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))))) (defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit) @@ -7523,12 +7764,11 @@ groups." ;; Replace the article. (let ((buf (current-buffer))) (with-temp-buffer - (insert-buffer buf) + (insert-buffer-substring buf) (if (and (not read-only) (not (gnus-request-replace-article (cdr gnus-article-current) (car gnus-article-current) - (current-buffer) - (not gnus-article-decoded-p)))) + (current-buffer) t))) (error "Couldn't replace article") ;; Update the summary buffer. (if (and references @@ -7566,7 +7806,8 @@ groups." (unless no-highlight (save-excursion (set-buffer gnus-article-buffer) - (gnus-run-hooks 'gnus-article-display-hook) + ;;;!!! Fix this -- article should be rehighlighted. + ;;;(gnus-run-hooks 'gnus-article-display-hook) (set-buffer gnus-original-article-buffer) (gnus-request-article (cdr gnus-article-current) @@ -7809,7 +8050,8 @@ the actual number of articles marked is returned." "Mark N articles as read forwards. If N is negative, mark backwards instead. Mark with MARK, ?r by default. The difference between N and the actual number of articles marked is -returned." +returned. +Iff NO-EXPIRE, auto-expiry will be inhibited." (interactive "p") (gnus-summary-show-thread) (let ((backward (< n 0)) @@ -7888,7 +8130,6 @@ returned." (save-excursion (gnus-cache-possibly-enter-article gnus-newsgroup-name article - (gnus-summary-article-header article) (= mark gnus-ticked-mark) (= mark gnus-dormant-mark) (= mark gnus-unread-mark)))) @@ -7902,7 +8143,8 @@ Four MARK strings are reserved: `? ' (unread), `?!' (ticked), `??' (dormant) and `?E' (expirable). If MARK is nil, then the default character `?r' is used. If ARTICLE is nil, then the article on the current line will be -marked." +marked. +Iff NO-EXPIRE, auto-expiry will be inhibited." ;; The mark might be a string. (when (stringp mark) (setq mark (aref mark 0))) @@ -7934,7 +8176,6 @@ marked." (save-excursion (gnus-cache-possibly-enter-article gnus-newsgroup-name article - (gnus-summary-article-header article) (= mark gnus-ticked-mark) (= mark gnus-dormant-mark) (= mark gnus-unread-mark)))) @@ -8066,7 +8307,8 @@ returned." The difference between N and the actual number of articles marked is returned." (interactive "p") - (gnus-summary-mark-forward (- n) gnus-del-mark gnus-inhibit-user-auto-expire)) + (gnus-summary-mark-forward + (- n) gnus-del-mark gnus-inhibit-user-auto-expire)) (defun gnus-summary-mark-as-read (&optional article mark) "Mark current article as read. @@ -8247,7 +8489,7 @@ If ALL is non-nil, also mark ticked and dormant articles as read." (gnus-summary-catchup t quietly)) (defun gnus-summary-catchup-and-exit (&optional all quietly) - "Mark all articles not marked as unread in this newsgroup as read, then exit. + "Mark all unread articles in this group as read, then exit. If prefix argument ALL is non-nil, all articles are marked as read." (interactive "P") (when (gnus-summary-catchup all quietly nil 'fast) @@ -8262,7 +8504,6 @@ If prefix argument ALL is non-nil, all articles are marked as read." (interactive "P") (gnus-summary-catchup-and-exit t quietly)) -;; Suggested by "Arne Eofsson" . (defun gnus-summary-catchup-and-goto-next-group (&optional all) "Mark all articles in this group as read and select the next group. If given a prefix, mark all articles, unread as well as ticked, as @@ -8270,7 +8511,7 @@ read." (interactive "P") (save-excursion (gnus-summary-catchup all)) - (gnus-summary-next-article t nil nil t)) + (gnus-summary-next-group)) ;; Thread-based commands. @@ -8432,9 +8673,7 @@ Returns nil if no threads were there to be hidden." (subst-char-in-region start (point) ?\n ?\^M) (gnus-summary-goto-subject article)) (goto-char start) - nil) - ;;(gnus-summary-position-point) - )))) + nil))))) (defun gnus-summary-go-to-next-thread (&optional previous) "Go to the same level (or less) next thread. @@ -8591,11 +8830,17 @@ Argument REVERSE means reverse order." (gnus-summary-sort 'score reverse)) (defun gnus-summary-sort-by-lines (&optional reverse) - "Sort the summary buffer by article length. + "Sort the summary buffer by the number of lines. Argument REVERSE means reverse order." (interactive "P") (gnus-summary-sort 'lines reverse)) +(defun gnus-summary-sort-by-chars (&optional reverse) + "Sort the summary buffer by article length. +Argument REVERSE means reverse order." + (interactive "P") + (gnus-summary-sort 'chars reverse)) + (defun gnus-summary-sort (predicate reverse) "Sort summary buffer by PREDICATE. REVERSE means reverse order." (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate))) @@ -8632,10 +8877,9 @@ The variable `gnus-default-article-saver' specifies the saver function." (save-buffer (save-excursion (nnheader-set-temp-buffer " *Gnus Save*"))) (num (length articles)) - header article file) - (while articles - (setq header (gnus-summary-article-header - (setq article (pop articles)))) + header file) + (dolist (article articles) + (setq header (gnus-summary-article-header article)) (if (not (vectorp header)) ;; This is a pseudo-article. (if (assq 'name header) @@ -8765,17 +9009,14 @@ save those articles instead." split-name)) ((consp result) (setq split-name (append result split-name))))))))) - split-name)) + (nreverse split-name))) (defun gnus-valid-move-group-p (group) (and (boundp group) (symbol-name group) (symbol-value group) - (memq 'respool - (assoc (symbol-name - (car (gnus-find-method-for-group - (symbol-name group)))) - gnus-valid-select-methods)))) + (gnus-get-function (gnus-find-method-for-group + (symbol-name group)) 'request-accept-article t))) (defun gnus-read-move-group-name (prompt default articles prefix) "Read a group name." @@ -8806,7 +9047,8 @@ save those articles instead." (mapcar (lambda (el) (list el)) (nreverse split-name)) nil nil nil - 'gnus-group-history))))) + 'gnus-group-history)))) + (to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))) (when to-newsgroup (if (or (string= to-newsgroup "") (string= to-newsgroup prefix)) @@ -8814,18 +9056,52 @@ save those articles instead." (unless to-newsgroup (error "No group name entered")) (or (gnus-active to-newsgroup) - (gnus-activate-group to-newsgroup) + (gnus-activate-group to-newsgroup nil nil to-method) (if (gnus-y-or-n-p (format "No such group: %s. Create it? " to-newsgroup)) - (or (and (gnus-request-create-group - to-newsgroup (gnus-group-name-to-method to-newsgroup)) - (gnus-activate-group to-newsgroup nil nil - (gnus-group-name-to-method - to-newsgroup))) + (or (and (gnus-request-create-group to-newsgroup to-method) + (gnus-activate-group + to-newsgroup nil nil to-method) + (gnus-subscribe-group to-newsgroup)) (error "Couldn't create group %s" to-newsgroup))) (error "No such group: %s" to-newsgroup))) to-newsgroup)) +(defun gnus-summary-save-parts (type dir n &optional reverse) + "Save parts matching TYPE to DIR. +If REVERSE, save parts that do not match TYPE." + (interactive + (list (read-string "Save parts of type: " "image/.*") + (read-file-name "Save to directory: " nil nil t) + current-prefix-arg)) + (gnus-summary-iterate n + (let ((gnus-display-mime-function nil) + (gnus-inhibit-treatment t)) + (gnus-summary-select-article)) + (save-excursion + (set-buffer gnus-article-buffer) + (let ((handles (or (mm-dissect-buffer) (mm-uu-dissect)))) + (when handles + (gnus-summary-save-parts-1 type dir handles reverse) + (mm-destroy-parts handles)))))) + +(defun gnus-summary-save-parts-1 (type dir handle reverse) + (if (stringp (car handle)) + (mapcar (lambda (h) (gnus-summary-save-parts-1 type dir h reverse)) + (cdr handle)) + (when (if reverse + (not (string-match type (mm-handle-media-type handle))) + (string-match type (mm-handle-media-type handle))) + (let ((file (expand-file-name + (file-name-nondirectory + (or + (mail-content-type-get + (mm-handle-disposition handle) 'filename) + (concat gnus-newsgroup-name "." gnus-current-article))) + dir))) + (unless (file-exists-p file) + (mm-save-part-to-file handle file)))))) + ;; Summary extract commands (defun gnus-summary-insert-pseudos (pslist &optional not-view) @@ -8938,8 +9214,10 @@ save those articles instead." "Read the headers of article ID and enter them into the Gnus system." (let ((group gnus-newsgroup-name) (gnus-override-method - (and (gnus-news-group-p gnus-newsgroup-name) - gnus-refer-article-method)) + (or + gnus-override-method + (and (gnus-news-group-p gnus-newsgroup-name) + (car (gnus-refer-article-methods))))) where) ;; First we check to see whether the header in question is already ;; fetched. @@ -9116,6 +9394,16 @@ save those articles instead." (gnus-info-set-read ',info ',(gnus-info-read info)) (gnus-get-unread-articles-in-group ',info (gnus-active ,group)) (gnus-group-update-group ,group t)))) + ;; Propagate the read marks to the backend. + (if (gnus-check-backend-function 'request-set-mark group) + (let ((del (gnus-remove-from-range (gnus-info-read info) read)) + (add (gnus-remove-from-range read (gnus-info-read info)))) + (when (or add del) + (unless (gnus-check-group group) + (error "Can't open server for %s" group)) + (gnus-request-set-mark + group (delq nil (list (if add (list add 'add '(read))) + (if del (list del 'del '(read))))))))) ;; Enter this list into the group info. (gnus-info-set-read info read) ;; Set the number of unread articles in gnus-newsrc-hashtb. @@ -9150,51 +9438,55 @@ save those articles instead." (gnus-summary-exit)) buffers))))) -(defun gnus-newsgroup-setup-default-charset () +(defun gnus-summary-setup-default-charset () "Setup newsgroup default charset." - (let ((name (and gnus-newsgroup-name - (string-match "[^:]+$" gnus-newsgroup-name) - (match-string 0 gnus-newsgroup-name)))) - (setq gnus-newsgroup-default-charset - (or (and gnus-newsgroup-name - (or (gnus-group-find-parameter - gnus-newsgroup-name 'charset) - (let ((alist gnus-newsgroup-default-charset-alist) - elem (charset nil)) - (while alist - (if (and name - (string-match - (car (setq elem (pop alist))) - name)) + (if (equal gnus-newsgroup-name "nndraft:drafts") + (setq gnus-newsgroup-charset nil) + (let* ((name (and gnus-newsgroup-name + (gnus-group-real-name gnus-newsgroup-name))) + (ignored-charsets + (or gnus-newsgroup-ephemeral-ignored-charsets + (append + (and gnus-newsgroup-name + (or (gnus-group-find-parameter gnus-newsgroup-name + 'ignored-charsets t) + (let ((alist gnus-group-ignored-charsets-alist) + elem (charsets nil)) + (while (setq elem (pop alist)) + (when (and name + (string-match (car elem) name)) + (setq alist nil + charsets (cdr elem)))) + charsets))) + gnus-newsgroup-ignored-charsets)))) + (setq gnus-newsgroup-charset + (or gnus-newsgroup-ephemeral-charset + (and gnus-newsgroup-name + (or (gnus-group-find-parameter gnus-newsgroup-name 'charset) + (let ((alist gnus-group-charset-alist) + elem charset) + (while (setq elem (pop alist)) + (when (and name + (string-match (car elem) name)) (setq alist nil - charset (cdr elem)))) - charset))) - gnus-default-charset)) - (setq gnus-newsgroup-iso-8859-1-forced - (and gnus-newsgroup-name - (or (gnus-group-find-parameter - gnus-newsgroup-name 'iso-8859-1-forced) - (and name - (string-match gnus-newsgroup-iso-8859-1-forced-regexp - name)))))) - (if (stringp gnus-newsgroup-default-charset) - (setq gnus-newsgroup-default-charset - (intern (downcase gnus-newsgroup-default-charset)))) - (setq gnus-newsgroup-iso-8859-1-forced - (if (stringp gnus-newsgroup-iso-8859-1-forced) - (intern (downcase gnus-newsgroup-iso-8859-1-forced)) - (and gnus-newsgroup-iso-8859-1-forced - gnus-newsgroup-default-charset)))) - + charset (cadr elem)))) + charset))) + gnus-default-charset)) + (set (make-local-variable 'gnus-newsgroup-ignored-charsets) + ignored-charsets)))) + ;;; -;;; MIME Commands +;;; Mime Commands ;;; -(defun gnus-summary-display-buttonized () - "Display the current article buffer fully MIME-buttonized." - (interactive) +(defun gnus-summary-display-buttonized (&optional show-all-parts) + "Display the current article buffer fully MIME-buttonized. +If SHOW-ALL-PARTS (the prefix) is non-nil, all multipart/* parts are +treated as multipart/mixed." + (interactive "P") (require 'gnus-art) - (let ((gnus-unbuttonized-mime-types nil)) + (let ((gnus-unbuttonized-mime-types nil) + (gnus-mime-display-multipart-as-mixed show-all-parts)) (gnus-summary-show-article))) (defun gnus-summary-repair-multipart (article) @@ -9226,7 +9518,116 @@ save those articles instead." (let ((gnus-unbuttonized-mime-types nil)) (gnus-summary-show-article)) (gnus-summary-show-article))) + +;;; +;;; with article +;;; + +(defmacro gnus-with-article (article &rest forms) + "Select ARTICLE and perform FORMS in the original article buffer. +Then replace the article with the result." + `(progn + ;; We don't want the article to be marked as read. + (let (gnus-mark-article-hook) + (gnus-summary-select-article t t nil ,article)) + (set-buffer gnus-original-article-buffer) + ,@forms + (if (not (gnus-check-backend-function + 'request-replace-article (car gnus-article-current))) + (gnus-message 5 "Read-only group; not replacing") + (unless (gnus-request-replace-article + ,article (car gnus-article-current) + (current-buffer) t) + (error "Couldn't replace article"))) + ;; The cache and backlog have to be flushed somewhat. + (when gnus-keep-backlog + (gnus-backlog-remove-article + (car gnus-article-current) (cdr gnus-article-current))) + (when gnus-use-cache + (gnus-cache-update-article + (car gnus-article-current) (cdr gnus-article-current))))) + +(put 'gnus-with-article 'lisp-indent-function 1) +(put 'gnus-with-article 'edebug-form-spec '(form body)) + +;;; +;;; Generic summary marking commands +;;; + +(defvar gnus-summary-marking-alist + '((read gnus-del-mark "d") + (unread gnus-unread-mark "u") + (ticked gnus-ticked-mark "!") + (dormant gnus-dormant-mark "?") + (expirable gnus-expirable-mark "e")) + "An alist of names/marks/keystrokes.") + +(defvar gnus-summary-generic-mark-map (make-sparse-keymap)) +(defvar gnus-summary-mark-map) + +(defun gnus-summary-make-all-marking-commands () + (define-key gnus-summary-mark-map "M" gnus-summary-generic-mark-map) + (dolist (elem gnus-summary-marking-alist) + (apply 'gnus-summary-make-marking-command elem))) + +(defun gnus-summary-make-marking-command (name mark keystroke) + (let ((map (make-sparse-keymap))) + (define-key gnus-summary-generic-mark-map keystroke map) + (dolist (lway `((next "next" next nil "n") + (next-unread "next unread" next t "N") + (prev "previous" prev nil "p") + (prev-unread "previous unread" prev t "P") + (nomove "" nil nil ,keystroke))) + (let ((func (gnus-summary-make-marking-command-1 + mark (car lway) lway name))) + (setq func (eval func)) + (define-key map (nth 4 lway) func))))) + +(defun gnus-summary-make-marking-command-1 (mark way lway name) + `(defun ,(intern + (format "gnus-summary-put-mark-as-%s%s" + name (if (eq way 'nomove) + "" + (concat "-" (symbol-name way))))) + (n) + ,(format + "Mark the current article as %s%s. +If N, the prefix, then repeat N times. +If N is negative, move in reverse order. +The difference between N and the actual number of articles marked is +returned." + name (cadr lway)) + (interactive "p") + (gnus-summary-generic-mark n ,mark ',(nth 2 lway) ,(nth 3 lway)))) +(defun gnus-summary-generic-mark (n mark move unread) + "Mark N articles with MARK." + (unless (eq major-mode 'gnus-summary-mode) + (error "This command can only be used in the summary buffer")) + (gnus-summary-show-thread) + (let ((nummove + (cond + ((eq move 'next) 1) + ((eq move 'prev) -1) + (t 0)))) + (if (zerop nummove) + (setq n 1) + (when (< n 0) + (setq n (abs n) + nummove (* -1 nummove)))) + (while (and (> n 0) + (gnus-summary-mark-article nil mark) + (zerop (gnus-summary-next-subject nummove unread t))) + (setq n (1- n))) + (when (/= 0 n) + (gnus-message 7 "No more %sarticles" (if mark "" "unread "))) + (gnus-summary-recenter) + (gnus-summary-position-point) + (gnus-set-mode-line 'summary) + n)) + +(gnus-summary-make-all-marking-commands) + (gnus-ems-redefine) (provide 'gnus-sum)