Synch with Oort Gnus.
[elisp/gnus.git-] / lisp / gnus-art.el
index 35e5f32..58008fe 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-art.el --- article mode commands for Semi-gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
     "^X-UIDL:" "^MIME-Version:" "^Return-Path:" "^In-Reply-To:"
     "^Content-Type:" "^Content-Transfer-Encoding:" "^X-WebTV-Signature:"
     "^X-MimeOLE:" "^X-MSMail-Priority:" "^X-Priority:" "^X-Loop:"
-    "^X-Authentication-Warning:" "^X-MIME-Autoconverted:" "^X-Face:"
+    "^X-Authentication-Warning:" "^X-MIME-Autoconverted:" "^X-Face"
     "^X-Attribution:" "^X-Originating-IP:" "^Delivered-To:"
     "^NNTP-[-A-Za-z]+:" "^Distribution:" "^X-no-archive:" "^X-Trace:"
     "^X-Complaints-To:" "^X-NNTP-Posting-Host:" "^X-Orig.*:"
     "^X-Abuse-Info:" "^X-From_:" "^X-Accept-Language:" "^Errors-To:"
     "^X-BeenThere:" "^X-Mailman-Version:" "^List-Help:" "^List-Post:"
     "^List-Subscribe:" "^List-Id:" "^List-Unsubscribe:" "^List-Archive:"
-     "^X-Content-length:" "^X-Posting-Agent:" "^Original-Received:")
+     "^X-Content-length:" "^X-Posting-Agent:" "^Original-Received:"
+     "^X-Request-PGP:" "^X-Fingerprint:" "^X-WRIEnvto:" "^X-WRIEnvfrom:"
+     "^X-Virus-Scanned:" "^X-Delivery-Agent:" "^Posted-Date:" "^X-Gateway:"
+     "^X-Local-Origin:" "^X-Local-Destination:" "^X-UserInfo1:"
+     "^X-Received-Date:")
   "*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."
