2001-08-19 Simon Josefsson <jas@extundo.com>
[gnus] / lisp / gnus-art.el
index 058ca5c..e28835c 100644 (file)
@@ -1,5 +1,6 @@
 ;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 (require 'wid-edit)
 (require 'mm-uu)
 
+(autoload 'gnus-msg-mail "gnus-msg" nil t)
+(autoload 'gnus-button-mailto "gnus-msg")
+(autoload 'gnus-button-reply "gnus-msg" nil t)
+
 (defgroup gnus-article nil
   "Article display."
   :link '(custom-manual "(gnus)The Article Buffer")
     "^Precedence:" "^Original-[-A-Za-z]+:" "^X-filename:" "^X-Orcpt:"
     "^Old-Received:" "^X-Pgp" "^X-Auth:" "^X-From-Line:"
     "^X-Gnus-Article-Number:" "^X-Majordomo:" "^X-Url:" "^X-Sender:"
-    "^MBOX-Line" "^Priority:" "^X-Pgp" "^X400-[-A-Za-z]+:"
+    "^MBOX-Line" "^Priority:" "^X400-[-A-Za-z]+:"
     "^Status:" "^X-Gnus-Mail-Source:" "^Cancel-Lock:"
     "^X-FTN" "^X-EXP32-SerialNo:" "^Encoding:" "^Importance:"
     "^Autoforwarded:" "^Original-Encoded-Information-Types:" "^X-Ya-Pop3:"
     "^List-[A-Za-z]+:" "^X-Listprocessor-Version:"
     "^X-Received:" "^X-Distribute:" "^X-Sequence:" "^X-Juno-Line-Breaks:"
     "^X-Notes-Item:" "^X-MS-TNEF-Correlator:" "^x-uunet-gateway:"
-    "^X-Received:" "^Content-length:" "X-precedence:")
+    "^X-Received:" "^Content-length:" "X-precedence:"
+    "^X-Authenticated-User:" "^X-Comment" "^X-Report:" "^X-Abuse-Info:"
+    "^X-HTTP-Proxy:" "^X-Mydeja-Info:" "^X-Copyright" "^X-No-Markup:"
+    "^X-Abuse-Info:")
   "*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."
@@ -160,14 +168,23 @@ this list."
 
 (defcustom gnus-boring-article-headers '(empty followup-to reply-to)
   "Headers that are only to be displayed if they have interesting data.
-Possible values in this list are `empty', `newsgroups', `followup-to',
-`reply-to', `date', `long-to', and `many-to'."
+Possible values in this list are:
+
+  'empty       Headers with no content.
+  'newsgroups  Newsgroup identical to Gnus group.
+  'to-address  To identical to To-address.
+  'followup-to Followup-to identical to Newsgroups.
+  'reply-to    Reply-to identical to From.
+  'date        Date less than four days old.
+  'long-to     To and/or Cc longer than 1024 characters.
+  'many-to     Multiple To and/or Cc."
   :type '(set (const :tag "Headers with no content." empty)
-             (const :tag "Newsgroups with only one group." newsgroups)
-             (const :tag "Followup-to identical to newsgroups." followup-to)
-             (const :tag "Reply-to identical to from." reply-to)
+             (const :tag "Newsgroups identical to Gnus group." newsgroups)
+             (const :tag "To identical to To-address." to-address)
+             (const :tag "Followup-to identical to Newsgroups." followup-to)
+             (const :tag "Reply-to identical to From." reply-to)
              (const :tag "Date less than four days old." date)
-             (const :tag "Very long To and/or Cc header." long-to)
+             (const :tag "To and/or Cc longer than 1024 characters." long-to)
              (const :tag "Multiple To and/or Cc headers." many-to))
   :group 'gnus-article-hiding)
 
@@ -215,6 +232,7 @@ asynchronously.      The compressed face will be piped to this command."
   :type '(choice string
                 (function-item gnus-article-display-xface)
                 function)
+  :version "21.1"
   :group 'gnus-article-washing)
 
 (defcustom gnus-article-x-face-too-ugly nil
@@ -224,11 +242,33 @@ asynchronously.    The compressed face will be piped to this command."
 
 (defcustom gnus-article-banner-alist nil
   "Banner alist for stripping.
-For example, 
-     ((egroups . \"^[ \\t\\n]*-------------------+\\\\( eGroups Sponsor -+\\\\)?....\\n\\\\(.+\\n\\\\)+\"))"
+For example,
+     ((egroups . \"^[ \\t\\n]*-------------------+\\\\( \\\\(e\\\\|Yahoo! \\\\)Groups Sponsor -+\\\\)?....\\n\\\\(.+\\n\\\\)+\"))"
+  :version "21.1"
   :type '(repeat (cons symbol regexp))
   :group 'gnus-article-washing)
 
+(gnus-define-group-parameter
+ banner
+ :variable-document
+ "Alist of regexps (to match group names) and banner."
+ :variable-group gnus-article-washing
+ :parameter-type
+ '(choice :tag "Banner"
+         :value nil
+         (const :tag "Remove signature" signature)
+         (symbol :tag "Item in `gnus-article-banner-alist'" none)
+         regexp
+         (const :tag "None" nil))
+ :parameter-document
+ "If non-nil, specify how to remove `banners' from articles.
+
+Symbol `signature' means to remove signatures delimited by
+`gnus-signature-separator'.  Any other symbol is used to look up a
+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-emphasis-alist
   (let ((format
         "\\(\\s-\\|^\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-,;:\"]\\s-\\|[?!.]+\\s-\\|\\s)\\)")
@@ -270,6 +310,7 @@ is the face used for highlighting."
 Typical values are \"^[ \\t]+\\\\|[ \\t]*\\n\" and \"[ \\t]+\\\\|[ \\t]*\\n\".
 The former avoids underlining of leading and trailing whitespace,
 and the latter avoids underlining any whitespace at all."
+  :version "21.1"
   :group 'gnus-article-emphasis
   :type 'regexp)
 
@@ -444,6 +485,13 @@ The following additional specs are available:
   :type 'hook
   :group 'gnus-article-various)
 
+(when (featurep 'xemacs)
+  ;; Extracted from gnus-xmas-define in order to preserve user settings
+  (when (fboundp 'turn-off-scroll-in-place)
+    (add-hook 'gnus-article-mode-hook 'turn-off-scroll-in-place))
+  ;; Extracted from gnus-xmas-redefine in order to preserve user settings
+  (add-hook 'gnus-article-mode-hook 'gnus-xmas-article-menu-add))
+
 (defcustom gnus-article-menu-hook nil
   "*Hook run after the creation of the article mode menu."
   :type 'hook
@@ -594,7 +642,8 @@ displayed by the first non-nil matching CONTENT face."
   "Function used to decode headers.")
 
 (defvar gnus-article-dumbquotes-map
-  '(("\202" ",")
+  '(("\200" "EUR")
+    ("\202" ",")
     ("\203" "f")
     ("\204" ",,")
     ("\205" "...")
@@ -615,11 +664,13 @@ displayed by the first non-nil matching CONTENT face."
 
 (defcustom gnus-ignored-mime-types nil
   "List of MIME types that should be ignored by Gnus."
+  :version "21.1"
   :group 'gnus-article-mime
   :type '(repeat regexp))
 
 (defcustom gnus-unbuttonized-mime-types '(".*/.*")
   "List of MIME types that should not be given buttons when rendered inline."
+  :version "21.1"
   :group 'gnus-article-mime
   :type '(repeat regexp))
 
@@ -631,32 +682,53 @@ on parts -- for instance, adding Vcard info to a database."
   :type 'function)
 
 (defcustom gnus-mime-multipart-functions nil
-  "An alist of MIME types to functions to display them.")
+  "An alist of MIME types to functions to display them."
+  :version "21.1"
+  :group 'gnus-article-mime
+  :type 'alist)
 
 (defcustom gnus-article-date-lapsed-new-header nil
   "Whether the X-Sent and Date headers can coexist.
 When using `gnus-treat-date-lapsed', the \"X-Sent:\" header will
 either replace the old \"Date:\" header (if this variable is nil), or
 be added below it (otherwise)."
+  :version "21.1"
   :group 'gnus-article-headers
   :type 'boolean)
 
 (defcustom gnus-article-mime-match-handle-function 'undisplayed-alternative
   "Function called with a MIME handle as the argument.
 This is meant for people who want to view first matched part.
-For `undisplayed-alternative' (default), the first undisplayed 
-part or alternative part is used.  For `undisplayed', the first 
-undisplayed part is used.  For a function, the first part which 
+For `undisplayed-alternative' (default), the first undisplayed
+part or alternative part is used.  For `undisplayed', the first
+undisplayed part is used.  For a function, the first part which
 the function return `t' is used.  For `nil', the first part is
 used."
+  :version "21.1"
   :group 'gnus-article-mime
-  :type '(choice 
+  :type '(choice
          (item :tag "first" :value nil)
          (item :tag "undisplayed" :value undisplayed)
-         (item :tag "undisplayed or alternative" 
+         (item :tag "undisplayed or alternative"
                :value undisplayed-alternative)
          (function)))
 
+(defcustom gnus-mime-action-alist
+  '(("save to file" . gnus-mime-save-part)
+    ("save and strip" . gnus-mime-save-part-and-strip)
+    ("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)
+    ("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))
+  "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)
@@ -667,6 +739,7 @@ used."
     ("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))))
@@ -721,7 +794,11 @@ See the manual for details."
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-buttonize-head 'highlight t)
 
-(defcustom gnus-treat-emphasize 50000
+(defcustom gnus-treat-emphasize
+  (and (or window-system
+          (featurep 'xemacs)
+          (>= (string-to-number emacs-version) 21))
+       50000)
   "Emphasize text.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
@@ -736,6 +813,13 @@ See the manual 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."
+  :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.
@@ -778,10 +862,18 @@ See the manual 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."
+  :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."
+  :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
@@ -837,6 +929,13 @@ See the manual 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."
+  :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.
@@ -855,6 +954,7 @@ See the manual for details."
   "Display the date in the ISO8601 format.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
+  :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-head-custom)
 
@@ -870,6 +970,7 @@ See the manual for details."
   "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."
+  :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
@@ -902,7 +1003,7 @@ See the manual for details."
   :type gnus-article-treat-custom)
 (put 'gnus-treat-overstrike 'highlight t)
 
-(defcustom gnus-treat-display-xface 
+(defcustom gnus-treat-display-xface
   (and (or (and (fboundp 'image-type-available-p)
                (image-type-available-p 'xbm)
                (string-match "^0x" (shell-command-to-string "uncompface")))
@@ -912,10 +1013,11 @@ See the manual for details."
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
   :group 'gnus-article-treat
+  :version "21.1"
   :type gnus-article-treat-head-custom)
 (put 'gnus-treat-display-xface 'highlight t)
 
-(defcustom gnus-treat-display-smileys 
+(defcustom gnus-treat-display-smileys
   (if (or (and (featurep 'xemacs)
               (featurep 'xpm))
          (and (fboundp 'image-type-available-p)
@@ -925,6 +1027,7 @@ See the manual for details."
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
   :group 'gnus-article-treat
+  :version "21.1"
   :type gnus-article-treat-custom)
 (put 'gnus-treat-display-smileys 'highlight t)
 
@@ -940,6 +1043,7 @@ See the manual for details."
   "Capitalize sentence-starting words.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
+  :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
@@ -954,25 +1058,52 @@ See the manual for details."
   "Play sounds.
 Valid values are nil, t, `head', `last', an integer or a predicate.
 See the manual for details."
+  :version "21.1"
   :group 'gnus-article-treat
   :type gnus-article-treat-custom)
 
 (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."
+  :version "21.1"
+  :group 'gnus-article-treat
+  :type gnus-article-treat-custom)
+
+(defcustom gnus-treat-x-pgp-sig nil
+  "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."
   :group 'gnus-article-treat
+  :group 'mime-security
   :type gnus-article-treat-custom)
 
+(defvar gnus-article-encrypt-protocol-alist
+  '(("PGP" . mml2015-self-encrypt)))
+
+;; Set to nil if more than one protocol added to
+;; gnus-article-encrypt-protocol-alist.
+(defcustom gnus-article-encrypt-protocol "PGP"
+  "The protocol used for encrypt articles.
+It is a string, such as \"PGP\". If nil, ask user."
+  :type 'string
+  :group 'mime-security)
+
 ;;; Internal variables
 
+(defvar gnus-english-month-names
+  '("January" "February" "March" "April" "May" "June" "July" "August"
+    "September" "October" "November" "December"))
+
 (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-mime-handle-alist-1 nil)
 (defvar gnus-treatment-function-alist
-  '((gnus-treat-strip-banner gnus-article-strip-banner)
+  '((gnus-treat-x-pgp-sig gnus-article-verify-x-pgp-sig)
+    (gnus-treat-strip-banner gnus-article-strip-banner)
     (gnus-treat-strip-headers-in-body gnus-article-strip-headers-in-body)
     (gnus-treat-highlight-signature gnus-article-highlight-signature)
     (gnus-treat-buttonize gnus-article-add-buttons)
@@ -981,23 +1112,25 @@ See the manual for details."
     (gnus-treat-strip-cr gnus-article-remove-cr)
     (gnus-treat-emphasize gnus-article-emphasize)
     (gnus-treat-display-xface gnus-article-display-x-face)
+    (gnus-treat-date-ut gnus-article-date-ut)
+    (gnus-treat-date-local gnus-article-date-local)
+    (gnus-treat-date-english gnus-article-date-english)
+    (gnus-treat-date-lapsed gnus-article-date-lapsed)
+    (gnus-treat-date-original gnus-article-date-original)
+    (gnus-treat-date-user-defined gnus-article-date-user)
+    (gnus-treat-date-iso8601 gnus-article-date-iso8601)
     (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-highlight-headers gnus-article-highlight-headers)
     (gnus-treat-highlight-citation gnus-article-highlight-citation)
     (gnus-treat-highlight-signature gnus-article-highlight-signature)
-    (gnus-treat-date-ut gnus-article-date-ut)
-    (gnus-treat-date-local gnus-article-date-local)
-    (gnus-treat-date-lapsed gnus-article-date-lapsed)
-    (gnus-treat-date-original gnus-article-date-original)
-    (gnus-treat-date-user-defined gnus-article-date-user)
-    (gnus-treat-date-iso8601 gnus-article-date-iso8601)
     (gnus-treat-strip-trailing-blank-lines
      gnus-article-remove-trailing-blank-lines)
     (gnus-treat-strip-leading-blank-lines
@@ -1017,7 +1150,8 @@ See the manual for details."
 
 (defvar gnus-article-mode-syntax-table
   (let ((table (copy-syntax-table text-mode-syntax-table)))
-    (modify-syntax-entry ?- "w" table)
+    ;; This causes the citation match run O(2^n).
+    ;; (modify-syntax-entry ?- "w" table)
     (modify-syntax-entry ?> ")" table)
     (modify-syntax-entry ?< "(" table)
     table)
@@ -1037,11 +1171,12 @@ Initialized from `text-mode-syntax-table.")
 
 (defsubst gnus-article-hide-text (b e props)
   "Set text PROPS on the B to E region, extending `intangible' 1 past B."
-  (add-text-properties b e props)
+  (gnus-add-text-properties-when 'article-type nil b e props)
   (when (memq 'intangible props)
     (put-text-property
      (max (1- b) (point-min))
      b 'intangible (cddr (memq 'intangible props)))))
+
 (defsubst gnus-article-unhide-text (b e)
   "Remove hidden text properties from region between B and E."
   (remove-text-properties b e gnus-hidden-properties)
@@ -1142,7 +1277,7 @@ Initialized from `text-mode-syntax-table.")
          ;; `gnus-ignored-headers' and `gnus-visible-headers' to
          ;; select which header lines is to remain visible in the
          ;; article buffer.
-         (while (re-search-forward "^[^ \t]*:" nil t)
+         (while (re-search-forward "^[^ \t:]*:" nil t)
            (beginning-of-line)
            ;; Mark the rank of the header.
            (put-text-property
@@ -1194,15 +1329,30 @@ always hide."
                 'boring-headers)))
             ;; Hide boring Newsgroups header.
             ((eq elem 'newsgroups)
-             (when (equal (gnus-fetch-field "newsgroups")
-                          (gnus-group-real-name
-                           (if (boundp 'gnus-newsgroup-name)
-                               gnus-newsgroup-name
-                             "")))
+             (when (gnus-string-equal
+                    (gnus-fetch-field "newsgroups")
+                    (gnus-group-real-name
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name
+                       "")))
                (gnus-article-hide-header "newsgroups")))
+            ((eq elem 'to-address)
+             (let ((to (message-fetch-field "to"))
+                   (to-address
+                    (gnus-parameter-to-address
+                     (if (boundp 'gnus-newsgroup-name)
+                         gnus-newsgroup-name ""))))
+               (when (and to to-address
+                          (ignore-errors
+                            (gnus-string-equal
+                             ;; only one address in To
+                             (nth 1 (mail-extract-address-components to))
+                             to-address)))
+                 (gnus-article-hide-header "to"))))
             ((eq elem 'followup-to)
-             (when (equal (message-fetch-field "followup-to")
-                          (message-fetch-field "newsgroups"))
+             (when (gnus-string-equal
+                    (message-fetch-field "followup-to")
+                    (message-fetch-field "newsgroups"))
                (gnus-article-hide-header "followup-to")))
             ((eq elem 'reply-to)
              (let ((from (message-fetch-field "from"))
@@ -1210,7 +1360,7 @@ always hide."
                (when (and
                       from reply-to
                       (ignore-errors
-                        (equal
+                        (gnus-string-equal
                          (nth 1 (mail-extract-address-components from))
                          (nth 1 (mail-extract-address-components reply-to)))))
                  (gnus-article-hide-header "reply-to"))))
@@ -1300,9 +1450,14 @@ always hide."
          (forward-line 1))))))
 
 (defun article-treat-dumbquotes ()
-  "Translate M******** sm*rtq**t*s into proper text.
+  "Translate M****s*** sm*rtq**t*s into proper text.
 Note that this function guesses whether a character is a sm*rtq**t* or
-not, so it should only be used interactively."
+not, so it should only be used interactively.
+
+Sm*rtq**t*s are M****s***'s unilateral extension to the character map
+in an attempt to provide more quoting characters.  If you see
+something like \\222 or \\264 where you're expecting some kind of
+apostrophe or quotation mark, then try this wash."
   (interactive)
   (article-translate-strings gnus-article-dumbquotes-map))
 
@@ -1369,7 +1524,7 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
          (width (window-width (get-buffer-window (current-buffer)))))
       (save-restriction
        (article-goto-body)
-       (let ((adaptive-fill-mode nil))
+       (let ((adaptive-fill-mode nil)) ;Why?  -sm
          (while (not (eobp))
            (end-of-line)
            (when (>= (current-column) (min fill-column width))
@@ -1427,10 +1582,46 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
     (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 "\\([^:]+\\): *")
+