]> code.delx.au - gnu-emacs/blobdiff - lisp/gnus/gnus-sum.el
Add "add-log-time-zone-rule: t" to Local Variables section.
[gnu-emacs] / lisp / gnus / gnus-sum.el
index c4f320e888b39236530754dbdfa7a3e8a01149ec..7d0b72036544a7308bc85cfc9cca8ebc01882e81 100644 (file)
@@ -1,6 +1,7 @@
 ;;; gnus-sum.el --- summary mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-;;        Free Software Foundation, Inc.
+
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
@@ -19,8 +20,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -28,7 +29,7 @@
 
 (eval-when-compile
   (require 'cl)
-  (defvar tool-bar-map))
+  (defvar tool-bar-mode))
 
 (require 'gnus)
 (require 'gnus-group)
@@ -37,6 +38,7 @@
 (require 'gnus-int)
 (require 'gnus-undo)
 (require 'gnus-util)
+(require 'gmm-utils)
 (require 'mm-decode)
 (require 'nnoo)
 
@@ -119,7 +121,7 @@ given by the `gnus-summary-same-subject' variable.)"
 
 (defcustom gnus-summary-make-false-root-always nil
   "Always make a false dummy root."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-thread
   :type 'boolean)
 
@@ -220,7 +222,7 @@ If this variable is nil, scoring will be disabled."
   "*Default threshold for a high scored article.
 An article will be highlighted as high scored if its score is greater
 than this score."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-score-default
   :type 'integer)
 
@@ -228,7 +230,7 @@ than this score."
   "*Default threshold for a low scored article.
 An article will be highlighted as low scored if its score is smaller
 than this score."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-score-default
   :type 'integer)
 
@@ -256,8 +258,7 @@ simplification is selected."
   "*If non-nil, hide all threads initially.
 This can be a predicate specifier which says which threads to hide.
 If threads are hidden, you have to run the command
-`gnus-summary-show-thread' by hand or use `gnus-select-article-hook'
-to expose hidden threads."
+`gnus-summary-show-thread' by hand or select an article."
   :group 'gnus-thread
   :type '(radio (sexp :format "Non-nil\n"
                      :match (lambda (widget value)
@@ -320,11 +321,11 @@ This variable can either be the symbols `first' (place point on the
 first subject), `unread' (place point on the subject line of the first
 unread article), `best' (place point on the subject line of the
 higest-scored article), `unseen' (place point on the subject line of
-the first unseen article), 'unseen-or-unread' (place point on the subject
+the first unseen article), `unseen-or-unread' (place point on the subject
 line of the first unseen article or, if all article have been seen, on the
 subject line of the first unread article), or a function to be called to
 place point on some subject line."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-group-select
   :type '(choice (const best)
                 (const unread)
@@ -368,7 +369,7 @@ ignores articles whose headers have not been fetched).
 
 NOTE: The list of unfetched articles will always be nil when plugged
 and, when unplugged, a subset of the undownloaded article list."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-maneuvering
   :type '(choice (const :tag "None" nil)
                  (const :tag "Undownloaded when unplugged" undownloaded)
@@ -469,7 +470,7 @@ this variable specifies group names."
 
 (defcustom gnus-spam-mark ?$
   "*Mark used for spam articles."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -500,13 +501,13 @@ this variable specifies group names."
 
 (defcustom gnus-forwarded-mark ?F
   "*Mark used for articles that have been forwarded."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
 (defcustom gnus-recent-mark ?N
   "*Mark used for articles that are recent."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -522,13 +523,13 @@ this variable specifies group names."
 
 (defcustom gnus-unseen-mark ?.
   "*Mark used for articles that haven't been seen."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
 (defcustom gnus-no-mark ?               ;Whitespace
   "*Mark used for articles that have no other secondary mark."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -554,7 +555,7 @@ this variable specifies group names."
 
 (defcustom gnus-undownloaded-mark ?-
   "*Mark used for articles that weren't downloaded."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary-marks
   :type 'character)
 
@@ -893,19 +894,19 @@ automatically when it is selected."
 
 (defcustom gnus-summary-article-move-hook nil
   "*A hook called after an article is moved, copied, respooled, or crossposted."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
 (defcustom gnus-summary-article-delete-hook nil
   "*A hook called after an article is deleted."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
 (defcustom gnus-summary-article-expire-hook nil
   "*A hook called after an article is expired."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type 'hook)
 
@@ -913,11 +914,11 @@ automatically when it is selected."
   (and (fboundp 'display-graphic-p)
        (display-graphic-p))
   "*If non-nil, display an arrow highlighting the current article."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type 'boolean)
 
-(defcustom gnus-summary-selected-face 'gnus-summary-selected-face
+(defcustom gnus-summary-selected-face 'gnus-summary-selected
   "Face used for highlighting the current article in the summary buffer."
   :group 'gnus-summary-visual
   :type 'face)
@@ -926,42 +927,42 @@ automatically when it is selected."
 
 (defcustom gnus-summary-highlight
   '(((eq mark gnus-canceled-mark)
-     . gnus-summary-cancelled-face)
+     . gnus-summary-cancelled)
     ((and uncached (> score default-high))
-     . gnus-summary-high-undownloaded-face)
+     . gnus-summary-high-undownloaded)
     ((and uncached (< score default-low))
-     . gnus-summary-low-undownloaded-face)
+     . gnus-summary-low-undownloaded)
     (uncached
-     . gnus-summary-normal-undownloaded-face)
+     . gnus-summary-normal-undownloaded)
     ((and (> score default-high)
          (or (eq mark gnus-dormant-mark)
              (eq mark gnus-ticked-mark)))
-     . gnus-summary-high-ticked-face)
+     . gnus-summary-high-ticked)
     ((and (< score default-low)
          (or (eq mark gnus-dormant-mark)
              (eq mark gnus-ticked-mark)))
-     . gnus-summary-low-ticked-face)
+     . gnus-summary-low-ticked)
     ((or (eq mark gnus-dormant-mark)
         (eq mark gnus-ticked-mark))
-     . gnus-summary-normal-ticked-face)
+     . gnus-summary-normal-ticked)
     ((and (> score default-high) (eq mark gnus-ancient-mark))
-     . gnus-summary-high-ancient-face)
+     . gnus-summary-high-ancient)
     ((and (< score default-low) (eq mark gnus-ancient-mark))
-     . gnus-summary-low-ancient-face)
+     . gnus-summary-low-ancient)
     ((eq mark gnus-ancient-mark)
-     . gnus-summary-normal-ancient-face)
+     . gnus-summary-normal-ancient)
     ((and (> score default-high) (eq mark gnus-unread-mark))
-     . gnus-summary-high-unread-face)
+     . gnus-summary-high-unread)
     ((and (< score default-low) (eq mark gnus-unread-mark))
-     . gnus-summary-low-unread-face)
+     . gnus-summary-low-unread)
     ((eq mark gnus-unread-mark)
-     . gnus-summary-normal-unread-face)
+     . gnus-summary-normal-unread)
     ((> score default-high)
-     . gnus-summary-high-read-face)
+     . gnus-summary-high-read)
     ((< score default-low)
-     . gnus-summary-low-read-face)
+     . gnus-summary-low-read)
     (t
-     . gnus-summary-normal-read-face))
+     . gnus-summary-normal-read))
   "*Controls the highlighting of summary buffer lines.
 
 A list of (FORM . FACE) pairs.  When deciding how a a particular
