Revision: miles@gnu.org--gnu-2005/gnus--devo--0--patch-37
[gnus] / lisp / gnus-art.el
index c92f394..ea588c9 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-art.el --- article mode commands for Gnus
 ;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 (autoload 'gnus-msg-mail "gnus-msg" nil t)
 (autoload 'gnus-button-mailto "gnus-msg")
 (autoload 'gnus-button-reply "gnus-msg" nil t)
 (autoload 'gnus-msg-mail "gnus-msg" nil t)
 (autoload 'gnus-button-mailto "gnus-msg")
 (autoload 'gnus-button-reply "gnus-msg" nil t)
+(autoload 'ansi-color-apply-on-region "ansi-color")
 
 (defgroup gnus-article nil
   "Article display."
 
 (defgroup gnus-article nil
   "Article display."
-  :link '(custom-manual "(gnus)The Article Buffer")
+  :link '(custom-manual "(gnus)Article Buffer")
   :group 'gnus)
 
 (defgroup gnus-article-treat nil
   :group 'gnus)
 
 (defgroup gnus-article-treat nil
      "X-Virus-Scanned" "X-Delivery-Agent" "Posted-Date" "X-Gateway"
      "X-Local-Origin" "X-Local-Destination" "X-UserInfo1"
      "X-Received-Date" "X-Hashcash" "Face" "X-DMCA-Notifications"
      "X-Virus-Scanned" "X-Delivery-Agent" "Posted-Date" "X-Gateway"
      "X-Local-Origin" "X-Local-Destination" "X-UserInfo1"
      "X-Received-Date" "X-Hashcash" "Face" "X-DMCA-Notifications"
-     "X-Abuse-and-DMCA-Info" "X-Postfilter"))
+     "X-Abuse-and-DMCA-Info" "X-Postfilter" "X-Gpg-.*" "X-Disclaimer"))
   "*All headers that start with this regexp will be hidden.
 This variable can also be a list of regexps of headers to be ignored.
 If `gnus-visible-headers' is non-nil, this variable will be ignored."
   "*All headers that start with this regexp will be hidden.
 This variable can also be a list of regexps of headers to be ignored.
 If `gnus-visible-headers' is non-nil, this variable will be ignored."
@@ -213,6 +214,7 @@ By default, if you set this t, then Gnus will display citations and
 signatures, but will never scroll down to show you a page consisting
 only of boring text.  Boring text is controlled by
 `gnus-article-boring-faces'."
 signatures, but will never scroll down to show you a page consisting
 only of boring text.  Boring text is controlled by
 `gnus-article-boring-faces'."
+  :version "22.1"
   :type 'boolean
   :group 'gnus-article-hiding)
 
   :type 'boolean
   :group 'gnus-article-hiding)
 
@@ -231,7 +233,9 @@ that number.  If it is a floating point number, no signature may be
 longer (in lines) than that number.  If it is a function, the function
 will be called without any parameters, and if it returns nil, there is
 no signature in the buffer.  If it is a string, it will be used as a
 longer (in lines) than that number.  If it is a function, the function
 will be called without any parameters, and if it returns nil, there is
 no signature in the buffer.  If it is a string, it will be used as a
-regexp.  If it matches, the text in question is not a signature."
+regexp.  If it matches, the text in question is not a signature.
+
+This can also be a list of the above values."
   :type '(choice (integer :value 200)
                 (number :value 4.0)
                 (function :value fun)
   :type '(choice (integer :value 200)
                 (number :value 4.0)
                 (function :value fun)
@@ -317,29 +321,56 @@ advertisements.  For example:
                   (symbol :tag "Item in `gnus-article-banner-alist'" none)
                   regexp
                   (const :tag "None" nil))))
                   (symbol :tag "Item in `gnus-article-banner-alist'" none)
                   regexp
                   (const :tag "None" nil))))
+  :version "22.1"
   :group 'gnus-article-washing)
 
   :group 'gnus-article-washing)
 
+(defmacro gnus-emphasis-custom-with-format (&rest body)
+  `(let ((format "\
+\\(\\s-\\|^\\|\\=\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\
+\\(\\([-,.;:!?\"]\\|\\s)\\)+\\s-\\|[?!.]\\s-\\|\\s)\\|\\s-\\)"))
+     ,@body))
+
+(defun gnus-emphasis-custom-value-to-external (value)
+  (gnus-emphasis-custom-with-format
+   (if (consp (car value))
+       (list (format format (car (car value)) (cdr (car value)))
+            2
+            (if (nth 1 value) 2 3)
+            (nth 2 value))
+     value)))
+
+(defun gnus-emphasis-custom-value-to-internal (value)
+  (gnus-emphasis-custom-with-format
+   (let ((regexp (concat "\\`"
+                        (format (regexp-quote format)
+                                "\\([^()]+\\)" "\\([^()]+\\)")
+                        "\\'"))
+        pattern)
+     (if (string-match regexp (setq pattern (car value)))
+        (list (cons (match-string 1 pattern) (match-string 2 pattern))
+              (= (nth 2 value) 2)
+              (nth 3 value))
+       value))))
+
 (defcustom gnus-emphasis-alist
 (defcustom gnus-emphasis-alist
-  (let ((format
-        "\\(\\s-\\|^\\|\\=\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\([-,.;:!?\"]\\|\\s)\\)+\\s-\\|[?!.]\\s-\\|\\s)\\|\\s-\\)")
-       (types
-        '(("\\*" "\\*" bold)
+  (let ((types
+        '(("\\*" "\\*" bold nil 2)
           ("_" "_" underline)
           ("/" "/" italic)
           ("_/" "/_" underline-italic)
           ("_\\*" "\\*_" underline-bold)
           ("\\*/" "/\\*" bold-italic)
           ("_\\*/" "/\\*_" underline-bold-italic))))
           ("_" "_" underline)
           ("/" "/" italic)
           ("_/" "/_" underline-italic)
           ("_\\*" "\\*_" underline-bold)
           ("\\*/" "/\\*" bold-italic)
           ("_\\*/" "/\\*_" underline-bold-italic))))
-    `(,@(mapcar
-        (lambda (spec)
-          (list
-           (format format (car spec) (cadr spec))
-           2 3 (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
-        types)
-       ("\\(\\s-\\|^\\)\\(-\\(\\(\\w\\|-[^-]\\)+\\)-\\)\\(\\s-\\|[?!.,;]\\)"
-        2 3 gnus-emphasis-strikethru)
-       ("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
-        2 3 gnus-emphasis-underline)))
+    (nconc
+     (gnus-emphasis-custom-with-format
+      (mapcar (lambda (spec)
+               (list (format format (car spec) (cadr spec))
+                     (or (nth 3 spec) 2)
+                     (or (nth 4 spec) 3)
+                     (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
+             types))
+     '(("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
+       2 3 gnus-emphasis-underline))))
   "*Alist that says how to fontify certain phrases.
 Each item looks like this:
 
   "*Alist that says how to fontify certain phrases.
 Each item looks like this:
 
@@ -350,11 +381,43 @@ is a number that says what regular expression grouping used to find
 the entire emphasized word.  The third is a number that says what
 regexp grouping should be displayed and highlighted.  The fourth
 is the face used for highlighting."
 the entire emphasized word.  The third is a number that says what
 regexp grouping should be displayed and highlighted.  The fourth
 is the face used for highlighting."
-  :type '(repeat (list :value ("" 0 0 default)
-                      regexp
-                      (integer :tag "Match group")
-                      (integer :tag "Emphasize group")
-                      face))
+  :type
+  '(repeat
+    (menu-choice
+     :format "%[Customizing Style%]\n%v"
+     :indent 2
+     (group :tag "Default"
+           :value ("" 0 0 default)
+           :value-create
+           (lambda (widget)
+             (let ((value (widget-get
+                           (cadr (widget-get (widget-get widget :parent)
+                                             :args))
+                           :value)))
+               (if (not (eq (nth 2 value) 'default))
+                   (widget-put
+                    widget
+                    :value
+                    (gnus-emphasis-custom-value-to-external value))))
+             (widget-group-value-create widget))
+           regexp
+           (integer :format "Match group: %v")
+           (integer :format "Emphasize group: %v")
+           face)
+     (group :tag "Simple"
+           :value (("_" . "_") nil default)
+           (cons :format "%v"
+                 (regexp :format "Start regexp: %v")
+                 (regexp :format "End regexp: %v"))
+           (boolean :format "Show start and end patterns: %[%v%]\n"
+                    :on " On " :off " Off ")
+           face)))
+  :get (lambda (symbol)
+        (mapcar 'gnus-emphasis-custom-value-to-internal
+                (default-value symbol)))
+  :set (lambda (symbol value)
+        (set-default symbol (mapcar 'gnus-emphasis-custom-value-to-external
+                                    value)))
   :group 'gnus-article-emphasis)
 
 (defcustom gnus-emphasize-whitespace-regexp "^[ \t]+\\|[ \t]*\n"
   :group 'gnus-article-emphasis)
 
 (defcustom gnus-emphasize-whitespace-regexp "^[ \t]+\\|[ \t]*\n"
@@ -396,7 +459,9 @@ and the latter avoids underlining any whitespace at all."
 Example: (_/*word*/_)."
   :group 'gnus-article-emphasis)
 
 Example: (_/*word*/_)."
   :group 'gnus-article-emphasis)
 
-(defface gnus-emphasis-strikethru '((t (:strikethru t)))
+(defface gnus-emphasis-strikethru (if (featurep 'xemacs)
+                                     '((t (:strikethru t)))
+                                   '((t (:strike-through t))))
   "Face used for displaying strike-through text (-word-)."
   :group 'gnus-article-emphasis)
 
   "Face used for displaying strike-through text (-word-)."
   :group 'gnus-article-emphasis)
 
@@ -405,14 +470,14 @@ Example: (_/*word*/_)."
   "Face used for displaying highlighted words."
   :group 'gnus-article-emphasis)
 
   "Face used for displaying highlighted words."
   :group 'gnus-article-emphasis)
 
-(defcustom gnus-article-time-format "%a, %b %d %Y %T %Z"
+(defcustom gnus-article-time-format "%a, %d %b %Y %T %Z"
   "Format for display of Date headers in article bodies.
 See `format-time-string' for the possible values.
 
 The variable can also be function, which should return a complete Date
 header.  The function is called with one argument, the time, which can
 be fed to `format-time-string'."
   "Format for display of Date headers in article bodies.
 See `format-time-string' for the possible values.
 
 The variable can also be function, which should return a complete Date
 header.  The function is called with one argument, the time, which can
 be fed to `format-time-string'."
-  :type '(choice string symbol)
+  :type '(choice string function)
   :link '(custom-manual "(gnus)Article Date")
   :group 'gnus-article-washing)
 
   :link '(custom-manual "(gnus)Article Date")
   :group 'gnus-article-washing)
 
@@ -504,17 +569,19 @@ you could set this variable to something like:
  '((\"^Subject:.*gnus\\|^Newsgroups:.*gnus\" \"gnus-stuff\")
    (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))
 
  '((\"^Subject:.*gnus\\|^Newsgroups:.*gnus\" \"gnus-stuff\")
    (\"^Subject:.*vm\\|^Xref:.*vm\" \"vm-stuff\"))
 
-This variable is an alist where the where the key is the match and the
-value is a list of possible files to save in if the match is non-nil.
+This variable is an alist where the key is the match and the
+value is a list of possible files to save in if the match is
+non-nil.
 
 If the match is a string, it is used as a regexp match on the
 article.  If the match is a symbol, that symbol will be funcalled
 
 If the match is a string, it is used as a regexp match on the
 article.  If the match is a symbol, that symbol will be funcalled
-from the buffer of the article to be saved with the newsgroup as the
-parameter.  If it is a list, it will be evaled in the same buffer.
+from the buffer of the article to be saved with the newsgroup as
+the parameter.  If it is a list, it will be evaled in the same
+buffer.
 
 
-If this form or function returns a string, this string will be used as
-a possible file name; and if it returns a non-nil list, that list will
-be used as possible file names."
+If this form or function returns a string, this string will be
+used as a possible file name; and if it returns a non-nil list,
+that list will be used as possible file names."
   :group 'gnus-article-saving
   :type '(repeat (choice (list :value (fun) function)
                         (cons :value ("" "") regexp (repeat string))
   :group 'gnus-article-saving
   :type '(repeat (choice (list :value (fun) function)
                         (cons :value ("" "") regexp (repeat string))
@@ -560,6 +627,13 @@ The following additional specs are available:
   :type 'hook
   :group 'gnus-article-various)
 
   :type 'hook
   :group 'gnus-article-various)
 
+(defcustom gnus-copy-article-ignored-headers nil
+  "List of headers to be removed when copying an article.
+Each element is a regular expression."
+  :version "22.0" ;; No Gnus
+  :type '(repeat regexp)
+  :group 'gnus-article-various)
+
 (make-obsolete-variable 'gnus-article-hide-pgp-hook
                        "This variable is obsolete in Gnus 5.10.")
 
 (make-obsolete-variable 'gnus-article-hide-pgp-hook
                        "This variable is obsolete in Gnus 5.10.")
 
@@ -742,7 +816,7 @@ If set, this variable overrides `gnus-unbuttonized-mime-types'.
 To see e.g. security buttons you could set this to
 `(\"multipart/signed\")'.
 This variable is only used when `gnus-inhibit-mime-unbuttonizing' is nil."
 To see e.g. security buttons you could set this to
 `(\"multipart/signed\")'.
 This variable is only used when `gnus-inhibit-mime-unbuttonizing' is nil."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-article-mime
   :type '(repeat regexp))
 
   :group 'gnus-article-mime
   :type '(repeat regexp))
 
@@ -751,21 +825,25 @@ This variable is only used when `gnus-inhibit-mime-unbuttonizing' is nil."
 When nil (the default value), then some MIME parts do not get buttons,
 as described by the variables `gnus-buttonized-mime-types' and
 `gnus-unbuttonized-mime-types'."
 When nil (the default value), then some MIME parts do not get buttons,
 as described by the variables `gnus-buttonized-mime-types' and
 `gnus-unbuttonized-mime-types'."
-  :version "21.3"
+  :version "22.1"
+  :group 'gnus-article-mime
   :type 'boolean)
 
 (defcustom gnus-body-boundary-delimiter "_"
   "String used to delimit header and body.
 This variable is used by `gnus-article-treat-body-boundary' which can
 be controlled by `gnus-treat-body-boundary'."
   :type 'boolean)
 
 (defcustom gnus-body-boundary-delimiter "_"
   "String used to delimit header and body.
 This variable is used by `gnus-article-treat-body-boundary' which can
 be controlled by `gnus-treat-body-boundary'."
+  :version "22.1"
   :group 'gnus-article-various
   :type '(choice (item :tag "None" :value nil)
                 string))
 
   :group 'gnus-article-various
   :type '(choice (item :tag "None" :value nil)
                 string))
 
-(defcustom gnus-picon-databases '("/usr/lib/picon" "/usr/local/faces")
+(defcustom gnus-picon-databases '("/usr/lib/picon" "/usr/local/faces"
+                                 "/usr/share/picons")
   "Defines the location of the faces database.
 For information on obtaining this database of pretty pictures, please
 see http://www.cs.indiana.edu/picons/ftp/index.html"
   "Defines the location of the faces database.
 For information on obtaining this database of pretty pictures, please
 see http://www.cs.indiana.edu/picons/ftp/index.html"
+  :version "22.1"
   :type '(repeat directory)
   :link '(url-link :tag "download"
                   "http://www.cs.indiana.edu/picons/ftp/index.html")
   :type '(repeat directory)
   :link '(url-link :tag "download"
                   "http://www.cs.indiana.edu/picons/ftp/index.html")
@@ -791,7 +869,7 @@ on parts -- for instance, adding Vcard info to a database."
   "An alist of MIME types to functions to display them."
   :version "21.1"
   :group 'gnus-article-mime
   "An alist of MIME types to functions to display them."
   :version "21.1"
   :group 'gnus-article-mime
-  :type 'alist)
+  :type '(repeat (cons :format "%v" (string :tag "MIME type") function)))
 
 (defcustom gnus-article-date-lapsed-new-header nil
   "Whether the X-Sent and Date headers can coexist.
 
 (defcustom gnus-article-date-lapsed-new-header nil
   "Whether the X-Sent and Date headers can coexist.
@@ -891,8 +969,7 @@ See Info node `(gnus)Customizing Articles' for details."
 
 (defcustom gnus-treat-emphasize
   (and (or window-system
 
 (defcustom gnus-treat-emphasize
   (and (or window-system
-          (featurep 'xemacs)
-          (>= (string-to-number emacs-version) 21))
+          (featurep 'xemacs))
        50000)
   "Emphasize text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
        50000)
   "Emphasize text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
@@ -906,6 +983,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Remove carriage returns.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Remove carriage returns.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -914,6 +992,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Remove newlines from within URLs.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Remove newlines from within URLs.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -922,6 +1001,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Remove leading whitespace in headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Remove leading whitespace in headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -1041,6 +1121,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Display the Date in a format that can be read aloud in English.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Display the Date in a format that can be read aloud in English.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-head-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-head-custom)
@@ -1116,6 +1197,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Unfold folded header lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Unfold folded header lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -1124,6 +1206,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Fold headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Fold headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -1132,6 +1215,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Fold the Newsgroups and Followup-To headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Fold the Newsgroups and Followup-To headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -1145,6 +1229,14 @@ See Info node `(gnus)Customizing Articles' for details."
   :type gnus-article-treat-custom)
 (put 'gnus-treat-overstrike 'highlight t)
 
   :type gnus-article-treat-custom)
 (put 'gnus-treat-overstrike 'highlight t)
 
+(defcustom gnus-treat-ansi-sequences (if (locate-library "ansi-color") t)
+  "Treat ANSI SGR control sequences.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
 (make-obsolete-variable 'gnus-treat-display-xface
                        'gnus-treat-display-x-face)
 
 (make-obsolete-variable 'gnus-treat-display-xface
                        'gnus-treat-display-x-face)
 
@@ -1167,7 +1259,7 @@ See Info node `(gnus)Customizing Articles' and Info node
   :link '(custom-manual "(gnus)X-Face")
   :type gnus-article-treat-head-custom
   :set (lambda (symbol value)
   :link '(custom-manual "(gnus)X-Face")
   :type gnus-article-treat-head-custom
   :set (lambda (symbol value)
-        (custom-set-default
+        (set-default
          symbol
          (cond ((or (boundp symbol) (get symbol 'saved-value))
                 value)
          symbol
          (cond ((or (boundp symbol) (get symbol 'saved-value))
                 value)
@@ -1197,7 +1289,7 @@ Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)X-Face' for details."
   :group 'gnus-article-treat
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)X-Face' for details."
   :group 'gnus-article-treat
-  :version "21.1"
+  :version "22.1"
   :link '(custom-manual "(gnus)Customizing Articles")
   :link '(custom-manual "(gnus)X-Face")
   :type gnus-article-treat-head-custom)
   :link '(custom-manual "(gnus)Customizing Articles")
   :link '(custom-manual "(gnus)X-Face")
   :type gnus-article-treat-head-custom)
@@ -1228,6 +1320,7 @@ See Info node `(gnus)Customizing Articles' and Info node
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
@@ -1243,6 +1336,7 @@ See Info node `(gnus)Customizing Articles' and Info node
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
@@ -1258,6 +1352,7 @@ See Info node `(gnus)Customizing Articles' and Info node
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' and Info node
 `(gnus)Picons' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
   :group 'gnus-article-treat
   :group 'gnus-picon
   :link '(custom-manual "(gnus)Customizing Articles")
@@ -1266,17 +1361,18 @@ See Info node `(gnus)Customizing Articles' and Info node
 (put 'gnus-treat-newsgroups-picon 'highlight t)
 
 (defcustom gnus-treat-body-boundary
 (put 'gnus-treat-newsgroups-picon 'highlight t)
 
 (defcustom gnus-treat-body-boundary
-  (if (or gnus-treat-newsgroups-picon
-         gnus-treat-mail-picon
-         gnus-treat-from-picon)
+  (if (and (eq window-system 'x)
+          (or gnus-treat-newsgroups-picon
+              gnus-treat-mail-picon
+              gnus-treat-from-picon))
       'head nil)
   "Draw a boundary at the end of the headers.
       'head nil)
   "Draw a boundary at the end of the headers.
-Valid values are nil, t, `head', `last', an integer or a predicate.
+Valid values are nil and `head'.
 See Info node `(gnus)Customizing Articles' for details."
 See Info node `(gnus)Customizing Articles' for details."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
-  :type gnus-article-treat-custom)
+  :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-capitalize-sentences nil
   "Capitalize sentence-starting words.
 
 (defcustom gnus-treat-capitalize-sentences nil
   "Capitalize sentence-starting words.
@@ -1291,6 +1387,7 @@ See Info node `(gnus)Customizing Articles' for details."
   "Format as HTML.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
   "Format as HTML.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
   :group 'gnus-article-treat
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
@@ -1326,6 +1423,7 @@ See Info node `(gnus)Customizing Articles' for details."
 To automatically treat X-PGP-Sig, set it to head.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
 To automatically treat X-PGP-Sig, set it to head.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See Info node `(gnus)Customizing Articles' for details."
+  :version "22.1"
   :group 'gnus-article-treat
   :group 'mime-security
   :link '(custom-manual "(gnus)Customizing Articles")
   :group 'gnus-article-treat
   :group 'mime-security
   :link '(custom-manual "(gnus)Customizing Articles")
@@ -1339,6 +1437,7 @@ See Info node `(gnus)Customizing Articles' for details."
 (defcustom gnus-article-encrypt-protocol "PGP"
   "The protocol used for encrypt articles.
 It is a string, such as \"PGP\". If nil, ask user."
 (defcustom gnus-article-encrypt-protocol "PGP"
   "The protocol used for encrypt articles.
 It is a string, such as \"PGP\". If nil, ask user."
+  :version "22.1"
   :type 'string
   :group 'mime-security)
 
   :type 'string
   :group 'mime-security)
 
@@ -1350,11 +1449,13 @@ It is a string, such as \"PGP\". If nil, ask user."
                              (executable-find idna-program))
   "Whether IDNA decoding of headers is used when viewing messages.
 This requires GNU Libidn, and by default only enabled if it is found."
                              (executable-find idna-program))
   "Whether IDNA decoding of headers is used when viewing messages.
 This requires GNU Libidn, and by default only enabled if it is found."
+  :version "22.1"
   :group 'gnus-article-headers
   :type 'boolean)
 
 (defcustom gnus-article-over-scroll nil
   "If non-nil, allow scrolling the article buffer even when there no more text."
   :group 'gnus-article-headers
   :type 'boolean)
 
 (defcustom gnus-article-over-scroll nil
   "If non-nil, allow scrolling the article buffer even when there no more text."
+  :version "22.1"
   :group 'gnus-article
   :type 'boolean)
 
   :group 'gnus-article
   :type 'boolean)
 
@@ -1364,6 +1465,13 @@ This requires GNU Libidn, and by default only enabled if it is found."
   '("January" "February" "March" "April" "May" "June" "July" "August"
     "September" "October" "November" "December"))
 
   '("January" "February" "March" "April" "May" "June" "July" "August"
     "September" "October" "November" "December"))
 
+(defvar gnus-button-regexp nil)
+(defvar gnus-button-marker-list nil)
+;; Regexp matching any of the regexps from `gnus-button-alist'.
+
+(defvar gnus-button-last nil)
+;; The value of `gnus-button-alist' when `gnus-button-regexp' was build.
+
 (defvar article-goto-body-goes-to-point-min-p nil)
 (defvar gnus-article-wash-types nil)
 (defvar gnus-article-emphasis-alist nil)
 (defvar article-goto-body-goes-to-point-min-p nil)
 (defvar gnus-article-wash-types nil)
 (defvar gnus-article-emphasis-alist nil)
@@ -1407,6 +1515,7 @@ This requires GNU Libidn, and by default only enabled if it is found."
     (gnus-treat-strip-multiple-blank-lines
      gnus-article-strip-multiple-blank-lines)
     (gnus-treat-overstrike gnus-article-treat-overstrike)
     (gnus-treat-strip-multiple-blank-lines
      gnus-article-strip-multiple-blank-lines)
     (gnus-treat-overstrike gnus-article-treat-overstrike)
+    (gnus-treat-ansi-sequences gnus-article-treat-ansi-sequences)
     (gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
     (gnus-treat-fold-headers gnus-article-treat-fold-headers)
     (gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
     (gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
     (gnus-treat-fold-headers gnus-article-treat-fold-headers)
     (gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
@@ -1449,13 +1558,15 @@ Initialized from `text-mode-syntax-table.")
 
 (defvar gnus-inhibit-hiding nil)
 
 
 (defvar gnus-inhibit-hiding nil)
 
+(defvar gnus-article-edit-mode nil)
+
 ;;; Macros for dealing with the article buffer.
 
 (defmacro gnus-with-article-headers (&rest forms)
   `(save-excursion
      (set-buffer gnus-article-buffer)
      (save-restriction
 ;;; Macros for dealing with the article buffer.
 
 (defmacro gnus-with-article-headers (&rest forms)
   `(save-excursion
      (set-buffer gnus-article-buffer)
      (save-restriction
-       (let ((buffer-read-only nil)
+       (let ((inhibit-read-only t)
             (inhibit-point-motion-hooks t)
             (case-fold-search t))
         (article-narrow-to-head)
             (inhibit-point-motion-hooks t)
             (case-fold-search t))
         (article-narrow-to-head)
@@ -1467,7 +1578,7 @@ Initialized from `text-mode-syntax-table.")
 (defmacro gnus-with-article-buffer (&rest forms)
   `(save-excursion
      (set-buffer gnus-article-buffer)
 (defmacro gnus-with-article-buffer (&rest forms)
   `(save-excursion
      (set-buffer gnus-article-buffer)
-     (let ((buffer-read-only nil))
+     (let ((inhibit-read-only t))
        ,@forms)))
 
 (put 'gnus-with-article-buffer 'lisp-indent-function 0)
        ,@forms)))
 
 (put 'gnus-with-article-buffer 'lisp-indent-function 0)
@@ -1553,25 +1664,35 @@ Initialized from `text-mode-syntax-table.")
   (interactive)
   ;; This function might be inhibited.
   (unless gnus-inhibit-hiding
   (interactive)
   ;; This function might be inhibited.
   (unless gnus-inhibit-hiding
-    (save-excursion
-      (save-restriction
-       (let ((buffer-read-only nil)
-             (case-fold-search t)
-             (max (1+ (length gnus-sorted-header-list)))
-             (ignored (when (not gnus-visible-headers)
-                        (cond ((stringp gnus-ignored-headers)
-                               gnus-ignored-headers)
-                              ((listp gnus-ignored-headers)
-                               (mapconcat 'identity gnus-ignored-headers
-                                          "\\|")))))
-             (visible
-              (cond ((stringp gnus-visible-headers)
-                     gnus-visible-headers)
-                    ((and gnus-visible-headers
-                          (listp gnus-visible-headers))
-                     (mapconcat 'identity gnus-visible-headers "\\|"))))
-             (inhibit-point-motion-hooks t)
-             beg)
+    (let ((inhibit-read-only nil)
+         (case-fold-search t)
+         (max (1+ (length gnus-sorted-header-list)))
+         (inhibit-point-motion-hooks t)
+         (cur (current-buffer))
+         ignored visible beg)
+      (save-excursion
+       ;; `gnus-ignored-headers' and `gnus-visible-headers' may be
+       ;; group parameters, so we should go to the summary buffer.
+       (when (prog1
+                 (condition-case nil
+                     (progn (set-buffer gnus-summary-buffer) t)
+                   (error nil))
+               (setq ignored (when (not gnus-visible-headers)
+                               (cond ((stringp gnus-ignored-headers)
+                                      gnus-ignored-headers)
+                                     ((listp gnus-ignored-headers)
+                                      (mapconcat 'identity
+                                                 gnus-ignored-headers
+                                                 "\\|"))))
+                     visible (cond ((stringp gnus-visible-headers)
+                                    gnus-visible-headers)
+                                   ((and gnus-visible-headers
+                                         (listp gnus-visible-headers))
+                                    (mapconcat 'identity
+                                               gnus-visible-headers
+                                               "\\|")))))
+         (set-buffer cur))
+       (save-restriction
          ;; First we narrow to just the headers.
          (article-narrow-to-head)
          ;; Hide any "From " lines at the beginning of (mail) articles.
          ;; First we narrow to just the headers.
          (article-narrow-to-head)
          ;; Hide any "From " lines at the beginning of (mail) articles.
@@ -1613,13 +1734,10 @@ always hide."
             (not gnus-show-all-headers))
     (save-excursion
       (save-restriction
             (not gnus-show-all-headers))
     (save-excursion
       (save-restriction
-       (let ((buffer-read-only nil)
-             (list gnus-boring-article-headers)
-             (inhibit-point-motion-hooks t)
-             elem)
+       (let ((inhibit-read-only t)
+             (inhibit-point-motion-hooks t))
          (article-narrow-to-head)
          (article-narrow-to-head)
-         (while list
-           (setq elem (pop list))
+         (dolist (elem gnus-boring-article-headers)
            (goto-char (point-min))
            (cond
             ;; Hide empty headers.
            (goto-char (point-min))
            (cond
             ;; Hide empty headers.
@@ -1627,7 +1745,7 @@ always hide."
              (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
                (forward-line -1)
                (gnus-article-hide-text-type
              (while (re-search-forward "^[^: \t]+:[ \t]*\n[^ \t]" nil t)
                (forward-line -1)
                (gnus-article-hide-text-type
-                (gnus-point-at-bol)
+                (point-at-bol)
                 (progn
                   (end-of-line)
                   (if (re-search-forward "^[^ \t]" nil t)
                 (progn
                   (end-of-line)
                   (if (re-search-forward "^[^ \t]" nil t)
@@ -1693,12 +1811,19 @@ always hide."
                  (gnus-article-hide-header "reply-to")
                (let ((from (message-fetch-field "from"))
                      (reply-to (message-fetch-field "reply-to")))
                  (gnus-article-hide-header "reply-to")
                (let ((from (message-fetch-field "from"))
                      (reply-to (message-fetch-field "reply-to")))
-                 (when (and
-                        from reply-to
-                        (ignore-errors
-                          (gnus-string-equal
-                           (nth 1 (mail-extract-address-components from))
-                           (nth 1 (mail-extract-address-components reply-to)))))
+                 (when
+                     (and
+                      from reply-to
+                      (ignore-errors
+                        (equal
+                         (sort (mapcar
+                                (lambda (x) (downcase (cadr x)))
+                                (mail-extract-address-components from t))
+                               'string<)
+                         (sort (mapcar
+                                (lambda (x) (downcase (cadr x)))
+                                (mail-extract-address-components reply-to t))
+                               'string<))))
                    (gnus-article-hide-header "reply-to")))))
             ((eq elem 'date)
              (let ((date (message-fetch-field "date")))
                    (gnus-article-hide-header "reply-to")))))
             ((eq elem 'date)
              (let ((date (message-fetch-field "date")))
@@ -1746,7 +1871,7 @@ always hide."
     (goto-char (point-min))
     (when (re-search-forward (concat "^" header ":") nil t)
       (gnus-article-hide-text-type
     (goto-char (point-min))
     (when (re-search-forward (concat "^" header ":") nil t)
       (gnus-article-hide-text-type
-       (gnus-point-at-bol)
+       (point-at-bol)
        (progn
         (end-of-line)
         (if (re-search-forward "^[^ \t]" nil t)
        (progn
         (end-of-line)
         (if (re-search-forward "^[^ \t]" nil t)
@@ -1760,14 +1885,14 @@ always hide."
 (defun article-normalize-headers ()
   "Make all header lines 40 characters long."
   (interactive)
 (defun article-normalize-headers ()
   "Make all header lines 40 characters long."
   (interactive)
-  (let ((buffer-read-only nil)
+  (let ((inhibit-read-only t)
        column)
     (save-excursion
       (save-restriction
        (article-narrow-to-head)
        (while (not (eobp))
          (cond
        column)
     (save-excursion
       (save-restriction
        (article-narrow-to-head)
        (while (not (eobp))
          (cond
-          ((< (setq column (- (gnus-point-at-eol) (point)))
+          ((< (setq column (- (point-at-eol) (point)))
               gnus-article-normalized-header-length)
            (end-of-line)
            (insert (make-string
               gnus-article-normalized-header-length)
            (end-of-line)
            (insert (make-string
@@ -1778,7 +1903,7 @@ always hide."
             (progn
               (forward-char gnus-article-normalized-header-length)
               (point))
             (progn
               (forward-char gnus-article-normalized-header-length)
               (point))
-            (gnus-point-at-eol)
+            (point-at-eol)
             'invisible t))
           (t
            ;; Do nothing.
             'invisible t))
           (t
            ;; Do nothing.
@@ -1786,14 +1911,15 @@ always hide."
          (forward-line 1))))))
 
 (defun article-treat-dumbquotes ()
          (forward-line 1))))))
 
 (defun article-treat-dumbquotes ()
-  "Translate M****s*** sm*rtq**t*s into proper text.
+  "Translate M****s*** sm*rtq**t*s and other symbols into proper text.
 Note that this function guesses whether a character is a sm*rtq**t* or
 not, so it should only be used interactively.
 
 Note that this function guesses whether a character is a sm*rtq**t* or
 not, so it should only be used interactively.
 
-Sm*rtq**t*s are M****s***'s unilateral extension to the character map
-in an attempt to provide more quoting characters.  If you see
-something like \\222 or \\264 where you're expecting some kind of
-apostrophe or quotation mark, then try this wash."
+Sm*rtq**t*s are M****s***'s unilateral extension to the
+iso-8859-1 character map in an attempt to provide more quoting
+characters.  If you see something like \\222 or \\264 where
+you're expecting some kind of apostrophe or quotation mark, then
+try this wash."
   (interactive)
   (article-translate-strings gnus-article-dumbquotes-map))
 
   (interactive)
   (article-translate-strings gnus-article-dumbquotes-map))
 
@@ -1803,7 +1929,7 @@ FROM is a string of characters to translate from; to is a string of
 characters to translate to."
   (save-excursion
     (when (article-goto-body)
 characters to translate to."
   (save-excursion
     (when (article-goto-body)
-      (let ((buffer-read-only nil)
+      (let ((inhibit-read-only t)
            (x (make-string 225 ?x))
            (i -1))
        (while (< (incf i) (length x))
            (x (make-string 225 ?x))
            (i -1))
        (while (< (incf i) (length x))
@@ -1819,9 +1945,8 @@ characters to translate to."
 MAP is an alist where the elements are on the form (\"from\" \"to\")."
   (save-excursion
     (when (article-goto-body)
 MAP is an alist where the elements are on the form (\"from\" \"to\")."
   (save-excursion
     (when (article-goto-body)
-      (let ((buffer-read-only nil)
-           elem)
-       (while (setq elem (pop map))
+      (let ((inhibit-read-only t))
+       (dolist (elem map)
          (save-excursion
            (while (search-forward (car elem) nil t)
              (replace-match (cadr elem)))))))))
          (save-excursion
            (while (search-forward (car elem) nil t)
              (replace-match (cadr elem)))))))))
@@ -1831,7 +1956,7 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
   (interactive)
   (save-excursion
     (when (article-goto-body)
   (interactive)
   (save-excursion
     (when (article-goto-body)
-      (let ((buffer-read-only nil))
+      (let ((inhibit-read-only t))
        (while (search-forward "\b" nil t)
          (let ((next (char-after))
                (previous (char-after (- (point) 2))))
        (while (search-forward "\b" nil t)
          (let ((next (char-after))
                (previous (char-after (- (point) 2))))
@@ -1852,6 +1977,14 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
              (put-text-property
               (point) (1+ (point)) 'face 'underline)))))))))
 
              (put-text-property
               (point) (1+ (point)) 'face 'underline)))))))))
 
+(defun article-treat-ansi-sequences ()
+  "Translate ANSI SGR control sequences into overlays or extents."
+  (interactive)
+  (save-excursion
+    (when (article-goto-body)
+      (let ((inhibit-read-only t))
+       (ansi-color-apply-on-region (point) (point-max))))))
+
 (defun gnus-article-treat-unfold-headers ()
   "Unfold folded message headers.
 Only the headers that fit into the current window width will be
 (defun gnus-article-treat-unfold-headers ()
   "Unfold folded message headers.
 Only the headers that fit into the current window width will be
@@ -1939,7 +2072,7 @@ unfolded."
   "Fill lines that are wider than the window width."
   (interactive)
   (save-excursion
   "Fill lines that are wider than the window width."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil)
+    (let ((inhibit-read-only t)
          (width (window-width (get-buffer-window (current-buffer)))))
       (save-restriction
        (article-goto-body)
          (width (window-width (get-buffer-window (current-buffer)))))
       (save-restriction
        (article-goto-body)
@@ -1948,7 +2081,7 @@ unfolded."
            (end-of-line)
            (when (>= (current-column) (min fill-column width))
              (narrow-to-region (min (1+ (point)) (point-max))
            (end-of-line)
            (when (>= (current-column) (min fill-column width))
              (narrow-to-region (min (1+ (point)) (point-max))
-                               (gnus-point-at-bol))
+                               (point-at-bol))
               (let ((goback (point-marker)))
                 (fill-paragraph nil)
                 (goto-char (marker-position goback)))
               (let ((goback (point-marker)))
                 (fill-paragraph nil)
                 (goto-char (marker-position goback)))
@@ -1959,7 +2092,7 @@ unfolded."
   "Capitalize the first word in each sentence."
   (interactive)
   (save-excursion
   "Capitalize the first word in each sentence."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil)
+    (let ((inhibit-read-only t)
          (paragraph-start "^[\n\^L]"))
       (article-goto-body)
       (while (not (eobp))
          (paragraph-start "^[\n\^L]"))
       (article-goto-body)
       (while (not (eobp))
@@ -1970,7 +2103,7 @@ unfolded."
   "Remove trailing CRs and then translate remaining CRs into LFs."
   (interactive)
   (save-excursion
   "Remove trailing CRs and then translate remaining CRs into LFs."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil))
+    (let ((inhibit-read-only t))
       (goto-char (point-min))
       (while (re-search-forward "\r+$" nil t)
        (replace-match "" t t))
       (goto-char (point-min))
       (while (re-search-forward "\r+$" nil t)
        (replace-match "" t t))
@@ -1982,7 +2115,7 @@ unfolded."
   "Remove all trailing blank lines from the article."
   (interactive)
   (save-excursion
   "Remove all trailing blank lines from the article."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil))
+    (let ((inhibit-read-only t))
       (goto-char (point-max))
       (delete-region
        (point)
       (goto-char (point-max))
       (delete-region
        (point)
@@ -1990,11 +2123,14 @@ unfolded."
         (while (and (not (bobp))
                     (looking-at "^[ \t]*$")
                     (not (gnus-annotation-in-region-p
         (while (and (not (bobp))
                     (looking-at "^[ \t]*$")
                     (not (gnus-annotation-in-region-p
-                          (point) (gnus-point-at-eol))))
+                          (point) (point-at-eol))))
           (forward-line -1))
         (forward-line 1)
         (point))))))
 
           (forward-line -1))
         (forward-line 1)
         (point))))))
 
+(eval-when-compile
+  (defvar gnus-face-properties-alist))
+
 (defun article-display-face ()
   "Display any Face headers in the header."
   (interactive)
 (defun article-display-face ()
   "Display any Face headers in the header."
   (interactive)
@@ -2018,12 +2154,14 @@ unfolded."
            (save-restriction
              (mail-narrow-to-head)
              (while (gnus-article-goto-header "Face")
            (save-restriction
              (mail-narrow-to-head)
              (while (gnus-article-goto-header "Face")
-               (push (mail-header-field-value) faces))))
-         (while (setq face (pop faces))
+               (setq faces (nconc faces (list (mail-header-field-value)))))))
+         (dolist (face faces)
            (let ((png (gnus-convert-face-to-png face))
                  image)
              (when png
            (let ((png (gnus-convert-face-to-png face))
                  image)
              (when png
-               (setq image (gnus-create-image png 'png t))
+               (setq image
+                     (apply 'gnus-create-image png 'png t
+                            (cdr (assq 'png gnus-face-properties-alist))))
                (gnus-article-goto-header "from")
                (when (bobp)
                  (insert "From: [no `from' set]\n")
                (gnus-article-goto-header "from")
                (when (bobp)
                  (insert "From: [no `from' set]\n")
@@ -2100,14 +2238,12 @@ unfolded."
 (defun article-decode-mime-words ()
   "Decode all MIME-encoded words in the article."
   (interactive)
 (defun article-decode-mime-words ()
   "Decode all MIME-encoded words in the article."
   (interactive)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
+  (gnus-with-article-buffer
     (let ((inhibit-point-motion-hooks t)
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only
          (mail-parse-charset gnus-newsgroup-charset)
          (mail-parse-ignored-charsets
          (mail-parse-charset gnus-newsgroup-charset)
          (mail-parse-ignored-charsets
-          (save-excursion (set-buffer gnus-summary-buffer)
-                          gnus-newsgroup-ignored-charsets)))
+          (with-current-buffer gnus-summary-buffer
+            gnus-newsgroup-ignored-charsets)))
       (mail-decode-encoded-word-region (point-min) (point-max)))))
 
 (defun article-decode-charset (&optional prompt)
       (mail-decode-encoded-word-region (point-min) (point-max)))))
 
 (defun article-decode-charset (&optional prompt)
@@ -2115,7 +2251,7 @@ unfolded."
 If PROMPT (the prefix), prompt for a coding system to use."
   (interactive "P")
   (let ((inhibit-point-motion-hooks t) (case-fold-search t)
 If PROMPT (the prefix), prompt for a coding system to use."
   (interactive "P")
   (let ((inhibit-point-motion-hooks t) (case-fold-search t)
-       buffer-read-only
+       (inhibit-read-only t)
        (mail-parse-charset gnus-newsgroup-charset)
        (mail-parse-ignored-charsets
         (save-excursion (condition-case nil
        (mail-parse-charset gnus-newsgroup-charset)
        (mail-parse-ignored-charsets
         (save-excursion (condition-case nil
@@ -2165,7 +2301,7 @@ If PROMPT (the prefix), prompt for a coding system to use."
                             (set-buffer gnus-summary-buffer)
                           (error))
                         gnus-newsgroup-ignored-charsets))
                             (set-buffer gnus-summary-buffer)
                           (error))
                         gnus-newsgroup-ignored-charsets))
-       buffer-read-only)
+       (inhibit-read-only t))
     (save-restriction
       (article-narrow-to-head)
       (funcall gnus-decode-header-function (point-min) (point-max)))))
     (save-restriction
       (article-narrow-to-head)
       (funcall gnus-decode-header-function (point-min) (point-max)))))
@@ -2173,7 +2309,7 @@ If PROMPT (the prefix), prompt for a coding system to use."
 (defun article-decode-group-name ()
   "Decode group names in `Newsgroups:'."
   (let ((inhibit-point-motion-hooks t)
 (defun article-decode-group-name ()
   "Decode group names in `Newsgroups:'."
   (let ((inhibit-point-motion-hooks t)
-       buffer-read-only
+       (inhibit-read-only t)
        (method (gnus-find-method-for-group gnus-newsgroup-name)))
     (when (and (or gnus-group-name-charset-method-alist
                   gnus-group-name-charset-group-alist)
        (method (gnus-find-method-for-group gnus-newsgroup-name)))
     (when (and (or gnus-group-name-charset-method-alist
                   gnus-group-name-charset-group-alist)
@@ -2217,18 +2353,16 @@ If PROMPT (the prefix), prompt for a coding system to use."
   (when gnus-use-idna
     (save-restriction
       (let ((inhibit-point-motion-hooks t)
   (when gnus-use-idna
     (save-restriction
       (let ((inhibit-point-motion-hooks t)
-           buffer-read-only)
+           (inhibit-read-only t))
        (article-narrow-to-head)
        (goto-char (point-min))
        (article-narrow-to-head)
        (goto-char (point-min))
-       (while (re-search-forward "\\(xn--[-A-Za-z0-9.]*\\)[ \t\n\r,>]" nil t)
+       (while (re-search-forward "@.*\\(xn--[-A-Za-z0-9.]*\\)[ \t\n\r,>]" nil t)
          (let (ace unicode)
            (when (save-match-data
                    (and (setq ace (match-string 1))
                         (save-excursion
                           (and (re-search-backward "^[^ \t]" nil t)
                                (looking-at "From\\|To\\|Cc")))
          (let (ace unicode)
            (when (save-match-data
                    (and (setq ace (match-string 1))
                         (save-excursion
                           (and (re-search-backward "^[^ \t]" nil t)
                                (looking-at "From\\|To\\|Cc")))
-                        (save-excursion (backward-char)
-                                        (message-idna-inside-rhs-p))
                         (setq unicode (idna-to-unicode ace))))
              (unless (string= ace unicode)
                (replace-match unicode nil nil nil 1)))))))))
                         (setq unicode (idna-to-unicode ace))))
              (unless (string= ace unicode)
                (replace-match unicode nil nil nil 1)))))))))
@@ -2240,7 +2374,7 @@ or not.
 If READ-CHARSET, ask for a coding system."
   (interactive (list 'force current-prefix-arg))
   (save-excursion
 If READ-CHARSET, ask for a coding system."
   (interactive (list 'force current-prefix-arg))
   (save-excursion
-    (let ((buffer-read-only nil) type charset)
+    (let ((inhibit-read-only t) type charset)
       (if (gnus-buffer-live-p gnus-original-article-buffer)
          (with-current-buffer gnus-original-article-buffer
            (setq type
       (if (gnus-buffer-live-p gnus-original-article-buffer)
          (with-current-buffer gnus-original-article-buffer
            (setq type
@@ -2270,7 +2404,7 @@ If FORCE, decode the article whether it is marked as base64 not.
 If READ-CHARSET, ask for a coding system."
   (interactive (list 'force current-prefix-arg))
   (save-excursion
 If READ-CHARSET, ask for a coding system."
   (interactive (list 'force current-prefix-arg))
   (save-excursion
-    (let ((buffer-read-only nil) type charset)
+    (let ((inhibit-read-only t) type charset)
       (if (gnus-buffer-live-p gnus-original-article-buffer)
          (with-current-buffer gnus-original-article-buffer
            (setq type
       (if (gnus-buffer-live-p gnus-original-article-buffer)
          (with-current-buffer gnus-original-article-buffer
            (setq type
@@ -2305,17 +2439,17 @@ If READ-CHARSET, ask for a coding system."
   (interactive)
   (require 'rfc1843)
   (save-excursion
   (interactive)
   (require 'rfc1843)
   (save-excursion
-    (let ((buffer-read-only nil))
+    (let ((inhibit-read-only t))
       (rfc1843-decode-region (point-min) (point-max)))))
 
 (defun article-unsplit-urls ()
   "Remove the newlines that some other mailers insert into URLs."
   (interactive)
   (save-excursion
       (rfc1843-decode-region (point-min) (point-max)))))
 
 (defun article-unsplit-urls ()
   "Remove the newlines that some other mailers insert into URLs."
   (interactive)
   (save-excursion
-    (let ((buffer-read-only nil))
+    (let ((inhibit-read-only t))
       (goto-char (point-min))
       (while (re-search-forward
       (goto-char (point-min))
       (while (re-search-forward
-             "^\\(\\(https?\\|ftp\\)://\\S-+\\) *\n\\(\\S-+\\)" nil t)
+             "\\(\\(https?\\|ftp\\)://\\S-+\\) *\n\\(\\S-+\\)" nil t)
        (replace-match "\\1\\3" t)))
     (when (interactive-p)
       (gnus-treat-article nil))))
        (replace-match "\\1\\3" t)))
     (when (interactive-p)
       (gnus-treat-article nil))))
@@ -2326,7 +2460,7 @@ If READ-CHARSET, ask for a coding system."
 If READ-CHARSET, ask for a coding system."
   (interactive "P")
   (save-excursion
 If READ-CHARSET, ask for a coding system."
   (interactive "P")
   (save-excursion
-    (let ((buffer-read-only nil)
+    (let ((inhibit-read-only t)
          charset)
       (when (gnus-buffer-live-p gnus-original-article-buffer)
        (with-current-buffer gnus-original-article-buffer
          charset)
       (when (gnus-buffer-live-p gnus-original-article-buffer)
        (with-current-buffer gnus-original-article-buffer
@@ -2372,16 +2506,17 @@ If READ-CHARSET, ask for a coding system."
   (mm-setup-w3m)
   (save-restriction
     (narrow-to-region (point) (point-max))
   (mm-setup-w3m)
   (save-restriction
     (narrow-to-region (point) (point-max))
-    (let ((w3m-safe-url-regexp (if mm-inline-text-html-with-images
-                                  nil
-                                "\\`cid:"))
+    (let ((w3m-safe-url-regexp mm-w3m-safe-url-regexp)
          w3m-force-redisplay)
       (w3m-region (point-min) (point-max)))
          w3m-force-redisplay)
       (w3m-region (point-min) (point-max)))
-    (when mm-inline-text-html-with-w3m-keymap
+    (when (and mm-inline-text-html-with-w3m-keymap
+              (boundp 'w3m-minor-mode-map)
+              w3m-minor-mode-map)
       (add-text-properties
        (point-min) (point-max)
       (add-text-properties
        (point-min) (point-max)
-       (nconc (mm-w3m-local-map-property)
-             '(mm-inline-text-html-with-w3m t))))))
+       (list 'keymap w3m-minor-mode-map
+            ;; Put the mark meaning this part was rendered by emacs-w3m.
+            'mm-inline-text-html-with-w3m t)))))
 
 (defun article-hide-list-identifiers ()
   "Remove list identifies from the Subject header.
 
 (defun article-hide-list-identifiers ()
   "Remove list identifies from the Subject header.
@@ -2391,7 +2526,7 @@ The `gnus-list-identifiers' variable specifies what to do."
        (regexp (if (consp gnus-list-identifiers)
                    (mapconcat 'identity gnus-list-identifiers " *\\|")
                  gnus-list-identifiers))
        (regexp (if (consp gnus-list-identifiers)
                    (mapconcat 'identity gnus-list-identifiers " *\\|")
                  gnus-list-identifiers))
-       buffer-read-only)
+       (inhibit-read-only t))
     (when regexp
       (save-excursion
        (save-restriction
     (when regexp
       (save-excursion
        (save-restriction
@@ -2413,7 +2548,7 @@ always hide."
   (interactive (gnus-article-hidden-arg))
   (unless (gnus-article-check-hidden-text 'pem arg)
     (save-excursion
   (interactive (gnus-article-hidden-arg))
   (unless (gnus-article-check-hidden-text 'pem arg)
     (save-excursion
-      (let (buffer-read-only end)
+      (let ((inhibit-read-only t) end)
        (goto-char (point-min))
        ;; Hide the horrendously ugly "header".
        (when (and (search-forward
        (goto-char (point-min))
        ;; Hide the horrendously ugly "header".
        (when (and (search-forward
@@ -2444,18 +2579,25 @@ always hide."
          (article-really-strip-banner
           (gnus-parameter-banner gnus-newsgroup-name)))
        (when gnus-article-address-banner-alist
          (article-really-strip-banner
           (gnus-parameter-banner gnus-newsgroup-name)))
        (when gnus-article-address-banner-alist
-         (article-really-strip-banner
-          (let ((from (save-restriction
-                        (widen)
-                        (article-narrow-to-head)
-                        (mail-fetch-field "from"))))
-            (when (and from
-                       (setq from
-                             (caar (mail-header-parse-addresses from))))
-              (catch 'found
-                (dolist (pair gnus-article-address-banner-alist)
-                  (when (string-match (car pair) from)
-                    (throw 'found (cdr pair)))))))))))))
+         ;; It is necessary to encode from fields before checking,
+         ;; because `mail-header-parse-addresses' does not work
+         ;; (reliably) on decoded headers.  And more, it is
+         ;; impossible to use `gnus-fetch-original-field' here,
+         ;; because `article-strip-banner' may be called in draft
+         ;; buffers to preview them.
+         (let ((from (save-restriction
+                       (widen)
+                       (article-narrow-to-head)
+                       (mail-fetch-field "from"))))
+           (when (and from
+                      (setq from
+                            (caar (mail-header-parse-addresses
+                                   (mail-encode-encoded-word-string from)))))
+             (catch 'found
+               (dolist (pair gnus-article-address-banner-alist)
+                 (when (string-match (car pair) from)
+                   (throw 'found
+                          (article-really-strip-banner (cdr pair)))))))))))))
 
 (defun article-really-strip-banner (banner)
   "Strip the banner specified by the argument."
 
 (defun article-really-strip-banner (banner)
   "Strip the banner specified by the argument."
@@ -2463,7 +2605,7 @@ always hide."
     (save-restriction
       (let ((inhibit-point-motion-hooks t)
            (gnus-signature-limit nil)
     (save-restriction
       (let ((inhibit-point-motion-hooks t)
            (gnus-signature-limit nil)
-           buffer-read-only)
+           (inhibit-read-only t))
        (article-goto-body)
        (cond
         ((eq banner 'signature)
        (article-goto-body)
        (cond
         ((eq banner 'signature)
@@ -2483,11 +2625,9 @@ always hide."
   "Translate article using an online translation service."
   (interactive)
   (require 'babel)
   "Translate article using an online translation service."
   (interactive)
   (require 'babel)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
+  (gnus-with-article-buffer
     (when (article-goto-body)
     (when (article-goto-body)
-      (let* ((buffer-read-only nil)
-            (start (point))
+      (let* ((start (point))
             (end (point-max))
             (orig (buffer-substring start end))
             (trans (babel-as-string orig)))
             (end (point-max))
             (orig (buffer-substring start end))
             (trans (babel-as-string orig)))
@@ -2504,7 +2644,7 @@ always hide."
   (unless (gnus-article-check-hidden-text 'signature arg)
     (save-excursion
       (save-restriction
   (unless (gnus-article-check-hidden-text 'signature arg)
     (save-excursion
       (save-restriction
-       (let ((buffer-read-only nil))
+       (let ((inhibit-read-only t))
          (when (gnus-article-narrow-to-signature)
            (gnus-article-hide-text-type
             (point-min) (point-max) 'signature))))))
          (when (gnus-article-narrow-to-signature)
            (gnus-article-hide-text-type
             (point-min) (point-max) 'signature))))))
@@ -2524,7 +2664,7 @@ always hide."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only)
+         (inhibit-read-only t))
       (when (article-goto-body)
        (while (and (not (eobp))
                    (looking-at "[ \t]*$"))
       (when (article-goto-body)
        (while (and (not (eobp))
                    (looking-at "[ \t]*$"))
@@ -2559,7 +2699,7 @@ Point is left at the beginning of the narrowed-to region."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only)
+         (inhibit-read-only t))
       ;; First make all blank lines empty.
       (article-goto-body)
       (while (re-search-forward "^[ \t]+$" nil t)
       ;; First make all blank lines empty.
       (article-goto-body)
       (while (re-search-forward "^[ \t]+$" nil t)
@@ -2578,7 +2718,7 @@ Point is left at the beginning of the narrowed-to region."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only)
+         (inhibit-read-only t))
       (article-goto-body)
       (while (re-search-forward "^[ \t]+" nil t)
        (replace-match "" t t)))))
       (article-goto-body)
       (while (re-search-forward "^[ \t]+" nil t)
        (replace-match "" t t)))))
@@ -2588,7 +2728,7 @@ Point is left at the beginning of the narrowed-to region."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only)
+         (inhibit-read-only t))
       (article-goto-body)
       (while (re-search-forward "[ \t]+$" nil t)
        (replace-match "" t t)))))
       (article-goto-body)
       (while (re-search-forward "[ \t]+$" nil t)
        (replace-match "" t t)))))
@@ -2605,7 +2745,7 @@ Point is left at the beginning of the narrowed-to region."
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
   (interactive)
   (save-excursion
     (let ((inhibit-point-motion-hooks t)
-         buffer-read-only)
+         (inhibit-read-only t))
       (article-goto-body)
       (while (re-search-forward "^[ \t]*\n" nil t)
        (replace-match "" t t)))))
       (article-goto-body)
       (while (re-search-forward "^[ \t]*\n" nil t)
        (replace-match "" t t)))))
@@ -2694,7 +2834,7 @@ means show, 0 means toggle."
 (defun gnus-article-show-hidden-text (type &optional dummy)
   "Show all hidden text of type TYPE.
 Originally it is hide instead of DUMMY."
 (defun gnus-article-show-hidden-text (type &optional dummy)
   "Show all hidden text of type TYPE.
 Originally it is hide instead of DUMMY."
-  (let ((buffer-read-only nil)
+  (let ((inhibit-read-only t)
        (inhibit-point-motion-hooks t))
     (gnus-remove-text-properties-when
      'article-type type
        (inhibit-point-motion-hooks t))
     (gnus-remove-text-properties-when
      'article-type type
@@ -2751,31 +2891,30 @@ should replace the \"Date:\" one, or should be added below it."
       (save-restriction
        (article-narrow-to-head)
        (when (re-search-forward tdate-regexp nil t)
       (save-restriction
        (article-narrow-to-head)
        (when (re-search-forward tdate-regexp nil t)
-         (setq bface (get-text-property (gnus-point-at-bol) 'face)
-               date (or (get-text-property (gnus-point-at-bol)
+         (setq bface (get-text-property (point-at-bol) 'face)
+               date (or (get-text-property (point-at-bol)
                                            'original-date)
                         date)
                                            'original-date)
                         date)
-               eface (get-text-property (1- (gnus-point-at-eol)) 'face))
+               eface (get-text-property (1- (point-at-eol)) 'face))
          (forward-line 1))
        (when (and date (not (string= date "")))
          (goto-char (point-min))
          (forward-line 1))
        (when (and date (not (string= date "")))
          (goto-char (point-min))
-         (let ((buffer-read-only nil))
+         (let ((inhibit-read-only t))
            ;; Delete any old Date headers.
            (while (re-search-forward date-regexp nil t)
              (if pos
            ;; Delete any old Date headers.
            (while (re-search-forward date-regexp nil t)
              (if pos
-                 (delete-region (progn (beginning-of-line) (point))
+                 (delete-region (point-at-bol)
                                 (progn (gnus-article-forward-header)
                                        (point)))
                                 (progn (gnus-article-forward-header)
                                        (point)))
-               (delete-region (progn (beginning-of-line) (point))
-                                (progn (gnus-article-forward-header)
-                                       (forward-char -1)
-                                       (point)))
+               (delete-region (point-at-bol)
+                              (progn (gnus-article-forward-header)
+                                     (forward-char -1)
+                                     (point)))
                (setq pos (point))))
            (when (and (not pos)
                       (re-search-forward tdate-regexp nil t))
              (forward-line 1))
                (setq pos (point))))
            (when (and (not pos)
                       (re-search-forward tdate-regexp nil t))
              (forward-line 1))
-           (when pos
-             (goto-char pos))
+           (gnus-goto-char pos)
            (insert (article-make-date-line date (or type 'ut)))
            (unless pos
              (insert "\n")
            (insert (article-make-date-line date (or type 'ut)))
            (unless pos
              (insert "\n")
@@ -2783,10 +2922,8 @@ should replace the \"Date:\" one, or should be added below it."
            ;; Do highlighting.
            (beginning-of-line)
            (when (looking-at "\\([^:]+\\): *\\(.*\\)$")
            ;; Do highlighting.
            (beginning-of-line)
            (when (looking-at "\\([^:]+\\): *\\(.*\\)$")
-             (put-text-property (match-beginning 1) (1+ (match-end 1))
-                                'original-date date)
-             (put-text-property (match-beginning 1) (1+ (match-end 1))
-                                'face bface)
+             (add-text-properties (match-beginning 1) (1+ (match-end 1))
+                                  (list 'original-date date 'face bface))
              (put-text-property (match-beginning 2) (match-end 2)
                                 'face eface))))))))
 
              (put-text-property (match-beginning 2) (match-end 2)
                                 'face eface))))))))
 
@@ -2799,22 +2936,21 @@ should replace the \"Date:\" one, or should be added below it."
        (cond
         ;; Convert to the local timezone.
         ((eq type 'local)
        (cond
         ;; Convert to the local timezone.
         ((eq type 'local)
-         (let ((tz (car (current-time-zone time))))
-           (format "Date: %s %s%02d%02d" (current-time-string time)
-                   (if (> tz 0) "+" "-") (/ (abs tz) 3600)
-                   (/ (% (abs tz) 3600) 60))))
+         (concat "Date: " (message-make-date time)))
         ;; Convert to Universal Time.
         ((eq type 'ut)
          (concat "Date: "
         ;; Convert to Universal Time.
         ((eq type 'ut)
          (concat "Date: "
-                 (current-time-string
-                  (let* ((e (parse-time-string date))
-                         (tm (apply 'encode-time e))
-                         (ms (car tm))
-                         (ls (- (cadr tm) (car (current-time-zone time)))))
-                    (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
-                          ((> ls 65535) (list (1+ ms) (- ls 65536)))
-                          (t (list ms ls)))))
-                 " UT"))
+                 (substring
+                  (message-make-date
+                   (let* ((e (parse-time-string date))
+                          (tm (apply 'encode-time e))
+                          (ms (car tm))
+                          (ls (- (cadr tm) (car (current-time-zone time)))))
+                     (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
+                           ((> ls 65535) (list (1+ ms) (- ls 65536)))
+                           (t (list ms ls)))))
+                  0 -5)
+                 "UT"))
         ;; Get the original date from the article.
         ((eq type 'original)
          (concat "Date: " (if (string-match "\n+$" date)
         ;; Get the original date from the article.
         ((eq type 'original)
          (concat "Date: " (if (string-match "\n+$" date)
@@ -2937,9 +3073,12 @@ function and want to see what the date was before converting."
         (lambda (w)
           (set-buffer (window-buffer w))
           (when (eq major-mode 'gnus-article-mode)
         (lambda (w)
           (set-buffer (window-buffer w))
           (when (eq major-mode 'gnus-article-mode)
-            (goto-char (point-min))
-            (when (re-search-forward "^X-Sent:" nil t)
-              (article-date-lapsed t))))
+            (let ((mark (point-marker)))
+              (goto-char (point-min))
+              (when (re-search-forward "^X-Sent:" nil t)
+                (article-date-lapsed t))
+              (goto-char (marker-position mark))
+              (move-marker mark nil))))
         nil 'visible)))))
 
 (defun gnus-start-date-timer (&optional n)
         nil 'visible)))))
 
 (defun gnus-start-date-timer (&optional n)
@@ -2951,7 +3090,7 @@ is to run."
     (setq n 1))
   (gnus-stop-date-timer)
   (setq article-lapsed-timer
     (setq n 1))
   (gnus-stop-date-timer)
   (setq article-lapsed-timer
-       (nnheader-run-at-time 1 n 'article-update-date-lapsed)))
+       (run-at-time 1 n 'article-update-date-lapsed)))
 
 (defun gnus-stop-date-timer ()
   "Stop the X-Sent timer."
 
 (defun gnus-stop-date-timer ()
   "Stop the X-Sent timer."
@@ -2975,7 +3114,7 @@ This format is defined by the `gnus-article-time-format' variable."
 ;;   "Show all hidden text in the article buffer."
 ;;   (interactive)
 ;;   (save-excursion
 ;;   "Show all hidden text in the article buffer."
 ;;   (interactive)
 ;;   (save-excursion
-;;     (let ((buffer-read-only nil))
+;;     (let ((inhibit-read-only t))
 ;;       (gnus-article-unhide-text (point-min) (point-max)))))
 
 (defun article-remove-leading-whitespace ()
 ;;       (gnus-article-unhide-text (point-min) (point-max)))))
 
 (defun article-remove-leading-whitespace ()
@@ -2983,7 +3122,7 @@ This format is defined by the `gnus-article-time-format' variable."
   (interactive)
   (save-excursion
     (save-restriction
   (interactive)
   (save-excursion
     (save-restriction
-      (let ((buffer-read-only nil))
+      (let ((inhibit-read-only t))
        (article-narrow-to-head)
        (goto-char (point-min))
        (while (re-search-forward "^[^ :]+: \\([ \t]+\\)" nil t)
        (article-narrow-to-head)
        (goto-char (point-min))
        (while (re-search-forward "^[^ :]+: \\([ \t]+\\)" nil t)
@@ -3000,7 +3139,7 @@ This format is defined by the `gnus-article-time-format' variable."
                          gnus-article-emphasis-alist)
                      (error))
                    gnus-emphasis-alist))
                          gnus-article-emphasis-alist)
                      (error))
                    gnus-emphasis-alist))
-           (buffer-read-only nil)
+           (inhibit-read-only t)
            (props (append '(article-type emphasis)
                           gnus-hidden-properties))
            regexp elem beg invisible visible face)
            (props (append '(article-type emphasis)
                           gnus-hidden-properties))
            regexp elem beg invisible visible face)
@@ -3272,17 +3411,9 @@ The directory to save in defaults to `gnus-article-save-directory'."
       (shell-command-on-region (point-min) (point-max) command nil)))
   (setq gnus-last-shell-command command))
 
       (shell-command-on-region (point-min) (point-max) command nil)))
   (setq gnus-last-shell-command command))
 
-(defmacro gnus-read-string (prompt &optional initial-contents history
-                           default-value)
-  "Like `read-string' but allow for older XEmacsen that don't have the 5th arg."
-  (if (and (featurep 'xemacs)
-          (< emacs-minor-version 2))
-      `(read-string ,prompt ,initial-contents ,history)
-    `(read-string ,prompt ,initial-contents ,history ,default-value)))
-
 (defun gnus-summary-pipe-to-muttprint (&optional command)
   "Pipe this article to muttprint."
 (defun gnus-summary-pipe-to-muttprint (&optional command)
   "Pipe this article to muttprint."
-  (setq command (gnus-read-string
+  (setq command (read-string
                 "Print using command: " gnus-summary-muttprint-program
                 nil gnus-summary-muttprint-program))
   (gnus-summary-save-in-pipe command))
                 "Print using command: " gnus-summary-muttprint-program
                 nil gnus-summary-muttprint-program))
   (gnus-summary-save-in-pipe command))
@@ -3400,13 +3531,13 @@ If variable `gnus-use-long-file-name' is non-nil, it is
                        (mm-handle-multipart-ctl-parameter
                         mm-security-handle 'gnus-info)))))
          (when info
                        (mm-handle-multipart-ctl-parameter
                         mm-security-handle 'gnus-info)))))
          (when info
-           (let (buffer-read-only bface eface)
+           (let ((inhibit-read-only t) bface eface)
              (save-restriction
                (message-narrow-to-head)
                (goto-char (point-max))
                (forward-line -1)
              (save-restriction
                (message-narrow-to-head)
                (goto-char (point-max))
                (forward-line -1)
-               (setq bface (get-text-property (gnus-point-at-bol) 'face)
-                     eface (get-text-property (1- (gnus-point-at-eol)) 'face))
+               (setq bface (get-text-property (point-at-bol) 'face)
+                     eface (get-text-property (1- (point-at-eol)) 'face))
                (message-remove-header "X-Gnus-PGP-Verify")
                (if (re-search-forward "^X-PGP-Sig:" nil t)
                    (forward-line)
                (message-remove-header "X-Gnus-PGP-Verify")
                (if (re-search-forward "^X-PGP-Sig:" nil t)
                    (forward-line)
@@ -3457,6 +3588,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      article-verify-cancel-lock
      article-hide-boring-headers
      article-treat-overstrike
      article-verify-cancel-lock
      article-hide-boring-headers
      article-treat-overstrike
+     article-treat-ansi-sequences
      article-fill-long-lines
      article-capitalize-sentences
      article-remove-cr
      article-fill-long-lines
      article-capitalize-sentences
      article-remove-cr
@@ -3557,6 +3689,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        ["Hide signature" gnus-article-hide-signature t]
        ["Hide citation" gnus-article-hide-citation t]
        ["Treat overstrike" gnus-article-treat-overstrike t]
        ["Hide signature" gnus-article-hide-signature t]
        ["Hide citation" gnus-article-hide-citation t]
        ["Treat overstrike" gnus-article-treat-overstrike t]
+       ["Treat ANSI sequences" gnus-article-treat-ansi-sequences t]
        ["Remove carriage return" gnus-article-remove-cr t]
        ["Remove leading whitespace" gnus-article-remove-leading-whitespace t]
        ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
        ["Remove carriage return" gnus-article-remove-cr t]
        ["Remove leading whitespace" gnus-article-remove-leading-whitespace t]
        ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
@@ -3598,7 +3731,7 @@ commands:
       (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
   (gnus-update-format-specifications nil 'article-mode)
   (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
       (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map)))
   (gnus-update-format-specifications nil 'article-mode)
   (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
-  (make-local-variable 'gnus-page-broken)
+  (set (make-local-variable 'gnus-page-broken) nil)
   (make-local-variable 'gnus-button-marker-list)
   (make-local-variable 'gnus-article-current-summary)
   (make-local-variable 'gnus-article-mime-handles)
   (make-local-variable 'gnus-button-marker-list)
   (make-local-variable 'gnus-article-current-summary)
   (make-local-variable 'gnus-article-mime-handles)
@@ -3608,9 +3741,12 @@ commands:
   (make-local-variable 'gnus-article-image-alist)
   (make-local-variable 'gnus-article-charset)
   (make-local-variable 'gnus-article-ignored-charsets)
   (make-local-variable 'gnus-article-image-alist)
   (make-local-variable 'gnus-article-charset)
   (make-local-variable 'gnus-article-ignored-charsets)
+  ;; Prevent recent Emacsen from displaying non-break space as "\ ".
+  (set (make-local-variable 'show-nonbreak-escape) nil)
   (gnus-set-default-directory)
   (buffer-disable-undo)
   (gnus-set-default-directory)
   (buffer-disable-undo)
-  (setq buffer-read-only t)
+  (setq buffer-read-only t
+       show-trailing-whitespace nil)
   (set-syntax-table gnus-article-mode-syntax-table)
   (mm-enable-multibyte)
   (gnus-run-hooks 'gnus-article-mode-hook))
   (set-syntax-table gnus-article-mode-syntax-table)
   (mm-enable-multibyte)
   (gnus-run-hooks 'gnus-article-mode-hook))
@@ -3640,14 +3776,19 @@ commands:
       (mm-enable-multibyte)
       (setq major-mode 'gnus-original-article-mode)
       (make-local-variable 'gnus-original-article))
       (mm-enable-multibyte)
       (setq major-mode 'gnus-original-article-mode)
       (make-local-variable 'gnus-original-article))
-    (if (get-buffer name)
+    (if (and (get-buffer name)
+            (with-current-buffer name
+              (if gnus-article-edit-mode
+                  (if (y-or-n-p "Article mode edit in progress; discard? ")
+                      (progn
+                        (set-buffer-modified-p nil)
+                        (gnus-kill-buffer name)
+                        (message "")
+                        nil)
+                    (error "Action aborted"))
+                t)))
        (save-excursion
          (set-buffer name)
        (save-excursion
          (set-buffer name)
-         (when (and gnus-article-edit-mode
-                    (buffer-modified-p)
-                    (not
-                     (y-or-n-p "Article mode edit in progress; discard? ")))
-           (error "Action aborted"))
          (set (make-local-variable 'gnus-article-edit-mode) nil)
          (when gnus-article-mime-handles
            (mm-destroy-parts gnus-article-mime-handles)
          (set (make-local-variable 'gnus-article-edit-mode) nil)
          (when gnus-article-mime-handles
            (mm-destroy-parts gnus-article-mime-handles)
@@ -3705,7 +3846,7 @@ If ALL-HEADERS is non-nil, no headers are hidden."
        (when (and (boundp 'transient-mark-mode)
                   transient-mark-mode)
          (setq mark-active nil))
        (when (and (boundp 'transient-mark-mode)
                   transient-mark-mode)
          (setq mark-active nil))
-       (if (not (setq result (let ((buffer-read-only nil))
+       (if (not (setq result (let ((inhibit-read-only t))
                                (gnus-request-article-this-buffer
                                 article group))))
            ;; There is no such article.
                                (gnus-request-article-this-buffer
                                 article group))))
            ;; There is no such article.
@@ -3782,10 +3923,8 @@ If ALL-HEADERS is non-nil, no headers are hidden."
              (gnus-article-prepare-display)
              ;; Do page break.
              (goto-char (point-min))
              (gnus-article-prepare-display)
              ;; Do page break.
              (goto-char (point-min))
-             (setq gnus-page-broken
-                   (when gnus-break-pages
-                     (gnus-narrow-to-page)
-                     t)))
+             (when gnus-break-pages
+               (gnus-narrow-to-page)))
            (let ((gnus-article-mime-handle-alist-1
                   gnus-article-mime-handle-alist))
              (gnus-set-mode-line 'article))
            (let ((gnus-article-mime-handle-alist-1
                   gnus-article-mime-handle-alist))
              (gnus-set-mode-line 'article))
@@ -3802,7 +3941,8 @@ If ALL-HEADERS is non-nil, no headers are hidden."
   ;; Hooks for getting information from the article.
   ;; This hook must be called before being narrowed.
   (let ((gnus-article-buffer (current-buffer))
   ;; Hooks for getting information from the article.
   ;; This hook must be called before being narrowed.
   (let ((gnus-article-buffer (current-buffer))
-       buffer-read-only)
+       buffer-read-only
+       (inhibit-read-only t))
     (unless (eq major-mode 'gnus-article-mode)
       (gnus-article-mode))
     (setq buffer-read-only nil
     (unless (eq major-mode 'gnus-article-mode)
       (gnus-article-mode))
     (setq buffer-read-only nil
@@ -3866,9 +4006,6 @@ General format specifiers can also be used.  See Info node
 
 (defvar gnus-mime-button-map
   (let ((map (make-sparse-keymap)))
 
 (defvar gnus-mime-button-map
   (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      ;; XEmacs doesn't care.
-      (set-keymap-parent map gnus-article-mode-map))
     (define-key map gnus-mouse-2 'gnus-article-push-button)
     (define-key map gnus-down-mouse-3 'gnus-mime-button-menu)
     (dolist (c gnus-mime-button-commands)
     (define-key map gnus-mouse-2 'gnus-article-push-button)
     (define-key map gnus-down-mouse-3 'gnus-mime-button-menu)
     (dolist (c gnus-mime-button-commands)
@@ -3882,22 +4019,6 @@ General format specifiers can also be used.  See Info node
                (vector (caddr c) (car c) :enable t))
              gnus-mime-button-commands)))
 
                (vector (caddr c) (car c) :enable t))
              gnus-mime-button-commands)))
 
-(eval-when-compile
-  (define-compiler-macro popup-menu (&whole form
-                                           menu &optional position prefix)
-    (if (and (fboundp 'popup-menu)
-            (not (memq 'popup-menu (assoc "lmenu" load-history))))
-       form
-      ;; Gnus is probably running under Emacs 20.
-      `(let* ((menu (cdr ,menu))
-             (response (x-popup-menu
-                        t (list (car menu)
-                                (cons "" (mapcar (lambda (c)
-                                                   (cons (caddr c) (car c)))
-                                                 (cdr menu)))))))
-        (if response
-            (call-interactively (nth 3 (assq response menu))))))))
-
 (defun gnus-mime-button-menu (event prefix)
  "Construct a context-sensitive menu of MIME commands."
  (interactive "e\nP")
 (defun gnus-mime-button-menu (event prefix)
  "Construct a context-sensitive menu of MIME commands."
  (interactive "e\nP")
@@ -3911,8 +4032,7 @@ General format specifiers can also be used.  See Info node
 (defun gnus-mime-view-all-parts (&optional handles)
   "View all the MIME parts."
   (interactive)
 (defun gnus-mime-view-all-parts (&optional handles)
   "View all the MIME parts."
   (interactive)
-  (save-current-buffer
-    (set-buffer gnus-article-buffer)
+  (with-current-buffer gnus-article-buffer
     (let ((handles (or handles gnus-article-mime-handles))
          (mail-parse-charset gnus-newsgroup-charset)
          (mail-parse-ignored-charsets
     (let ((handles (or handles gnus-article-mime-handles))
          (mail-parse-charset gnus-newsgroup-charset)
          (mail-parse-ignored-charsets
@@ -3922,80 +4042,99 @@ General format specifiers can also be used.  See Info node
        (mm-remove-parts handles)
        (goto-char (point-min))
        (or (search-forward "\n\n") (goto-char (point-max)))
        (mm-remove-parts handles)
        (goto-char (point-min))
        (or (search-forward "\n\n") (goto-char (point-max)))
-       (let (buffer-read-only)
+       (let ((inhibit-read-only t))
          (delete-region (point) (point-max))
          (mm-display-parts handles))))))
 
          (delete-region (point) (point-max))
          (mm-display-parts handles))))))
 
+(eval-when-compile
+  (defsubst gnus-article-edit-part (handles)
+    "Edit an article in order to delete a mime part.
+This function is exclusively used by `gnus-mime-save-part-and-strip'
+and `gnus-mime-delete-part', and not provided at run-time normally."
+    (gnus-article-edit-article
+     `(lambda ()
+       (erase-buffer)
+       (let ((mail-parse-charset (or gnus-article-charset
+                                     ',gnus-newsgroup-charset))
+             (mail-parse-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  ',gnus-newsgroup-ignored-charsets))
+             (mbl mml-buffer-list))
+         (setq mml-buffer-list nil)
+         (insert-buffer gnus-original-article-buffer)
+         (mime-to-mml ',handles)
+         (setq gnus-article-mime-handles nil)
+         (let ((mbl1 mml-buffer-list))
+           (setq mml-buffer-list mbl)
+           (set (make-local-variable 'mml-buffer-list) mbl1))
+         (gnus-make-local-hook 'kill-buffer-hook)
+         (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
+     `(lambda (no-highlight)
+       (let ((mail-parse-charset (or gnus-article-charset
+                                     ',gnus-newsgroup-charset))
+             (message-options message-options)
+             (message-options-set-recipient)
+             (mail-parse-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  ',gnus-newsgroup-ignored-charsets)))
+         (mml-to-mime)
+         (mml-destroy-buffers)
+         (remove-hook 'kill-buffer-hook
+                      'mml-destroy-buffers t)
+         (kill-local-variable 'mml-buffer-list))
+       (gnus-summary-edit-article-done
+        ,(or (mail-header-references gnus-current-headers) "")
+        ,(gnus-group-read-only-p)
+        ,gnus-summary-buffer no-highlight)))
+    (gnus-article-edit-done)
+    (gnus-summary-expand-window)
+    (gnus-summary-show-article)))
+
 (defun gnus-mime-save-part-and-strip ()
   "Save the MIME part under point then replace it with an external body."
   (interactive)
   (gnus-article-check-buffer)
 (defun gnus-mime-save-part-and-strip ()
   "Save the MIME part under point then replace it with an external body."
   (interactive)
   (gnus-article-check-buffer)
-  (let* ((data (get-text-property (point) 'gnus-data))
-        file param
-        (handles gnus-article-mime-handles))
-    (if (mm-multiple-handles gnus-article-mime-handles)
-       (error "This function is not implemented"))
-    (setq file (and data (mm-save-part data)))
-    (when file
-      (with-current-buffer (mm-handle-buffer data)
-       (erase-buffer)
-       (insert "Content-Type: " (mm-handle-media-type data))
-       (mml-insert-parameter-string (cdr (mm-handle-type data))
-                                    '(charset))
-       (insert "\n")
-       (insert "Content-ID: " (message-make-message-id) "\n")
-       (insert "Content-Transfer-Encoding: binary\n")
-       (insert "\n"))
-      (setcdr data
-             (cdr (mm-make-handle nil
-                                  `("message/external-body"
-                                    (access-type . "LOCAL-FILE")
-                                    (name . ,file)))))
-      (set-buffer gnus-summary-buffer)
-      (gnus-article-edit-article
-       `(lambda ()
-          (erase-buffer)
-          (let ((mail-parse-charset (or gnus-article-charset
-                                        ',gnus-newsgroup-charset))
-                (mail-parse-ignored-charsets
-                 (or gnus-article-ignored-charsets
-                     ',gnus-newsgroup-ignored-charsets))
-                (mbl mml-buffer-list))
-            (setq mml-buffer-list nil)
-            (insert-buffer gnus-original-article-buffer)
-            (mime-to-mml ',handles)
-            (setq gnus-article-mime-handles nil)
-            (let ((mbl1 mml-buffer-list))
-              (setq mml-buffer-list mbl)
-              (set (make-local-variable 'mml-buffer-list) mbl1))
-            (gnus-make-local-hook 'kill-buffer-hook)
-            (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
-       `(lambda (no-highlight)
-         (let ((mail-parse-charset (or gnus-article-charset
-                                       ',gnus-newsgroup-charset))
-               (message-options message-options)
-               (message-options-set-recipient)
-               (mail-parse-ignored-charsets
-                (or gnus-article-ignored-charsets
-                    ',gnus-newsgroup-ignored-charsets)))
-          (mml-to-mime)
-          (mml-destroy-buffers)
-          (remove-hook 'kill-buffer-hook
-                       'mml-destroy-buffers t)
-          (kill-local-variable 'mml-buffer-list))
-         (gnus-summary-edit-article-done
-          ,(or (mail-header-references gnus-current-headers) "")
-          ,(gnus-group-read-only-p)
-          ,gnus-summary-buffer no-highlight))))))
+  (when (gnus-group-read-only-p)
+    (error "The current group does not support deleting of parts"))
+  (when (mm-complicated-handles gnus-article-mime-handles)
+    (error "\
+The current article has a complicated MIME structure, giving up..."))
+  (when (gnus-yes-or-no-p "\
+Deleting parts may malfunction or destroy the article; continue? ")
+    (let* ((data (get-text-property (point) 'gnus-data))
+          file param
+          (handles gnus-article-mime-handles))
+      (setq file (and data (mm-save-part data)))
+      (when file
+       (with-current-buffer (mm-handle-buffer data)
+         (erase-buffer)
+         (insert "Content-Type: " (mm-handle-media-type data))
+         (mml-insert-parameter-string (cdr (mm-handle-type data))
+                                      '(charset))
+         (insert "\n")
+         (insert "Content-ID: " (message-make-message-id) "\n")
+         (insert "Content-Transfer-Encoding: binary\n")
+         (insert "\n"))
+       (setcdr data
+               (cdr (mm-make-handle nil
+                                    `("message/external-body"
+                                      (access-type . "LOCAL-FILE")
+                                      (name . ,file)))))
+       (set-buffer gnus-summary-buffer)
+       (gnus-article-edit-part handles)))))
 
 (defun gnus-mime-delete-part ()
   "Delete the MIME part under point.
 Replace it with some information about the removed part."
   (interactive)
   (gnus-article-check-buffer)
 
 (defun gnus-mime-delete-part ()
   "Delete the MIME part under point.
 Replace it with some information about the removed part."
   (interactive)
   (gnus-article-check-buffer)
-  (unless (and gnus-novice-user
-              (not (gnus-yes-or-no-p
-                    "Really delete attachment forever? ")))
+  (when (gnus-group-read-only-p)
+    (error "The current group does not support deleting of parts"))
+  (when (mm-complicated-handles gnus-article-mime-handles)
+    (error "\
+The current article has a complicated MIME structure, giving up..."))
+  (when (gnus-yes-or-no-p "\
+Deleting parts may malfunction or destroy the article; continue? ")
     (let* ((data (get-text-property (point) 'gnus-data))
           (handles gnus-article-mime-handles)
           (none "(none)")
     (let* ((data (get-text-property (point) 'gnus-data))
           (handles gnus-article-mime-handles)
           (none "(none)")
@@ -4007,15 +4146,13 @@ Replace it with some information about the removed part."
            (or (mail-content-type-get (mm-handle-disposition data) 'filename)
                none))
           (type (mm-handle-media-type data)))
            (or (mail-content-type-get (mm-handle-disposition data) 'filename)
                none))
           (type (mm-handle-media-type data)))
-      (if (mm-multiple-handles gnus-article-mime-handles)
-         (error "This function is not implemented"))
+      (unless data
+       (error "No MIME part under point"))
       (with-current-buffer (mm-handle-buffer data)
        (let ((bsize (format "%s" (buffer-size))))
          (erase-buffer)
          (insert
           (concat
       (with-current-buffer (mm-handle-buffer data)
        (let ((bsize (format "%s" (buffer-size))))
          (erase-buffer)
          (insert
           (concat
-           "<#part type=text/plain nofile=yes disposition=attachment"
-           " description=\"Deleted attachment (" bsize " Byte)\">"
            ",----\n"
            "| The following attachment has been deleted:\n"
            "|\n"
            ",----\n"
            "| The following attachment has been deleted:\n"
            "|\n"
@@ -4023,52 +4160,14 @@ Replace it with some information about the removed part."
            "| Filename:       " filename "\n"
            "| Size (encoded): " bsize " Byte\n"
            "| Description:    " description "\n"
            "| Filename:       " filename "\n"
            "| Size (encoded): " bsize " Byte\n"
            "| Description:    " description "\n"
-           "`----\n"
-           "<#/part>"))
+           "`----\n"))
          (setcdr data
          (setcdr data
-                 (cdr (mm-make-handle nil `("text/plain"))))))
+                 (cdr (mm-make-handle
+                       nil `("text/plain") nil nil
+                       (list "attachment")
+                       (format "Deleted attachment (%s bytes)" bsize))))))
       (set-buffer gnus-summary-buffer)
       (set-buffer gnus-summary-buffer)
-      ;; FIXME: maybe some of the following code (borrowed from
-      ;; `gnus-mime-save-part-and-strip') isn't necessary?
-      (gnus-article-edit-article
-       `(lambda ()
-         (erase-buffer)
-         (let ((mail-parse-charset (or gnus-article-charset
-                                       ',gnus-newsgroup-charset))
-               (mail-parse-ignored-charsets
-                (or gnus-article-ignored-charsets
-                    ',gnus-newsgroup-ignored-charsets))
-               (mbl mml-buffer-list))
-           (setq mml-buffer-list nil)
-           (insert-buffer gnus-original-article-buffer)
-           (mime-to-mml ',handles)
-           (setq gnus-article-mime-handles nil)
-           (let ((mbl1 mml-buffer-list))
-             (setq mml-buffer-list mbl)
-             (set (make-local-variable 'mml-buffer-list) mbl1))
-           (gnus-make-local-hook 'kill-buffer-hook)
-           (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
-       `(lambda (no-highlight)
-         (let ((mail-parse-charset (or gnus-article-charset
-                                       ',gnus-newsgroup-charset))
-               (message-options message-options)
-               (message-options-set-recipient)
-               (mail-parse-ignored-charsets
-                (or gnus-article-ignored-charsets
-                    ',gnus-newsgroup-ignored-charsets)))
-           (mml-to-mime)
-           (mml-destroy-buffers)
-           (remove-hook 'kill-buffer-hook
-                        'mml-destroy-buffers t)
-           (kill-local-variable 'mml-buffer-list))
-         (gnus-summary-edit-article-done
-          ,(or (mail-header-references gnus-current-headers) "")
-          ,(gnus-group-read-only-p)
-          ,gnus-summary-buffer no-highlight)))))
-  ;; Not in `gnus-mime-save-part-and-strip':
-  (gnus-article-edit-done)
-  (gnus-summary-expand-window)
-  (gnus-summary-show-article))
+      (gnus-article-edit-part handles))))
 
 (defun gnus-mime-save-part ()
   "Save the MIME part under point."
 
 (defun gnus-mime-save-part ()
   "Save the MIME part under point."
@@ -4130,60 +4229,63 @@ Replace it with some information about the removed part."
            (mm-merge-handles gnus-article-mime-handles handle))
       (gnus-mm-display-part handle))))
 
            (mm-merge-handles gnus-article-mime-handles handle))
       (gnus-mm-display-part handle))))
 
-(eval-when-compile
-  (require 'jka-compr))
-
-;; jka-compr.el uses a "sh -c" to direct stderr to err-file, but these days
-;; emacs can do that itself.
-;;
-(defun gnus-mime-jka-compr-maybe-uncompress ()
-  "Uncompress the current buffer if `auto-compression-mode' is enabled.
-The uncompress method used is derived from `buffer-file-name'."
-  (when (and (fboundp 'jka-compr-installed-p)
-             (jka-compr-installed-p))
-    (let ((info (jka-compr-get-compression-info buffer-file-name)))
-      (when info
-        (let ((basename (file-name-nondirectory buffer-file-name))
-              (args     (jka-compr-info-uncompress-args    info))
-              (prog     (jka-compr-info-uncompress-program info))
-              (message  (jka-compr-info-uncompress-message info))
-              (err-file (jka-compr-make-temp-name)))
-          (if message
-              (message "%s %s..." message basename))
-          (unwind-protect
-              (unless (memq (apply 'call-process-region
-                                   (point-min) (point-max)
-                                   prog
-                                   t (list t err-file) nil
-                                   args)
-                            jka-compr-acceptable-retval-list)
-                (jka-compr-error prog args basename message err-file))
-            (jka-compr-delete-temp-file err-file)))))))
-
-(defun gnus-mime-copy-part (&optional handle)
+(defun gnus-mime-copy-part (&optional handle arg)
   "Put the MIME part under point into a new buffer.
 If `auto-compression-mode' is enabled, compressed files like .gz and .bz2
 are decompressed."
   "Put the MIME part under point into a new buffer.
 If `auto-compression-mode' is enabled, compressed files like .gz and .bz2
 are decompressed."
-  (interactive)
+  (interactive (list nil current-prefix-arg))
   (gnus-article-check-buffer)
   (gnus-article-check-buffer)
-  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
-        (contents (and handle (mm-get-part handle)))
-        (base (and handle
-                   (file-name-nondirectory
-                    (or
-                     (mail-content-type-get (mm-handle-type handle) 'name)
-                     (mail-content-type-get (mm-handle-disposition handle)
-                                            'filename)
-                     "*decoded*"))))
-        (buffer (and base (generate-new-buffer base))))
-    (when contents
-      (switch-to-buffer buffer)
-      (insert contents)
+  (unless handle
+    (setq handle (get-text-property (point) 'gnus-data)))
+  (when handle
+    (let ((filename (or (mail-content-type-get (mm-handle-disposition handle)
+                                              'name)
+                       (mail-content-type-get (mm-handle-disposition handle)
+                                              'filename)))
+         contents dont-decode charset coding-system)
+      (mm-with-unibyte-buffer
+       (mm-insert-part handle)
+       (setq contents (or (condition-case nil
+                              (mm-decompress-buffer filename nil 'sig)
+                            (error
+                             (setq dont-decode t)
+                             nil))
+                          (buffer-string))))
+      (setq filename (cond (filename (file-name-nondirectory filename))
+                          (dont-decode "*raw data*")
+                          (t "*decoded*")))
+      (cond
+       (dont-decode)
+       ((not arg)
+       (unless (setq charset (mail-content-type-get
+                              (mm-handle-type handle) 'charset))
+         (unless (setq coding-system (mm-with-unibyte-buffer
+                                       (insert contents)
+                                       (mm-find-buffer-file-coding-system)))
+           (setq charset gnus-newsgroup-charset))))
+       ((numberp arg)
+       (setq charset (or (cdr (assq arg
+                                    gnus-summary-show-article-charset-alist))
+                         (mm-read-coding-system "Charset: ")))))
+      (switch-to-buffer (generate-new-buffer filename))
+      (if (or coding-system
+             (and charset
+                  (setq coding-system (mm-charset-to-coding-system charset))
+                  (not (eq charset 'ascii))))
+         (progn
+           (mm-enable-multibyte)
+           (insert (mm-decode-coding-string contents coding-system))
+           (setq buffer-file-coding-system
+                 (if (boundp 'last-coding-system-used)
+                     (symbol-value 'last-coding-system-used)
+                   coding-system)))
+       (mm-disable-multibyte)
+       (insert contents)
+       (setq buffer-file-coding-system mm-binary-coding-system))
       ;; We do it this way to make `normal-mode' set the appropriate mode.
       (unwind-protect
          (progn
       ;; We do it this way to make `normal-mode' set the appropriate mode.
       (unwind-protect
          (progn
-           (setq buffer-file-name (expand-file-name base))
-           (gnus-mime-jka-compr-maybe-uncompress)
+           (setq buffer-file-name (expand-file-name filename))
            (normal-mode))
        (setq buffer-file-name nil))
       (goto-char (point-min)))))
            (normal-mode))
        (setq buffer-file-name nil))
       (goto-char (point-min)))))
@@ -4214,37 +4316,57 @@ are decompressed."
          (ps-despool filename)))))
 
 (defun gnus-mime-inline-part (&optional handle arg)
          (ps-despool filename)))))
 
 (defun gnus-mime-inline-part (&optional handle arg)
-  "Insert the MIME part under point into the current buffer."
+  "Insert the MIME part under point into the current buffer.
+Compressed files like .gz and .bz2 are decompressed."
   (interactive (list nil current-prefix-arg))
   (gnus-article-check-buffer)
   (interactive (list nil current-prefix-arg))
   (gnus-article-check-buffer)
-  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
-        contents charset
-        (b (point))
-        buffer-read-only)
-    (when handle
+  (unless handle
+    (setq handle (get-text-property (point) 'gnus-data)))
+  (when handle
+    (let ((b (point))
+         (inhibit-read-only t)
+         contents charset coding-system)
       (if (and (not arg) (mm-handle-undisplayer handle))
          (mm-remove-part handle)
       (if (and (not arg) (mm-handle-undisplayer handle))
          (mm-remove-part handle)
-       (setq contents (mm-get-part handle))
+       (mm-with-unibyte-buffer
+         (mm-insert-part handle)
+         (setq contents
+               (or (mm-decompress-buffer
+                    (or (mail-content-type-get (mm-handle-disposition handle)
+                                               'name)
+                        (mail-content-type-get (mm-handle-disposition handle)
+                                               'filename))
+                    nil t)
+                   (buffer-string))))
        (cond
         ((not arg)
        (cond
         ((not arg)
-         (setq charset (or (mail-content-type-get
-                            (mm-handle-type handle) 'charset)
-                           gnus-newsgroup-charset)))
+         (unless (setq charset (mail-content-type-get
+                                (mm-handle-type handle) 'charset))
+           (unless (setq coding-system
+                         (mm-with-unibyte-buffer
+                           (insert contents)
+                           (mm-find-buffer-file-coding-system)))
+             (setq charset gnus-newsgroup-charset))))
         ((numberp arg)
          (if (mm-handle-undisplayer handle)
              (mm-remove-part handle))
          (setq charset
                (or (cdr (assq arg
                               gnus-summary-show-article-charset-alist))
         ((numberp arg)
          (if (mm-handle-undisplayer handle)
              (mm-remove-part handle))
          (setq charset
                (or (cdr (assq arg
                               gnus-summary-show-article-charset-alist))
-                   (mm-read-coding-system "Charset: ")))))
+                   (mm-read-coding-system "Charset: "))))
+        (t
+         (if (mm-handle-undisplayer handle)
+             (mm-remove-part handle))))
        (forward-line 2)
        (forward-line 2)
-       (mm-insert-inline handle
-                         (if (and charset
-                                  (setq charset (mm-charset-to-coding-system
-                                                 charset))
-                                  (not (eq charset 'ascii)))
-                             (mm-decode-coding-string contents charset)
-                           contents))
+       (mm-insert-inline
+        handle
+        (if (or coding-system
+                (and charset
+                     (setq coding-system
+                           (mm-charset-to-coding-system charset))
+                     (not (eq charset 'ascii))))
+            (mm-decode-coding-string contents coding-system)
+          (mm-string-to-multibyte contents)))
        (goto-char b)))))
 
 (defun gnus-mime-view-part-as-charset (&optional handle arg)
        (goto-char b)))))
 
 (defun gnus-mime-view-part-as-charset (&optional handle arg)
@@ -4255,7 +4377,7 @@ specified charset."
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
         contents charset
         (b (point))
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
         contents charset
         (b (point))
-        buffer-read-only)
+        (inhibit-read-only t))
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle))
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle))
@@ -4275,8 +4397,8 @@ specified charset."
         (mm-inlined-types nil)
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
         (mm-inlined-types nil)
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
-         (save-excursion (set-buffer gnus-summary-buffer)
-                         gnus-newsgroup-ignored-charsets)))
+         (with-current-buffer gnus-summary-buffer
+           gnus-newsgroup-ignored-charsets)))
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle)
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle)
@@ -4292,9 +4414,9 @@ If no internal viewer is available, use an external viewer."
         (mm-inline-large-images t)
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
         (mm-inline-large-images t)
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
-         (save-excursion (set-buffer gnus-summary-buffer)
-                         gnus-newsgroup-ignored-charsets))
-        buffer-read-only)
+         (with-current-buffer gnus-summary-buffer
+           gnus-newsgroup-ignored-charsets))
+        (inhibit-read-only t))
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle)
     (when handle
       (if (mm-handle-undisplayer handle)
          (mm-remove-part handle)
@@ -4310,8 +4432,7 @@ If no internal viewer is available, use an external viewer."
        (funcall (cdr action-pair)))))
 
 (defun gnus-article-part-wrapper (n function)
        (funcall (cdr action-pair)))))
 
 (defun gnus-article-part-wrapper (n function)
-  (save-current-buffer
-    (set-buffer gnus-article-buffer)
+  (with-current-buffer gnus-article-buffer
     (when (> n (length gnus-article-mime-handle-alist))
       (error "No such part"))
     (gnus-article-goto-part n)
     (when (> n (length gnus-article-mime-handle-alist))
       (error "No such part"))
     (gnus-article-goto-part n)
@@ -4339,7 +4460,8 @@ If no internal viewer is available, use an external viewer."
   (gnus-article-part-wrapper n 'gnus-mime-copy-part))
 
 (defun gnus-article-view-part-as-charset (n)
   (gnus-article-part-wrapper n 'gnus-mime-copy-part))
 
 (defun gnus-article-view-part-as-charset (n)
-  "Copy MIME part N, which is the numerical prefix."
+  "View MIME part N using a specified charset.
+N is the numerical prefix."
   (interactive "p")
   (gnus-article-part-wrapper n 'gnus-mime-view-part-as-charset))
 
   (interactive "p")
   (gnus-article-part-wrapper n 'gnus-mime-view-part-as-charset))
 
@@ -4355,8 +4477,8 @@ If no internal viewer is available, use an external viewer."
 
 (defun gnus-article-mime-match-handle-first (condition)
   (if condition
 
 (defun gnus-article-mime-match-handle-first (condition)
   (if condition
-      (let ((alist gnus-article-mime-handle-alist) ihandle n)
-       (while (setq ihandle (pop alist))
+      (let (n)
+       (dolist (ihandle gnus-article-mime-handle-alist)
          (if (and (cond
                    ((functionp condition)
                     (funcall condition (cdr ihandle)))
          (if (and (cond
                    ((functionp condition)
                     (funcall condition (cdr ihandle)))
@@ -4376,8 +4498,7 @@ If no internal viewer is available, use an external viewer."
 (defun gnus-article-view-part (&optional n)
   "View MIME part N, which is the numerical prefix."
   (interactive "P")
 (defun gnus-article-view-part (&optional n)
   "View MIME part N, which is the numerical prefix."
   (interactive "P")
-  (save-current-buffer
-    (set-buffer gnus-article-buffer)
+  (with-current-buffer gnus-article-buffer
     (or (numberp n) (setq n (gnus-article-mime-match-handle-first
                             gnus-article-mime-match-handle-function)))
     (when (> n (length gnus-article-mime-handle-alist))
     (or (numberp n) (setq n (gnus-article-mime-match-handle-first
                             gnus-article-mime-match-handle-function)))
     (when (> n (length gnus-article-mime-handle-alist))
@@ -4398,15 +4519,14 @@ If no internal viewer is available, use an external viewer."
   "Display HANDLE and fix MIME button."
   (let ((id (get-text-property (point) 'gnus-part))
        (point (point))
   "Display HANDLE and fix MIME button."
   (let ((id (get-text-property (point) 'gnus-part))
        (point (point))
-       buffer-read-only)
+       (inhibit-read-only t))
     (forward-line 1)
     (prog1
        (let ((window (selected-window))
              (mail-parse-charset gnus-newsgroup-charset)
              (mail-parse-ignored-charsets
               (if (gnus-buffer-live-p gnus-summary-buffer)
     (forward-line 1)
     (prog1
        (let ((window (selected-window))
              (mail-parse-charset gnus-newsgroup-charset)
              (mail-parse-ignored-charsets
               (if (gnus-buffer-live-p gnus-summary-buffer)
-                  (save-excursion
-                    (set-buffer gnus-summary-buffer)
+                  (with-current-buffer gnus-summary-buffer
                     gnus-newsgroup-ignored-charsets)
                 nil)))
          (save-excursion
                     gnus-newsgroup-ignored-charsets)
                 nil)))
          (save-excursion
@@ -4474,11 +4594,11 @@ If no internal viewer is available, use an external viewer."
     (setq b (point))
     (gnus-eval-format
      gnus-mime-button-line-format gnus-mime-button-line-format-alist
     (setq b (point))
     (gnus-eval-format
      gnus-mime-button-line-format gnus-mime-button-line-format-alist
-     `(,@(gnus-local-map-property gnus-mime-button-map)
-        gnus-callback gnus-mm-display-part
-        gnus-part ,gnus-tmp-id
-        article-type annotation
-        gnus-data ,handle))
+     `(keymap ,gnus-mime-button-map
+             gnus-callback gnus-mm-display-part
+             gnus-part ,gnus-tmp-id
+             article-type annotation
+             gnus-data ,handle))
     (setq e (if (bolp)
                ;; Exclude a newline.
                (1- (point))
     (setq e (if (bolp)
                ;; Exclude a newline.
                (1- (point))
@@ -4525,11 +4645,15 @@ If no internal viewer is available, use an external viewer."
          ;; We have to do this since selecting the window
          ;; may change the point.  So we set the window point.
          (set-window-point window point)))
          ;; We have to do this since selecting the window
          ;; may change the point.  So we set the window point.
          (set-window-point window point)))
-      (let* ((handles (or ihandles
-                         (mm-dissect-buffer nil gnus-article-loose-mime)
-                         (and gnus-article-emulate-mime
-                              (mm-uu-dissect))))
-            buffer-read-only handle name type b e display)
+      (let ((handles ihandles)
+           (inhibit-read-only t)
+           handle name type b e display)
+       (cond (handles)
+             ((setq handles (mm-dissect-buffer nil gnus-article-loose-mime))
+              (when gnus-article-emulate-mime
+                (mm-uu-dissect-text-parts handles)))
+             (gnus-article-emulate-mime
+              (setq handles (mm-uu-dissect))))
        (when (and (not ihandles)
                   (not gnus-displaying-mime))
          ;; Top-level call; we clean up.
        (when (and (not ihandles)
                   (not gnus-displaying-mime))
          ;; Top-level call; we clean up.
@@ -4575,6 +4699,7 @@ If t, it overrides nil values of
 
 (defcustom gnus-mime-display-multipart-alternative-as-mixed nil
   "Display \"multipart/alternative\" parts as  \"multipart/mixed\"."
 
 (defcustom gnus-mime-display-multipart-alternative-as-mixed nil
   "Display \"multipart/alternative\" parts as  \"multipart/mixed\"."
+  :version "22.1"
   :group 'gnus-article-mime
   :type 'boolean)
 
   :group 'gnus-article-mime
   :type 'boolean)
 
@@ -4584,6 +4709,7 @@ If t, it overrides nil values of
 If displaying \"text/html\" is discouraged \(see
 `mm-discouraged-alternatives'\) images or other material inside a
 \"multipart/related\" part might be overlooked when this variable is nil."
 If displaying \"text/html\" is discouraged \(see
 `mm-discouraged-alternatives'\) images or other material inside a
 \"multipart/related\" part might be overlooked when this variable is nil."
+  :version "22.1"
   :group 'gnus-article-mime
   :type 'boolean)
 
   :group 'gnus-article-mime
   :type 'boolean)
 
@@ -4664,11 +4790,9 @@ If displaying \"text/html\" is discouraged \(see
          (push (cons id handle) gnus-article-mime-handle-alist)
          (when (or (not display)
                    (not (gnus-unbuttonized-mime-type-p type)))
          (push (cons id handle) gnus-article-mime-handle-alist)
          (when (or (not display)
                    (not (gnus-unbuttonized-mime-type-p type)))
-           ;(gnus-article-insert-newline)
            (gnus-insert-mime-button
             handle id (list (or display (and not-attachment text))))
            (gnus-article-insert-newline)
            (gnus-insert-mime-button
             handle id (list (or display (and not-attachment text))))
            (gnus-article-insert-newline)
-           ;(gnus-article-insert-newline)
            ;; Remember modify the number of forward lines.
            (setq move t))
          (setq beg (point))
            ;; Remember modify the number of forward lines.
            (setq move t))
          (setq beg (point))
@@ -4690,7 +4814,7 @@ If displaying \"text/html\" is discouraged \(see
              (forward-line -1)
              (setq beg (point)))
            (gnus-article-insert-newline)
              (forward-line -1)
              (setq beg (point)))
            (gnus-article-insert-newline)
-           (mm-insert-inline handle (mm-get-part handle))
+           (mm-display-inline handle)
            (goto-char (point-max))))
          ;; Do highlighting.
          (save-excursion
            (goto-char (point-max))))
          ;; Do highlighting.
          (save-excursion
@@ -4724,7 +4848,7 @@ If displaying \"text/html\" is discouraged \(see
   (let* ((preferred (or preferred (mm-preferred-alternative handles)))
         (ihandles handles)
         (point (point))
   (let* ((preferred (or preferred (mm-preferred-alternative handles)))
         (ihandles handles)
         (point (point))
-        handle buffer-read-only from props begend not-pref)
+        handle (inhibit-read-only t) from props begend not-pref)
     (save-window-excursion
       (save-restriction
        (when ibegend
     (save-window-excursion
       (save-restriction
        (when ibegend
@@ -4756,7 +4880,7 @@ If displaying \"text/html\" is discouraged \(see
                       ',gnus-article-mime-handle-alist))
               (gnus-mime-display-alternative
                ',ihandles ',not-pref ',begend ,id))
                       ',gnus-article-mime-handle-alist))
               (gnus-mime-display-alternative
                ',ihandles ',not-pref ',begend ,id))
-            ,@(gnus-local-map-property gnus-mime-button-map)
+            keymap ,gnus-mime-button-map
             ,gnus-mouse-face-prop ,gnus-article-mouse-face
             face ,gnus-article-button-face
             gnus-part ,id
             ,gnus-mouse-face-prop ,gnus-article-mouse-face
             face ,gnus-article-button-face
             gnus-part ,id
@@ -4780,7 +4904,7 @@ If displaying \"text/html\" is discouraged \(see
                         ',gnus-article-mime-handle-alist))
                 (gnus-mime-display-alternative
                  ',ihandles ',handle ',begend ,id))
                         ',gnus-article-mime-handle-alist))
                 (gnus-mime-display-alternative
                  ',ihandles ',handle ',begend ,id))
-              ,@(gnus-local-map-property gnus-mime-button-map)
+              keymap ,gnus-mime-button-map
               ,gnus-mouse-face-prop ,gnus-article-mouse-face
               face ,gnus-article-button-face
               gnus-part ,id
               ,gnus-mouse-face-prop ,gnus-article-mouse-face
               face ,gnus-article-button-face
               gnus-part ,id
@@ -4795,8 +4919,8 @@ If displaying \"text/html\" is discouraged \(see
              (gnus-display-mime preferred)
            (let ((mail-parse-charset gnus-newsgroup-charset)
                  (mail-parse-ignored-charsets
              (gnus-display-mime preferred)
            (let ((mail-parse-charset gnus-newsgroup-charset)
                  (mail-parse-ignored-charsets
-                  (save-excursion (set-buffer gnus-summary-buffer)
-                                  gnus-newsgroup-ignored-charsets)))
+                  (with-current-buffer gnus-summary-buffer
+                    gnus-newsgroup-ignored-charsets)))
              (mm-display-part preferred)
              ;; Do highlighting.
              (save-excursion
              (mm-display-part preferred)
              ;; Do highlighting.
              (save-excursion
@@ -4846,8 +4970,7 @@ is the string to use when it is inactive.")
 
 (defun gnus-article-wash-status ()
   "Return a string which display status of article washing."
 
 (defun gnus-article-wash-status ()
   "Return a string which display status of article washing."
-  (save-excursion
-    (set-buffer gnus-article-buffer)
+  (with-current-buffer gnus-article-buffer
     (let ((cite (memq 'cite gnus-article-wash-types))
          (headers (memq 'headers gnus-article-wash-types))
          (boring (memq 'boring-headers gnus-article-wash-types))
     (let ((cite (memq 'cite gnus-article-wash-types))
          (headers (memq 'headers gnus-article-wash-types))
          (boring (memq 'boring-headers gnus-article-wash-types))
@@ -4896,8 +5019,8 @@ is the string to use when it is inactive.")
   "Hide unwanted headers if `gnus-have-all-headers' is nil.
 Provided for backwards compatibility."
   (when (and (or (not (gnus-buffer-live-p gnus-summary-buffer))
   "Hide unwanted headers if `gnus-have-all-headers' is nil.
 Provided for backwards compatibility."
   (when (and (or (not (gnus-buffer-live-p gnus-summary-buffer))
-                (not (save-excursion (set-buffer gnus-summary-buffer)
-                                     gnus-have-all-headers)))
+                (not (with-current-buffer gnus-summary-buffer
+                       gnus-have-all-headers)))
             (not gnus-inhibit-hiding))
     (gnus-article-hide-headers)))
 
             (not gnus-inhibit-hiding))
     (gnus-article-hide-headers)))
 
@@ -4927,30 +5050,35 @@ If given a numerical ARG, move forward ARG pages."
     (widen)
     ;; Remove any old next/prev buttons.
     (when (gnus-visual-p 'page-marker)
     (widen)
     ;; Remove any old next/prev buttons.
     (when (gnus-visual-p 'page-marker)
-      (let ((buffer-read-only nil))
+      (let ((inhibit-read-only t))
        (gnus-remove-text-with-property 'gnus-prev)
        (gnus-remove-text-with-property 'gnus-next)))
        (gnus-remove-text-with-property 'gnus-prev)
        (gnus-remove-text-with-property 'gnus-next)))
-    (when
+    (if
        (cond ((< arg 0)
               (re-search-backward page-delimiter nil 'move (1+ (abs arg))))
              ((> arg 0)
               (re-search-forward page-delimiter nil 'move arg)))
        (cond ((< arg 0)
               (re-search-backward page-delimiter nil 'move (1+ (abs arg))))
              ((> arg 0)
               (re-search-forward page-delimiter nil 'move arg)))
-      (goto-char (match-end 0)))
-    (narrow-to-region
-     (point)
-     (if (re-search-forward page-delimiter nil 'move)
-        (match-beginning 0)
-       (point)))
-    (when (and (gnus-visual-p 'page-marker)
-              (not (= (point-min) 1)))
+       (goto-char (match-end 0))
       (save-excursion
        (goto-char (point-min))
       (save-excursion
        (goto-char (point-min))
-       (gnus-insert-prev-page-button)))
-    (when (and (gnus-visual-p 'page-marker)
-              (< (+ (point-max) 2) (buffer-size)))
-      (save-excursion
-       (goto-char (point-max))
-       (gnus-insert-next-page-button)))))
+       (setq gnus-page-broken
+             (and (re-search-forward page-delimiter nil t) t))))
+    (when gnus-page-broken
+      (narrow-to-region
+       (point)
+       (if (re-search-forward page-delimiter nil 'move)
+          (match-beginning 0)
+        (point)))
+      (when (and (gnus-visual-p 'page-marker)
+                (> (point-min) (save-restriction (widen) (point-min))))
+       (save-excursion
+         (goto-char (point-min))
+         (gnus-insert-prev-page-button)))
+      (when (and (gnus-visual-p 'page-marker)
+                (< (point-max) (save-restriction (widen) (point-max))))
+       (save-excursion
+         (goto-char (point-max))
+         (gnus-insert-next-page-button))))))
 
 ;; Article mode commands
 
 
 ;; Article mode commands
 
@@ -4963,7 +5091,7 @@ If given a numerical ARG, move forward ARG pages."
 
 
 (defun gnus-article-goto-prev-page ()
 
 
 (defun gnus-article-goto-prev-page ()
-  "Show the next page of the article."
+  "Show the previous page of the article."
   (interactive)
   (if (bobp)
       (gnus-article-read-summary-keys nil (gnus-character-to-event ?p))
   (interactive)
   (if (bobp)
       (gnus-article-read-summary-keys nil (gnus-character-to-event ?p))
@@ -4997,7 +5125,9 @@ Argument LINES specifies lines to be scrolled up."
       (if (or (not gnus-page-broken)
              (save-excursion
                (save-restriction
       (if (or (not gnus-page-broken)
              (save-excursion
                (save-restriction
-                 (widen) (forward-line 1) (eobp)))) ;Real end-of-buffer?
+                 (widen)
+                 (forward-line)
+                 (eobp)))) ;Real end-of-buffer?
          (progn
            (when gnus-article-over-scroll
              (gnus-article-next-page-1 lines))
          (progn
            (when gnus-article-over-scroll
              (gnus-article-next-page-1 lines))
@@ -5058,9 +5188,9 @@ not have a face in `gnus-article-boring-faces'."
   "Read article specified by message-id around point."
   (interactive)
   (save-excursion
   "Read article specified by message-id around point."
   (interactive)
   (save-excursion
-    (re-search-backward "[ \t]\\|^" (gnus-point-at-bol) t)
-    (re-search-forward "<?news:<?\\|<" (gnus-point-at-eol) t)
-    (if (re-search-forward "[^@ ]+@[^ \t>]+" (gnus-point-at-eol) t)
+    (re-search-backward "[ \t]\\|^" (point-at-bol) t)
+    (re-search-forward "<?news:<?\\|<" (point-at-eol) t)
+    (if (re-search-forward "[^@ ]+@[^ \t>]+" (point-at-eol) t)
        (let ((msg-id (concat "<" (match-string 0) ">")))
          (set-buffer gnus-summary-buffer)
          (gnus-summary-refer-article msg-id))
        (let ((msg-id (concat "<" (match-string 0) ">")))
          (set-buffer gnus-summary-buffer)
          (gnus-summary-refer-article msg-id))
@@ -5154,11 +5284,13 @@ not have a face in `gnus-article-boring-faces'."
       (let ((obuf (current-buffer))
            (owin (current-window-configuration))
            (opoint (point))
       (let ((obuf (current-buffer))
            (owin (current-window-configuration))
            (opoint (point))
-           (summary gnus-article-current-summary)
-           func in-buffer selected)
-       (if not-restore-window
-           (pop-to-buffer summary 'norecord)
-         (switch-to-buffer summary 'norecord))
+           win func in-buffer selected new-sum-start new-sum-hscroll)
+       (cond (not-restore-window
+              (pop-to-buffer gnus-article-current-summary 'norecord))
+             ((setq win (get-buffer-window gnus-article-current-summary))
+              (select-window win))
+             (t
+              (switch-to-buffer gnus-article-current-summary 'norecord)))
        (setq in-buffer (current-buffer))
        ;; We disable the pick minor mode commands.
        (if (and (setq func (let (gnus-pick-mode)
        (setq in-buffer (current-buffer))
        ;; We disable the pick minor mode commands.
        (if (and (setq func (let (gnus-pick-mode)
@@ -5166,7 +5298,10 @@ not have a face in `gnus-article-boring-faces'."
                 (functionp func))
            (progn
              (call-interactively func)
                 (functionp func))
            (progn
              (call-interactively func)
-             (setq new-sum-point (point))
+             (when (eq win (selected-window))
+               (setq new-sum-point (point)
+                     new-sum-start (window-start win)
+                     new-sum-hscroll (window-hscroll win))
              (when (eq in-buffer (current-buffer))
                (setq selected (gnus-summary-select-article))
                (set-buffer obuf)
              (when (eq in-buffer (current-buffer))
                (setq selected (gnus-summary-select-article))
                (set-buffer obuf)
@@ -5178,10 +5313,12 @@ not have a face in `gnus-article-boring-faces'."
                                    1)
                  (set-window-point (get-buffer-window (current-buffer))
                                    (point)))
                                    1)
                  (set-window-point (get-buffer-window (current-buffer))
                                    (point)))
-               (let ((win (get-buffer-window gnus-article-current-summary)))
-                 (when win
-                   (set-window-point win new-sum-point))))    )
-         (switch-to-buffer gnus-article-buffer)
+               (when (and (not not-restore-window)
+                          new-sum-point)
+                 (set-window-point win new-sum-point)
+                 (set-window-start win new-sum-start)
+                 (set-window-hscroll win new-sum-hscroll)))))
+         (set-window-configuration owin)
          (ding))))))
 
 (defun gnus-article-describe-key (key)
          (ding))))))
 
 (defun gnus-article-describe-key (key)
@@ -5233,7 +5370,7 @@ the entire article will be yanked."
   (interactive "P")
   (let ((article (cdr gnus-article-current))
        contents)
   (interactive "P")
   (let ((article (cdr gnus-article-current))
        contents)
-    (if (not (gnus-mark-active-p))
+    (if (not (gnus-region-active-p))
        (with-current-buffer gnus-summary-buffer
          (gnus-summary-reply (list (list article)) wide))
       (setq contents (buffer-substring (point) (mark t)))
        (with-current-buffer gnus-summary-buffer
          (gnus-summary-reply (list (list article)) wide))
       (setq contents (buffer-substring (point) (mark t)))
@@ -5252,7 +5389,7 @@ the entire article will be yanked."
   (interactive)
   (let ((article (cdr gnus-article-current))
        contents)
   (interactive)
   (let ((article (cdr gnus-article-current))
        contents)
-      (if (not (gnus-mark-active-p))
+      (if (not (gnus-region-active-p))
          (with-current-buffer gnus-summary-buffer
            (gnus-summary-followup (list (list article))))
        (setq contents (buffer-substring (point) (mark t)))
          (with-current-buffer gnus-summary-buffer
            (gnus-summary-followup (list (list article))))
        (setq contents (buffer-substring (point) (mark t)))
@@ -5352,16 +5489,14 @@ If given a prefix, show the hidden text instead."
                 gnus-summary-buffer
                 (get-buffer gnus-summary-buffer)
                 (gnus-buffer-exists-p gnus-summary-buffer)
                 gnus-summary-buffer
                 (get-buffer gnus-summary-buffer)
                 (gnus-buffer-exists-p gnus-summary-buffer)
-                (eq (cdr (save-excursion
-                           (set-buffer gnus-summary-buffer)
+                (eq (cdr (with-current-buffer gnus-summary-buffer
                            (assq article gnus-newsgroup-reads)))
                     gnus-canceled-mark))
            nil)
           ;; We first check `gnus-original-article-buffer'.
           ((and (get-buffer gnus-original-article-buffer)
                 (numberp article)
                            (assq article gnus-newsgroup-reads)))
                     gnus-canceled-mark))
            nil)
           ;; We first check `gnus-original-article-buffer'.
           ((and (get-buffer gnus-original-article-buffer)
                 (numberp article)
-                (save-excursion
-                  (set-buffer gnus-original-article-buffer)
+                (with-current-buffer gnus-original-article-buffer
                   (and (equal (car gnus-original-article) group)
                        (eq (cdr gnus-original-article) article))))
            (insert-buffer-substring gnus-original-article-buffer)
                   (and (equal (car gnus-original-article) group)
                        (eq (cdr gnus-original-article) article))))
            (insert-buffer-substring gnus-original-article-buffer)
@@ -5393,7 +5528,7 @@ If given a prefix, show the hidden text instead."
                  (backend (car (gnus-find-method-for-group
                                 gnus-newsgroup-name)))
                  result
                  (backend (car (gnus-find-method-for-group
                                 gnus-newsgroup-name)))
                  result
-                 (buffer-read-only nil))
+                 (inhibit-read-only t))
              (if (or (not (listp methods))
                      (and (symbolp (car methods))
                           (assq (car methods) nnoo-definition-alist)))
              (if (or (not (listp methods))
                      (and (symbolp (car methods))
                           (assq (car methods) nnoo-definition-alist)))
@@ -5445,7 +5580,7 @@ If given a prefix, show the hidden text instead."
            (buffer-disable-undo)
            (setq major-mode 'gnus-original-article-mode)
            (setq buffer-read-only t))
            (buffer-disable-undo)
            (setq major-mode 'gnus-original-article-mode)
            (setq buffer-read-only t))
-         (let (buffer-read-only)
+         (let ((inhibit-read-only t))
            (erase-buffer)
            (insert-buffer-substring gnus-article-buffer))
          (setq gnus-original-article (cons group article)))
            (erase-buffer)
            (insert-buffer-substring gnus-article-buffer))
          (setq gnus-original-article (cons group article)))
@@ -5479,7 +5614,6 @@ If given a prefix, show the hidden text instead."
 (defvar gnus-article-edit-done-function nil)
 
 (defvar gnus-article-edit-mode-map nil)
 (defvar gnus-article-edit-done-function nil)
 
 (defvar gnus-article-edit-mode-map nil)
-(defvar gnus-article-edit-mode nil)
 
 ;; Should we be using derived.el for this?
 (unless gnus-article-edit-mode-map
 
 ;; Should we be using derived.el for this?
 (unless gnus-article-edit-mode-map
@@ -5544,7 +5678,7 @@ If given a prefix, show the hidden text instead."
     ["Body" message-goto-body t]
     ["Signature" message-goto-signature t]))
 
     ["Body" message-goto-body t]
     ["Signature" message-goto-signature t]))
 
-(define-derived-mode gnus-article-edit-mode text-mode "Article Edit"
+(define-derived-mode gnus-article-edit-mode message-mode "Article Edit"
   "Major mode for editing articles.
 This is an extended text-mode.
 
   "Major mode for editing articles.
 This is an extended text-mode.
 
@@ -5583,7 +5717,10 @@ groups."
   "Start editing the contents of the current article buffer."
   (let ((winconf (current-window-configuration)))
     (set-buffer gnus-article-buffer)
   "Start editing the contents of the current article buffer."
   (let ((winconf (current-window-configuration)))
     (set-buffer gnus-article-buffer)
-    (gnus-article-edit-mode)
+    (let ((message-auto-save-directory
+          ;; Don't associate the article buffer with a draft file.
+          nil))
+      (gnus-article-edit-mode))
     (funcall start-func)
     (set-buffer-modified-p nil)
     (gnus-configure-windows 'edit-article)
     (funcall start-func)
     (set-buffer-modified-p nil)
     (gnus-configure-windows 'edit-article)
@@ -5616,7 +5753,7 @@ groups."
        (car gnus-article-current) (cdr gnus-article-current)))
     ;; We remove all text props from the article buffer.
     (kill-all-local-variables)
        (car gnus-article-current) (cdr gnus-article-current)))
     ;; We remove all text props from the article buffer.
     (kill-all-local-variables)
-    (gnus-set-text-properties (point-min) (point-max) nil)
+    (set-text-properties (point-min) (point-max) nil)
     (gnus-article-mode)
     (set-window-configuration winconf)
     (set-buffer buf)
     (gnus-article-mode)
     (set-window-configuration winconf)
     (set-buffer buf)
@@ -5674,6 +5811,7 @@ groups."
 (defcustom gnus-button-valid-fqdn-regexp
   message-valid-fqdn-regexp
   "Regular expression that matches a valid FQDN."
 (defcustom gnus-button-valid-fqdn-regexp
   message-valid-fqdn-regexp
   "Regular expression that matches a valid FQDN."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type 'regexp)
 
   :group 'gnus-article-buttons
   :type 'regexp)
 
@@ -5681,6 +5819,7 @@ groups."
   "Function to use for displaying man pages.
 The function must take at least one argument with a string naming the
 man page."
   "Function to use for displaying man pages.
 The function must take at least one argument with a string naming the
 man page."
+  :version "22.1"
   :type '(choice (function-item :tag "Man" manual-entry)
                 (function-item :tag "Woman" woman)
                 (function :tag "Other"))
   :type '(choice (function-item :tag "Man" manual-entry)
                 (function-item :tag "Woman" woman)
                 (function :tag "Other"))
@@ -5691,6 +5830,7 @@ man page."
 If the default site is too slow, try to find a CTAN mirror, see
 <URL:http://tug.ctan.org/tex-archive/CTAN.sites?action=/index.html>.  See also
 the variable `gnus-button-handle-ctan'."
 If the default site is too slow, try to find a CTAN mirror, see
 <URL:http://tug.ctan.org/tex-archive/CTAN.sites?action=/index.html>.  See also
 the variable `gnus-button-handle-ctan'."
+  :version "22.1"
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type '(choice (const "http://www.tex.ac.uk/tex-archive/")
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type '(choice (const "http://www.tex.ac.uk/tex-archive/")
@@ -5701,33 +5841,38 @@ the variable `gnus-button-handle-ctan'."
 (defcustom gnus-button-ctan-handler 'browse-url
   "Function to use for displaying CTAN links.
 The function must take one argument, the string naming the URL."
 (defcustom gnus-button-ctan-handler 'browse-url
   "Function to use for displaying CTAN links.
 The function must take one argument, the string naming the URL."
+  :version "22.1"
   :type '(choice (function-item :tag "Browse Url" browse-url)
                 (function :tag "Other"))
   :group 'gnus-article-buttons)
 
 (defcustom gnus-button-handle-ctan-bogus-regexp "^/?tex-archive/\\|^/"
   "Bogus strings removed from CTAN URLs."
   :type '(choice (function-item :tag "Browse Url" browse-url)
                 (function :tag "Other"))
   :group 'gnus-article-buttons)
 
 (defcustom gnus-button-handle-ctan-bogus-regexp "^/?tex-archive/\\|^/"
   "Bogus strings removed from CTAN URLs."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type '(choice (const "^/?tex-archive/\\|/")
                 (regexp :tag "Other")))
 
 (defcustom gnus-button-ctan-directory-regexp
   (concat
   :group 'gnus-article-buttons
   :type '(choice (const "^/?tex-archive/\\|/")
                 (regexp :tag "Other")))
 
 (defcustom gnus-button-ctan-directory-regexp
   (concat
-   "\\("; Cannot use `\(?: ... \)' (compatibility with Emacs 20).
+   "\\(?:"
    "biblio\\|digests\\|dviware\\|fonts\\|graphics\\|help\\|"
    "indexing\\|info\\|language\\|macros\\|support\\|systems\\|"
    "tds\\|tools\\|usergrps\\|web\\|nonfree\\|obsolete"
    "\\)")
   "Regular expression for ctan directories.
 It should match all directories in the top level of `gnus-ctan-url'."
    "biblio\\|digests\\|dviware\\|fonts\\|graphics\\|help\\|"
    "indexing\\|info\\|language\\|macros\\|support\\|systems\\|"
    "tds\\|tools\\|usergrps\\|web\\|nonfree\\|obsolete"
    "\\)")
   "Regular expression for ctan directories.
 It should match all directories in the top level of `gnus-ctan-url'."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type 'regexp)
 
 (defcustom gnus-button-mid-or-mail-regexp
   :group 'gnus-article-buttons
   :type 'regexp)
 
 (defcustom gnus-button-mid-or-mail-regexp
-  (concat "\\b\\(<?[a-z0-9][^<>\")!;:,{}\n\t ]*@"
+  (concat "\\b\\(<?[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t ]*@"
+         ;; Felix Wiemann in <87oeuomcz9.fsf@news2.ososo.de>
          gnus-button-valid-fqdn-regexp
          ">?\\)\\b")
   "Regular expression that matches a message ID or a mail address."
          gnus-button-valid-fqdn-regexp
          ">?\\)\\b")
   "Regular expression that matches a message ID or a mail address."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type 'regexp)
 
   :group 'gnus-article-buttons
   :type 'regexp)
 
@@ -5739,6 +5884,7 @@ message ID or a mail address, respectively.  If this variable is set to the
 symbol `ask', always query the user what do do.  If it is a function, this
 function will be called with the string as it's only argument.  The function
 must return `mid', `mail', `invalid' or `ask'."
 symbol `ask', always query the user what do do.  If it is a function, this
 function will be called with the string as it's only argument.  The function
 must return `mid', `mail', `invalid' or `ask'."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type '(choice (function-item :tag "Heuristic function"
                                gnus-button-mid-or-mail-heuristic)
   :group 'gnus-article-buttons
   :type '(choice (function-item :tag "Heuristic function"
                                gnus-button-mid-or-mail-heuristic)
@@ -5802,6 +5948,7 @@ must return `mid', `mail', `invalid' or `ask'."
 
 A negative RATE indicates a message IDs, whereas a positive indicates a mail
 address.  The REGEXP is processed with `case-fold-search' set to nil."
 
 A negative RATE indicates a message IDs, whereas a positive indicates a mail
 address.  The REGEXP is processed with `case-fold-search' set to nil."
+  :version "22.1"
   :group 'gnus-article-buttons
   :type '(repeat (cons (number :tag "Rate")
                       (regexp :tag "Regexp"))))
   :group 'gnus-article-buttons
   :type '(repeat (cons (number :tag "Rate")
                       (regexp :tag "Regexp"))))
@@ -5819,13 +5966,14 @@ address, `ask' if unsure and `invalid' if the string is invalid."
     ;; Certain special cases...
     (when (string-match
           (concat
     ;; Certain special cases...
     (when (string-match
           (concat
-           "^0[0-9]+-[0-9][0-9][0-9][0-9]@t-online\\.de$" "\\|"
-           "^[0-9]+\.[0-9]+\@compuserve")
+           "^0[0-9]+-[0-9][0-9][0-9][0-9]@t-online\\.de$\\|"
+           "^[0-9]+\\.[0-9]+@compuserve\\|"
+           "@public\\.gmane\\.org")
           mid-or-mail)
           mid-or-mail)
-      (gnus-message 8 "`%s' is a known mail address.")
+      (gnus-message 8 "`%s' is a known mail address." mid-or-mail)
       (setq result 'mail))
     (when (string-match "@.*@\\| " mid-or-mail)
       (setq result 'mail))
     (when (string-match "@.*@\\| " mid-or-mail)
-      (gnus-message 8 "`%s' is invalid.")
+      (gnus-message 8 "`%s' is invalid." mid-or-mail)
       (setq result 'invalid))
     ;; Nothing more to do, if result is not a number here...
     (when (numberp result)
       (setq result 'invalid))
     ;; Nothing more to do, if result is not a number here...
     (when (numberp result)
@@ -5867,8 +6015,10 @@ address, `ask' if unsure and `invalid' if the string is invalid."
          (gnus-message
           9 "`%s', rate `%s', result `%s'." mid-or-mail 5.0 result)))))
     (gnus-message 8 "`%s': Final rate is `%s'." mid-or-mail result)
          (gnus-message
           9 "`%s', rate `%s', result `%s'." mid-or-mail 5.0 result)))))
     (gnus-message 8 "`%s': Final rate is `%s'." mid-or-mail result)
+    ;; Maybe we should make this a customizable alist: (condition . 'result)
     (cond
     (cond
-     ;; Maybe we should make this a customizable alist: (condition . 'result)
+     ((symbolp result) result)
+     ;; Now convert number into proper results:
      ((< result -10.0) 'mid)
      ((> result  10.0) 'mail)
      (t 'ask))))
      ((< result -10.0) 'mid)
      ((> result  10.0) 'mail)
      (t 'ask))))
@@ -5983,6 +6133,7 @@ positives are possible.  Note that you can set this variable local to
 specific groups.  Setting it higher in TeX groups is probably a good idea.
 See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
 how to set variables in specific groups."
 specific groups.  Setting it higher in TeX groups is probably a good idea.
 See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
 how to set variables in specific groups."
+  :version "22.1"
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
@@ -5994,6 +6145,7 @@ positives are possible.  Note that you can set this variable local to
 specific groups.  Setting it higher in Unix groups is probably a good idea.
 See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
 how to set variables in specific groups."
 specific groups.  Setting it higher in Unix groups is probably a good idea.
 See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
 how to set variables in specific groups."
+  :version "22.1"
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
@@ -6005,6 +6157,7 @@ positives are possible.  Note that you can set this variable local to
 specific groups.  Setting it higher in Emacs or Gnus related groups is
 probably a good idea.  See Info node `(gnus)Group Parameters' and the variable
 `gnus-parameters' on how to set variables in specific groups."
 specific groups.  Setting it higher in Emacs or Gnus related groups is
 probably a good idea.  See Info node `(gnus)Group Parameters' and the variable
 `gnus-parameters' on how to set variables in specific groups."
+  :version "22.1"
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
   :group 'gnus-article-buttons
   :link '(custom-manual "(gnus)Group Parameters")
   :type 'integer)
@@ -6014,6 +6167,7 @@ probably a good idea.  See Info node `(gnus)Group Parameters' and the variable
 The higher the number, the more buttons will appear and the more false
 positives are possible."
   ;; mail addresses, MIDs, URLs for news, ...
 The higher the number, the more buttons will appear and the more false
 positives are possible."
   ;; mail addresses, MIDs, URLs for news, ...
+  :version "22.1"
   :group 'gnus-article-buttons
   :type 'integer)
 
   :group 'gnus-article-buttons
   :type 'integer)
 
@@ -6022,6 +6176,7 @@ positives are possible."
 The higher the number, the more buttons will appear and the more false
 positives are possible."
   ;; stuff handled by `browse-url' or `gnus-button-embedded-url'
 The higher the number, the more buttons will appear and the more false
 positives are possible."
   ;; stuff handled by `browse-url' or `gnus-button-embedded-url'
+  :version "22.1"
   :group 'gnus-article-buttons
   :type 'integer)
 
   :group 'gnus-article-buttons
   :type 'integer)
 
@@ -6034,11 +6189,15 @@ positives are possible."
      1 (>= gnus-button-message-level 0) gnus-button-fetch-group 5)
     ("\\b\\(nntp\\|news\\):\\(//\\)?\\([^'\">\n\t ]+\\)"
      0 (>= gnus-button-message-level 0) gnus-button-fetch-group 3)
      1 (>= gnus-button-message-level 0) gnus-button-fetch-group 5)
     ("\\b\\(nntp\\|news\\):\\(//\\)?\\([^'\">\n\t ]+\\)"
      0 (>= gnus-button-message-level 0) gnus-button-fetch-group 3)
+    ;; RFC 2392 (Don't allow `/' in domain part --> CID)
+    ("\\bmid:\\(//\\)?\\([^'\">\n\t ]+@[^'\">\n\t /]+\\)"
+     0 (>= gnus-button-message-level 0) gnus-button-message-id 2)
     ("\\bin\\( +article\\| +message\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)"
      2 (>= gnus-button-message-level 0) gnus-button-message-id 3)
     ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 2)
     ("\\bin\\( +article\\| +message\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)"
      2 (>= gnus-button-message-level 0) gnus-button-message-id 3)
     ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 2)
-    ("mailto:\\([-a-z.@_+0-9%=?]+\\)"
+    ;; RFC 2368 (The mailto URL scheme)
+    ("\\bmailto:\\([-a-z.@_+0-9%=?&/]+\\)"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
     ("\\bmailto:\\([^ \n\t]+\\)"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
     ("\\bmailto:\\([^ \n\t]+\\)"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
@@ -6056,9 +6215,15 @@ positives are possible."
       gnus-button-ctan-directory-regexp
       "/[-_.a-z0-9]+/[-_./a-z0-9]+[/a-z0-9]\\)")
      1 (>= gnus-button-tex-level 8) gnus-button-handle-ctan 1)
       gnus-button-ctan-directory-regexp
       "/[-_.a-z0-9]+/[-_./a-z0-9]+[/a-z0-9]\\)")
      1 (>= gnus-button-tex-level 8) gnus-button-handle-ctan 1)
-    ;; This is info
-    ("\\binfo:\\(//\\)?\\([^'\">\n\t ]+\\)"
-     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 2)
+    ;; This is info (home-grown style) <info://foo/bar+baz>
+    ("\\binfo://\\([^'\">\n\t ]+\\)"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 1)
+    ;; Info GNOME style <info:foo#bar_baz>
+    ("\\binfo:\\([^('\n\t\r \"><][^'\n\t\r \"><]*\\)"
+     0 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url-gnome 1)
+    ;; Info KDE style <info:(foo)bar baz>
+    ("<\\(info:\\(([^)]+)[^>\n\r]*\\)\\)>"
+     1 (>= gnus-button-emacs-level 1) gnus-button-handle-info-url-kde 2)
     ("\\((Info-goto-node\\|(info\\)[ \t\n]*\\(\"[^\"]*\"\\))" 0
      (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 2)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+i[ \t\n]+d?[ \t\n]?m[ \t\n]+\\([^ ]+ ?[^ ]+\\)[ \t\n]+RET"
     ("\\((Info-goto-node\\|(info\\)[ \t\n]*\\(\"[^\"]*\"\\))" 0
      (>= gnus-button-emacs-level 1) gnus-button-handle-info-url 2)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+i[ \t\n]+d?[ \t\n]?m[ \t\n]+\\([^ ]+ ?[^ ]+\\)[ \t\n]+RET"
@@ -6080,8 +6245,9 @@ positives are possible."
     ("M-x[ \t\n]+apropos-documentation[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos-documentation 1)
     ;; The following entries may lead to many false positives so don't enable
     ("M-x[ \t\n]+apropos-documentation[ \t\n]+RET[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-apropos-documentation 1)
     ;; The following entries may lead to many false positives so don't enable
-    ;; them by default (use a high button level):
-    ("/\\([a-z][-a-z0-9]+\\.el\\)\\>"
+    ;; them by default (use a high button level).
+    ("/\\([a-z][-a-z0-9]+\\.el\\)\\>[^.?]"
+     ;; Exclude [.?] for URLs in gmane.emacs.cvs
      1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
     ("`\\([a-z][-a-z0-9]+\\.el\\)'"
      1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
      1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
     ("`\\([a-z][-a-z0-9]+\\.el\\)'"
      1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1)
@@ -6091,6 +6257,8 @@ positives are possible."
      0 (>= gnus-button-emacs-level 9) gnus-button-handle-symbol 1)
     ("(setq[ \t\n]+\\([a-z][a-z0-9]+-[-a-z0-9]+\\)[ \t\n]+.+)"
      1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-variable 1)
      0 (>= gnus-button-emacs-level 9) gnus-button-handle-symbol 1)
     ("(setq[ \t\n]+\\([a-z][a-z0-9]+-[-a-z0-9]+\\)[ \t\n]+.+)"
      1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-variable 1)
+    ("\\bM-x[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
+     1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-function 1)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+f[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-function 2)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+v[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+f[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
      0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-function 2)
     ("\\b\\(C-h\\|<?[Ff]1>?\\)[ \t\n]+v[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET"
@@ -6099,23 +6267,29 @@ positives are possible."
      ;; Unlike the other regexps we really have to require quoting
      ;; here to determine where it ends.
      1 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3)
      ;; Unlike the other regexps we really have to require quoting
      ;; here to determine where it ends.
      1 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3)
-    ;; This is how URLs _should_ be embedded in text (RFC 1738)...
+    ;; This is how URLs _should_ be embedded in text (RFC 1738, RFC 2396)...
     ("<URL: *\\([^<>]*\\)>"
      1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
     ("<URL: *\\([^<>]*\\)>"
      1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
+    ;; RFC 2396 (2.4.3., delims) ...
+    ("\"URL: *\\([^\"]*\\)\""
+     1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
+    ;; RFC 2396 (2.4.3., delims) ...
+    ("\"URL: *\\([^\"]*\\)\""
+     1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
     ;; Raw URLs.
     (gnus-button-url-regexp
      0 (>= gnus-button-browse-level 0) browse-url 0)
     ;; man pages
     ;; Raw URLs.
     (gnus-button-url-regexp
      0 (>= gnus-button-browse-level 0) browse-url 0)
     ;; man pages
-    ("\\b\\([a-z][a-z]+\\)([1-9])\\W"
+    ("\\b\\([a-z][a-z]+([1-9])\\)\\W"
      0 (and (>= gnus-button-man-level 1) (< gnus-button-man-level 3))
      gnus-button-handle-man 1)
     ;; more man pages: resolv.conf(5), iso_8859-1(7), xterm(1x)
      0 (and (>= gnus-button-man-level 1) (< gnus-button-man-level 3))
      gnus-button-handle-man 1)
     ;; more man pages: resolv.conf(5), iso_8859-1(7), xterm(1x)
-    ("\\b\\([a-z][-_.a-z0-9]+\\)([1-9])\\W"
+    ("\\b\\([a-z][-_.a-z0-9]+([1-9])\\)\\W"
      0 (and (>= gnus-button-man-level 3) (< gnus-button-man-level 5))
      gnus-button-handle-man 1)
     ;; even more: Apache::PerlRun(3pm), PDL::IO::FastRaw(3pm),
     ;; SoWWWAnchor(3iv), XSelectInput(3X11), X(1), X(7)
      0 (and (>= gnus-button-man-level 3) (< gnus-button-man-level 5))
      gnus-button-handle-man 1)
     ;; even more: Apache::PerlRun(3pm), PDL::IO::FastRaw(3pm),
     ;; SoWWWAnchor(3iv), XSelectInput(3X11), X(1), X(7)
-    ("\\b\\([a-z][-+_.:a-z0-9]+\\)([1-9][X1a-z]*)\\W\\|\\b\\(X\\)([1-9])\\W"
+    ("\\b\\(\\(?:[a-z][-+_.:a-z0-9]+([1-9][X1a-z]*)\\)\\|\\b\\(?:X([1-9])\\)\\)\\W"
      0 (>= gnus-button-man-level 5) gnus-button-handle-man 1)
     ;; MID or mail: To avoid too many false positives we don't try to catch
     ;; all kind of allowed MIDs or mail addresses.  Domain part must contain
      0 (>= gnus-button-man-level 5) gnus-button-handle-man 1)
     ;; MID or mail: To avoid too many false positives we don't try to catch
     ;; all kind of allowed MIDs or mail addresses.  Domain part must contain
@@ -6159,7 +6333,9 @@ variable it the real callback function."
      0 (>= gnus-button-browse-level 0) browse-url 0)
     ("^[^:]+:" gnus-button-url-regexp
      0 (>= gnus-button-browse-level 0) browse-url 0)
      0 (>= gnus-button-browse-level 0) browse-url 0)
     ("^[^:]+:" gnus-button-url-regexp
      0 (>= gnus-button-browse-level 0) browse-url 0)
-    ("^[^:]+:" "\\bmailto:\\([-a-z.@_+0-9%=?]+\\)"
+    ("^OpenPGP:.*url=" gnus-button-url-regexp
+     0 (>= gnus-button-browse-level 0) gnus-button-openpgp 0)
+    ("^[^:]+:" "\\bmailto:\\([-a-z.@_+0-9%=?&/]+\\)"
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
     ("^[^:]+:" "\\(<\\(url: \\)?\\(nntp\\|news\\):\\([^>\n ]*\\)>\\)"
      1 (>= gnus-button-message-level 0) gnus-button-message-id 4))
      0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
     ("^[^:]+:" "\\(<\\(url: \\)?\\(nntp\\|news\\):\\([^>\n ]*\\)>\\)"
      1 (>= gnus-button-message-level 0) gnus-button-message-id 4))
@@ -6183,13 +6359,6 @@ HEADER is a regexp to match a header.  For a fuller explanation, see
                               :inline t
                               (integer :tag "Regexp group")))))
 
                               :inline t
                               (integer :tag "Regexp group")))))
 
-(defvar gnus-button-regexp nil)
-(defvar gnus-button-marker-list nil)
-;; Regexp matching any of the regexps from `gnus-button-alist'.
-
-(defvar gnus-button-last nil)
-;; The value of `gnus-button-alist' when `gnus-button-regexp' was build.
-
 ;;; Commands:
 
 (defun gnus-article-push-button (event)
 ;;; Commands:
 
 (defun gnus-article-push-button (event)
@@ -6241,51 +6410,42 @@ do the highlighting.  See the documentation for those functions."
 (defun gnus-article-highlight-headers ()
   "Highlight article headers as specified by `gnus-header-face-alist'."
   (interactive)
 (defun gnus-article-highlight-headers ()
   "Highlight article headers as specified by `gnus-header-face-alist'."
   (interactive)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (save-restriction
-      (let ((alist gnus-header-face-alist)
-           (buffer-read-only nil)
-           (case-fold-search t)
-           (inhibit-point-motion-hooks t)
-           entry regexp header-face field-face from hpoints fpoints)
-       (article-narrow-to-head)
-       (while (setq entry (pop alist))
-         (goto-char (point-min))
-         (setq regexp (concat "^\\("
-                              (if (string-equal "" (nth 0 entry))
-                                  "[^\t ]"
-                                (nth 0 entry))
-                              "\\)")
-               header-face (nth 1 entry)
-               field-face (nth 2 entry))
-         (while (and (re-search-forward regexp nil t)
-                     (not (eobp)))
-           (beginning-of-line)
-           (setq from (point))
-           (unless (search-forward ":" nil t)
-             (forward-char 1))
-           (when (and header-face
-                      (not (memq (point) hpoints)))
-             (push (point) hpoints)
-             (gnus-put-text-property from (point) 'face header-face))
-           (when (and field-face
-                      (not (memq (setq from (point)) fpoints)))
-             (push from fpoints)
-             (if (re-search-forward "^[^ \t]" nil t)
-                 (forward-char -2)
-               (goto-char (point-max)))
-             (gnus-put-text-property from (point) 'face field-face))))))))
+  (gnus-with-article-headers
+    (let (regexp header-face field-face from hpoints fpoints)
+      (dolist (entry gnus-header-face-alist)
+       (goto-char (point-min))
+       (setq regexp (concat "^\\("
+                            (if (string-equal "" (nth 0 entry))
+                                "[^\t ]"
+                              (nth 0 entry))
+                            "\\)")
+             header-face (nth 1 entry)
+             field-face (nth 2 entry))
+       (while (and (re-search-forward regexp nil t)
+                   (not (eobp)))
+         (beginning-of-line)
+         (setq from (point))
+         (unless (search-forward ":" nil t)
+           (forward-char 1))
+         (when (and header-face
+                    (not (memq (point) hpoints)))
+           (push (point) hpoints)
+           (gnus-put-text-property from (point) 'face header-face))
+         (when (and field-face
+                    (not (memq (setq from (point)) fpoints)))
+           (push from fpoints)
+           (if (re-search-forward "^[^ \t]" nil t)
+               (forward-char -2)
+             (goto-char (point-max)))
+           (gnus-put-text-property from (point) 'face field-face)))))))
 
 (defun gnus-article-highlight-signature ()
   "Highlight the signature in an article.
 It does this by highlighting everything after
 `gnus-signature-separator' using `gnus-signature-face'."
   (interactive)
 
 (defun gnus-article-highlight-signature ()
   "Highlight the signature in an article.
 It does this by highlighting everything after
 `gnus-signature-separator' using `gnus-signature-face'."
   (interactive)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil)
-         (inhibit-point-motion-hooks t))
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t))
       (save-restriction
        (when (and gnus-signature-face
                   (gnus-article-narrow-to-signature))
       (save-restriction
        (when (and gnus-signature-face
                   (gnus-article-narrow-to-signature))
@@ -6307,10 +6467,8 @@ It does this by highlighting everything after
 \"External references\" are things like Message-IDs and URLs, as
 specified by `gnus-button-alist'."
   (interactive (list 'force))
 \"External references\" are things like Message-IDs and URLs, as
 specified by `gnus-button-alist'."
   (interactive (list 'force))
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil)
-         (inhibit-point-motion-hooks t)
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t)
          (case-fold-search t)
          (alist gnus-button-alist)
          beg entry regexp)
          (case-fold-search t)
          (alist gnus-button-alist)
          beg entry regexp)
@@ -6351,40 +6509,31 @@ specified by `gnus-button-alist'."
 (defun gnus-article-add-buttons-to-head ()
   "Add buttons to the head of the article."
   (interactive)
 (defun gnus-article-add-buttons-to-head ()
   "Add buttons to the head of the article."
   (interactive)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (save-restriction
-      (let ((buffer-read-only nil)
-           (inhibit-point-motion-hooks t)
-           (case-fold-search t)
-           (alist gnus-header-button-alist)
-           entry beg end)
-       (article-narrow-to-head)
-       (while alist
-         ;; Each alist entry.
-         (setq entry (car alist)
-               alist (cdr alist))
-         (goto-char (point-min))
-         (while (re-search-forward (car entry) nil t)
-           ;; Each header matching the entry.
-           (setq beg (match-beginning 0))
-           (setq end (or (and (re-search-forward "^[^ \t]" nil t)
-                              (match-beginning 0))
-                         (point-max)))
-           (goto-char beg)
-           (while (re-search-forward (eval (nth 1 entry)) end t)
-             ;; Each match within a header.
-             (let* ((entry (cdr entry))
-                    (start (match-beginning (nth 1 entry)))
-                    (end (match-end (nth 1 entry)))
-                    (form (nth 2 entry)))
-               (goto-char (match-end 0))
-               (when (eval form)
-                 (gnus-article-add-button
-                  start end (nth 3 entry)
-                  (buffer-substring (match-beginning (nth 4 entry))
-                                    (match-end (nth 4 entry)))))))
-           (goto-char end)))))))
+  (gnus-with-article-headers
+    (let (beg end)
+      (dolist (entry gnus-header-button-alist)
+       ;; Each alist entry.
+       (goto-char (point-min))
+       (while (re-search-forward (car entry) nil t)
+         ;; Each header matching the entry.
+         (setq beg (match-beginning 0))
+         (setq end (or (and (re-search-forward "^[^ \t]" nil t)
+                            (match-beginning 0))
+                       (point-max)))
+         (goto-char beg)
+         (while (re-search-forward (eval (nth 1 entry)) end t)
+           ;; Each match within a header.
+           (let* ((entry (cdr entry))
+                  (start (match-beginning (nth 1 entry)))
+                  (end (match-end (nth 1 entry)))
+                  (form (nth 2 entry)))
+             (goto-char (match-end 0))
+             (when (eval form)
+               (gnus-article-add-button
+                start end (nth 3 entry)
+                (buffer-substring (match-beginning (nth 4 entry))
+                                  (match-end (nth 4 entry)))))))
+         (goto-char end))))))
 
 ;;; External functions:
 
 
 ;;; External functions:
 
@@ -6405,15 +6554,12 @@ specified by `gnus-button-alist'."
 ;;; Internal functions:
 
 (defun gnus-article-set-globals ()
 ;;; Internal functions:
 
 (defun gnus-article-set-globals ()
-  (save-excursion
-    (set-buffer gnus-summary-buffer)
+  (with-current-buffer gnus-summary-buffer
     (gnus-set-global-variables)))
 
 (defun gnus-signature-toggle (end)
     (gnus-set-global-variables)))
 
 (defun gnus-signature-toggle (end)
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil)
-         (inhibit-point-motion-hooks t))
+  (gnus-with-article-buffer
+    (let ((inhibit-point-motion-hooks t))
       (if (text-property-any end (point-max) 'article-type 'signature)
          (progn
            (gnus-delete-wash-type 'signature)
       (if (text-property-any end (point-max) 'article-type 'signature)
          (progn
            (gnus-delete-wash-type 'signature)
@@ -6449,7 +6595,7 @@ specified by `gnus-button-alist'."
           (fun (nth 3 entry))
           (args (mapcar (lambda (group)
                           (let ((string (match-string group)))
           (fun (nth 3 entry))
           (args (mapcar (lambda (group)
                           (let ((string (match-string group)))
-                            (gnus-set-text-properties
+                            (set-text-properties
                              0 (length string) nil string)
                             string))
                         (nthcdr 4 entry))))
                              0 (length string) nil string)
                             string))
                         (nthcdr 4 entry))))
@@ -6504,10 +6650,15 @@ specified by `gnus-button-alist'."
 
 (defun gnus-button-handle-man (url)
   "Fetch a man page."
 
 (defun gnus-button-handle-man (url)
   "Fetch a man page."
+  (gnus-message 9 "`%s' `%s'" gnus-button-man-handler url)
+  (when (eq gnus-button-man-handler 'woman)
+    (setq url (gnus-replace-in-string url "([1-9][X1a-z]*).*\\'" "")))
+  (gnus-message 9 "`%s' `%s'" gnus-button-man-handler url)
   (funcall gnus-button-man-handler url))
 
 (defun gnus-button-handle-info-url (url)
   "Fetch an info URL."
   (funcall gnus-button-man-handler url))
 
 (defun gnus-button-handle-info-url (url)
   "Fetch an info URL."
+  (setq url (mm-subst-char-in-string ?+ ?\  url))
   (cond
    ((string-match "^\\([^:/]+\\)?/\\(.*\\)" url)
     (gnus-info-find-node
   (cond
    ((string-match "^\\([^:/]+\\)?/\\(.*\\)" url)
     (gnus-info-find-node
@@ -6521,6 +6672,24 @@ specified by `gnus-button-alist'."
     (gnus-info-find-node url))
    (t (error "Can't parse %s" url))))
 
     (gnus-info-find-node url))
    (t (error "Can't parse %s" url))))
 
+(defun gnus-button-handle-info-url-gnome (url)
+  "Fetch GNOME style info URL."
+  (setq url (mm-subst-char-in-string ?_ ?\  url))
+  (if (string-match "\\([^#]+\\)#?\\(.*\\)" url)
+      (gnus-info-find-node
+       (concat "("
+              (gnus-url-unhex-string
+                (match-string 1 url))
+              ")"
+              (or (gnus-url-unhex-string
+                   (match-string 2 url))
+                  "Top")))
+    (error "Can't parse %s" url)))
+
+(defun gnus-button-handle-info-url-kde (url)
+  "Fetch KDE style info URL."
+  (gnus-info-find-node (gnus-url-unhex-string url)))
+
 (defun gnus-button-handle-info-keystrokes (url)
   "Call `info' when pushing the corresponding URL button."
   ;; For links like `C-h i d m gnus RET', `C-h i d m CC Mode RET'.
 (defun gnus-button-handle-info-keystrokes (url)
   "Call `info' when pushing the corresponding URL button."
   ;; For links like `C-h i d m gnus RET', `C-h i d m CC Mode RET'.
@@ -6528,10 +6697,16 @@ specified by `gnus-button-alist'."
   (Info-directory)
   (Info-menu url))
 
   (Info-directory)
   (Info-menu url))
 
+(defun gnus-button-openpgp (url)
+  "Retrieve and add an OpenPGP key given URL from an OpenPGP header."
+  (with-temp-buffer
+    (mm-url-insert-file-contents-external url)
+    (pgg-snarf-keys-region (point-min) (point-max))
+    (pgg-display-output-buffer nil nil nil)))
+
 (defun gnus-button-message-id (message-id)
   "Fetch MESSAGE-ID."
 (defun gnus-button-message-id (message-id)
   "Fetch MESSAGE-ID."
-  (save-excursion
-    (set-buffer gnus-summary-buffer)
+  (with-current-buffer gnus-summary-buffer
     (gnus-summary-refer-article message-id)))
 
 (defun gnus-button-fetch-group (address)
     (gnus-summary-refer-article message-id)))
 
 (defun gnus-button-fetch-group (address)
@@ -6577,12 +6752,14 @@ specified by `gnus-button-alist'."
   (when (string-match "mailto:/*\\(.*\\)" url)
     (setq url (substring url (match-beginning 1) nil)))
   (let (to args subject func)
   (when (string-match "mailto:/*\\(.*\\)" url)
     (setq url (substring url (match-beginning 1) nil)))
   (let (to args subject func)
-    (if (string-match (regexp-quote "?") url)
-       (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
-             args (gnus-url-parse-query-string
-                   (substring url (match-end 0) nil) t))
-      (setq to (gnus-url-unhex-string url)))
-    (setq args (cons (list "to" to) args)
+    (setq args (gnus-url-parse-query-string
+               (if (string-match "^\\?" url)
+                   (substring url 1)
+                 (if (string-match "^\\([^?]+\\)\\?\\(.*\\)" url)
+                     (concat "to=" (match-string 1 url) "&"
+                             (match-string 2 url))
+                   (concat "to=" url)))
+               t)
          subject (cdr-safe (assoc "subject" args)))
     (gnus-msg-mail)
     (while args
          subject (cdr-safe (assoc "subject" args)))
     (gnus-msg-mail)
     (while args
@@ -6590,7 +6767,9 @@ specified by `gnus-button-alist'."
       (if (fboundp func)
          (funcall func)
        (message-position-on-field (caar args)))
       (if (fboundp func)
          (funcall func)
        (message-position-on-field (caar args)))
-      (insert (mapconcat 'identity (cdar args) ", "))
+      (insert (gnus-replace-in-string
+              (mapconcat 'identity (reverse (cdar args)) ", ")
+              "\r\n" "\n" t))
       (setq args (cdr args)))
     (if subject
        (message-goto-body)
       (setq args (cdr args)))
     (if subject
        (message-goto-body)
@@ -6606,20 +6785,26 @@ specified by `gnus-button-alist'."
 (defvar gnus-prev-page-line-format "%{%(Previous page...%)%}\n")
 
 (defvar gnus-prev-page-map
 (defvar gnus-prev-page-line-format "%{%(Previous page...%)%}\n")
 
 (defvar gnus-prev-page-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map gnus-mouse-2 'gnus-button-prev-page)
+    (define-key map "\r" 'gnus-button-prev-page)
+    map))
+
+(defvar gnus-next-page-map
   (let ((map (make-sparse-keymap)))
     (unless (>= emacs-major-version 21)
       ;; XEmacs doesn't care.
       (set-keymap-parent map gnus-article-mode-map))
   (let ((map (make-sparse-keymap)))
     (unless (>= emacs-major-version 21)
       ;; XEmacs doesn't care.
       (set-keymap-parent map gnus-article-mode-map))
-    (define-key map gnus-mouse-2 'gnus-button-prev-page)
-    (define-key map "\r" 'gnus-button-prev-page)
+    (define-key map gnus-mouse-2 'gnus-button-next-page)
+    (define-key map "\r" 'gnus-button-next-page)
     map))
 
 (defun gnus-insert-prev-page-button ()
   (let ((b (point))
     map))
 
 (defun gnus-insert-prev-page-button ()
   (let ((b (point))
-       (buffer-read-only nil))
+       (inhibit-read-only t))
     (gnus-eval-format
      gnus-prev-page-line-format nil
     (gnus-eval-format
      gnus-prev-page-line-format nil
-     `(,@(gnus-local-map-property gnus-prev-page-map)
+     `(keymap ,gnus-prev-page-map
         gnus-prev t
         gnus-callback gnus-article-button-prev-page
         article-type annotation))
         gnus-prev t
         gnus-callback gnus-article-button-prev-page
         article-type annotation))
@@ -6631,24 +6816,6 @@ specified by `gnus-button-alist'."
      :action 'gnus-button-prev-page
      :button-keymap gnus-prev-page-map)))
 
      :action 'gnus-button-prev-page
      :button-keymap gnus-prev-page-map)))
 
-(defvar gnus-prev-page-map
-  (let ((map (make-sparse-keymap)))
-    (unless (>= emacs-major-version 21)
-      ;; XEmacs doesn't care.
-      (set-keymap-parent map gnus-article-mode-map))
-    (define-key map gnus-mouse-2 'gnus-button-prev-page)
-    (define-key map "\r" 'gnus-button-prev-page)
-    map))
-
-(defvar gnus-next-page-map
-  (let ((map (make-sparse-keymap)))
-    (unless (>= emacs-major-version 21)
-      ;; XEmacs doesn't care.
-      (set-keymap-parent map gnus-article-mode-map))
-    (define-key map gnus-mouse-2 'gnus-button-next-page)
-    (define-key map "\r" 'gnus-button-next-page)
-    map))
-
 (defun gnus-button-next-page (&optional args more-args)
   "Go to the next page."
   (interactive)
 (defun gnus-button-next-page (&optional args more-args)
   "Go to the next page."
   (interactive)
@@ -6667,9 +6834,9 @@ specified by `gnus-button-alist'."
 
 (defun gnus-insert-next-page-button ()
   (let ((b (point))
 
 (defun gnus-insert-next-page-button ()
   (let ((b (point))
-       (buffer-read-only nil))
+       (inhibit-read-only t))
     (gnus-eval-format gnus-next-page-line-format nil
     (gnus-eval-format gnus-next-page-line-format nil
-                     `(,@(gnus-local-map-property gnus-next-page-map)
+                     `(keymap ,gnus-next-page-map
                          gnus-next t
                          gnus-callback gnus-article-button-next-page
                          article-type annotation))
                          gnus-next t
                          gnus-callback gnus-article-button-next-page
                          article-type annotation))
@@ -6702,7 +6869,7 @@ specified by `gnus-button-alist'."
   "List of methods used to decode headers.
 
 This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
   "List of methods used to decode headers.
 
 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
+is FUNCTION, FUNCTION will be applied to all newsgroups.  If item is a
 \(REGEXP . FUNCTION), FUNCTION will be only apply to the newsgroups
 whose names match REGEXP.
 
 \(REGEXP . FUNCTION), FUNCTION will be only apply to the newsgroups
 whose names match REGEXP.
 
@@ -6841,7 +7008,7 @@ For example:
          (setq references
              (or (mail-header-references gnus-current-headers) ""))
          (set-buffer gnus-article-buffer)
          (setq references
              (or (mail-header-references gnus-current-headers) ""))
          (set-buffer gnus-article-buffer)
-         (let* ((buffer-read-only nil)
+         (let* ((inhibit-read-only t)
                 (headers
                  (mapcar (lambda (field)
                            (and (save-restriction
                 (headers
                  (mapcar (lambda (field)
                            (and (save-restriction
@@ -6905,8 +7072,6 @@ For example:
 
 (defvar gnus-mime-security-button-map
   (let ((map (make-sparse-keymap)))
 
 (defvar gnus-mime-security-button-map
   (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      (set-keymap-parent map gnus-article-mode-map))
     (define-key map gnus-mouse-2 'gnus-article-push-button)
     (define-key map "\r" 'gnus-article-press-button)
     map))
     (define-key map gnus-mouse-2 'gnus-article-push-button)
     (define-key map "\r" 'gnus-article-press-button)
     map))
@@ -6921,7 +7086,7 @@ For example:
 (defun gnus-mime-security-verify-or-decrypt (handle)
   (mm-remove-parts (cdr handle))
   (let ((region (mm-handle-multipart-ctl-parameter handle 'gnus-region))
 (defun gnus-mime-security-verify-or-decrypt (handle)
   (mm-remove-parts (cdr handle))
   (let ((region (mm-handle-multipart-ctl-parameter handle 'gnus-region))
-       point buffer-read-only)
+       point (inhibit-read-only t))
     (if region
        (goto-char (car region)))
     (save-restriction
     (if region
        (goto-char (car region)))
     (save-restriction
@@ -6951,7 +7116,7 @@ For example:
                 (not (get-text-property (point) 'gnus-mime-details)))
                (gnus-mime-security-button-line-format
                 (get-text-property (point) 'gnus-line-format))
                 (not (get-text-property (point) 'gnus-mime-details)))
                (gnus-mime-security-button-line-format
                 (get-text-property (point) 'gnus-line-format))
-               buffer-read-only)
+               (inhibit-read-only t))
            (forward-char -1)
            (while (eq (get-text-property (point) 'gnus-line-format)
                       gnus-mime-security-button-line-format)
            (forward-char -1)
            (while (eq (get-text-property (point) 'gnus-line-format)
                       gnus-mime-security-button-line-format)
@@ -7013,7 +7178,7 @@ For example:
     (gnus-eval-format
      gnus-mime-security-button-line-format
      gnus-mime-security-button-line-format-alist
     (gnus-eval-format
      gnus-mime-security-button-line-format
      gnus-mime-security-button-line-format-alist
-     `(,@(gnus-local-map-property gnus-mime-security-button-map)
+     `(keymap ,gnus-mime-security-button-map
         gnus-callback gnus-mime-security-press-button
         gnus-line-format ,gnus-mime-security-button-line-format
         gnus-mime-details ,gnus-mime-security-button-pressed
         gnus-callback gnus-mime-security-press-button
         gnus-line-format ,gnus-mime-security-button-line-format
         gnus-mime-details ,gnus-mime-security-button-pressed
@@ -7061,4 +7226,5 @@ For example:
 
 (run-hooks 'gnus-art-load-hook)
 
 
 (run-hooks 'gnus-art-load-hook)
 
+;;; arch-tag: 2654516f-6279-48f9-a83b-05c1fa450c33
 ;;; gnus-art.el ends here
 ;;; gnus-art.el ends here