@@ -234,21 +238,18 @@ regexp.  If it matches, the text in question is not a signature."
 (defcustom gnus-article-x-face-command
   (cond
    ((featurep 'xemacs)
-    (if (or (featurep 'xface)
-           (featurep 'xpm))
-       'gnus-xmas-article-display-xface
+    (if (or (gnus-image-type-available-p 'xface)
+           (gnus-image-type-available-p 'pbm))
+       'gnus-display-x-face-in-from
       "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | ee -"))
    ((and (fboundp 'image-type-available-p)
         (module-installed-p 'x-face-e21))
     'x-face-decode-message-header)
-   ((and (fboundp 'image-type-available-p)
-        (image-type-available-p 'xbm))
-    'gnus-article-display-xface)
+   ((gnus-image-type-available-p 'pbm)
+    'gnus-display-x-face-in-from)
    ((and window-system
         (module-installed-p 'x-face-mule))
     'x-face-mule-gnus-article-display-x-face)
-   (gnus-article-compface-xbm
-    "{ echo '/* Width=48, Height=48 */'; uncompface; } | display -")
    (t
     "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | \
 display -"))
@@ -264,10 +265,9 @@ asynchronously.     The compressed face will be piped to this command."
              (delq nil
                    (list
                     'string
-                    (if (and (featurep 'xemacs)
-                             (or (featurep 'xface)
-                                 (featurep 'xpm)))
-                        '(function-item gnus-xmas-article-display-xface))
+                    (if (or (gnus-image-type-available-p 'xface)
+                            (gnus-image-type-available-p 'pbm))
+                        '(function-item gnus-display-x-face-in-from))
                     (if (and x-face-e21
                              (fboundp 'image-type-available-p))
                         '(function-item
@@ -278,6 +278,7 @@ asynchronously.      The compressed face will be piped to this command."
                           x-face-mule-gnus-article-display-x-face))
                     'function))))
   ;;:version "21.1"
+  :group 'gnus-picon
   :group 'gnus-article-washing)
 
 (defcustom gnus-article-x-face-too-ugly nil
@@ -314,25 +315,47 @@ regular expression to match the banner in `gnus-article-banner-alist'.
 A string is used as a regular expression to match the banner
 directly.")
 
+(defcustom gnus-article-address-banner-alist nil
+  "Alist of mail addresses and banners.
+Each element has the form (ADDRESS . BANNER), where ADDRESS is a regexp
+to match a mail address in the From: header, BANNER is one of a symbol
+`signature', an item in `gnus-article-banner-alist', a regexp and nil.
+If ADDRESS matches author's mail address, it will remove things like
+advertisements.  For example:
+
+\((\"@yoo-hoo\\\\.co\\\\.jp\\\\'\" . \"\\n_+\\nDo You Yoo-hoo!\\\\?\\n.*\\n.*\\n\"))
+"
+  :type '(repeat
+         (cons
+          (regexp :tag "Address")
+          (choice :tag "Banner" :value nil
+                  (const :tag "Remove signature" signature)
+                  (symbol :tag "Item in `gnus-article-banner-alist'" none)
+                  regexp
+                  (const :tag "None" nil))))
+  :group 'gnus-article-washing)
+
 (defcustom gnus-emphasis-alist
   (let ((format
-        "\\(\\s-\\|^\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-,;:\"]\\s-\\|[?!.]+\\s-\\|\\s)\\)")
+        "\\(\\s-\\|^\\|\\=\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\([-,.;:!?\"]\\|\\s)\\)+\\s-\\|[?!.]\\s-\\|\\s)\\|\\s-\\)")
        (types
-        '(("_" "_" underline)
+        '(("\\*" "\\*" bold)
+          ("_" "_" underline)
           ("/" "/" italic)
-          ("\\*" "\\*" bold)
           ("_/" "/_" underline-italic)
           ("_\\*" "\\*_" underline-bold)
           ("\\*/" "/\\*" bold-italic)
           ("_\\*/" "/\\*_" underline-bold-italic))))
-    `(("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
-       2 3 gnus-emphasis-underline)
-      ,@(mapcar
+    `(,@(mapcar
         (lambda (spec)
           (list
            (format format (car spec) (car (cdr spec)))
            2 3 (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
-        types)))
+        types)
+       ("\\(\\s-\\|^\\)\\(-\\(\\(\\w\\|-[^-]\\)+\\)-\\)\\(\\s-\\|[?!.,;]\\)"
+        2 3 gnus-emphasis-strikethru)
+       ("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
+        2 3 gnus-emphasis-underline)))
   "*Alist that says how to fontify certain phrases.
 Each item looks like this:
 
@@ -386,7 +409,11 @@ and the latter avoids underlining any whitespace at all."
 (defface gnus-emphasis-underline-bold-italic
   '((t (:bold t :italic t :underline t)))
   "Face used for displaying underlined bold italic emphasized text.
-Esample: (_/*word*/_)."
+Example: (_/*word*/_)."
+  :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-strikethru '((t (:strikethru t)))
+  "Face used for displaying strike-through text (-word-)."
   :group 'gnus-article-emphasis)
 
 (defface gnus-emphasis-highlight-words
@@ -717,6 +744,7 @@ displayed by the first non-nil matching CONTENT face."
     ("\225" "*")
     ("\226" "-")
     ("\227" "--")
+    ("\230" "-")                       ; This might not be correct.
     ("\231" "(TM)")
     ("\233" ">")
     ("\234" "oe")
@@ -745,6 +773,32 @@ To see e.g. security buttons you could set this to
   :group 'gnus-article-mime
   :type '(repeat regexp))
 
+(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'."
+  :group 'gnus-article-various
+  :type '(choice (item :tag "None" :value nil)
+                string))
+
+(defcustom gnus-picon-databases '("/usr/lib/picon" "/usr/local/faces")
+  "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"
+  :type '(repeat directory)
+  :link '(url-link :tag "download" 
+                  "http://www.cs.indiana.edu/picons/ftp/index.html")
+  :link '(custom-manual "(gnus)Picons")
+  :group 'gnus-picon)
+
+(defun gnus-picons-installed-p ()
+  "Say whether picons are installed on your machine."
+  (let ((installed nil))
+    (dolist (database gnus-picon-databases)
+      (when (file-exists-p database)
+       (setq installed t)))
+    installed))
+
 (defcustom gnus-article-mime-part-function nil
   "Function called with a MIME handle as the argument.
 This is meant for people who want to do something automatic based
@@ -793,28 +847,13 @@ used."
     ("toggle display" . gnus-article-press-button)
     ("toggle display" . gnus-article-view-part-as-charset)
     ("view as type" . gnus-mime-view-part-as-type)
-    ("internalize type" . gnus-mime-internalize-part)
-    ("externalize type" . gnus-mime-externalize-part))
+    ("view internally" . gnus-mime-view-part-internally)
+    ("view externally" . gnus-mime-view-part-externally))
   "An alist of actions that run on the MIME attachment."
   :group 'gnus-article-mime
   :type '(repeat (cons (string :tag "name")
                       (function))))
 
-(defcustom gnus-mime-action-alist
-  '(("save to file" . gnus-mime-save-part)
-    ("display as text" . gnus-mime-inline-part)
-    ("view the part" . gnus-mime-view-part)
-    ("pipe to command" . gnus-mime-pipe-part)
-    ("toggle display" . gnus-article-press-button)
-    ("view as type" . gnus-mime-view-part-as-type)
-    ("internalize type" . gnus-mime-internalize-part)
-    ("externalize type" . gnus-mime-externalize-part))
-  "An alist of actions that run on the MIME attachment."
-  :version "21.1"
-  :group 'gnus-article-mime
-  :type '(repeat (cons (string :tag "name")
-                      (function))))
-
 ;;;
 ;;; The treatment variables
 ;;;
@@ -853,7 +892,7 @@ See Info node `(gnus)Customizing Articles'."
 (defcustom gnus-treat-buttonize 100000
   "Add buttons.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles'."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 (put 'gnus-treat-buttonize 'highlight t)
@@ -861,7 +900,7 @@ See the manual for details."
 (defcustom gnus-treat-buttonize-head 'head
   "Add buttons to the head.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-buttonize-head 'highlight t)
@@ -873,7 +912,7 @@ See the manual for details."
        50000)
   "Emphasize text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 (put 'gnus-treat-emphasize 'highlight t)
@@ -881,63 +920,70 @@ See the manual for details."
 (defcustom gnus-treat-strip-cr nil
   "Remove carriage returns.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-unsplit-urls nil
+  "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."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-leading-whitespace nil
   "Remove leading whitespace in headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-hide-headers 'head
   "Hide headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-hide-boring-headers nil
   "Hide boring headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-hide-signature nil
   "Hide the signature.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-fill-article nil
   "Fill the article.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-hide-citation nil
   "Hide cited text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-hide-citation-maybe nil
   "Hide cited text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-strip-list-identifiers 'head
   "Strip list identifiers from `gnus-list-identifiers`.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
@@ -945,14 +991,14 @@ See the manual for details."
 (defcustom gnus-treat-strip-pgp t
   "Strip PGP signatures.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-strip-pem nil
   "Strip PEM signatures.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
@@ -960,14 +1006,14 @@ See the manual for details."
   "Strip banners from articles.
 The banner to be stripped is specified in the `banner' group parameter.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-highlight-headers 'head
   "Highlight the headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-highlight-headers 'highlight t)
@@ -975,7 +1021,7 @@ See the manual for details."
 (defcustom gnus-treat-highlight-citation t
   "Highlight cited text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 (put 'gnus-treat-highlight-citation 'highlight t)
@@ -983,42 +1029,42 @@ See the manual for details."
 (defcustom gnus-treat-date-ut nil
   "Display the Date in UT (GMT).
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-date-local nil
   "Display the Date in the local timezone.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-date-english nil
   "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 the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-date-lapsed nil
   "Display the Date header in a way that says how much time has elapsed.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-date-original nil
   "Display the date in the original timezone.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-date-iso8601 nil
   "Display the date in the ISO8601 format.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
@@ -1027,14 +1073,14 @@ See the manual for details."
   "Display the date in a user-defined format.
 The format is defined by the `gnus-article-time-format' variable.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
 (defcustom gnus-treat-strip-headers-in-body t
   "Strip the X-No-Archive header line from the beginning of the body.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
@@ -1042,53 +1088,116 @@ See the manual for details."
 (defcustom gnus-treat-strip-trailing-blank-lines nil
   "Strip trailing blank lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-strip-leading-blank-lines nil
   "Strip leading blank lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-strip-multiple-blank-lines nil
   "Strip multiple blank lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-unfold-headers 'head
+  "Unfold folded header lines.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fold-headers nil
+  "Fold headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-fold-newsgroups 'head
+  "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."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-overstrike t
   "Treat overstrike highlighting.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 (put 'gnus-treat-overstrike 'highlight t)
 
 (defcustom gnus-treat-display-xface
-  (and (or (and (fboundp 'image-type-available-p)
+  (and (not noninteractive)
+       (or (and (fboundp 'image-type-available-p)
                (image-type-available-p 'xbm)
                (string-match "^0x" (shell-command-to-string "uncompface")))
-          (and (featurep 'xemacs) (featurep 'xface))
+          (and (featurep 'xemacs)
+               (featurep 'xface))
           (eq 'x-face-mule-gnus-article-display-x-face
               gnus-article-x-face-command))
        'head)
   "Display X-Face headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)X-Face' for details."
   :group 'gnus-article-treat
   ;;:version "21.1"
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-display-xface 'highlight t)
 
+(defcustom gnus-article-should-use-smiley-mule
+  (not (or (featurep 'xemacs)
+          (gnus-image-type-available-p 'xpm)
+          (gnus-image-type-available-p 'pbm)))
+  "If non-nil, gnus uses `smiley-mule' for displaying smileys rather than
+`smiley'.  It defaults to t when Emacs 20 or earlier is running.
+`smiley-mule' is boundled in BITMAP-MULE package.  You can set it to t
+even if you are using Emacs 21+.  It has no effect on XEmacs."
+  :group 'gnus-article-various
+  :type 'boolean
+  :get (lambda (symbol)
+        (and (default-value symbol)
+             (not (featurep 'xemacs))
+             (module-installed-p 'smiley-mule)
+             t))
+  :set (lambda (symbol value)
+        (set-default symbol (and value
+                                 (not (featurep 'xemacs))
+                                 (module-installed-p 'smiley-mule)
+                                 t))))
+
+(defvar gnus-article-smiley-mule-loaded-p nil
+  "Internal variable used to say whether `smiley-mule' is loaded (whether
+smiley functions are not overridden by `smiley').")
+
+(defcustom gnus-treat-display-grey-xface
+  (and (not noninteractive)
+       (or (featurep 'xemacs)
+          (and (fboundp 'display-images-p)
+               (display-images-p)))
+       (string-match "^0x" (shell-command-to-string "uncompface"))
+       t)
+  "Display grey X-Face headers.
+Valid values are nil, t."
+  :group 'gnus-article-treat
+  :version "21.3"
+  :type 'boolean)
+(put 'gnus-treat-display-grey-xface 'highlight t)
+
 (defcustom gnus-treat-display-smileys
   (if (or (and (featurep 'xemacs)
               (featurep 'xpm))
-         (and (fboundp 'image-type-available-p)
-              (image-type-available-p 'pbm))
+         (gnus-image-type-available-p 'xpm)
+         (gnus-image-type-available-p 'pbm)
          (and (not (featurep 'xemacs))
               window-system
               (module-installed-p 'smiley-mule)))
@@ -1096,24 +1205,74 @@ See the manual for details."
     nil)
   "Display smileys.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)Smileys' for details."
   :group 'gnus-article-treat
   ;;:version "21.1"
   :type gnus-article-treat-custom)
 (put 'gnus-treat-display-smileys 'highlight t)
 
-(defcustom gnus-treat-display-picons (if (featurep 'xemacs) 'head nil)
-  "Display picons.
+(defcustom gnus-treat-from-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in the From header.
+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."
+  :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(info-link "(gnus)Customizing Articles")
+  :link '(info-link "(gnus)Picons")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-from-picon 'highlight t)
+
+(defcustom gnus-treat-mail-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in To and Cc headers.
+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."
+  :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(info-link "(gnus)Customizing Articles")
+  :link '(info-link "(gnus)Picons")
+  :type gnus-article-treat-head-custom)
+(put 'gnus-treat-mail-picon 'highlight t)
+
+(defcustom gnus-treat-newsgroups-picon
+  (if (and (gnus-image-type-available-p 'xpm)
+          (gnus-picons-installed-p))
+      'head nil)
+  "Display picons in the Newsgroups and Followup-To headers.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)Picons' for details."
   :group 'gnus-article-treat
+  :group 'gnus-picon
+  :link '(info-link "(gnus)Customizing Articles")
+  :link '(info-link "(gnus)Picons")
   :type gnus-article-treat-head-custom)
-(put 'gnus-treat-display-picons 'highlight t)
+(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)
+      'head nil)
+  "Draw a boundary at the end of the headers.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' for details."
+  :version "21.1"
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-capitalize-sentences nil
   "Capitalize sentence-starting words.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
@@ -1121,14 +1280,14 @@ See the manual for details."
 (defcustom gnus-treat-fill-long-lines nil
   "Fill long lines.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (defcustom gnus-treat-play-sounds nil
   "Play sounds.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
@@ -1146,7 +1305,7 @@ decode the body, '(or header t) for the whole article, etc."
 (defcustom gnus-treat-translate nil
   "Translate articles from one language to another.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
   :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
@@ -1155,7 +1314,15 @@ See the manual for details."
   "Verify X-PGP-Sig.
 To automatically treat X-PGP-Sig, set it to head.
 Valid values are nil, t, `head', `last', an integer or a predicate.
-See the manual for details."
+See Info node `(gnus)Customizing Articles' for details."
+  :group 'gnus-article-treat
+  :group 'mime-security
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-monafy nil
+  "Display body part with mona font.
+Valid values are nil, t, `head', `last', an integer or a predicate.
+See Info node `(gnus)Customizing Articles' for details."
   :group 'gnus-article-treat
   :group 'mime-security
   :type gnus-article-treat-custom)
@@ -1171,6 +1338,9 @@ It is a string, such as \"PGP\". If nil, ask user."
   :type 'string
   :group 'mime-security)
 
+(defvar gnus-article-wash-function nil
+  "Function used for converting HTML into text.")
+
 ;;; Internal variables
 
 (defvar gnus-english-month-names
@@ -1180,19 +1350,21 @@ It is a string, such as \"PGP\". If nil, ask user."
 (defvar article-goto-body-goes-to-point-min-p nil)
 (defvar gnus-article-wash-types nil)
 (defvar gnus-article-emphasis-alist nil)
+(defvar gnus-article-image-alist nil)
 
 (defvar gnus-article-mime-handle-alist-1 nil)
 (defvar gnus-treatment-function-alist
-  `((gnus-treat-decode-article-as-default-mime-charset
+  '((gnus-treat-decode-article-as-default-mime-charset
      gnus-article-decode-article-as-default-mime-charset)
     (gnus-treat-x-pgp-sig gnus-article-verify-x-pgp-sig)
+    (gnus-treat-monafy gnus-article-monafy)
     (gnus-treat-strip-banner gnus-article-strip-banner)
     (gnus-treat-strip-headers-in-body gnus-article-strip-headers-in-body)
     (gnus-treat-buttonize gnus-article-add-buttons)
     (gnus-treat-fill-article gnus-article-fill-cited-article)
     (gnus-treat-fill-long-lines gnus-article-fill-long-lines)
     (gnus-treat-strip-cr gnus-article-remove-cr)
-    (gnus-treat-display-xface gnus-article-display-x-face)
+    (gnus-treat-unsplit-urls gnus-article-unsplit-urls)
     (gnus-treat-date-ut gnus-article-date-ut)
     (gnus-treat-date-local gnus-article-date-local)
     (gnus-treat-date-english gnus-article-date-english)
@@ -1203,15 +1375,14 @@ It is a string, such as \"PGP\". If nil, ask user."
     (gnus-treat-hide-headers gnus-article-maybe-hide-headers)
     (gnus-treat-hide-boring-headers gnus-article-hide-boring-headers)
     (gnus-treat-hide-signature gnus-article-hide-signature)
-    (gnus-treat-hide-citation gnus-article-hide-citation)
-    (gnus-treat-hide-citation-maybe gnus-article-hide-citation-maybe)
     (gnus-treat-strip-list-identifiers gnus-article-hide-list-identifiers)
     (gnus-treat-leading-whitespace gnus-article-remove-leading-whitespace)
     (gnus-treat-strip-pgp gnus-article-hide-pgp)
     (gnus-treat-strip-pem gnus-article-hide-pem)
+    (gnus-treat-from-picon gnus-treat-from-picon)
+    (gnus-treat-mail-picon gnus-treat-mail-picon)
+    (gnus-treat-newsgroups-picon gnus-treat-newsgroups-picon)
     (gnus-treat-highlight-headers gnus-article-highlight-headers)
-    (gnus-treat-emphasize gnus-article-emphasize)
-    (gnus-treat-highlight-citation gnus-article-highlight-citation)
     (gnus-treat-highlight-signature gnus-article-highlight-signature)
     (gnus-treat-strip-trailing-blank-lines
      gnus-article-remove-trailing-blank-lines)
@@ -1220,13 +1391,20 @@ It is a string, such as \"PGP\". If nil, ask user."
     (gnus-treat-strip-multiple-blank-lines
      gnus-article-strip-multiple-blank-lines)
     (gnus-treat-overstrike gnus-article-treat-overstrike)
+    (gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
+    (gnus-treat-fold-headers gnus-article-treat-fold-headers)
+    ;; Displaying X-Face should be done after unfolding headers
+    ;; to protect bitmap lines.
+    (gnus-treat-display-xface gnus-article-display-x-face)
+    (gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
     (gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
-    (gnus-treat-display-smileys ,(if (or (featurep 'xemacs)
-                                        (>= emacs-major-version 21))
-                                    'gnus-smiley-display
-                                  'gnus-article-smiley-display))
+    (gnus-treat-display-smileys gnus-treat-smiley)
     (gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
-    (gnus-treat-display-picons gnus-article-display-picons)
+    (gnus-treat-emphasize gnus-article-emphasize)
+    (gnus-treat-hide-citation gnus-article-hide-citation)
+    (gnus-treat-hide-citation-maybe gnus-article-hide-citation-maybe)
+    (gnus-treat-highlight-citation gnus-article-highlight-citation)
+    (gnus-treat-body-boundary gnus-article-treat-body-boundary)
     (gnus-treat-play-sounds gnus-earcon-display)))
 
 (defvar gnus-article-mime-handle-alist nil)
@@ -1237,8 +1415,8 @@ It is a string, such as \"PGP\". If nil, ask user."
   (let ((table (copy-syntax-table text-mode-syntax-table)))
     ;; This causes the citation match run O(2^n).
     ;; (modify-syntax-entry ?- "w" table)
-    (modify-syntax-entry ?> ")" table)
-    (modify-syntax-entry ?< "(" table)
+    (modify-syntax-entry ?> ")<" table)
+    (modify-syntax-entry ?< "(>" table)
     table)
   "Syntax table used in article mode buffers.
 Initialized from `text-mode-syntax-table.")
@@ -1254,6 +1432,34 @@ Initialized from `text-mode-syntax-table.")
 
 (defvar gnus-inhibit-hiding nil)
 
+;;; 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)
+            (inhibit-point-motion-hooks t)
+            (case-fold-search t))
+        (article-narrow-to-head)
+        ,@forms))))
+
+(put 'gnus-with-article-headers 'lisp-indent-function 0)
+(put 'gnus-with-article-headers 'edebug-form-spec '(body))
+
+(defmacro gnus-with-article-buffer (&rest forms)
+  `(save-excursion
+     (set-buffer gnus-article-buffer)
+     (let ((buffer-read-only nil))
+       ,@forms)))
+
+(put 'gnus-with-article-buffer 'lisp-indent-function 0)
+(put 'gnus-with-article-buffer 'edebug-form-spec '(body))
+
+(defun gnus-article-goto-header (header)
+  "Go to HEADER, which is a regular expression."
+  (re-search-forward (concat "^\\(" header "\\):") nil t))
+
 (defsubst gnus-article-hide-text (b e props)
   "Set text PROPS on the B to E region, extending `intangible' 1 past B."
   (gnus-add-text-properties-when 'article-type nil b e props)
@@ -1271,14 +1477,13 @@ Initialized from `text-mode-syntax-table.")
 
 (defun gnus-article-hide-text-type (b e type)
   "Hide text of TYPE between B and E."
-  (push type gnus-article-wash-types)
+  (gnus-add-wash-type type)
   (gnus-article-hide-text
    b e (cons 'article-type (cons type gnus-hidden-properties))))
 
 (defun gnus-article-unhide-text-type (b e type)
   "Unhide text of TYPE between B and E."
-  (setq gnus-article-wash-types
-       (delq type gnus-article-wash-types))
+  (gnus-delete-wash-type type)
   (remove-text-properties
    b e (cons 'article-type (cons type gnus-hidden-properties)))
   (when (memq 'intangible gnus-hidden-properties)
@@ -1387,15 +1592,14 @@ Initialized from `text-mode-syntax-table.")
            (when (setq beg (text-property-any
                             (point-min) (point-max) 'message-rank (+ 2 max)))
              ;; We delete or make invisible the unwanted headers.
-             (push 'headers gnus-article-wash-types)
+             (gnus-add-wash-type 'headers)
              (if delete
                  (progn
                    (add-text-properties
                     (point-min) (+ 5 (point-min))
                     '(article-type headers dummy-invisible t))
                    (delete-region beg (point-max)))
-               (gnus-article-hide-text-type beg (point-max) 'headers))))))))
-  )
+               (gnus-article-hide-text-type beg (point-max) 'headers)))))))))
 
 (defun article-hide-boring-headers (&optional arg)
   "Toggle hiding of headers that aren't very interesting.
@@ -1518,86 +1722,6 @@ always hide."
           (point-max)))
        'boring-headers))))
 
-(defun article-toggle-headers (&optional arg)
-  "Toggle hiding of headers.  If given a negative prefix, always show;
-if given a positive prefix, always hide."
-  (interactive (gnus-article-hidden-arg))
-  (let ((force (when (numberp arg)
-                (cond ((> arg 0) 'always-hide)
-                      ((< arg 0) 'always-show))))
-       (window (get-buffer-window gnus-article-buffer))
-       (header-end (point-min))
-       header-start field-end field-start
-       (inhibit-point-motion-hooks t)
-       (inhibit-read-only t))
-    (save-restriction
-      (widen)
-      (while (and (setq header-start
-                       (text-property-any header-end (point-max)
-                                          'article-treated-header t))
-                 (setq header-end
-                       (text-property-not-all header-start (point-max)
-                                              'article-treated-header t)))
-       (setq field-end header-start)
-       (cond
-        (;; Hide exposed invisible fields.
-         (and (not (eq 'always-show force))
-              (setq field-start
-                    (text-property-any field-end header-end
-                                       'exposed-invisible-field t)))
-         (while (and field-start
-                     (setq field-end (text-property-not-all
-                                      field-start header-end
-                                      'exposed-invisible-field t)))
-           (add-text-properties field-start field-end gnus-hidden-properties)
-           (setq field-start (text-property-any field-end header-end
-                                                'exposed-invisible-field t)))
-         (put-text-property header-start header-end
-                            'exposed-invisible-field nil))
-        (;; Expose invisible fields.
-         (and (not (eq 'always-hide force))
-              (setq field-start
-                    (text-property-any field-end header-end 'invisible t)))
-         (while (and field-start
-                     (setq field-end (text-property-not-all
-                                      field-start header-end
-                                      'invisible t)))
-           ;; If the invisible text is not terminated with newline, we
-           ;; won't expose it.  Because it may be created by x-face-mule.
-           ;; BTW, XEmacs sometimes fail in putting a invisible text
-           ;; property with `gnus-article-hide-text' (really?).  In that
-           ;; case, the invisible text might be started from the middle of
-           ;; a line so we will expose the sort of thing.
-           (when (or (not (or (eq header-start field-start)
-                              (eq ?\n (char-before field-start))))
-                     (eq ?\n (char-before field-end)))
-             (remove-text-properties field-start field-end
-                                     gnus-hidden-properties)
-             (put-text-property field-start field-end
-                                'exposed-invisible-field t))
-           (setq field-start (text-property-any field-end header-end
-                                                'invisible t))))
-        (;; Hide fields.
-         (not (eq 'always-show force))
-         (narrow-to-region header-start header-end)
-         (article-hide-headers)
-         ;; Re-display X-Face image under XEmacs.
-         (when (and (featurep 'xemacs)
-                    (gnus-functionp gnus-article-x-face-command))
-           (let ((func (cadr (assq 'gnus-treat-display-xface
-                                   gnus-treatment-function-alist)))
-                 (condition 'head))
-             (when (and (not gnus-inhibit-treatment)
-                        func
-                        (gnus-treat-predicate gnus-treat-display-xface))
-               (funcall func)
-               (put-text-property header-start header-end 'read-only nil))))
-         (widen))
-        ))
-      (goto-char (point-min))
-      (when window
-       (set-window-start window (point-min))))))
-
 (defvar gnus-article-normalized-header-length 40
   "Length of normalized headers.")
 
@@ -1702,6 +1826,99 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
              (put-text-property
               (point) end 'face 'underline)))))))))
 
+(defun gnus-article-treat-unfold-headers ()
+  "Unfold folded message headers.
+Only the headers that fit into the current window width will be
+unfolded."
+  (interactive)
+  (gnus-with-article-headers
+    (let (length)
+      (while (not (eobp))
+       (save-restriction
+         (mail-header-narrow-to-field)
+         (let ((header (buffer-substring (point-min) (point-max))))
+           (with-temp-buffer
+             (insert header)
+             (goto-char (point-min))
+             (while (re-search-forward "\n[\t ]" nil t)
+               (replace-match " " t t)))
+           (setq length (- (point-max) (point-min) 1)))
+         (when (< length (window-width))
+           (while (re-search-forward "\n[\t ]" nil t)
+             (replace-match " " t t)))
+         (goto-char (point-max)))))))
+
+(defun gnus-article-treat-fold-headers ()
+  "Fold message headers."
+  (interactive)
+  (gnus-with-article-headers
+    (while (not (eobp))
+      (save-restriction
+       (mail-header-narrow-to-field)
+       (mail-header-fold-field)
+       (goto-char (point-max))))))
+
+(defun gnus-treat-smiley ()
+  "Toggle display of textual emoticons (\"smileys\") as small graphical icons."
+  (interactive)
+  (unless (featurep 'xemacs)
+    (when (and (>= emacs-major-version 21)
+              (not gnus-article-should-use-smiley-mule)
+              gnus-article-smiley-mule-loaded-p)
+      (load "smiley" nil t)
+      (setq gnus-article-smiley-mule-loaded-p nil))
+    (when (and gnus-article-should-use-smiley-mule
+              (not gnus-article-smiley-mule-loaded-p))
+      (load "smiley-mule" nil t)
+      (setq gnus-article-smiley-mule-loaded-p t)))
+  (gnus-with-article-buffer
+    (if (memq 'smiley gnus-article-wash-types)
+       (gnus-delete-images 'smiley)
+      (article-goto-body)
+      (let ((images (smiley-region (point) (point-max))))
+       (when images
+         (gnus-add-wash-type 'smiley)
+         (dolist (image images)
+           (gnus-add-image 'smiley image)))))))
+
+(defun gnus-article-remove-images ()
+  "Remove all images from the article buffer."
+  (interactive)
+  (gnus-with-article-buffer
+    (dolist (elem gnus-article-image-alist)
+      (gnus-delete-images (car elem)))))
+
+(defun gnus-article-treat-fold-newsgroups ()
+  "Unfold folded message headers.
+Only the headers that fit into the current window width will be
+unfolded."
+  (interactive)
+  (gnus-with-article-headers
+    (while (gnus-article-goto-header "newsgroups\\|followup-to")
+      (save-restriction
+       (mail-header-narrow-to-field)
+       (while (re-search-forward ", *" nil t)
+         (replace-match ", " t t))
+       (mail-header-fold-field)
+       (goto-char (point-max))))))
+
+(defun gnus-article-treat-body-boundary ()
+  "Place a boundary line at the end of the headers."
+  (interactive)
+  (when (and gnus-body-boundary-delimiter
+            (> (length gnus-body-boundary-delimiter) 0))
+    (gnus-with-article-headers
+      (goto-char (point-max))
+      (let ((start (point)))
+       (insert "X-Boundary: ")
+       (gnus-add-text-properties start (point) '(invisible t intangible t))
+       (insert (let (str)
+                 (while (>= (1- (window-width)) (length str))
+                   (setq str (concat str gnus-body-boundary-delimiter)))
+                 (substring str 0 (1- (window-width))))
+               "\n")
+       (gnus-put-text-property start (point) 'gnus-decoration 'header)))))
+
 (defun article-fill-long-lines ()
   "Fill lines that are wider than the window width."
   (interactive)
@@ -1763,80 +1980,78 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
 (defun article-display-x-face (&optional force)
   "Look for an X-Face header and display it if present."
   (interactive (list 'force))
-  (save-excursion
-    ;; Delete the old process, if any.
-    (when (process-status "article-x-face")
-      (delete-process "article-x-face"))
-    (let ((inhibit-point-motion-hooks t)
-         x-faces
-         (case-fold-search t)
-         from last)
-      (save-restriction
-       (article-narrow-to-head)
-;;     (when (and buffer-read-only ;; When type `W f'
-;;                (progn
-;;                  (goto-char (point-min))
-;;                  (not (re-search-forward "^X-Face:[\t ]*" nil t)))
-;;                (gnus-buffer-live-p gnus-original-article-buffer))
-;;       (with-current-buffer gnus-original-article-buffer
-;;         (save-restriction
-;;           (article-narrow-to-head)
-;;           (while (re-search-forward "^X-Face:" nil t)
-;;             (setq x-faces
-;;                   (concat
-;;                    (or x-faces "")
-;;                    (buffer-substring
-;;                     (match-beginning 0)
-;;                     (1- (re-search-forward
-;;                          "^\\($\\|[^ \t]\\)" nil t))))))))
-;;       (if x-faces
-;;           (let (point start bface eface buffer-read-only)
-;;             (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))
-;;             (goto-char (point-max))
-;;             (setq point (point))
-;;             (insert x-faces)
-;;             (goto-char point)
-;;             (while (looking-at "\\([^:]+\\): *")
-;;               (put-text-property (match-beginning 1) (1+ (match-end 1))
-;;                                  'face bface)
-;;               (setq start (match-end 0))
-;;               (forward-line 1)
-;;               (while (looking-at "[\t ]")
-;;                 (forward-line 1))
-;;               (put-text-property start (point)
-;;                                  'face eface)))))
-       (goto-char (point-min))
-       (setq from (message-fetch-field "from"))
-       (goto-char (point-min))
-       (while (and gnus-article-x-face-command
-                   (not last)
-                   (or force
-                       ;; Check whether this face is censored.
-                       (not gnus-article-x-face-too-ugly)
-                       (and gnus-article-x-face-too-ugly from
-                            (not (string-match gnus-article-x-face-too-ugly
-                                               from))))
-                   ;; Has to be present.
-                   (re-search-forward "^X-Face:[\t ]*" nil t))
-         ;; This used to try to do multiple faces (`while' instead of
-         ;; `when' above), but (a) sending multiple EOFs to xv doesn't
-         ;; work (b) it can crash some versions of Emacs (c) are
-         ;; multiple faces really something to encourage?
-         (when (stringp gnus-article-x-face-command)
-           (setq last t))
-         ;; We now have the area of the buffer where the X-Face is stored.
+  (let ((wash-face-p buffer-read-only))        ;; When type `W f'
+    (gnus-with-article-headers
+      ;; Delete the old process, if any.
+      (when (process-status "article-x-face")
+       (delete-process "article-x-face"))
+      (if (memq 'xface gnus-article-wash-types)
+         ;; We have already displayed X-Faces, so we remove them
+         ;; instead.
+         (gnus-delete-images 'xface)
+       ;; Display X-Faces.
+       (let (x-faces from face grey)
          (save-excursion
-           (let ((beg (point))
-                 (end (1- (re-search-forward "^\\($\\|[^ \t]\\)" nil t)))
-                 buffer-read-only)
+           (when (and wash-face-p
+                      (progn
+                        (goto-char (point-min))
+                        (not (re-search-forward
+                              "^X-Face\\(-[0-9]+\\)?:[\t ]*" nil t)))
+                      (gnus-buffer-live-p gnus-original-article-buffer))
+             ;; If type `W f', use gnus-original-article-buffer,
+             ;; otherwise use the current buffer because displaying
+             ;; RFC822 parts calls this function too.
+             (set-buffer gnus-original-article-buffer))
+           (save-restriction
+             (mail-narrow-to-head)
+             (if gnus-treat-display-grey-xface
+                 (progn
+                   (while (gnus-article-goto-header "X-Face\\(-[0-9]+\\)?")
+                     (if (match-beginning 2)
+                         (progn
+                           (setq grey t)
+                           (push (cons (- (string-to-number (match-string 2)))
+                                       (mail-header-field-value))
+                                 x-faces))
+                       (push (cons 0 (mail-header-field-value)) x-faces)))
+                   (dolist (x-face (prog1
+                                       (if grey
+                                           (sort x-faces 'car-less-than-car)
+                                         (nreverse x-faces))
+                                     (setq x-faces nil)))
+                     (push (cdr x-face) x-faces)))
+               (while (gnus-article-goto-header "X-Face")
+                 (push (mail-header-field-value) x-faces)))
+             (setq from (message-fetch-field "from"))))
+         (if grey
+             (let ((xpm (gnus-convert-gray-x-face-to-xpm x-faces))
+                   image)
+               (when xpm
+                 (setq image (gnus-create-image xpm 'xpm t))
+                 (gnus-article-goto-header "from")
+                 (when (bobp)
+                   (insert "From: [no `from' set]\n")
+                   (forward-char -17))
+                 (gnus-add-wash-type 'xface)
+                 (gnus-add-image 'xface image)
+                 (gnus-put-image image)))
+           ;; Sending multiple EOFs to xv doesn't work, so we only do a
+           ;; single external face.
+           (when (stringp gnus-article-x-face-command)
+             (setq x-faces (list (car x-faces))))
+           (while (and (setq face (pop x-faces))
+                       gnus-article-x-face-command
+                       (or force
+                           ;; Check whether this face is censored.
+                           (not gnus-article-x-face-too-ugly)
+                           (and gnus-article-x-face-too-ugly from
+                                (not (string-match gnus-article-x-face-too-ugly
+                                                   from)))))
              ;; We display the face.
              (if (symbolp gnus-article-x-face-command)
                  ;; The command is a lisp function, so we call it.
                  (if (gnus-functionp gnus-article-x-face-command)
-                     (funcall gnus-article-x-face-command beg end)
+                     (funcall gnus-article-x-face-command face)
                    (error "%s is not a function" gnus-article-x-face-command))
                ;; The command is a string, so we interpret the command
                ;; as a, well, command, and fork it off.
@@ -1845,7 +2060,10 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
                   (start-process
                    "article-x-face" nil shell-file-name shell-command-switch
                    gnus-article-x-face-command))
-                 (process-send-region "article-x-face" beg end)
+                 (with-temp-buffer
+                   (insert face)
+                   (process-send-region "article-x-face"
+                                        (point-min) (point-max)))
                  (process-send-eof "article-x-face"))))))))))
 
 (defun article-decode-mime-words ()
@@ -2013,6 +2231,19 @@ If READ-CHARSET, ask for a coding system."
     (let ((buffer-read-only nil))
       (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))
+      (goto-char (point-min))
+      (while (re-search-forward
+             "^\\(\\(https?\\|ftp\\)://\\S-+\\) *\n\\(\\S-+\\)" nil t)
+       (replace-match "\\1\\3" t)))
+    (when (and gnus-display-mime-function (interactive-p))
+      (funcall gnus-display-mime-function))))
+
+
 (defun article-wash-html (&optional read-charset)
   "Format an html article.
 If READ-CHARSET, ask for a coding system."
@@ -2038,12 +2269,43 @@ If READ-CHARSET, ask for a coding system."
       (save-window-excursion
        (save-restriction
          (narrow-to-region (point) (point-max))
-         (mm-setup-w3)
-         (let ((w3-strict-width (window-width))
-               (url-standalone-mode t))
-           (condition-case var
-               (w3-region (point-min) (point-max))
-             (error))))))))
+         (let* ((func (or gnus-article-wash-function mm-text-html-renderer))
+                (entry (assq func mm-text-html-washer-alist)))
+           (if entry
+               (setq func (cdr entry)))
+           (cond
+            ((gnus-functionp func)
+             (funcall func))
+            (t
+             (apply (car func) (cdr func))))))))))
+
+(defun gnus-article-wash-html-with-w3 ()
+  "Wash the current buffer with w3."
+  (mm-setup-w3)
+  (let ((w3-strict-width (window-width))
+       (url-standalone-mode t)
+       (url-gateway-unplugged t)
+       (w3-honor-stylesheets nil))
+    (condition-case ()
+       (w3-region (point-min) (point-max))
+      (error))))
+
+(defun gnus-article-wash-html-with-w3m ()
+  "Wash the current buffer with emacs-w3m."
+  (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:"))
+         (w3m-display-inline-images mm-inline-text-html-with-images)
+         w3m-force-redisplay)
+      (w3m-region (point-min) (point-max)))
+    (when mm-inline-text-html-with-w3m-keymap
+      (add-text-properties
+       (point-min) (point-max)
+       (append '(mm-inline-text-html-with-w3m t)
+              (gnus-local-map-property mm-w3m-mode-map))))))
 
 (defun article-hide-list-identifiers ()
   "Remove list identifies from the Subject header.
@@ -2078,7 +2340,7 @@ The `gnus-list-identifiers' variable specifies what to do."
        (article-goto-body)
        ;; Hide the "header".
        (when (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
-         (push 'pgp gnus-article-wash-types)
+         (gnus-add-wash-type 'pgp)
          (delete-region (match-beginning 0) (match-end 0))
          ;; Remove armor headers (rfc2440 6.2)
          (delete-region (point) (or (re-search-forward "^[ \t]*\n" nil t)
@@ -2118,7 +2380,7 @@ always hide."
                    "\n-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n"
                    nil t)
                   (setq end (1+ (match-beginning 0))))
-         (push 'pem gnus-article-wash-types)
+         (gnus-add-wash-type 'pem)
          (gnus-article-hide-text-type
           end
           (if (search-forward "\n\n" nil t)
@@ -2140,6 +2402,18 @@ always hide."
            (banner (gnus-parameter-banner gnus-newsgroup-name))
            (gnus-signature-limit nil)
            buffer-read-only beg end)
+       (when (and gnus-article-address-banner-alist
+                  (not banner))
+         (setq banner
+               (let ((from (save-restriction
+                             (widen)
+                             (article-narrow-to-head)
+                             (caar (mail-header-parse-addresses
+                                    (mail-fetch-field "from"))))))
+                 (catch 'found
+                   (dolist (pair gnus-article-address-banner-alist)
+                     (when (string-match (car pair) from)
+                       (throw 'found (cdr pair))))))))
        (when banner
          (article-goto-body)
          (cond
@@ -2199,7 +2473,8 @@ always hide."
               (1+ button)
               (next-single-property-change (1+ button) 'mime-view-entity
                                            nil (point-max))
-              'signature))))))))
+              'signature)))))))
+  (gnus-set-mode-line 'article))
 
 (defun article-strip-headers-in-body ()
   "Strip offensive headers from bodies."
@@ -2351,7 +2626,7 @@ Put point at the beginning of the signature separator."
 
 (defun gnus-article-check-hidden-text (type arg)
   "Return nil if hiding is necessary.
-Arg can be nil or a number.  Nil and positive means hide, negative
+Arg can be nil or a number.  nil and positive means hide, negative
 means show, 0 means toggle."
   (save-excursion
     (save-restriction
@@ -2391,7 +2666,8 @@ Originally it is hide instead of DUMMY."
      'article-type type
      (point-min) (point-max)
      (cons 'article-type (cons type
-                              gnus-hidden-properties)))))
+                              gnus-hidden-properties)))
+    (gnus-delete-wash-type type)))
 
 (defconst article-time-units
   `((year . ,(* 365.25 24 60 60))
@@ -2512,11 +2788,14 @@ should replace the \"Date:\" one, or should be added below it."
                             date)))
         ;; Let the user define the format.
         ((eq type 'user)
-         (if (gnus-functionp gnus-article-time-format)
-             (funcall gnus-article-time-format time)
-           (concat
-            "Date: "
-            (format-time-string gnus-article-time-format time))))
+         (let ((format (or (condition-case nil
+                               (with-current-buffer gnus-summary-buffer
+                                 gnus-article-time-format)
+                             (error nil))
+                           gnus-article-time-format)))
+           (if (gnus-functionp format)
+               (funcall format time)
+             (concat "Date: " (format-time-string format time)))))
         ;; ISO 8601.
         ((eq type 'iso8601)
          (let ((tz (car (current-time-zone time))))
@@ -2591,7 +2870,7 @@ should replace the \"Date:\" one, or should be added below it."
             ":"
             (format "%02d" (nth 1 dtime)))))))
     (error
-     (format "Date: %s (from Oort)" date))))
+     (format "Date: %s (from T-gnus)" date))))
 
 (defun article-date-local (&optional highlight)
   "Convert the current article date to the local timezone."
@@ -2658,15 +2937,15 @@ This format is defined by the `gnus-article-time-format' variable."
   (interactive (list t))
   (article-date-ut 'iso8601 highlight))
 
-(defun article-show-all ()
-  "Show all hidden text in the article buffer."
-  (interactive)
-  (save-excursion
-    (widen)
-    (let ((buffer-read-only nil))
-      (gnus-article-unhide-text (point-min) (point-max))
-      (gnus-remove-text-with-property 'gnus-prev)
-      (gnus-remove-text-with-property 'gnus-next))))
+;; (defun article-show-all ()
+;;   "Show all hidden text in the article buffer."
+;;   (interactive)
+;;   (save-excursion
+;;     (widen)
+;;     (let ((buffer-read-only nil))
+;;       (gnus-article-unhide-text (point-min) (point-max))
+;;       (gnus-remove-text-with-property 'gnus-prev)
+;;       (gnus-remove-text-with-property 'gnus-next))))
 
 (defun article-show-all-headers ()
   "Show all hidden headers in the article buffer."
@@ -2718,9 +2997,9 @@ This format is defined by the `gnus-article-time-format' variable."
               (match-beginning invisible) (match-end invisible) props)
              (gnus-article-unhide-text-type
               (match-beginning visible) (match-end visible) 'emphasis)
-             (gnus-put-text-property-excluding-newlines
+             (gnus-put-overlay-excluding-newlines
               (match-beginning visible) (match-end visible) 'face face)
-             (push 'emphasis gnus-article-wash-types)
+             (gnus-add-wash-type 'emphasis)
              (goto-char (match-end invisible)))))))))
 
 (defun gnus-article-setup-highlight-words (&optional highlight-words)
@@ -3055,7 +3334,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
                   mml2015-use
                   (mml2015-clear-verify-function))
          (with-temp-buffer
-           (insert-buffer gnus-original-article-buffer)
+           (insert-buffer-substring gnus-original-article-buffer)
            (setq items (split-string sig))
            (message-narrow-to-head)
            (let ((inhibit-point-motion-hooks t)
@@ -3123,6 +3402,21 @@ If variable `gnus-use-long-file-name' is non-nil, it is
   (if (gnus-buffer-live-p gnus-original-article-buffer)
       (canlock-verify gnus-original-article-buffer)))
 
+(defun article-monafy ()
+  "Display body part with mona font."
+  (interactive)
+  (unless (if (featurep 'xemacs)
+             (find-face 'gnus-mona-face)
+           (facep 'gnus-mona-face))
+    (require 'navi2ch-mona)
+    (set-face-font (make-face 'gnus-mona-face) navi2ch-mona-font))
+  (save-excursion
+    (let ((buffer-read-only nil))
+      (article-goto-body)
+      (gnus-overlay-put
+       (gnus-make-overlay (point) (point-max))
+       'face 'gnus-mona-face))))
+
 (eval-and-compile
   (mapcar
    (lambda (func)
@@ -3133,20 +3427,20 @@ If variable `gnus-use-long-file-name' is non-nil, it is
         (setq afunc func
               gfunc (intern (format "gnus-%s" func))))
        (defalias gfunc
-        (if (fboundp afunc)
-            `(lambda (&optional interactive &rest args)
-               ,(documentation afunc t)
-               (interactive (list t))
-               (save-excursion
-                 (set-buffer gnus-article-buffer)
-                 (if interactive
-                     (call-interactively ',afunc)
-                   (apply ',afunc args))))))))
+        (when (fboundp afunc)
+          `(lambda (&optional interactive &rest args)
+             ,(documentation afunc t)
+             (interactive (list t))
+             (save-excursion
+               (set-buffer gnus-article-buffer)
+               (if interactive
+                   (call-interactively ',afunc)
+                 (apply ',afunc args))))))))
    '(article-hide-headers
      article-verify-x-pgp-sig
      article-verify-cancel-lock
+     article-monafy
      article-hide-boring-headers
-     article-toggle-headers
      article-treat-overstrike
      article-fill-long-lines
      article-capitalize-sentences
@@ -3157,6 +3451,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      article-de-base64-unreadable
      article-decode-HZ
      article-wash-html
+     article-unsplit-urls
      article-hide-list-identifiers
      article-hide-pgp
      article-strip-banner
@@ -3185,7 +3480,8 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      article-treat-dumbquotes
      article-normalize-headers
      (article-show-all-headers . gnus-article-show-all-headers)
-     (article-show-all . gnus-article-show-all))))
+;;      (article-show-all . gnus-article-show-all)
+     )))
 \f
 ;;;
 ;;; Gnus article mode
@@ -3208,6 +3504,8 @@ If variable `gnus-use-long-file-name' is non-nil, it is
   ">" end-of-buffer
   "\C-c\C-i" gnus-info-find-node
   "\C-c\C-b" gnus-bug
+  "R" gnus-article-reply-with-original
+  "F" gnus-article-followup-with-original
   "\C-hk" gnus-article-describe-key
   "\C-hc" gnus-article-describe-key-briefly
 
@@ -3252,12 +3550,14 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      gnus-article-treatment-menu gnus-article-mode-map ""
      ;; Fixme: this should use :active (and maybe :visible).
      '("Treatment"
-       ["Hide headers" gnus-article-toggle-headers t]
+       ["Hide headers" gnus-article-hide-headers t]
        ["Hide signature" gnus-article-hide-signature t]
        ["Hide citation" gnus-article-hide-citation t]
        ["Treat overstrike" gnus-article-treat-overstrike t]
        ["Remove carriage return" gnus-article-remove-cr t]
        ["Remove leading whitespace" gnus-article-remove-leading-whitespace t]
+       ["Treat html" gnus-article-wash-html t]
+       ["Remove newlines from within URLs" gnus-article-unsplit-urls t]
        ["Decode HZ" gnus-article-decode-HZ t]))
 
     ;; Note "Commands" menu is defined in gnus-sum.el for consistency
@@ -3303,6 +3603,7 @@ commands:
   (make-local-variable 'gnus-article-decoded-p)
   (make-local-variable 'gnus-article-mime-handle-alist)
   (make-local-variable 'gnus-article-wash-types)
+  (make-local-variable 'gnus-article-image-alist)
   (make-local-variable 'gnus-article-charset)
   (make-local-variable 'gnus-article-ignored-charsets)
   (gnus-set-default-directory)
@@ -3333,7 +3634,7 @@ commands:
     ;; Init original article buffer.
     (save-excursion
       (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
-      (set-buffer-multibyte nil)
+      (set-buffer-multibyte t)
       (setq major-mode 'gnus-original-article-mode)
       (make-local-variable 'gnus-original-article))
     (if (get-buffer name)
@@ -3531,6 +3832,8 @@ If ALL-HEADERS is non-nil, no headers are hidden."
                   gnus-article-mime-handle-alist))
              (gnus-set-mode-line 'article))
            (article-goto-body)
+           (unless (bobp)
+             (forward-line -1))
            (set-window-point (get-buffer-window (current-buffer)) (point))
            (gnus-configure-windows 'article)
            t))))))
@@ -3611,7 +3914,8 @@ If ALL-HEADERS is non-nil, no headers are hidden."
       (gnus-article-mode))
     (setq buffer-read-only nil
          gnus-button-marker-list nil
-         gnus-article-wash-types nil)
+         gnus-article-wash-types nil
+         gnus-article-image-alist nil)
     (save-restriction
       (widen)
       (static-if (featurep 'xemacs)
@@ -3667,14 +3971,19 @@ value of the variable `gnus-show-mime' is non-nil."
 ;;;
 
 (defvar gnus-mime-button-line-format "%{%([%p. %d%T]%)%}%e\n"
-  "The following specs can be used:
+  "Format of the MIME buttons.
+
+Valid specifiers include:
 %t  The MIME type
 %T  MIME type, along with additional info
 %n  The `name' parameter
 %d  The description, if any
 %l  The length of the encoded part
 %p  The part identifier number
-%e  Dots if the part isn't displayed")
+%e  Dots if the part isn't displayed
+
+General format specifiers can also be used.  See
+(gnus)Formatting Variables.")
 
 (defvar gnus-mime-button-line-format-alist
   '((?t gnus-tmp-type ?s)
@@ -3694,8 +4003,9 @@ value of the variable `gnus-show-mime' is non-nil."
     (gnus-mime-save-part-and-strip "\C-o" "Save and Strip")
     (gnus-mime-copy-part "c" "View As Text, In Other Buffer")
     (gnus-mime-inline-part "i" "View As Text, In This Buffer")
-    (gnus-mime-internalize-part "E" "View Internally")
-    (gnus-mime-externalize-part "e" "View Externally")
+    (gnus-mime-view-part-internally "E" "View Internally")
+    (gnus-mime-view-part-externally "e" "View Externally")
+    (gnus-mime-print-part "p" "Print")
     (gnus-mime-pipe-part "|" "Pipe To Command...")
     (gnus-mime-action-on-part "." "Take action on the part")))
 
@@ -3881,7 +4191,7 @@ value of the variable `gnus-show-mime' is non-nil."
       (gnus-mm-display-part handle))))
 
 (defun gnus-mime-copy-part (&optional handle)
-  "Put the the MIME part under point into a new buffer."
+  "Put the MIME part under point into a new buffer."
   (interactive)
   (gnus-article-check-buffer)
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
@@ -3905,6 +4215,32 @@ value of the variable `gnus-show-mime' is non-nil."
        (setq buffer-file-name nil))
       (goto-char (point-min)))))
 
+(defun gnus-mime-print-part (&optional handle filename)
+  "Print the MIME part under point."
+  (interactive (list nil (ps-print-preprint current-prefix-arg)))
+  (gnus-article-check-buffer)
+  (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
+        (contents (and handle (mm-get-part handle)))
+        (file (mm-make-temp-file (expand-file-name "mm." mm-tmp-directory)))
+        (printer (mailcap-mime-info (mm-handle-type handle) "print")))
+    (when contents
+       (if printer
+           (unwind-protect
+               (progn
+                 (with-temp-file file
+                   (insert contents))
+                 (call-process shell-file-name nil
+                               (generate-new-buffer " *mm*")
+                               nil
+                               shell-command-switch
+                               (mm-mailcap-command
+                                printer file (mm-handle-type handle))))
+             (delete-file file))
+         (with-temp-buffer
+           (insert contents)
+           (gnus-print-buffer))
+         (ps-despool filename)))))
+
 (defun gnus-mime-inline-part (&optional handle arg)
   "Insert the MIME part under point into the current buffer."
   (interactive (list nil current-prefix-arg))
@@ -3958,7 +4294,7 @@ specified charset."
            (gnus-newsgroup-ignored-charsets 'gnus-all))
        (gnus-article-press-button)))))
 
-(defun gnus-mime-externalize-part (&optional handle)
+(defun gnus-mime-view-part-externally (&optional handle)
   "View the MIME part under point with an external viewer."
   (interactive)
   (gnus-article-check-buffer)
@@ -3974,7 +4310,7 @@ specified charset."
          (mm-remove-part handle)
        (mm-display-part handle)))))
 
-(defun gnus-mime-internalize-part (&optional handle)
+(defun gnus-mime-view-part-internally (&optional handle)
   "View the MIME part under point with an internal viewer.
 If no internal viewer is available, use an external viewer."
   (interactive)
@@ -4034,10 +4370,10 @@ If no internal viewer is available, use an external viewer."
   (interactive "p")
   (gnus-article-part-wrapper n 'gnus-mime-view-part-as-charset))
 
-(defun gnus-article-externalize-part (n)
+(defun gnus-article-view-part-externally (n)
   "View MIME part N externally, which is the numerical prefix."
   (interactive "p")
-  (gnus-article-part-wrapper n 'gnus-mime-externalize-part))
+  (gnus-article-part-wrapper n 'gnus-mime-view-part-externally))
 
 (defun gnus-article-inline-part (n)
   "Inline MIME part N, which is the numerical prefix."
@@ -4095,8 +4431,11 @@ If no internal viewer is available, use an external viewer."
        (let ((window (selected-window))
              (mail-parse-charset gnus-newsgroup-charset)
              (mail-parse-ignored-charsets
-              (save-excursion (set-buffer gnus-summary-buffer)
-                              gnus-newsgroup-ignored-charsets)))
+              (if (gnus-buffer-live-p gnus-summary-buffer)
+                  (save-excursion
+                    (set-buffer gnus-summary-buffer)
+                    gnus-newsgroup-ignored-charsets)
+                nil)))
          (save-excursion
            (unwind-protect
                (let ((win (gnus-get-buffer-window (current-buffer) t))
@@ -4164,14 +4503,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
-     `(keymap ,gnus-mime-button-map
-             ,@(if (>= (string-to-number emacs-version) 21)
-                   nil
-                 (list 'local-map gnus-mime-button-map))
-             gnus-callback gnus-mm-display-part
-             gnus-part ,gnus-tmp-id
-             article-type annotation
-             gnus-data ,handle))
+     `(,@(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))
     (setq e (point))
     (widget-convert-button
      'link b e
@@ -4215,7 +4551,9 @@ 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)))
-      (let* ((handles (or ihandles (mm-dissect-buffer) (mm-uu-dissect)))
+      (let* ((handles (or ihandles (mm-dissect-buffer
+                                   nil gnus-article-loose-mime)
+                         (mm-uu-dissect)))
             buffer-read-only handle name type b e display)
        (when (and (not ihandles)
                   (not gnus-displaying-mime))
@@ -4285,12 +4623,10 @@ If no internal viewer is available, use an external viewer."
     ;;;!!! No, w3 can display everything just fine.
     (gnus-mime-display-part (cadr handle)))
    ((equal (car handle) "multipart/signed")
-    (or (memq 'signed gnus-article-wash-types)
-       (push 'signed gnus-article-wash-types))
+    (gnus-add-wash-type 'signed)
     (gnus-mime-display-security handle))
    ((equal (car handle) "multipart/encrypted")
-    (or (memq 'encrypted gnus-article-wash-types)
-       (push 'encrypted gnus-article-wash-types))
+    (gnus-add-wash-type 'encrypted)
     (gnus-mime-display-security handle))
    ;; Other multiparts are handled like multipart/mixed.
    (t
@@ -4426,12 +4762,9 @@ If no internal viewer is available, use an external viewer."
                       ',gnus-article-mime-handle-alist))
               (gnus-mime-display-alternative
                ',ihandles ',not-pref ',begend ,id))
-            ,@(if (>= (string-to-number emacs-version) 21)
-                  nil ;; XEmacs doesn't care
-                (list 'local-map gnus-mime-button-map))
+            ,@(gnus-local-map-property gnus-mime-button-map)
             ,gnus-mouse-face-prop ,gnus-article-mouse-face
             face ,gnus-article-button-face
-            keymap ,gnus-mime-button-map
             gnus-part ,id
             gnus-data ,handle))
          (widget-convert-button 'link from (point)
@@ -4453,12 +4786,9 @@ If no internal viewer is available, use an external viewer."
                         ',gnus-article-mime-handle-alist))
                 (gnus-mime-display-alternative
                  ',ihandles ',handle ',begend ,id))
-              ,@(if (>= (string-to-number emacs-version) 21)
-                    nil ;; XEmacs doesn't care
-                  (list 'local-map gnus-mime-button-map))
+              ,@(gnus-local-map-property gnus-mime-button-map)
               ,gnus-mouse-face-prop ,gnus-article-mouse-face
               face ,gnus-article-button-face
-              keymap ,gnus-mime-button-map
               gnus-part ,id
               gnus-data ,handle))
            (widget-convert-button 'link from (point)
@@ -4518,7 +4848,7 @@ representing the particular washing function, ON is the string to use
 in the article mode line when the washing function is active, and OFF
 is the string to use when it is inactive.")
 
-(defun gnus-gnus-article-wash-status-entry (key value)
+(defun gnus-article-wash-status-entry (key value)
   (let ((entry (assoc key gnus-article-wash-status-strings)))
     (if value (nth 1 entry) (nth 2 entry))))
 
@@ -4536,16 +4866,38 @@ is the string to use when it is inactive.")
          (signature (memq 'signature gnus-article-wash-types))
          (overstrike (memq 'overstrike gnus-article-wash-types))
          (emphasis (memq 'emphasis gnus-article-wash-types)))
-      (concat (gnus-gnus-article-wash-status-entry 'cite cite)
-             (gnus-gnus-article-wash-status-entry 'headers
-                                                  (or headers boring))
-             (gnus-gnus-article-wash-status-entry
-              'pgp (or pgp pem signed encrypted))
-             (gnus-gnus-article-wash-status-entry 'signature signature)
-             (gnus-gnus-article-wash-status-entry 'overstrike overstrike)
-             (gnus-gnus-article-wash-status-entry 'gnus-show-mime
-                                                  gnus-show-mime)
-             (gnus-gnus-article-wash-status-entry 'emphasis emphasis)))))
+      (concat
+       (gnus-article-wash-status-entry 'cite cite)
+       (gnus-article-wash-status-entry 'headers (or headers boring))
+       (gnus-article-wash-status-entry 'pgp (or pgp pem signed encrypted))
+       (gnus-article-wash-status-entry 'signature signature)
+       (gnus-article-wash-status-entry 'overstrike overstrike)
+       (gnus-article-wash-status-entry 'gnus-show-mime gnus-show-mime)
+       (gnus-article-wash-status-entry 'emphasis emphasis)))))
+
+(defun gnus-add-wash-type (type)
+  "Add a washing of TYPE to the current status."
+  (add-to-list 'gnus-article-wash-types type))
+
+(defun gnus-delete-wash-type (type)
+  "Add a washing of TYPE to the current status."
+  (setq gnus-article-wash-types (delq type gnus-article-wash-types)))
+
+(defun gnus-add-image (category image)
+  "Add IMAGE of CATEGORY to the list of displayed images."
+  (let ((entry (assq category gnus-article-image-alist)))
+    (unless entry
+      (setq entry (list category))
+      (push entry gnus-article-image-alist))
+    (nconc entry (list image))))
+
+(defun gnus-delete-images (category)
+  "Delete all images in CATEGORY."
+  (let ((entry (assq category gnus-article-image-alist)))
+    (dolist (image (cdr entry))
+      (gnus-remove-image image))
+    (setq gnus-article-image-alist (delq entry gnus-article-image-alist))
+    (gnus-delete-wash-type category)))
 
 (defalias 'gnus-article-hide-headers-if-wanted 'gnus-article-maybe-hide-headers)
 
@@ -4740,7 +5092,7 @@ Argument LINES specifies lines to be scrolled down."
   (interactive "P")
   (gnus-article-check-buffer)
   (let ((nosaves
-        '("q" "Q"  "c" "r" "R" "\C-c\C-f" "m"  "a" "f" "F"
+        '("q" "Q"  "c" "r" "\C-c\C-f" "m"  "a" "f"
           "Zc" "ZC" "ZE" "ZJ" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
           "=" "^" "\M-^" "|"))
        (nosave-but-article
@@ -4853,6 +5205,39 @@ Argument LINES specifies lines to be scrolled down."
        (describe-key-briefly key insert))
     (describe-key-briefly key insert)))
 
+(defun gnus-article-reply-with-original (&optional wide)
+  "Start composing a reply mail to the current message.
+The text in the region will be yanked.  If the region isn't active,
+the entire article will be yanked."
+  (interactive "P")
+  (let ((article (cdr gnus-article-current)) cont)
+    (if (not (mark t))
+       (gnus-summary-reply (list (list article)) wide)
+      (setq cont (buffer-substring (point) (mark t)))
+      ;; Deactivate active regions.
+      (when (and (boundp 'transient-mark-mode)
+                transient-mark-mode)
+       (setq mark-active nil))
+      (gnus-summary-reply
+       (list (list article cont)) wide))))
+
+(defun gnus-article-followup-with-original ()
+  "Compose a followup to the current article.
+The text in the region will be yanked.  If the region isn't active,
+the entire article will be yanked."
+  (interactive)
+  (let ((article (cdr gnus-article-current))
+       cont)
+    (if (not (mark t))
+       (gnus-summary-followup (list (list article)))
+      (setq cont (buffer-substring (point) (mark t)))
+      ;; Deactivate active regions.
+      (when (and (boundp 'transient-mark-mode)
+                transient-mark-mode)
+       (setq mark-active nil))
+      (gnus-summary-followup
+       (list (list article cont))))))
+
 (defun gnus-article-hide (&optional arg force)
   "Hide all the gruft in the current article.
 This means that PGP stuff, signatures, cited text and (some)
@@ -4877,11 +5262,12 @@ If given a prefix, show the hidden text instead."
     (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
     (gnus-request-group gnus-newsgroup-name t)))
 
+(eval-when-compile
+  (autoload 'nneething-get-file-name "nneething"))
+
 (defun gnus-request-article-this-buffer (article group)
-  "Get an article and insert it into this buffer.
-T-gnus change: Insert an article into `gnus-original-article-buffer'."
+  "Get an article and insert it into this buffer."
   (let (do-update-line sparse-header)
-    ;; The current buffer is `gnus-article-buffer'.
     (prog1
        (save-excursion
          (erase-buffer)
@@ -4928,24 +5314,12 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
                               gnus-newsgroup-name)))
                  (when (and (eq (car method) 'nneething)
                             (vectorp header))
-                   (let ((dir (expand-file-name
-                               (mail-header-subject header)
-                               (file-name-as-directory
-                                (or (cadr (assq 'nneething-address method))
-                                    (nth 1 method))))))
-                     (when (file-directory-p dir)
+                   (let ((dir (nneething-get-file-name
+                               (mail-header-id header))))
+                     (when (and (stringp dir)
+                                (file-directory-p dir))
                        (setq article 'nneething)
                        (gnus-group-enter-directory dir))))))))
-         (setq gnus-original-article (cons group article))
-
-         ;; The current buffer is `gnus-original-article-buffer'.
-         (if (get-buffer gnus-original-article-buffer)
-             (set-buffer gnus-original-article-buffer)
-           (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
-           (set-buffer-multibyte nil)
-           (buffer-disable-undo)
-           (setq major-mode 'gnus-original-article-mode)
-           (setq buffer-read-only nil))
 
          (cond
           ;; Refuse to select canceled articles.
@@ -4958,6 +5332,15 @@ T-gnus change: Insert an article into `gnus-original-article-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)
+                (save-excursion
+                  (set-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)
+           'article)
           ;; Check the backlog.
           ((and gnus-keep-backlog
                 (gnus-backlog-request-article group article (current-buffer)))
@@ -4973,12 +5356,19 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
                 (numberp article)
                 (gnus-cache-request-article article group))
            'article)
+          ;; Check the agent cache.
+          ((and gnus-agent gnus-agent-cache gnus-plugged
+                (numberp article)
+                (gnus-agent-request-article article group))
+           'article)
           ;; Get the article and put into the article buffer.
           ((or (stringp article)
                (numberp article))
            (let ((gnus-override-method gnus-override-method)
                  (methods (and (stringp article)
                                gnus-refer-article-method))
+                 (backend (car (gnus-find-method-for-group
+                                gnus-newsgroup-name)))
                  result
                  (buffer-read-only nil))
              (if (or (not (listp methods))
@@ -4997,7 +5387,8 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
                (gnus-kill-all-overlays)
                (let ((gnus-newsgroup-name group))
                  (gnus-check-group-server))
-               (when (gnus-request-article article group (current-buffer))
+               (cond
+                ((gnus-request-article article group (current-buffer))
                  (when (numberp article)
                    (gnus-async-prefetch-next group article
                                              gnus-summary-buffer)
@@ -5005,10 +5396,13 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
                      (gnus-backlog-enter-article
                       group article (current-buffer))))
                  (setq result 'article))
-               (if (not result)
-                   (if methods
-                       (setq gnus-override-method (pop methods))
-                     (setq result 'done))))
+                (methods
+                 (setq gnus-override-method (pop methods)))
+                ((not (string-match "^400 "
+                                    (nnheader-get-report backend)))
+                 ;; If we get 400 server disconnect, reconnect and
+                 ;; retry; otherwise, assume the article has expired.
+                 (setq result 'done))))
              (and (eq result 'article) 'article)))
           ;; It was a pseudo.
           (t article)))
@@ -5016,15 +5410,27 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
       ;; Associate this article with the current summary buffer.
       (setq gnus-article-current-summary gnus-summary-buffer)
 
-      ;; Copy the requested article from `gnus-original-article-buffer'.
-      (unless (equal (buffer-name (current-buffer))
-                    (buffer-name (get-buffer gnus-original-article-buffer)))
-       (insert-buffer gnus-original-article-buffer))
+      ;; Take the article from the original article buffer
+      ;; and place it in the buffer it's supposed to be in.
+      (when (and (get-buffer gnus-article-buffer)
+                (equal (buffer-name (current-buffer))
+                       (buffer-name (get-buffer gnus-article-buffer))))
+       (save-excursion
+         (if (get-buffer gnus-original-article-buffer)
+             (set-buffer gnus-original-article-buffer)
+           (set-buffer (gnus-get-buffer-create gnus-original-article-buffer))
+           (buffer-disable-undo)
+           (setq major-mode 'gnus-original-article-mode)
+           (setq buffer-read-only t))
+         (let (buffer-read-only)
+           (erase-buffer)
+           (insert-buffer-substring gnus-article-buffer))
+         (setq gnus-original-article (cons group article)))
 
-      ;; Decode charsets.
-      (run-hooks 'gnus-article-decode-hook)
-      ;; Mark article as decoded or not.
-      (setq gnus-article-decoded-p gnus-article-decode-hook)
+       ;; Decode charsets.
+       (run-hooks 'gnus-article-decode-hook)
+       ;; Mark article as decoded or not.
+       (setq gnus-article-decoded-p gnus-article-decode-hook))
 
       ;; Update sparse articles.
       (when (and do-update-line
@@ -5059,17 +5465,67 @@ T-gnus change: Insert an article into `gnus-original-article-buffer'."
 
 ;; Should we be using derived.el for this?
 (unless gnus-article-edit-mode-map
-  (setq gnus-article-edit-mode-map (make-sparse-keymap))
+  (setq gnus-article-edit-mode-map (make-keymap))
   (set-keymap-parent gnus-article-edit-mode-map text-mode-map)
 
   (gnus-define-keys gnus-article-edit-mode-map
+    "\C-c?"    describe-mode
     "\C-c\C-c" gnus-article-edit-done
-    "\C-c\C-k" gnus-article-edit-exit)
+    "\C-c\C-k" gnus-article-edit-exit
+    "\C-c\C-f\C-t" message-goto-to
+    "\C-c\C-f\C-o" message-goto-from
+    "\C-c\C-f\C-b" message-goto-bcc
+    ;;"\C-c\C-f\C-w" message-goto-fcc
+    "\C-c\C-f\C-c" message-goto-cc
+    "\C-c\C-f\C-s" message-goto-subject
+    "\C-c\C-f\C-r" message-goto-reply-to
+    "\C-c\C-f\C-n" message-goto-newsgroups
+    "\C-c\C-f\C-d" message-goto-distribution
+    "\C-c\C-f\C-f" message-goto-followup-to
+    "\C-c\C-f\C-m" message-goto-mail-followup-to
+    "\C-c\C-f\C-k" message-goto-keywords
+    "\C-c\C-f\C-u" message-goto-summary
+    "\C-c\C-f\C-i" message-insert-or-toggle-importance
+    "\C-c\C-f\C-a" message-gen-unsubscribed-mft
+    "\C-c\C-b" message-goto-body
+    "\C-c\C-i" message-goto-signature
+
+    "\C-c\C-t" message-insert-to
+    "\C-c\C-n" message-insert-newsgroups
+    "\C-c\C-o" message-sort-headers
+    "\C-c\C-e" message-elide-region
+    "\C-c\C-v" message-delete-not-region
+    "\C-c\C-z" message-kill-to-signature
+    "\M-\r" message-newline-and-reformat
+    "\C-c\C-a" mml-attach-file
+    "\C-a" message-beginning-of-line
+    "\t" message-tab
+    "\M-;" comment-region)
 
   (gnus-define-keys (gnus-article-edit-wash-map
                     "\C-c\C-w" gnus-article-edit-mode-map)
     "f" gnus-article-edit-full-stops))
 
+(easy-menu-define
+  gnus-article-edit-mode-field-menu gnus-article-edit-mode-map ""
+  '("Field"
+    ["Fetch To" message-insert-to t]
+    ["Fetch Newsgroups" message-insert-newsgroups t]
+    "----"
+    ["To" message-goto-to t]
+    ["From" message-goto-from t]
+    ["Subject" message-goto-subject t]
+    ["Cc" message-goto-cc t]
+    ["Reply-To" message-goto-reply-to t]
+    ["Summary" message-goto-summary t]
+    ["Keywords" message-goto-keywords t]
+    ["Newsgroups" message-goto-newsgroups t]
+    ["Followup-To" message-goto-followup-to t]
+    ["Mail-Followup-To" message-goto-mail-followup-to t]
+    ["Distribution" message-goto-distribution t]
+    ["Body" message-goto-body t]
+    ["Signature" message-goto-signature t]))
+
 (define-derived-mode gnus-article-edit-mode text-mode "Article Edit"
   "Major mode for editing articles.
 This is an extended text-mode.
@@ -5079,6 +5535,8 @@ This is an extended text-mode.
   (make-local-variable 'gnus-prev-winconf)
   (set (make-local-variable 'font-lock-defaults)
        '(message-font-lock-keywords t))
+  (set (make-local-variable 'mail-header-separator) "")
+  (easy-menu-add message-mode-field-menu message-mode-map)
   (setq buffer-read-only nil)
   (buffer-enable-undo)
   (widen))
@@ -5120,39 +5578,31 @@ groups."
   (interactive "P")
   (let ((func gnus-article-edit-done-function)
        (buf (current-buffer))
-       (start (window-start)))
+       (start (window-start))
+       (p (point))
+       (winconf gnus-prev-winconf))
     (remove-hook 'gnus-article-mode-hook
                 'gnus-article-mime-edit-article-unwind)
-    ;; We remove all text props from the article buffer.
-    (let ((content
-          (buffer-substring-no-properties (point-min) (point-max)))
-         (p (point)))
-      (erase-buffer)
-      (insert content)
-      (let ((winconf gnus-prev-winconf))
-       (gnus-article-mode)
-       (set-window-configuration winconf)
-       ;; Tippy-toe some to make sure that point remains where it was.
-       (save-current-buffer
-         (set-buffer buf)
-         (set-window-start (get-buffer-window (current-buffer)) start)
-         (goto-char p))))
+    (widen) ;; Widen it in case that users narrowed the buffer.
+    (funcall func arg)
+    (set-buffer buf)
+    ;; The cache and backlog have to be flushed somewhat.
+    (when gnus-keep-backlog
+      (gnus-backlog-remove-article
+       (car gnus-article-current) (cdr gnus-article-current)))
+    ;; Flush original article as well.
     (save-excursion
-      (set-buffer buf)
-      (let ((buffer-read-only nil))
-       (funcall func arg))
-      ;; The cache and backlog have to be flushed somewhat.
-      (when gnus-keep-backlog
-       (gnus-backlog-remove-article
-        (car gnus-article-current) (cdr gnus-article-current)))
-      ;; Flush original article as well.
-      (save-excursion
-       (when (get-buffer gnus-original-article-buffer)
-         (set-buffer gnus-original-article-buffer)
-         (setq gnus-original-article nil)))
-      (when gnus-use-cache
-       (gnus-cache-update-article
-        (car gnus-article-current) (cdr gnus-article-current))))
+      (when (get-buffer gnus-original-article-buffer)
+       (set-buffer gnus-original-article-buffer)
+       (setq gnus-original-article nil)))
+    (when gnus-use-cache
+      (gnus-cache-update-article
+       (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)
+    (gnus-article-mode)
+    (set-window-configuration winconf)
     (set-buffer buf)
     (set-window-start (get-buffer-window buf) start)
     (set-window-point (get-buffer-window buf) (point))))
@@ -5167,7 +5617,7 @@ groups."
          (window-start (window-start)))
       (erase-buffer)
       (if (gnus-buffer-live-p gnus-original-article-buffer)
-         (insert-buffer gnus-original-article-buffer))
+         (insert-buffer-substring gnus-original-article-buffer))
       (let ((winconf gnus-prev-winconf))
        (gnus-article-mode)
        (set-window-configuration winconf)
@@ -5237,7 +5687,7 @@ after replacing with the original article."
                             'gnus-article-mime-edit-exit
                             gnus-article-edit-mode-map)
   (erase-buffer)
-  (insert-buffer gnus-original-article-buffer)
+  (insert-buffer-substring gnus-original-article-buffer)
   (let ((ofn (symbol-function 'mime-edit-decode-single-part-in-buffer)))
     (fset 'mime-edit-decode-single-part-in-buffer
          (lambda (&rest args)
@@ -5303,13 +5753,25 @@ after replacing with the original article."
 
 ;;; Internal Variables:
 
-(defcustom gnus-button-url-regexp "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)"
+(defcustom gnus-button-url-regexp 
+  (if (string-match "[[:digit:]]" "1") ;; support POSIX?
+      "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?[-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,[:word:]]+[-a-zA-Z0-9_=#$@~`%&*+|\\/[:word:]]\\)"
+    "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?\\([-a-zA-Z0-9_=!?#$@~`%&*+|\\/:;.,]\\|\\w\\)+\\([-a-zA-Z0-9_=#$@~`%&*+|\\/]\\|\\w\\)\\)")
   "Regular expression that matches URLs."
   :group 'gnus-article-buttons
   :type 'regexp)
 
+(defcustom gnus-button-man-handler 'man
+  "Function to use for displaying man pages.
+The function must take at least one argument with a string naming the
+man page."
+  :type '(choice (function-item :tag "Man" man)
+                (function-item :tag "Woman" woman)
+                (function :tag "Other"))
+  :group 'gnus-article-buttons)
+
 (defcustom gnus-button-alist
-  `(("<\\(url:[>\n\t ]*?\\)?\\(nntp\\|news\\):[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
+  '(("<\\(url:[>\n\t ]*?\\)?\\(nntp\\|news\\):[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
      0 t gnus-button-handle-news 3)
     ("\\b\\(nntp\\|news\\):\\([^>\n\t ]*@[^>)!;:,\n\t ]*\\)" 0 t
      gnus-button-handle-news 2)
@@ -5326,13 +5788,16 @@ after replacing with the original article."
     ("\\binfo:\\(//\\)?\\([^'\">\n\t ]+\\)" 0 t
      gnus-button-handle-info 2)
     ;; This is how URLs _should_ be embedded in text...
-    ("<URL: *\\([^<>]*\\)>" 0 t gnus-button-embedded-url 1)
+    ("<URL: *\\([^<>]*\\)>" 1 t gnus-button-embedded-url 1)
     ;; Raw URLs.
-    (,gnus-button-url-regexp 0 t browse-url 0))
+    (gnus-button-url-regexp 0 t browse-url 0)
+    ;; man pages
+    ("\\b\\([a-z]+\\)([0-9])\\W" 0 t gnus-button-handle-man 1))
   "*Alist of regexps matching buttons in article bodies.
 
 Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
-REGEXP: is the string matching text around the button,
+REGEXP: is the string matching text around the button (can also be lisp 
+expression evaluating to a string),
 BUTTON: is the number of the regexp grouping actually matching the button,
 FORM: is a lisp expression which must eval to true for the button to
 be added,
@@ -5342,7 +5807,7 @@ PAR: is a number of a regexp grouping whose text will be passed to CALLBACK.
 CALLBACK can also be a variable, in that case the value of that
 variable it the real callback function."
   :group 'gnus-article-buttons
-  :type '(repeat (list regexp
+  :type '(repeat (list (choice regexp variable)
                       (integer :tag "Button")
                       (sexp :tag "Form")
                       (function :tag "Callback")
@@ -5351,14 +5816,15 @@ variable it the real callback function."
                               (integer :tag "Regexp group")))))
 
 (defcustom gnus-header-button-alist
-  `(("^\\(References\\|Message-I[Dd]\\):" "<[^<>]+>"
+  '(("^\\(References\\|Message-I[Dd]\\):" "<[^<>]+>"
      0 t gnus-button-message-id 0)
     ("^\\(From\\|Reply-To\\):" ": *\\(.+\\)$" 1 t gnus-button-reply 1)
     ("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
      0 t gnus-button-mailto 0)
-    ("^X-[Uu][Rr][Ll]:" ,gnus-button-url-regexp 0 t browse-url 0)
-    ("^Subject:" ,gnus-button-url-regexp 0 t browse-url 0)
-    ("^[^:]+:" ,gnus-button-url-regexp 0 t browse-url 0)
+    ("^X-[Uu][Rr][Ll]:" gnus-button-url-regexp 0 t browse-url 0)
+    ("^Subject:" gnus-button-url-regexp 0 t browse-url 0)
+    ("^[^:]+:" gnus-button-url-regexp 0 t browse-url 0)
+    ("^[^:]+:" "\\bmailto:\\([-a-zA-Z.@_+0-9%=?]+\\)" 0 t gnus-url-mailto 1)
     ("^[^:]+:" "\\(<\\(url: \\)?news:\\([^>\n ]*\\)>\\)" 1 t
      gnus-button-message-id 3))
   "*Alist of headers and regexps to match buttons in article heads.
@@ -5569,7 +6035,7 @@ specified by `gnus-button-alist'."
       (article-goto-body)
       (setq beg (point))
       (while (setq entry (pop alist))
-       (setq regexp (car entry))
+       (setq regexp (eval (car entry)))
        (goto-char beg)
        (while (re-search-forward regexp nil t)
          (let* ((start (and entry (match-beginning (nth 1 entry))))
@@ -5611,7 +6077,7 @@ specified by `gnus-button-alist'."
                               (match-beginning 0))
                          (point-max)))
            (goto-char beg)
-           (while (re-search-forward (nth 1 entry) end t)
+           (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)))
@@ -5659,14 +6125,12 @@ specified by `gnus-button-alist'."
                                              nil (point-max))))
       (if (text-property-any end limit 'article-type 'signature)
          (progn
-           (setq gnus-article-wash-types
-                 (delq 'signature gnus-article-wash-types))
+           (gnus-delete-wash-type 'signature)
            (gnus-remove-text-properties-when
             'article-type 'signature end limit
             (cons 'article-type (cons 'signature
                                       gnus-hidden-properties))))
-       (or (memq 'signature gnus-article-wash-types)
-           (push 'signature gnus-article-wash-types))
+       (gnus-add-wash-type 'signature)
        (gnus-add-text-properties-when
         'article-type nil end limit
         (cons 'article-type (cons 'signature
@@ -5680,7 +6144,7 @@ specified by `gnus-button-alist'."
        (entry nil))
     (while alist
       (setq entry (pop alist))
-      (if (looking-at (car entry))
+      (if (looking-at (eval (car entry)))
          (setq alist nil)
        (setq entry nil)))
     entry))
@@ -5747,6 +6211,10 @@ specified by `gnus-button-alist'."
      (group
       (gnus-button-fetch-group url)))))
 
+(defun gnus-button-handle-man (url)
+  "Fetch a man page."
+  (funcall gnus-button-man-handler url))
+
 (defun gnus-button-handle-info (url)
   "Fetch an info URL."
   (if (string-match
@@ -5794,7 +6262,7 @@ specified by `gnus-button-alist'."
       (if (not (string-match "=" cur))
          nil                           ; Grace
        (setq key (gnus-url-unhex-string (substring cur 0 (match-beginning 0)))
-             val (gnus-url-unhex-string (substring cur (match-end 0) nil)))
+             val (gnus-url-unhex-string (substring cur (match-end 0) nil) t))
        (if downcase
            (setq key (downcase key)))
        (setq cur (assoc key retval))
@@ -5831,51 +6299,46 @@ specified by `gnus-button-alist'."
   "Activate ADDRESS with `browse-url'."
   (browse-url (gnus-strip-whitespace address)))
 
-(eval-when-compile
-  ;; Silence the byte-compiler.
-  (autoload 'smiley-toggle-buffer "gnus-bitmap"))
-(defun gnus-article-smiley-display ()
-  "Display \"smileys\" as small graphical icons."
-  (smiley-toggle-buffer 1 (current-buffer) (point-min) (point-max)))
-
 ;;; Next/prev buttons in the article buffer.
 
 (defvar gnus-next-page-line-format "%{%(Next page...%)%}\n")
 (defvar gnus-prev-page-line-format "%{%(Previous page...%)%}\n")
 
-(defvar gnus-prev-page-map nil)
-(unless gnus-prev-page-map
-  (setq gnus-prev-page-map (make-sparse-keymap))
-  (define-key gnus-prev-page-map gnus-mouse-2 'gnus-button-prev-page)
-  (define-key gnus-prev-page-map "\r" 'gnus-button-prev-page))
+(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))
 
-(static-if (featurep 'xemacs)
-    (defun gnus-insert-prev-page-button ()
-      (let ((buffer-read-only nil))
-       (gnus-eval-format
-        gnus-prev-page-line-format nil
-        `(gnus-prev t local-map ,gnus-prev-page-map
-                    gnus-callback gnus-article-button-prev-page
-                    article-type annotation))))
-  (defun gnus-insert-prev-page-button ()
-    (let ((buffer-read-only nil)
-         (situation (get-text-property (point-min) 'mime-view-situation)))
-      (set-keymap-parent gnus-prev-page-map (current-local-map))
-      (gnus-eval-format
-       gnus-prev-page-line-format nil
-       `(gnus-prev t local-map ,gnus-prev-page-map
-                  gnus-callback gnus-article-button-prev-page
-                  article-type annotation
-                  mime-view-situation ,situation))))
-  )
+(defun gnus-insert-prev-page-button ()
+  (let ((b (point))
+       (buffer-read-only nil)
+       (situation (get-text-property (point-min) 'mime-view-situation)))
+    (gnus-eval-format
+     gnus-prev-page-line-format nil
+     `(,@(gnus-local-map-property gnus-prev-page-map)
+        gnus-prev t
+        gnus-callback gnus-article-button-prev-page
+        article-type annotation
+        mime-view-situation ,situation))
+    (widget-convert-button
+     'link b (point)
+     :action 'gnus-button-prev-page
+     :button-keymap gnus-prev-page-map)))
 
-(defvar gnus-next-page-map nil)
-(unless gnus-next-page-map
-  (setq gnus-next-page-map (make-sparse-keymap))
-  (define-key gnus-next-page-map gnus-mouse-2 'gnus-button-next-page)
-  (define-key gnus-next-page-map "\r" 'gnus-button-next-page))
+(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 ()
+(defun gnus-button-next-page (&optional args more-args)
   "Go to the next page."
   (interactive)
   (let ((win (selected-window)))
@@ -5883,7 +6346,7 @@ specified by `gnus-button-alist'."
     (gnus-article-next-page)
     (select-window win)))
 
-(defun gnus-button-prev-page ()
+(defun gnus-button-prev-page (&optional args more-args)
   "Go to the prev page."
   (interactive)
   (let ((win (selected-window)))
@@ -5891,25 +6354,20 @@ specified by `gnus-button-alist'."
     (gnus-article-prev-page)
     (select-window win)))
 
-(static-if (featurep 'xemacs)
-    (defun gnus-insert-next-page-button ()
-      (let ((buffer-read-only nil))
-       (gnus-eval-format gnus-next-page-line-format nil
-                         `(gnus-next
-                           t local-map ,gnus-next-page-map
-                           gnus-callback gnus-article-button-next-page
-                           article-type annotation))))
-  (defun gnus-insert-next-page-button ()
-    (let ((buffer-read-only nil)
-         (situation (get-text-property (point-min) 'mime-view-situation)))
-      (set-keymap-parent gnus-next-page-map (current-local-map))
-      (gnus-eval-format gnus-next-page-line-format nil
-                       `(gnus-next
-                         t local-map ,gnus-next-page-map
+(defun gnus-insert-next-page-button ()
+  (let ((b (point))
+       (buffer-read-only nil)
+       (situation (get-text-property (point-min) 'mime-view-situation)))
+    (gnus-eval-format gnus-next-page-line-format nil
+                     `(,@(gnus-local-map-property gnus-next-page-map)
+                         gnus-next t
                          gnus-callback gnus-article-button-next-page
                          article-type annotation
-                         mime-view-situation ,situation))))
-  )
+                         mime-view-situation ,situation))
+    (widget-convert-button
+     'link b (point)
+     :action 'gnus-button-next-page
+     :button-keymap gnus-next-page-map)))
 
 (defun gnus-article-button-next-page (arg)
   "Go to the next page."
@@ -5933,11 +6391,11 @@ specified by `gnus-button-alist'."
 
 This variable is a list of FUNCTION or (REGEXP . FUNCTION).  If item
 is FUNCTION, FUNCTION will be apply to all newsgroups.  If item is a
-(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
+\(REGEXP . FUNCTION), FUNCTION will be only apply to thes newsgroups
 whose names match REGEXP.
 
 For example:
-((\"chinese\" . gnus-decode-encoded-word-region-by-guess)
+\((\"chinese\" . gnus-decode-encoded-word-region-by-guess)
  mail-decode-encoded-word-region
  (\"chinese\" . rfc1843-decode-region))
 ")
@@ -6256,14 +6714,11 @@ For example:
     (gnus-eval-format
      gnus-mime-security-button-line-format
      gnus-mime-security-button-line-format-alist
-     `(keymap ,gnus-mime-security-button-map
-             ,@(if (>= (string-to-number emacs-version) 21)
-                   nil ;; XEmacs doesn't care
-                 (list 'local-map gnus-mime-security-button-map))
-             gnus-callback gnus-mime-security-press-button
-             gnus-line-format ,gnus-mime-security-button-line-format
-             article-type annotation
-             gnus-data ,handle))
+     `(,@(gnus-local-map-property gnus-mime-security-button-map)
+        gnus-callback gnus-mime-security-press-button
+        gnus-line-format ,gnus-mime-security-button-line-format
+        article-type annotation
+        gnus-data ,handle))
     (setq e (point))
     (widget-convert-button
      'link b e