@@ -991,7 +992,11 @@ which it may alter in any way."
   :group 'gnus-summary)
 
 (defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
-  "Variable that says which function should be used to decode a string with encoded words.")
+  "Function used to decode a string with encoded words.")
+
+(defvar gnus-decode-encoded-address-function
+  'mail-decode-encoded-address-string
+  "Function used to decode addresses with encoded words.")
 
 (defcustom gnus-extra-headers '(To Newsgroups)
   "*Extra headers to parse."
@@ -1000,7 +1005,9 @@ which it may alter in any way."
   :type '(repeat symbol))
 
 (defcustom gnus-ignored-from-addresses
-  (and user-mail-address (regexp-quote user-mail-address))
+  (and user-mail-address
+       (not (string= user-mail-address ""))
+       (regexp-quote user-mail-address))
   "*Regexp of From headers that may be suppressed in favor of To headers."
   :version "21.1"
   :group 'gnus-summary
@@ -1091,13 +1098,13 @@ type of files to save."
 This is mostly relevant for slow back ends where the user may
 wish to widen the summary buffer to include all headers
 that were fetched.  Say, for nnultimate groups."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type '(choice boolean regexp))
 
 (defcustom gnus-summary-muttprint-program "muttprint"
   "Command (and optional arguments) used to run Muttprint."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-summary
   :type 'string)
 
@@ -1107,7 +1114,7 @@ Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
 supply the MIME-Version header or deliberately strip it from the mail.
 Set it to non-nil, Gnus will treat some articles as MIME even if
 the MIME-Version header is missed."
-  :version "21.4"
+  :version "22.1"
   :type 'boolean
   :group 'gnus-article-mime)
 
@@ -1116,7 +1123,7 @@ the MIME-Version header is missed."
 This means that Gnus will search message bodies for text that look
 like uuencoded bits, yEncoded bits, and so on, and present that using
 the normal Gnus MIME machinery."
-  :version "21.4"
+  :version "22.1"
   :type 'boolean
   :group 'gnus-article-mime)
 
@@ -1246,6 +1253,7 @@ the type of the variable (string, integer, character, etc).")
 (defvar gnus-newsgroup-last-mail nil)
 (defvar gnus-newsgroup-last-folder nil)
 (defvar gnus-newsgroup-last-file nil)
+(defvar gnus-newsgroup-last-directory nil)
 (defvar gnus-newsgroup-auto-expire nil)
 (defvar gnus-newsgroup-active nil)
 
@@ -1361,6 +1369,7 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
     gnus-newsgroup-begin gnus-newsgroup-end
     gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
     gnus-newsgroup-last-folder gnus-newsgroup-last-file
+    gnus-newsgroup-last-directory
     gnus-newsgroup-auto-expire gnus-newsgroup-unreads
     gnus-newsgroup-unselected gnus-newsgroup-marked
     gnus-newsgroup-spam-marked
@@ -1988,6 +1997,7 @@ increase the score of each group you read."
   "r" gnus-summary-save-article-rmail
   "f" gnus-summary-save-article-file
   "b" gnus-summary-save-article-body-file
+  "B" gnus-summary-write-article-body-file
   "h" gnus-summary-save-article-folder
   "v" gnus-summary-save-article-vm
   "p" gnus-summary-pipe-output
@@ -2250,7 +2260,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
               ,@(if (featurep 'xemacs) '(t)
                   '(:help "Generate and print a PostScript image"))])
             ("Copy, move,... (Backend)"
-             ,@(if (featurep 'xemacs) '(t)
+             ,@(if (featurep 'xemacs) nil
                  '(:help "Copying, moving, expiring articles..."))
              ["Respool article..." gnus-summary-respool-article t]
              ["Move article..." gnus-summary-move-article
@@ -2428,7 +2438,7 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
         ["Unread" gnus-summary-limit-to-unread t]
         ["Unseen" gnus-summary-limit-to-unseen t]
         ["Non-dormant" gnus-summary-limit-exclude-dormant t]
-        ["Next articles" gnus-summary-limit-to-articles t]
+        ["Next or process marked articles" gnus-summary-limit-to-articles t]
         ["Pop limit" gnus-summary-pop-limit t]
         ["Show dormant" gnus-summary-limit-include-dormant t]
         ["Hide childless dormant"
@@ -2544,47 +2554,161 @@ gnus-summary-show-article-from-menu-as-charset-%s" cs))))
 
 (defvar gnus-summary-tool-bar-map nil)
 
-;; Emacs 21 tool bar.  Should be no-op otherwise.
-(defun gnus-summary-make-tool-bar ()
-  (if (and (fboundp 'tool-bar-add-item-from-menu)
-          (default-value 'tool-bar-mode)
-          (not gnus-summary-tool-bar-map))
-      (setq gnus-summary-tool-bar-map
-           (let ((tool-bar-map (make-sparse-keymap))
-                 (load-path (mm-image-load-path)))
-             (tool-bar-add-item-from-menu
-              'gnus-summary-prev-unread "prev-ur" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-next-unread "next-ur" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-post-news "post" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-followup-with-original "fuwo" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-followup "followup" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-reply-with-original "reply-wo" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-reply "reply" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-caesar-message "rot13" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-uu-decode-uu "uu-decode" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-save-article-file "save-aif" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-save-article "save-art" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-uu-post-news "uu-post" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-catchup "catchup" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-catchup-and-exit "cu-exit" gnus-summary-mode-map)
-             (tool-bar-add-item-from-menu
-              'gnus-summary-exit "exit-summ" gnus-summary-mode-map)
-             tool-bar-map)))
-  (if gnus-summary-tool-bar-map
-      (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
+;; Note: The :set function in the `gnus-summary-tool-bar*' variables will only
+;; affect _new_ message buffers.  We might add a function that walks thru all
+;; summary-mode buffers and force the update.
+(defun gnus-summary-tool-bar-update (&optional symbol value)
+  "Update summary mode toolbar.
+Setter function for custom variables."
+  (setq-default gnus-summary-tool-bar-map nil)
+  (when symbol
+    ;; When used as ":set" function:
+    (set-default symbol value))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (with-current-buffer gnus-summary-buffer
+      (gnus-summary-make-tool-bar))))
+
+(defcustom gnus-summary-tool-bar (if (eq gmm-tool-bar-style 'gnome)
+                                    'gnus-summary-tool-bar-gnome
+                                  'gnus-summary-tool-bar-retro)
+  "Specifies the Gnus summary tool bar.
+
+It can be either a list or a symbol refering to a list.  See
+`gmm-tool-bar-from-list' for the format of the list.  The
+default key map is `gnus-summary-mode-map'.
+
+Pre-defined symbols include `gnus-summary-tool-bar-gnome' and
+`gnus-summary-tool-bar-retro'."
+  :type '(choice (const :tag "GNOME style" gnus-summary-tool-bar-gnome)
+                (const :tag "Retro look"  gnus-summary-tool-bar-retro)
+                (repeat :tag "User defined list" gmm-tool-bar-item)
+                (symbol))
+  :version "22.1" ;; Gnus 5.10.9
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-gnome
+  '((gnus-summary-post-news "mail/compose" nil)
+    (gnus-summary-insert-new-articles "mail/inbox" nil
+                                     :visible (or (not gnus-agent)
+                                                  gnus-plugged))
+    (gnus-summary-reply-with-original "mail/reply")
+    (gnus-summary-reply "mail/reply" nil :visible nil)
+    (gnus-summary-followup-with-original "mail/reply-all")
+    (gnus-summary-followup "mail/reply-all" nil :visible nil)
+    (gnus-summary-mail-forward "mail/forward")
+    (gnus-summary-save-article "mail/save")
+    (gnus-summary-search-article-forward "search" nil :visible nil)
+    (gnus-summary-print-article "print")
+    (gnus-summary-tick-article-forward "flag-followup" nil :visible nil)
+    ;; Some new commands that may need more suitable icons:
+    (gnus-summary-save-newsrc "save" nil :visible nil)
+    ;; (gnus-summary-show-article "stock_message-display" nil :visible nil)
+    (gnus-summary-prev-article "left-arrow")
+    (gnus-summary-next-article "right-arrow")
+    (gnus-summary-next-page "next-page")
+    ;; (gnus-summary-enter-digest-group "right_arrow" nil :visible nil)
+    ;;
+    ;; Maybe some sort-by-... could be added:
+    ;; (gnus-summary-sort-by-author "sort-a-z" nil :visible nil)
+    ;; (gnus-summary-sort-by-date "sort-1-9" nil :visible nil)
+    (gnus-summary-mark-as-expirable
+     "delete" nil
+     :visible (gnus-check-backend-function 'request-expire-articles
+                                          gnus-newsgroup-name))
+    (gnus-summary-mark-as-spam
+     "mail/spam" t
+     :visible (and (fboundp 'spam-group-ham-contents-p)
+                  (spam-group-ham-contents-p gnus-newsgroup-name))
+     :help "Mark as spam")
+    (gnus-summary-mark-as-read-forward
+     "mail/not-spam" nil
+     :visible (and (fboundp 'spam-group-spam-contents-p)
+                  (spam-group-spam-contents-p gnus-newsgroup-name)))
+    ;;
+    (gnus-summary-exit "exit")
+    (gmm-customize-mode "preferences" t :help "Edit mode preferences")
+    (gnus-info-find-node "help"))
+  "List of functions for the summary tool bar (GNOME style).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "22.1" ;; Gnus 5.10.9
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-retro
+  '((gnus-summary-prev-unread-article "gnus/prev-ur")
+    (gnus-summary-next-unread-article "gnus/next-ur")
+    (gnus-summary-post-news "gnus/post")
+    (gnus-summary-followup-with-original "gnus/fuwo")
+    (gnus-summary-followup "gnus/followup")
+    (gnus-summary-reply-with-original "gnus/reply-wo")
+    (gnus-summary-reply "gnus/reply")
+    (gnus-summary-caesar-message "gnus/rot13")
+    (gnus-uu-decode-uu "gnus/uu-decode")
+    (gnus-summary-save-article-file "gnus/save-aif")
+    (gnus-summary-save-article "gnus/save-art")
+    (gnus-uu-post-news "gnus/uu-post")
+    (gnus-summary-catchup "gnus/catchup")
+    (gnus-summary-catchup-and-exit "gnus/cu-exit")
+    (gnus-summary-exit "gnus/exit-summ")
+    ;; Some new command that may need more suitable icons:
+    (gnus-summary-print-article "gnus/print" nil :visible nil)
+    (gnus-summary-mark-as-expirable "gnus/close" nil :visible nil)
+    (gnus-summary-save-newsrc "gnus/save" nil :visible nil)
+    ;; (gnus-summary-enter-digest-group "gnus/right_arrow" nil :visible nil)
+    (gnus-summary-search-article-forward "gnus/search" nil :visible nil)
+    ;; (gnus-summary-insert-new-articles "gnus/paste" nil :visible nil)
+    ;; (gnus-summary-toggle-threads "gnus/open" nil :visible nil)
+    ;;
+    (gnus-info-find-node "gnus/help" nil :visible nil))
+  "List of functions for the summary tool bar (retro look).
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type '(repeat gmm-tool-bar-item)
+  :version "22.1" ;; Gnus 5.10.9
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defcustom gnus-summary-tool-bar-zap-list t
+  "List of icon items from the global tool bar.
+These items are not displayed in the Gnus summary mode tool bar.
+
+See `gmm-tool-bar-from-list' for the format of the list."
+  :type 'gmm-tool-bar-zap-list
+  :version "22.1" ;; Gnus 5.10.9
+  :initialize 'custom-initialize-default
+  :set 'gnus-summary-tool-bar-update
+  :group 'gnus-summary)
+
+(defvar image-load-path)
+
+(defun gnus-summary-make-tool-bar (&optional force)
+  "Make a summary mode tool bar from `gnus-summary-tool-bar'.
+When FORCE, rebuild the tool bar."
+  (when (and (not (featurep 'xemacs))
+            (boundp 'tool-bar-mode)
+            tool-bar-mode
+            (or (not gnus-summary-tool-bar-map) force))
+    (let* ((load-path
+           (gmm-image-load-path-for-library "gnus"
+                                            "mail/save.xpm"
+                                            nil t))
+           (image-load-path (cons (car load-path)
+                                  (when (boundp 'image-load-path)
+                                    image-load-path)))
+          (map (gmm-tool-bar-from-list gnus-summary-tool-bar
+                                       gnus-summary-tool-bar-zap-list
+                                       'gnus-summary-mode-map)))
+      (when map
+       ;; Need to set `gnus-summary-tool-bar-map' because `gnus-article-mode'
+       ;; uses it's value.
+       (setq gnus-summary-tool-bar-map map))))
+  (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map))
 
 (defun gnus-score-set-default (var value)
   "A version of set that updates the GNU Emacs menu-bar."
@@ -2722,7 +2846,7 @@ The following commands are available:
   (make-local-variable 'gnus-summary-mark-positions)
   (gnus-make-local-hook 'pre-command-hook)
   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
-  (gnus-run-hooks 'gnus-summary-mode-hook)
+  (gnus-run-mode-hooks 'gnus-summary-mode-hook)
   (turn-on-gnus-mailing-list-mode)
   (mm-enable-multibyte)
   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
@@ -3096,8 +3220,11 @@ display only a single character."
     (aset table ?\r nil)
     ;; We keep TAB as well.
     (aset table ?\t nil)
-    ;; We nix out any glyphs over 126 that are not set already.
-    (let ((i 256))
+    ;; We nix out any glyphs 127 through 255, or 127 through 159 in
+    ;; Emacs 23 (unicode), that are not set already.
+    (let ((i (if (ignore-errors (= (make-char 'latin-iso8859-1 160) 160))
+                160
+              256)))
       (while (>= (setq i (1- i)) 127)
        ;; Only modify if the entry is nil.
        (unless (aref table i)
@@ -3313,7 +3440,7 @@ buffer that was in action when the last article was fetched."
              (concat "-> "
                      (inline
                        (gnus-summary-extract-address-component
-                        (funcall gnus-decode-encoded-word-function to)))))
+                        (funcall gnus-decode-encoded-address-function to)))))
             ((setq newsgroups (cdr (assq 'Newsgroups extra-headers)))
              (concat "=> " newsgroups)))))
      (inline (gnus-summary-extract-address-component gnus-tmp-from)))))
@@ -3589,16 +3716,10 @@ If NO-DISPLAY, don't generate a summary buffer."
       (when gnus-build-sparse-threads
        (gnus-build-sparse-threads))
       ;; Find the initial limit.
-      (if gnus-show-threads
-         (if show-all
-             (let ((gnus-newsgroup-dormant nil))
-               (gnus-summary-initial-limit show-all))
+      (if show-all
+         (let ((gnus-newsgroup-dormant nil))
            (gnus-summary-initial-limit show-all))
-       ;; When unthreaded, all articles are always shown.
-       (setq gnus-newsgroup-limit
-             (mapcar
-              (lambda (header) (mail-header-number header))
-              gnus-newsgroup-headers)))
+       (gnus-summary-initial-limit show-all))
       ;; Generate the summary buffer.
       (unless no-display
        (gnus-summary-prepare))
@@ -4065,7 +4186,7 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                   (error x))
                 (condition-case ()     ; from
                     (gnus-remove-odd-characters
-                     (funcall gnus-decode-encoded-word-function
+                     (funcall gnus-decode-encoded-address-function
                               (setq x (nnheader-nov-field))))
                   (error x))
                 (nnheader-nov-field)   ; date
@@ -4639,39 +4760,39 @@ Unscored articles will be counted as having a score of zero."
 (defcustom gnus-sum-thread-tree-root "> "
   "With %B spec, used for the root of a thread.
 If nil, use subject instead."
-  :version "21.4"
+  :version "22.1"
   :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-false-root "> "
   "With %B spec, used for a false root of a thread.
 If nil, use subject instead."
-  :version "21.4"
+  :version "22.1"
   :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-single-indent ""
   "With %B spec, used for a thread with just one message.
 If nil, use subject instead."
-  :version "21.4"
+  :version "22.1"
   :type '(radio (const :format "%v  " nil) string)
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-vertical "| "
   "With %B spec, used for drawing a vertical line."
-  :version "21.4"
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-indent "  "
   "With %B spec, used for indenting."
-  :version "21.4"
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-leaf-with-other "+-> "
   "With %B spec, used for a leaf with brothers."
-  :version "21.4"
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 (defcustom gnus-sum-thread-tree-single-leaf "\\-> "
   "With %B spec, used for a leaf without brothers."
-  :version "21.4"
+  :version "22.1"
   :type 'string
   :group 'gnus-thread)
 
@@ -5087,13 +5208,13 @@ If SELECT-ARTICLES, only select those articles from GROUP."
          (when (equal major-mode 'gnus-summary-mode)
            (gnus-kill-buffer (current-buffer)))
          (error "Couldn't activate group %s: %s"
-                group (gnus-status-message group))))
+                (gnus-group-decoded-name group) (gnus-status-message group))))
 
     (unless (gnus-request-group group t)
       (when (equal major-mode 'gnus-summary-mode)
        (gnus-kill-buffer (current-buffer)))
       (error "Couldn't request group %s: %s"
-            group (gnus-status-message group)))
+            (gnus-group-decoded-name group) (gnus-status-message group)))
 
     (when gnus-agent
       (gnus-agent-possibly-alter-active group (gnus-active group) info)
@@ -5299,8 +5420,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
 
 (defun gnus-articles-to-read (group &optional read-all)
   "Find out what articles the user wants to read."
-  (let* ((display (gnus-group-find-parameter group 'display))
-        (articles
+  (let* ((articles
          ;; Select all articles if `read-all' is non-nil, or if there
          ;; are no unread articles.
          (if (or read-all
@@ -5591,8 +5711,9 @@ If WHERE is `summary', the summary mode line format will be used."
        (let* ((mformat (symbol-value
                         (intern
                          (format "gnus-%s-mode-line-format-spec" where))))
-              (gnus-tmp-group-name (gnus-group-decoded-name
-                                    gnus-newsgroup-name))
+              (gnus-tmp-group-name (gnus-mode-string-quote
+                                    (gnus-group-decoded-name
+                                     gnus-newsgroup-name)))
               (gnus-tmp-article-number (or gnus-current-article 0))
               (gnus-tmp-unread gnus-newsgroup-unreads)
               (gnus-tmp-unread-and-unticked (length gnus-newsgroup-unreads))
@@ -5660,7 +5781,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                                                    (match-end 1)))
                        (substring xrefs (match-beginning 1) (match-end 1))))
          (setq number
-               (string-to-int (substring xrefs (match-beginning 2)
+               (string-to-number (substring xrefs (match-beginning 2)
                                          (match-end 2))))
          (if (setq entry (gnus-gethash group xref-hashtb))
              (setcdr entry (cons number (cdr entry)))
@@ -5840,7 +5961,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            (progn
              (goto-char p)
              (if (search-forward "\nfrom:" nil t)
-                 (funcall gnus-decode-encoded-word-function
+                 (funcall gnus-decode-encoded-address-function
                           (nnheader-header-value))
                "(nobody)"))
            ;; Date.
@@ -5957,7 +6078,8 @@ Return a list of headers that match SEQUENCE (see
        (allp (cond
               ((eq gnus-read-all-available-headers t)
                t)
-              ((stringp gnus-read-all-available-headers)
+              ((and (stringp gnus-read-all-available-headers)
+                    group)
                (string-match gnus-read-all-available-headers group))
               (t
                nil)))
@@ -6112,7 +6234,7 @@ current article will be taken into consideration."
       (let ((max (max (point) (mark)))
            articles article)
        (save-excursion
-         (goto-char (min (min (point) (mark))))
+         (goto-char (min (point) (mark)))
          (while
              (and
               (push (setq article (gnus-summary-article-number)) articles)
@@ -6450,10 +6572,12 @@ displayed, no centering will be performed."
          (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
          (setq read (cdr read)))))
     ;; And add the last unread articles.
-    (cond ((< first last)
-           (push (cons first last) unread))
-          ((= first last)
-           (push first unread)))
+    (cond ((not (and first last))
+          nil)
+         ((< first last)
+          (push (cons first last) unread))
+         ((= first last)
+          (push first unread)))
     ;; Return the sequence of unread articles.
     (delq 0 (nreverse unread))))
 
@@ -6681,6 +6805,10 @@ If FORCE (the prefix), also save the .newsrc file(s)."
       (if quit-config
          (gnus-handle-ephemeral-exit quit-config)
        (goto-char group-point)
+       ;; If gnus-group-buffer is already displayed, make sure we also move
+       ;; the cursor in the window that displays it.
+       (let ((win (get-buffer-window (current-buffer) 0)))
+         (if win (set-window-point win (point))))
        (unless leave-hidden
          (gnus-configure-windows 'group 'force)))
       ;; Clear the current group name.
@@ -7250,11 +7378,12 @@ If BACKWARD, the previous article is selected instead of the next."
             (if (and group
                      (not (gnus-ephemeral-group-p gnus-newsgroup-name)))
                 (format " (Type %s for %s [%s])"
-                        (single-key-description cmd) group
+                        (single-key-description cmd)
+                        (gnus-group-decoded-name group)
                         (car (gnus-gethash group gnus-newsrc-hashtb)))
               (format " (Type %s to exit %s)"
                       (single-key-description cmd)
-                      gnus-newsgroup-name))))
+                      (gnus-group-decoded-name gnus-newsgroup-name)))))
       ;; Confirm auto selection.
       (setq key (car (setq keve (gnus-read-event-char prompt)))
            ended t)
@@ -7691,8 +7820,8 @@ articles that are younger than AGE days."
           (gnus-completing-read-with-default
            (symbol-name (car gnus-extra-headers))
            (if current-prefix-arg
-               "Exclude extra header:"
-             "Limit extra header:")
+               "Exclude extra header"
+             "Limit extra header")
            (mapcar (lambda (x)
                      (cons (symbol-name x) x))
                    gnus-extra-headers)
@@ -8325,10 +8454,11 @@ to guess what the document format is."
        ;; the parent article.
        (when (setq to-address (or (gnus-fetch-field "reply-to")
                                   (gnus-fetch-field "from")))
-         (setq params (append
-                       (list (cons 'to-address
-                                   (funcall gnus-decode-encoded-word-function
-                                            to-address))))))
+         (setq params
+               (append
+                (list (cons 'to-address
+                            (funcall gnus-decode-encoded-address-function
+                                     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
@@ -8859,7 +8989,9 @@ forward."
        (let ((start (window-start))
              buffer-read-only)
          (message-caesar-buffer-body arg)
-         (set-window-start (get-buffer-window (current-buffer)) start))))))
+         (set-window-start (get-buffer-window (current-buffer)) start)))))
+  ;; Create buttons and stuff...
+  (gnus-treat-article nil))
 
 (autoload 'unmorse-region "morse"
   "Convert morse coded text in region to ordinary ASCII text."
@@ -9022,7 +9154,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
             (gnus-request-article-this-buffer article gnus-newsgroup-name)
             (when (consp (setq art-group
                                (gnus-request-accept-article
-                                to-newsgroup select-method (not articles))))
+                                to-newsgroup select-method (not articles) t)))
               (setq new-xref (concat new-xref " " (car art-group)
                                      ":"
                                      (number-to-string (cdr art-group))))
@@ -9030,7 +9162,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
               ;; it and replace the new article.
               (nnheader-replace-header "Xref" new-xref)
               (gnus-request-replace-article
-               (cdr art-group) to-newsgroup (current-buffer))
+               (cdr art-group) to-newsgroup (current-buffer) t)
               art-group))))))
       (cond
        ((not art-group)
@@ -9128,7 +9260,7 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
              (gnus-request-article-this-buffer article gnus-newsgroup-name)
              (nnheader-replace-header "Xref" new-xref)
              (gnus-request-replace-article
-              article gnus-newsgroup-name (current-buffer))))
+              article gnus-newsgroup-name (current-buffer) t)))
 
          ;; run the move/copy/crosspost/respool hook
          (run-hook-with-args 'gnus-summary-article-move-hook
@@ -9182,7 +9314,7 @@ If nil, use to the current newsgroup method."
   "If non-nil, show and update the summary buffer as it's being built.
 If the value is t, update the buffer after every line is inserted.  If
 the value is an integer (N), update the display every N lines."
-  :version "21.4"
+  :version "22.1"
   :group 'gnus-thread
   :type '(choice (const :tag "off" nil)
                 number
@@ -9211,7 +9343,7 @@ latter case, they will be copied into the relevant groups."
                                        gnus-newsgroup-name)))))
                (method
                 (gnus-completing-read-with-default
-                 methname "What backend do you want to use when respooling?"
+                 methname "Backend to use when respooling"
                  methods nil t nil 'gnus-mail-method-history))
                ms)
           (cond
@@ -9377,14 +9509,14 @@ deleted forever, right now."
   (interactive)
   (or gnus-expert-user
       (gnus-yes-or-no-p
-       "Are you really, really, really sure you want to delete all these messages? ")
+       "Are you really, really sure you want to delete all expirable messages? ")
       (error "Phew!"))
   (gnus-summary-expire-articles t))
 
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
 (defun gnus-summary-delete-article (&optional n)
   "Delete the N next (mail) articles.
-This command actually deletes articles.         This is not a marking
+This command actually deletes articles.  This is not a marking
 command.  The article will disappear forever from your life, never to
 return.
 
@@ -9485,7 +9617,8 @@ groups."
           `(lambda ()
              (let ((mbl mml-buffer-list))
                (setq mml-buffer-list nil)
-               (mime-to-mml ,'current-handles)
+               (let ((rfc2047-quote-decoded-words-containing-tspecials t))
+                 (mime-to-mml ,'current-handles))
                (let ((mbl1 mml-buffer-list))
                  (setq mml-buffer-list mbl)
                  (set (make-local-variable 'mml-buffer-list) mbl1))
@@ -9553,7 +9686,8 @@ groups."
            (save-excursion
              (save-restriction
                (message-narrow-to-head)
-               (let ((head (buffer-string))
+               (let ((head (buffer-substring-no-properties
+                            (point-min) (point-max)))
                      header)
                  (with-temp-buffer
                    (insert (format "211 %d Article retrieved.\n"
@@ -10603,7 +10737,9 @@ Returns nil if no thread was there to be shown."
 (defun gnus-map-articles (predicate articles)
   "Map PREDICATE over ARTICLES and return non-nil if any predicate is non-nil."
   (apply 'gnus-or (mapcar predicate
-                         (mapcar 'gnus-summary-article-header articles))))
+                         (mapcar (lambda (number)
+                                   (gnus-summary-article-header number))
+                                 articles))))
 
 (defun gnus-summary-hide-all-threads (&optional predicate)
   "Hide all thread subtrees.
@@ -10859,12 +10995,26 @@ If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead.
-The variable `gnus-default-article-saver' specifies the saver function."
+The variable `gnus-default-article-saver' specifies the saver function.
+
+If the optional second argument NOT-SAVED is non-nil, articles saved
+will not be marked as saved."
   (interactive "P")
+  (require 'gnus-art)
   (let* ((articles (gnus-summary-work-articles n))
         (save-buffer (save-excursion
                        (nnheader-set-temp-buffer " *Gnus Save*")))
         (num (length articles))
+        ;; Whether to save decoded articles or raw articles.
+        (decode (when gnus-article-save-coding-system
+                  (get gnus-default-article-saver :decode)))
+        ;; When saving many articles in a single file, use the other
+        ;; function to save articles other than the first one.
+        (saver2 (get gnus-default-article-saver :function))
+        (gnus-prompt-before-saving (if saver2
+                                       t
+                                     gnus-prompt-before-saving))
+        (gnus-default-article-saver gnus-default-article-saver)
         header file)
     (dolist (article articles)
       (setq header (gnus-summary-article-header article))
@@ -10875,17 +11025,25 @@ The variable `gnus-default-article-saver' specifies the saver function."
            (gnus-message 1 "Article %d is unsaveable" article))
        ;; This is a real article.
        (save-window-excursion
-         (let ((gnus-display-mime-function nil)
-               (gnus-article-prepare-hook nil))
-           (gnus-summary-select-article t nil nil article)))
+         (let ((gnus-display-mime-function (when decode
+                                             gnus-display-mime-function))
+               (gnus-article-prepare-hook (when decode
+                                            gnus-article-prepare-hook)))
+           (gnus-summary-select-article t nil nil article)
+           (gnus-summary-goto-subject article)))
        (save-excursion
          (set-buffer save-buffer)
          (erase-buffer)
-         (insert-buffer-substring gnus-original-article-buffer))
+         (insert-buffer-substring (if decode
+                                      gnus-article-buffer
+                                    gnus-original-article-buffer)))
        (setq file (gnus-article-save save-buffer file num))
        (gnus-summary-remove-process-mark article)
        (unless not-saved
-         (gnus-summary-set-saved-mark article))))
+         (gnus-summary-set-saved-mark article)))
+      (when saver2
+       (setq gnus-default-article-saver saver2
+             saver2 nil)))
     (gnus-kill-buffer save-buffer)
     (gnus-summary-position-point)
     (gnus-set-mode-line 'summary)
@@ -10909,7 +11067,7 @@ If HEADERS (the symbolic prefix), include the headers, too."
       (gnus-configure-windows 'pipe))))
 
 (defun gnus-summary-save-article-mail (&optional arg)
-  "Append the current article to an mail file.
+  "Append the current article to a Unix mail box file.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
@@ -10963,6 +11121,17 @@ save those articles instead."
   (let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
     (gnus-summary-save-article arg)))
 
+(defun gnus-summary-write-article-body-file (&optional arg)
+  "Write the current article body to a file, deleting the previous file.
+If N is a positive number, save the N next articles.
+If N is a negative number, save the N previous articles.
+If N is nil and any articles have been marked with the process mark,
+save those articles instead."
+  (interactive "P")
+  (require 'gnus-art)
+  (let ((gnus-default-article-saver 'gnus-summary-write-body-to-file))
+    (gnus-summary-save-article arg)))
+
 (defun gnus-summary-muttprint (&optional arg)
   "Print the current article using Muttprint.
 If N is a positive number, save the N next articles.
@@ -11035,7 +11204,7 @@ save those articles instead."
   (let* ((split-name (gnus-get-split-value gnus-move-split-methods))
         (minibuffer-confirm-incomplete nil) ; XEmacs
         (prom
-         (format "%s %s to:"
+         (format "%s %s to"
                  prompt
                  (if (> (length articles) 1)
                      (format "these %d articles" (length articles))