Synch with Oort Gnus.
[elisp/gnus.git-] / lisp / gnus-art.el
index 2cd1726..e7e4098 100644 (file)
@@ -178,15 +178,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',
-`to-address', `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 "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 "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)
 
@@ -626,7 +634,8 @@ Obsolete; use the face `gnus-signature-face' for customizations instead."
       (background light))
      (:foreground "indianred4" :italic t))
     (t
-     (:italic t)))  "Face used for displaying header content."
+     (:italic t)))
+  "Face used for displaying header content."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
 
@@ -842,6 +851,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.
@@ -1163,6 +1179,7 @@ It is a string, such as \"PGP\". If nil, ask user."
     (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)
@@ -1292,66 +1309,65 @@ Initialized from `text-mode-syntax-table.")
        (gnus-article-show-hidden-text 'boring-headers)
        (when (eq 1 (point-min))
          (set-window-start (get-buffer-window (current-buffer)) 1)))
-  (unless gnus-inhibit-hiding
-    (save-excursion
-      (save-restriction
-       (let ((buffer-read-only nil)
-             (inhibit-read-only t)
-             (case-fold-search t)
-             (max (1+ (length gnus-sorted-header-list)))
-             (ignored (when (not gnus-visible-headers)
-                        (cond ((stringp gnus-ignored-headers)
-                               gnus-ignored-headers)
-                              ((listp gnus-ignored-headers)
-                               (mapconcat 'identity gnus-ignored-headers
-                                          "\\|")))))
-             (visible
-              (cond ((stringp gnus-visible-headers)
-                     gnus-visible-headers)
-                    ((and gnus-visible-headers
-                          (listp gnus-visible-headers))
-                     (mapconcat 'identity gnus-visible-headers "\\|"))))
-             (inhibit-point-motion-hooks t)
-             beg)
-         ;; First we narrow to just the headers.
-         (article-narrow-to-head)
-         ;; Hide any "From " lines at the beginning of (mail) articles.
-         (while (looking-at "From ")
-           (forward-line 1))
-         (unless (bobp)
-           (if delete
-               (delete-region (point-min) (point))
-             (gnus-article-hide-text (point-min) (point)
-                                     (nconc (list 'article-type 'headers)
-                                            gnus-hidden-properties))))
-         ;; Then treat the rest of the header lines.
-         ;; Then we use the two regular expressions
-         ;; `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)
-           (beginning-of-line)
-           ;; Mark the rank of the header.
-           (put-text-property
-            (point) (1+ (point)) 'message-rank
-            (if (or (and visible (looking-at visible))
-                    (and ignored
-                         (not (looking-at ignored))))
-                (gnus-article-header-rank)
-              (+ 2 max)))
-           (forward-line 1))
-         (message-sort-headers-1)
-         (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)
-           (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))))))))
+    (unless gnus-inhibit-hiding
+      (save-excursion
+       (save-restriction
+         (let ((inhibit-read-only t)
+               (case-fold-search t)
+               (max (1+ (length gnus-sorted-header-list)))
+               (ignored (when (not gnus-visible-headers)
+                          (cond ((stringp gnus-ignored-headers)
+                                 gnus-ignored-headers)
+                                ((listp gnus-ignored-headers)
+                                 (mapconcat 'identity gnus-ignored-headers
+                                            "\\|")))))
+               (visible
+                (cond ((stringp gnus-visible-headers)
+                       gnus-visible-headers)
+                      ((and gnus-visible-headers
+                            (listp gnus-visible-headers))
+                       (mapconcat 'identity gnus-visible-headers "\\|"))))
+               (inhibit-point-motion-hooks t)
+               beg)
+           ;; First we narrow to just the headers.
+           (article-narrow-to-head)
+           ;; Hide any "From " lines at the beginning of (mail) articles.
+           (while (looking-at "From ")
+             (forward-line 1))
+           (unless (bobp)
+             (if delete
+                 (delete-region (point-min) (point))
+               (gnus-article-hide-text (point-min) (point)
+                                       (nconc (list 'article-type 'headers)
+                                              gnus-hidden-properties))))
+           ;; Then treat the rest of the header lines.
+           ;; Then we use the two regular expressions
+           ;; `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)
+             (beginning-of-line)
+             ;; Mark the rank of the header.
+             (put-text-property
+              (point) (1+ (point)) 'message-rank
+              (if (or (and visible (looking-at visible))
+                      (and ignored
+                           (not (looking-at ignored))))
+                  (gnus-article-header-rank)
+                (+ 2 max)))
+             (forward-line 1))
+           (message-sort-headers-1)
+           (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)
+             (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))))))))
   )
 
 (defun article-hide-boring-headers (&optional arg)
@@ -1396,9 +1412,9 @@ always hide."
             ((eq elem 'to-address)
              (let ((to (message-fetch-field "to"))
                    (to-address
-                    (gnus-group-find-parameter
+                    (gnus-parameter-to-address
                      (if (boundp 'gnus-newsgroup-name)
-                         gnus-newsgroup-name "") 'to-address)))
+                         gnus-newsgroup-name ""))))
                (when (and to to-address
                           (ignore-errors
                             (gnus-string-equal
@@ -1486,8 +1502,7 @@ if given a positive prefix, always hide."
        (header-end (point-min))
        header-start field-end field-start
        (inhibit-point-motion-hooks t)
-       (inhibit-read-only t)
-       buffer-read-only)
+       (inhibit-read-only t))
     (save-restriction
       (widen)
       (while (and (setq header-start
@@ -1668,7 +1683,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))
@@ -1731,41 +1746,41 @@ MAP is an alist where the elements are on the form (\"from\" \"to\")."
          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)))))
+;;     (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))
@@ -1831,38 +1846,38 @@ If PROMPT (the prefix), prompt for a coding system to use."
                           (error))
                         gnus-newsgroup-ignored-charsets))
        ct cte ctl charset format)
-  (save-excursion
-    (save-restriction
-      (article-narrow-to-head)
-      (setq ct (message-fetch-field "Content-Type" t)
-           cte (message-fetch-field "Content-Transfer-Encoding" t)
-           ctl (and ct (ignore-errors
-                         (mail-header-parse-content-type ct)))
-           charset (cond
-                    (prompt
-                     (mm-read-coding-system "Charset to decode: "))
-                    (ctl
-                     (mail-content-type-get ctl 'charset)))
-           format (and ctl (mail-content-type-get ctl 'format)))
-      (when cte
-       (setq cte (mail-header-strip cte)))
-      (if (and ctl (not (string-match "/" (car ctl))))
-         (setq ctl nil))
-      (goto-char (point-max)))
-    (forward-line 1)
-    (save-restriction
-      (narrow-to-region (point) (point-max))
-      (when (and (eq mail-parse-charset 'gnus-decoded)
-                (eq (mm-body-7-or-8) '8bit))
-       ;; The text code could have been decoded.
-       (setq charset mail-parse-charset))
-      (when (and (or (not ctl)
-                    (equal (car ctl) "text/plain"))
-                (not format)) ;; article with format will decode later.
-       (mm-decode-body
-        charset (and cte (intern (downcase
-                                  (gnus-strip-whitespace cte))))
-        (car ctl)))))))
+    (save-excursion
+      (save-restriction
+       (article-narrow-to-head)
+       (setq ct (message-fetch-field "Content-Type" t)
+             cte (message-fetch-field "Content-Transfer-Encoding" t)
+             ctl (and ct (ignore-errors
+                           (mail-header-parse-content-type ct)))
+             charset (cond
+                      (prompt
+                       (mm-read-coding-system "Charset to decode: "))
+                      (ctl
+                       (mail-content-type-get ctl 'charset)))
+             format (and ctl (mail-content-type-get ctl 'format)))
+       (when cte
+         (setq cte (mail-header-strip cte)))
+       (if (and ctl (not (string-match "/" (car ctl))))
+           (setq ctl nil))
+       (goto-char (point-max)))
+      (forward-line 1)
+      (save-restriction
+       (narrow-to-region (point) (point-max))
+       (when (and (eq mail-parse-charset 'gnus-decoded)
+                  (eq (mm-body-7-or-8) '8bit))
+         ;; The text code could have been decoded.
+         (setq charset mail-parse-charset))
+       (when (and (or (not ctl)
+                      (equal (car ctl) "text/plain"))
+                  (not format)) ;; article with format will decode later.
+         (mm-decode-body
+          charset (and cte (intern (downcase
+                                    (gnus-strip-whitespace cte))))
+          (car ctl)))))))
 
 (defun article-decode-encoded-words ()
   "Remove encoded-word encoding from headers."
@@ -1873,11 +1888,12 @@ If PROMPT (the prefix), prompt for a coding system to use."
       (mime-decode-header-in-buffer charset)
       )))
 
-(defun article-de-quoted-unreadable (&optional force)
+(defun article-de-quoted-unreadable (&optional force read-charset)
   "Translate a quoted-printable-encoded article.
 If FORCE, decode the article whether it is marked as quoted-printable
-or not."
-  (interactive (list 'force))
+or not.
+If READ-CHARSET, ask for a coding system."
+  (interactive (list 'force current-prefix-arg))
   (save-excursion
     (let ((buffer-read-only nil) type charset)
       (if (gnus-buffer-live-p gnus-original-article-buffer)
@@ -1892,6 +1908,8 @@ or not."
                                 (mail-content-type-get ctl 'charset)))
              (if (stringp charset)
                  (setq charset (intern (downcase charset)))))))
+      (if read-charset
+         (setq charset (mm-read-coding-system "Charset: " charset)))
       (unless charset
        (setq charset gnus-newsgroup-charset))
       (when (or force
@@ -1901,10 +1919,11 @@ or not."
        (quoted-printable-decode-region
         (point) (point-max) (mm-charset-to-coding-system charset))))))
 
-(defun article-de-base64-unreadable (&optional force)
+(defun article-de-base64-unreadable (&optional force read-charset)
   "Translate a base64 article.
-If FORCE, decode the article whether it is marked as base64 not."
-  (interactive (list 'force))
+If FORCE, decode the article whether it is marked as base64 not.
+If READ-CHARSET, ask for a coding system."
+  (interactive (list 'force current-prefix-arg))
   (save-excursion
     (let ((buffer-read-only nil) type charset)
       (if (gnus-buffer-live-p gnus-original-article-buffer)
@@ -1919,6 +1938,8 @@ If FORCE, decode the article whether it is marked as base64 not."
                                 (mail-content-type-get ctl 'charset)))
              (if (stringp charset)
                  (setq charset (intern (downcase charset)))))))
+      (if read-charset
+         (setq charset (mm-read-coding-system "Charset: " charset)))
       (unless charset
        (setq charset gnus-newsgroup-charset))
       (when (or force
@@ -1942,9 +1963,10 @@ If FORCE, decode the article whether it is marked as base64 not."
     (let ((buffer-read-only nil))
       (rfc1843-decode-region (point-min) (point-max)))))
 
-(defun article-wash-html ()
-  "Format an html article."
-  (interactive)
+(defun article-wash-html (&optional read-charset)
+  "Format an html article.
+If READ-CHARSET, ask for a coding system."
+  (interactive "P")
   (save-excursion
     (let ((buffer-read-only nil)
          charset)
@@ -1958,6 +1980,8 @@ If FORCE, decode the article whether it is marked as base64 not."
                                 (mail-content-type-get ctl 'charset)))
              (if (stringp charset)
                  (setq charset (intern (downcase charset)))))))
+      (if read-charset
+         (setq charset (mm-read-coding-system "Charset: " charset)))
       (unless charset
        (setq charset gnus-newsgroup-charset))
       (article-goto-body)
@@ -2093,11 +2117,11 @@ always hide."
             (start (point))
             (end (point-max))
             (orig (buffer-substring start end))
-             (trans (babel-as-string orig)))
+            (trans (babel-as-string orig)))
        (save-restriction
          (narrow-to-region start end)
          (delete-region start end)
-          (insert trans))))))
+         (insert trans))))))
 
 (defun article-hide-signature (&optional arg)
   "Hide the signature in the current article.
@@ -2185,10 +2209,10 @@ Point is left at the beginning of the narrowed-to region."
          (replace-match "" nil t)))
       ;; Then replace multiple empty lines with a single empty line.
       (article-goto-body)
-      (while (re-search-forward "\n\n\n+" nil t)
+      (while (re-search-forward "\n\n\\(\n+\\)" nil t)
        (unless (gnus-annotation-in-region-p
                 (match-beginning 0) (match-end 0))
-         (replace-match "\n\n" t t))))))
+         (delete-region (match-beginning 1) (match-end 1)))))))
 
 (defun article-strip-leading-space ()
   "Remove all white space from the beginning of the lines in the article."
@@ -2359,8 +2383,8 @@ should replace the \"Date:\" one, or should be added below it."
                    (re-search-forward "^X-Sent:[ \t]" nil t))
            (setq bface (get-text-property (gnus-point-at-bol) 'face)
                  date (or (get-text-property (gnus-point-at-bol)
-                                               'original-date)
-                            date)
+                                             'original-date)
+                          date)
                  eface (get-text-property (1- (gnus-point-at-eol))
                                           'face)))
          (let ((buffer-read-only nil))
@@ -2408,118 +2432,116 @@ should replace the \"Date:\" one, or should be added below it."
 
 (defun article-make-date-line (date type)
   "Return a DATE line of TYPE."
-  (let ((time (condition-case ()
-                 (date-to-time date)
-               (error '(0 0)))))
-    (cond
-     ;; Convert to the local timezone.  We have to slap a
-     ;; `condition-case' round the calls to the timezone
-     ;; functions since they aren't particularly resistant to
-     ;; buggy dates.
-     ((eq type 'local)
-      (let ((tz (car (current-time-zone time))))
-       (format "Date: %s %s%02d%02d" (current-time-string time)
-               (if (> tz 0) "+" "-") (/ (abs tz) 3600)
-               (/ (% (abs tz) 3600) 60))))
-     ;; Convert to Universal Time.
-     ((eq type 'ut)
-      (concat "Date: "
-             (current-time-string
-              (let* ((e (parse-time-string date))
-                     (tm (apply 'encode-time e))
-                     (ms (car tm))
-                     (ls (- (cadr tm) (car (current-time-zone time)))))
-                (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
-                      ((> ls 65535) (list (1+ ms) (- ls 65536)))
-                      (t (list ms ls)))))
-             " UT"))
-     ;; Get the original date from the article.
-     ((eq type 'original)
-      (concat "Date: " (if (string-match "\n+$" date)
-                          (substring date 0 (match-beginning 0))
-                        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))))
-     ;; ISO 8601.
-     ((eq type 'iso8601)
-      (let ((tz (car (current-time-zone time))))
-       (concat
-        "Date: "
-        (format-time-string "%Y%m%dT%H%M%S" time)
-        (format "%s%02d%02d"
-                (if (> tz 0) "+" "-") (/ (abs tz) 3600)
-                (/ (% (abs tz) 3600) 60)))))
-     ;; Do an X-Sent lapsed format.
-     ((eq type 'lapsed)
-      ;; If the date is seriously mangled, the timezone functions are
-      ;; liable to bug out, so we ignore all errors.
-      (let* ((now (current-time))
-            (real-time (subtract-time now time))
-            (real-sec (and real-time
-                           (+ (* (float (car real-time)) 65536)
-                              (cadr real-time))))
-            (sec (and real-time (abs real-sec)))
-            num prev)
+  (unless (memq type '(local ut original user iso8601 lapsed english))
+    (error "Unknown conversion type: %s" type))
+  (condition-case ()
+      (let ((time (date-to-time date)))
        (cond
-        ((null real-time)
-         "X-Sent: Unknown")
-        ((zerop sec)
-         "X-Sent: Now")
-        (t
-         (concat
-          "X-Sent: "
-          ;; This is a bit convoluted, but basically we go
-          ;; through the time units for years, weeks, etc,
-          ;; and divide things to see whether that results
-          ;; in positive answers.
-          (mapconcat
-           (lambda (unit)
-             (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
-                 ;; The (remaining) seconds are too few to
-                 ;; be divided into this time unit.
-                 ""
-               ;; It's big enough, so we output it.
-               (setq sec (- sec (* num (cdr unit))))
-               (prog1
-                   (concat (if prev ", " "") (int-to-string
-                                              (floor num))
-                           " " (symbol-name (car unit))
-                           (if (> num 1) "s" ""))
-                 (setq prev t))))
-           article-time-units "")
-          ;; If dates are odd, then it might appear like the
-          ;; article was sent in the future.
-          (if (> real-sec 0)
-              " ago"
-            " in the future"))))))
-     ;; Display the date in proper English
-     ((eq type 'english)
-      (let ((dtime (decode-time time)))
-       (concat
-        "Date: the "
-        (number-to-string (nth 3 dtime))
-        (let ((digit (% (nth 3 dtime) 10)))
-          (cond
-           ((memq (nth 3 dtime) '(11 12 13)) "th")
-           ((= digit 1) "st")
-           ((= digit 2) "nd")
-           ((= digit 3) "rd")
-           (t "th")))
-        " of "
-        (nth (1- (nth 4 dtime)) gnus-english-month-names)
-        " "
-        (number-to-string (nth 5 dtime))
-        " at "
-        (format "%02d" (nth 2 dtime))
-        ":"
-        (format "%02d" (nth 1 dtime)))))
-     (t
-      (error "Unknown conversion type: %s" type)))))
+        ;; Convert to the local timezone.
+        ((eq type 'local)
+         (let ((tz (car (current-time-zone time))))
+           (format "Date: %s %s%02d%02d" (current-time-string time)
+                   (if (> tz 0) "+" "-") (/ (abs tz) 3600)
+                   (/ (% (abs tz) 3600) 60))))
+        ;; Convert to Universal Time.
+        ((eq type 'ut)
+         (concat "Date: "
+                 (current-time-string
+                  (let* ((e (parse-time-string date))
+                         (tm (apply 'encode-time e))
+                         (ms (car tm))
+                         (ls (- (cadr tm) (car (current-time-zone time)))))
+                    (cond ((< ls 0) (list (1- ms) (+ ls 65536)))
+                          ((> ls 65535) (list (1+ ms) (- ls 65536)))
+                          (t (list ms ls)))))
+                 " UT"))
+        ;; Get the original date from the article.
+        ((eq type 'original)
+         (concat "Date: " (if (string-match "\n+$" date)
+                              (substring date 0 (match-beginning 0))
+                            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))))
+        ;; ISO 8601.
+        ((eq type 'iso8601)
+         (let ((tz (car (current-time-zone time))))
+           (concat
+            "Date: "
+            (format-time-string "%Y%m%dT%H%M%S" time)
+            (format "%s%02d%02d"
+                    (if (> tz 0) "+" "-") (/ (abs tz) 3600)
+                    (/ (% (abs tz) 3600) 60)))))
+        ;; Do an X-Sent lapsed format.
+        ((eq type 'lapsed)
+         ;; If the date is seriously mangled, the timezone functions are
+         ;; liable to bug out, so we ignore all errors.
+         (let* ((now (current-time))
+                (real-time (subtract-time now time))
+                (real-sec (and real-time
+                               (+ (* (float (car real-time)) 65536)
+                                  (cadr real-time))))
+                (sec (and real-time (abs real-sec)))
+                num prev)
+           (cond
+            ((null real-time)
+             "X-Sent: Unknown")
+            ((zerop sec)
+             "X-Sent: Now")
+            (t
+             (concat
+              "X-Sent: "
+              ;; This is a bit convoluted, but basically we go
+              ;; through the time units for years, weeks, etc,
+              ;; and divide things to see whether that results
+              ;; in positive answers.
+              (mapconcat
+               (lambda (unit)
+                 (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
+                     ;; The (remaining) seconds are too few to
+                     ;; be divided into this time unit.
+                     ""
+                   ;; It's big enough, so we output it.
+                   (setq sec (- sec (* num (cdr unit))))
+                   (prog1
+                       (concat (if prev ", " "") (int-to-string
+                                                  (floor num))
+                               " " (symbol-name (car unit))
+                               (if (> num 1) "s" ""))
+                     (setq prev t))))
+               article-time-units "")
+              ;; If dates are odd, then it might appear like the
+              ;; article was sent in the future.
+              (if (> real-sec 0)
+                  " ago"
+                " in the future"))))))
+        ;; Display the date in proper English
+        ((eq type 'english)
+         (let ((dtime (decode-time time)))
+           (concat
+            "Date: the "
+            (number-to-string (nth 3 dtime))
+            (let ((digit (% (nth 3 dtime) 10)))
+              (cond
+               ((memq (nth 3 dtime) '(11 12 13)) "th")
+               ((= digit 1) "st")
+               ((= digit 2) "nd")
+               ((= digit 3) "rd")
+               (t "th")))
+            " of "
+            (nth (1- (nth 4 dtime)) gnus-english-month-names)
+            " "
+            (number-to-string (nth 5 dtime))
+            " at "
+            (format "%02d" (nth 2 dtime))
+            ":"
+            (format "%02d" (nth 1 dtime)))))))
+    (error
+     (format "Date: %s (from Oort)" date))))
 
 (defun article-date-local (&optional highlight)
   "Convert the current article date to the local timezone."
@@ -2606,6 +2628,17 @@ This format is defined by the `gnus-article-time-format' variable."
       (let ((buffer-read-only nil))
        (gnus-article-unhide-text (point-min) (point-max))))))
 
+(defun article-remove-leading-whitespace ()
+  "Remove excessive whitespace from all headers."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (let ((buffer-read-only nil))
+       (article-narrow-to-head)
+       (goto-char (point-min))
+       (while (re-search-forward "^[^ :]+: \\([ \t]+\\)" nil t)
+         (delete-region (match-beginning 1) (match-end 1)))))))
+
 (defun article-emphasize (&optional arg)
   "Emphasize text according to `gnus-emphasis-alist'."
   (interactive (gnus-article-hidden-arg))
@@ -2630,15 +2663,15 @@ This format is defined by the `gnus-article-time-format' variable."
                visible (nth 2 elem)
                face (nth 3 elem))
          (while (re-search-forward regexp nil t)
-           (when (and (match-beginning visible) (match-beginning invisible))
+           (when (and (match-beginning visible) (match-beginning invisible))
              (push 'emphasis gnus-article-wash-types)
-             (gnus-article-hide-text
-              (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
-              (match-beginning visible) (match-end visible) 'face face)
-             (goto-char (match-end invisible)))))))))
+             (gnus-article-hide-text
+              (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
+              (match-beginning visible) (match-end visible) 'face face)
+             (goto-char (match-end invisible)))))))))
 
 (defun gnus-article-setup-highlight-words (&optional highlight-words)
   "Setup newsgroup emphasis alist."
@@ -2660,8 +2693,9 @@ This format is defined by the `gnus-article-time-format' variable."
                                 gnus-newsgroup-name 'highlight-words t)))
             gnus-emphasis-alist)))))
 
-(defvar gnus-summary-article-menu)
-(defvar gnus-summary-post-menu)
+(eval-when-compile
+  (defvar gnus-summary-article-menu)
+  (defvar gnus-summary-post-menu))
 
 ;;; Saving functions.
 
@@ -2764,7 +2798,7 @@ This format is defined by the `gnus-article-time-format' variable."
                         (car (push result file-name-history)))))))
               ;; Create the directory.
               (gnus-make-directory (file-name-directory file))
-      ;; If we have read a directory, we append the default file name.
+              ;; If we have read a directory, we append the default file name.
               (when (file-directory-p file)
                 (setq file (expand-file-name (file-name-nondirectory
                                               default-name)
@@ -2880,7 +2914,7 @@ The directory to save in defaults to `gnus-article-save-directory'."
   (when (string-equal command "")
     (if gnus-last-shell-command
        (setq command gnus-last-shell-command)
-      (error "A command is required.")))
+      (error "A command is required")))
   (gnus-eval-in-buffer-window gnus-article-buffer
     (save-restriction
       (widen)
@@ -2939,9 +2973,20 @@ If variable `gnus-use-long-file-name' is non-nil, it is
       (expand-file-name
        (if (gnus-use-long-file-name 'not-save)
           newsgroup
-        (expand-file-name "news" (gnus-newsgroup-directory-form newsgroup)))
+        (file-relative-name
+         (expand-file-name "news" (gnus-newsgroup-directory-form newsgroup))
+         default-directory))
        gnus-article-save-directory)))
 
+(defun gnus-sender-save-name (newsgroup headers &optional last-file)
+  "Generate file name from sender."
+  (let ((from (mail-header-from headers)))
+    (expand-file-name
+     (if (and from (string-match "\\([^ <]+\\)@" from))
+        (match-string 1 from)
+       "nobody")
+     gnus-article-save-directory)))
+
 (defun article-verify-x-pgp-sig ()
   "Verify X-PGP-Sig."
   (interactive)
@@ -3026,14 +3071,14 @@ If variable `gnus-use-long-file-name' is non-nil, it is
               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))))))))
+            `(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-hide-boring-headers
@@ -3042,6 +3087,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
      article-fill-long-lines
      article-capitalize-sentences
      article-remove-cr
+     article-remove-leading-whitespace
      article-display-x-face
      article-de-quoted-unreadable
      article-de-base64-unreadable
@@ -3108,32 +3154,24 @@ If variable `gnus-use-long-file-name' is non-nil, it is
   "\M-g" gnus-article-read-summary-keys)
 
 ;; Define almost undefined keys to `gnus-article-read-summary-keys'.
-(mapcar
- (lambda (key)
-   (unless (lookup-key gnus-article-mode-map key)
-     (define-key gnus-article-mode-map key
-       'gnus-article-read-summary-keys)))
- (delq nil
-       (append
-       (mapcar
-        (lambda (elt)
-          (let ((key (car elt)))
-            (and (> (length key) 0)
-                 (not (eq 'menu-bar (aref key 0)))
-                 (symbolp (lookup-key gnus-summary-mode-map key))
-                 key)))
-        (accessible-keymaps gnus-summary-mode-map))
-       (let ((c 127)
-             keys)
-         (while (>= c 32)
-           (push (char-to-string c) keys)
-           (decf c))
-         keys))))
-
-(eval-when-compile
-  (defvar gnus-article-commands-menu))
+(let (keys)
+  (let ((key 32))
+    (while (<= key 127)
+      (push (char-to-string key) keys)
+      (incf key))
+    (dolist (elem (accessible-keymaps gnus-summary-mode-map))
+      (setq key (car elem))
+      (when (and (> (length key) 0)
+                (not (eq 'menu-bar (aref key 0)))
+                (symbolp (lookup-key gnus-summary-mode-map key)))
+       (push key keys))))
+  (dolist (key keys)
+    (unless (lookup-key gnus-article-mode-map key)
+      (define-key gnus-article-mode-map key 'gnus-article-read-summary-keys))))
 
 (defun gnus-article-make-menu-bar ()
+  (unless (boundp 'gnus-article-commands-menu)
+    (gnus-summary-make-menu-bar))
   (gnus-turn-off-edit-menu 'article)
   (unless (boundp 'gnus-article-article-menu)
     (easy-menu-define
@@ -3155,20 +3193,14 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        ["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]
        ["Decode HZ" gnus-article-decode-HZ t]))
 
     ;; Note "Commands" menu is defined in gnus-sum.el for consistency
 
-    (when (boundp 'gnus-summary-post-menu)
-      (define-key gnus-article-mode-map [menu-bar post]
-       (cons "Post" gnus-summary-post-menu)))
+    ;; Note "Post" menu is defined in gnus-sum.el for consistency
 
-    (gnus-run-hooks 'gnus-article-menu-hook))
-  ;; Add the menu.
-  (when (boundp 'gnus-article-commands-menu)
-    (easy-menu-add gnus-article-commands-menu gnus-article-mode-map))
-  (when (boundp 'gnus-summary-post-menu)
-    (easy-menu-add gnus-summary-post-menu gnus-article-mode-map)))
+    (gnus-run-hooks 'gnus-article-menu-hook)))
 
 ;; Fixme: do something for the Emacs tool bar in Article mode a la
 ;; Summary.
@@ -3189,8 +3221,6 @@ commands:
 \\[gnus-article-describe-briefly]\t Describe the current mode briefly
 \\[gnus-info-find-node]\t Go to the Gnus info node"
   (interactive)
-  (when (gnus-visual-p 'article-menu 'menu)
-    (gnus-article-make-menu-bar))
   (gnus-simplify-mode-line)
   (setq mode-name "Article")
   (setq major-mode 'gnus-article-mode)
@@ -3198,6 +3228,8 @@ commands:
   (unless (assq 'gnus-show-mime minor-mode-alist)
     (push (list 'gnus-show-mime " MIME") minor-mode-alist))
   (use-local-map gnus-article-mode-map)
+  (when (gnus-visual-p 'article-menu 'menu)
+    (gnus-article-make-menu-bar))
   (gnus-update-format-specifications nil 'article-mode)
   (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
   (make-local-variable 'gnus-page-broken)
@@ -3347,7 +3379,7 @@ If ALL-HEADERS is non-nil, no headers are hidden."
           result)
       (save-excursion
        (gnus-article-setup-buffer)
-       (set-buffer gnus-original-article-buffer)
+       (set-buffer gnus-article-buffer)
        ;; Deactivate active regions.
        (when (and (boundp 'transient-mark-mode)
                   transient-mark-mode)
@@ -3509,29 +3541,36 @@ If ALL-HEADERS is non-nil, no headers are hidden."
 ;;;###autoload
 (defun gnus-article-prepare-display ()
   "Make the current buffer look like a nice article."
-  (setq gnus-article-wash-types nil)
-  (gnus-run-hooks 'gnus-tmp-internal-hook)
-  (gnus-run-hooks 'gnus-article-prepare-hook)
+  (let ((gnus-article-buffer (current-buffer))
+       buffer-read-only)
+    (unless (eq major-mode 'gnus-article-mode)
+      (gnus-article-mode))
+    (setq buffer-read-only nil
+         gnus-button-marker-list nil
+         gnus-article-wash-types nil)
+    (save-restriction
+      (widen)
+      (static-if (featurep 'xemacs)
+         (map-extents (lambda (extent maparg) (delete-extent extent)))
+       (let ((lists (overlay-lists)))
+         (dolist (overlay (nconc (car lists) (cdr lists)))
+           (delete-overlay overlay)))))
+    (gnus-run-hooks 'gnus-tmp-internal-hook))
+  (set-buffer gnus-original-article-buffer)
   ;; Display message.
-  (let (mime-display-header-hook mime-display-text/plain-hook)
-    (funcall (if gnus-show-mime
-                (progn
-                  (setq mime-message-structure gnus-current-headers)
-                  (mime-buffer-entity-set-buffer-internal
-                   mime-message-structure
-                   gnus-original-article-buffer)
-                  (mime-entity-set-representation-type-internal
-                   mime-message-structure 'mime-buffer-entity)
-                  (luna-send mime-message-structure
-                             'initialize-instance
-                             mime-message-structure)
-                  gnus-article-display-method-for-mime)
-              gnus-article-display-method-for-traditional)))
-  ;; Associate this article with the current summary buffer.
-  (setq gnus-article-current-summary gnus-summary-buffer)
+  (setq mime-message-structure gnus-current-headers)
+  (mime-buffer-entity-set-buffer-internal mime-message-structure
+                                         gnus-original-article-buffer)
+  (mime-entity-set-representation-type-internal mime-message-structure
+                                               'mime-buffer-entity)
+  (luna-send mime-message-structure 'initialize-instance
+            mime-message-structure)
+  (if gnus-show-mime
+      (let (mime-display-header-hook mime-display-text/plain-hook)
+       (funcall gnus-article-display-method-for-mime))
+    (funcall gnus-article-display-method-for-traditional))
   ;; Call the treatment functions.
-  (let ((inhibit-read-only t)
-       buffer-read-only)
+  (let ((inhibit-read-only t))
     (save-restriction
       (widen)
       (if gnus-show-mime
@@ -3547,17 +3586,17 @@ If ALL-HEADERS is non-nil, no headers are hidden."
        (narrow-to-region (point) (point-max))
        (gnus-treat-article nil))
       (put-text-property (point-min) (point-max) 'read-only nil)))
-  ;; Perform the article display hooks.  Incidentally, this hook is
-  ;; an obsolete variable by now.
-  (gnus-run-hooks 'gnus-article-display-hook))
+  (gnus-run-hooks 'gnus-article-prepare-hook))
 
 (defun gnus-article-decode-article-as-default-mime-charset ()
   "Decode an article as `default-mime-charset'.  It won't work if the
 value of the variable `gnus-show-mime' is non-nil."
   (unless gnus-show-mime
+    (set (make-local-variable 'default-mime-charset)
+        (with-current-buffer gnus-summary-buffer
+          default-mime-charset))
     (decode-mime-charset-region (point-min) (point-max)
-                               (with-current-buffer gnus-summary-buffer
-                                 default-mime-charset))))
+                               default-mime-charset)))
 
 ;;;
 ;;; Gnus MIME viewing functions
@@ -3598,9 +3637,14 @@ value of the variable `gnus-show-mime' is non-nil."
 
 (defun gnus-article-mime-part-status ()
   (with-current-buffer gnus-article-buffer
-    (let ((entity (get-text-property (point-min) 'mime-view-entity)))
-      (if (and entity (mime-entity-children entity))
-         (format " (%d parts)" (length (mime-entity-children entity)))
+    (let ((entity (get-text-property (point-min) 'mime-view-entity))
+         children)
+      (if (and entity
+              (setq children (mime-entity-children entity))
+              (setq children (length children)))
+         (if (eq 1 children)
+             " (1 part)"
+           (format " (%d parts)" children))
        ""))))
 
 (defvar gnus-mime-button-map
@@ -3645,16 +3689,19 @@ value of the variable `gnus-show-mime' is non-nil."
        (goto-char (point-min))
        (or (search-forward "\n\n") (goto-char (point-max)))
        (let (buffer-read-only)
-         (delete-region (point) (point-max)))
-       (mm-display-parts handles)))))
+         (delete-region (point) (point-max))
+         (mm-display-parts handles))))))
 
 (defun gnus-mime-save-part-and-strip ()
   "Save the MIME part under point then replace it with an external body."
   (interactive)
   (gnus-article-check-buffer)
   (let* ((data (get-text-property (point) 'gnus-data))
-        (file (and data (mm-save-part data)))
-        param)
+        file param
+        (handles gnus-article-mime-handles))
+    (if (mm-multiple-handles gnus-article-mime-handles)
+       (error "This function is not implemented"))
+    (setq file (and data (mm-save-part data)))
     (when file
       (with-current-buffer (mm-handle-buffer data)
        (erase-buffer)
@@ -3673,22 +3720,24 @@ value of the variable `gnus-show-mime' is non-nil."
       (set-buffer gnus-summary-buffer)
       (gnus-article-edit-article
        `(lambda ()
-          (erase-buffer)
-          (let ((mail-parse-charset (or gnus-article-charset
-                                        ',gnus-newsgroup-charset))
-                (mail-parse-ignored-charsets
-                 (or gnus-article-ignored-charsets
-                     ',gnus-newsgroup-ignored-charsets))
-                (mbl mml-buffer-list))
-            (setq mml-buffer-list nil)
-            (insert-buffer gnus-original-article-buffer)
-            (mime-to-mml gnus-article-mime-handles)
-            (setq gnus-article-mime-handles nil)
-            (make-local-hook 'kill-buffer-hook)
-            (let ((mbl1 mml-buffer-list))
-              (setq mml-buffer-list mbl)
-              (set (make-local-variable 'mml-buffer-list) mbl1))
-            (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
+         (erase-buffer)
+         (let ((mail-parse-charset (or gnus-article-charset
+                                       ',gnus-newsgroup-charset))
+               (mail-parse-ignored-charsets
+                (or gnus-article-ignored-charsets
+                    ',gnus-newsgroup-ignored-charsets))
+               (mbl mml-buffer-list))
+           (setq mml-buffer-list nil)
+           (insert-buffer gnus-original-article-buffer)
+           (mime-to-mml ',handles)
+           (setq gnus-article-mime-handles nil)
+           (let ((mbl1 mml-buffer-list))
+             (setq mml-buffer-list mbl)
+             (set (make-local-variable 'mml-buffer-list) mbl1))
+           ;; LOCAL argument of add-hook differs between GNU Emacs
+           ;; and XEmacs. make-local-hook makes sure they are local.
+           (make-local-hook 'kill-buffer-hook)
+           (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t)))
        `(lambda (no-highlight)
          (let ((mail-parse-charset (or gnus-article-charset
                                        ',gnus-newsgroup-charset))
@@ -3697,11 +3746,11 @@ value of the variable `gnus-show-mime' is non-nil."
                (mail-parse-ignored-charsets
                 (or gnus-article-ignored-charsets
                     ',gnus-newsgroup-ignored-charsets)))
-          (mml-to-mime)
-          (mml-destroy-buffers)
-          (remove-hook 'kill-buffer-hook
-                       'mml-destroy-buffers t)
-          (kill-local-variable 'mml-buffer-list))
+           (mml-to-mime)
+           (mml-destroy-buffers)
+           (remove-hook 'kill-buffer-hook
+                        'mml-destroy-buffers t)
+           (kill-local-variable 'mml-buffer-list))
          (gnus-summary-edit-article-done
           ,(or (mail-header-references gnus-current-headers) "")
           ,(gnus-group-read-only-p)
@@ -3729,7 +3778,9 @@ value of the variable `gnus-show-mime' is non-nil."
   (gnus-article-check-buffer)
   (let ((data (get-text-property (point) 'gnus-data)))
     (when data
-      (push (setq data (copy-sequence data)) gnus-article-mime-handles)
+      (setq gnus-article-mime-handles
+           (mm-merge-handles
+            gnus-article-mime-handles (setq data (copy-sequence data))))
       (mm-interactively-view-part data))))
 
 (defun gnus-mime-view-part-as-type-internal ()
@@ -3759,9 +3810,10 @@ value of the variable `gnus-show-mime' is non-nil."
                            (mm-handle-undisplayer handle)
                            (mm-handle-disposition handle)
                            (mm-handle-description handle)
-                           (mm-handle-cache handle)
+                           nil
                            (mm-handle-id handle)))
-      (push handle gnus-article-mime-handles)
+      (setq gnus-article-mime-handles
+           (mm-merge-handles gnus-article-mime-handles handle))
       (gnus-mm-display-part handle))))
 
 (defun gnus-mime-copy-part (&optional handle)
@@ -3812,7 +3864,7 @@ value of the variable `gnus-show-mime' is non-nil."
          (setq charset
                (or (cdr (assq arg
                               gnus-summary-show-article-charset-alist))
-                   (read-coding-system "Charset: ")))))
+                   (mm-read-coding-system "Charset: ")))))
        (forward-line 2)
        (mm-insert-inline handle
                          (if (and charset
@@ -3824,7 +3876,8 @@ value of the variable `gnus-show-mime' is non-nil."
        (goto-char b)))))
 
 (defun gnus-mime-view-part-as-charset (&optional handle arg)
-  "Insert the MIME part under point into the current buffer."
+  "Insert the MIME part under point into the current buffer using the
+specified charset."
   (interactive (list nil current-prefix-arg))
   (gnus-article-check-buffer)
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
@@ -3837,8 +3890,8 @@ value of the variable `gnus-show-mime' is non-nil."
       (let ((gnus-newsgroup-charset
             (or (cdr (assq arg
                            gnus-summary-show-article-charset-alist))
-                (read-coding-system "Charset: ")))
-         (gnus-newsgroup-ignored-charsets 'gnus-all))
+                (mm-read-coding-system "Charset: ")))
+           (gnus-newsgroup-ignored-charsets 'gnus-all))
        (gnus-article-press-button)))))
 
 (defun gnus-mime-externalize-part (&optional handle)
@@ -3859,7 +3912,7 @@ value of the variable `gnus-show-mime' is non-nil."
 
 (defun gnus-mime-internalize-part (&optional handle)
   "View the MIME part under point with an internal viewer.
-In no internal viewer is available, use an external viewer."
+If no internal viewer is available, use an external viewer."
   (interactive)
   (gnus-article-check-buffer)
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
@@ -3992,7 +4045,8 @@ In no internal viewer is available, use an external viewer."
                      ;; This will remove the part.
                      (mm-display-part handle)
                    (save-restriction
-                     (narrow-to-region (point) (1+ (point)))
+                     (narrow-to-region (point)
+                                       (if (eobp) (point) (1+ (point))))
                      (mm-display-part handle)
                      ;; We narrow to the part itself and
                      ;; then call the treatment functions.
@@ -4003,7 +4057,8 @@ In no internal viewer is available, use an external viewer."
                       nil id
                       (gnus-article-mime-total-parts)
                       (mm-handle-media-type handle)))))
-             (select-window window))))
+             (if (window-live-p window)
+                 (select-window window)))))
       (goto-char point)
       (delete-region (gnus-point-at-bol) (progn (forward-line 1) (point)))
       (gnus-insert-mime-button
@@ -4136,6 +4191,8 @@ In no internal viewer is available, use an external viewer."
              (gnus-treat-article 'head))))))))
 
 (defvar gnus-mime-display-multipart-as-mixed nil)
+(defvar gnus-mime-display-multipart-alternative-as-mixed nil)
+(defvar gnus-mime-display-multipart-related-as-mixed nil)
 
 (defun gnus-mime-display-part (handle)
   (cond
@@ -4148,13 +4205,15 @@ In no internal viewer is available, use an external viewer."
             handle))
    ;; multipart/alternative
    ((and (equal (car handle) "multipart/alternative")
-        (not gnus-mime-display-multipart-as-mixed))
+        (not (or gnus-mime-display-multipart-as-mixed
+                 gnus-mime-display-multipart-alternative-as-mixed)))
     (let ((id (1+ (length gnus-article-mime-handle-alist))))
       (push (cons id handle) gnus-article-mime-handle-alist)
       (gnus-mime-display-alternative (cdr handle) nil nil id)))
    ;; multipart/related
    ((and (equal (car handle) "multipart/related")
-        (not gnus-mime-display-multipart-as-mixed))
+        (not (or gnus-mime-display-multipart-as-mixed
+                 gnus-mime-display-multipart-related-as-mixed)))
     ;;;!!!We should find the start part, but we just default
     ;;;!!!to the first part.
     ;;(gnus-mime-display-part (cadr handle))
@@ -4202,7 +4261,9 @@ In no internal viewer is available, use an external viewer."
                                       "inline")
                                (mm-attachment-override-p handle))))
                 (mm-automatic-display-p handle)
-                (or (mm-inlined-p handle)
+                (or (and
+                     (mm-inlinable-p handle)
+                     (mm-inlined-p handle))
                     (mm-automatic-external-display-p type)))
            (setq display t)
          (when (equal (mm-handle-media-supertype handle) "text")
@@ -4574,60 +4635,60 @@ 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"
-           "Zc" "ZC" "ZE" "ZJ" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
-           "=" "^" "\M-^" "|"))
-        (nosave-but-article
-         '("A\r"))
-        (nosave-in-article
-         '("\C-d"))
-        (up-to-top
-         '("n" "Gn" "p" "Gp"))
-        keys new-sum-point)
+        '("q" "Q"  "c" "r" "R" "\C-c\C-f" "m"  "a" "f" "F"
+          "Zc" "ZC" "ZE" "ZJ" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
+          "=" "^" "\M-^" "|"))
+       (nosave-but-article
+        '("A\r"))
+       (nosave-in-article
+        '("\C-d"))
+       (up-to-top
+        '("n" "Gn" "p" "Gp"))
+       keys new-sum-point)
     (save-excursion
       (set-buffer gnus-article-current-summary)
       (let (gnus-pick-mode)
-        (push (or key last-command-event) unread-command-events)
+       (push (or key last-command-event) unread-command-events)
        (setq keys (static-if (featurep 'xemacs)
                       (events-to-keys (read-key-sequence nil))
                     (read-key-sequence nil)))))
     (message "")
 
     (if (or (member keys nosaves)
-            (member keys nosave-but-article)
-            (member keys nosave-in-article))
-        (let (func)
-          (save-window-excursion
-            (pop-to-buffer gnus-article-current-summary 'norecord)
-            ;; We disable the pick minor mode commands.
-            (let (gnus-pick-mode)
-              (setq func (lookup-key (current-local-map) keys))))
-          (if (or (not func)
+           (member keys nosave-but-article)
+           (member keys nosave-in-article))
+       (let (func)
+         (save-window-excursion
+           (pop-to-buffer gnus-article-current-summary 'norecord)
+           ;; We disable the pick minor mode commands.
+           (let (gnus-pick-mode)
+             (setq func (lookup-key (current-local-map) keys))))
+         (if (or (not func)
                  (numberp func))
-              (ding)
-            (unless (member keys nosave-in-article)
-              (set-buffer gnus-article-current-summary))
-            (call-interactively func)
-            (setq new-sum-point (point)))
-          (when (member keys nosave-but-article)
-            (pop-to-buffer gnus-article-buffer 'norecord)))
+             (ding)
+           (unless (member keys nosave-in-article)
+             (set-buffer gnus-article-current-summary))
+           (call-interactively func)
+           (setq new-sum-point (point)))
+         (when (member keys nosave-but-article)
+           (pop-to-buffer gnus-article-buffer 'norecord)))
       ;; These commands should restore window configuration.
       (let ((obuf (current-buffer))
-            (owin (current-window-configuration))
-            (opoint (point))
-            (summary gnus-article-current-summary)
-            func in-buffer selected)
-        (if not-restore-window
-            (pop-to-buffer summary 'norecord)
-          (switch-to-buffer summary 'norecord))
-        (setq in-buffer (current-buffer))
-        ;; We disable the pick minor mode commands.
-        (if (and (setq func (let (gnus-pick-mode)
+           (owin (current-window-configuration))
+           (opoint (point))
+           (summary gnus-article-current-summary)
+           func in-buffer selected)
+       (if not-restore-window
+           (pop-to-buffer summary 'norecord)
+         (switch-to-buffer summary 'norecord))
+       (setq in-buffer (current-buffer))
+       ;; We disable the pick minor mode commands.
+       (if (and (setq func (let (gnus-pick-mode)
                              (lookup-key (current-local-map) keys)))
                 (functionp func))
-            (progn
-              (call-interactively func)
-              (setq new-sum-point (point))
+           (progn
+             (call-interactively func)
+             (setq new-sum-point (point))
              (when (eq in-buffer (current-buffer))
                (setq selected (gnus-summary-select-article))
                (set-buffer obuf)
@@ -4643,7 +4704,7 @@ Argument LINES specifies lines to be scrolled down."
                  (when win
                    (set-window-point win new-sum-point))))    )
          (switch-to-buffer gnus-article-buffer)
-          (ding))))))
+         (ding))))))
 
 (defun gnus-article-describe-key (key)
   "Display documentation of the function invoked by KEY.  KEY is a string."
@@ -4653,10 +4714,16 @@ Argument LINES specifies lines to be scrolled down."
       (save-excursion
        (set-buffer gnus-article-current-summary)
        (let (gnus-pick-mode)
-         (push (elt key 0) unread-command-events)
-         (setq key (if (featurep 'xemacs)
-                       (events-to-keys (read-key-sequence "Describe key: "))
-                     (read-key-sequence "Describe key: "))))
+         (if (featurep 'xemacs)
+             (progn
+               (push (elt key 0) unread-command-events)
+               (setq key (events-to-keys
+                          (read-key-sequence "Describe key: "))))
+           (setq unread-command-events
+                 (mapcar
+                  (lambda (x) (if (>= x 128) (list 'meta (- x 128)) x))
+                  key))
+           (setq key (read-key-sequence "Describe key: "))))
        (describe-key key))
     (describe-key key)))
 
@@ -4668,10 +4735,16 @@ Argument LINES specifies lines to be scrolled down."
       (save-excursion
        (set-buffer gnus-article-current-summary)
        (let (gnus-pick-mode)
-         (push (elt key 0) unread-command-events)
-         (setq key (if (featurep 'xemacs)
-                       (events-to-keys (read-key-sequence "Describe key: "))
-                     (read-key-sequence "Describe key: "))))
+         (if (featurep 'xemacs)
+             (progn
+               (push (elt key 0) unread-command-events)
+               (setq key (events-to-keys
+                          (read-key-sequence "Describe key: "))))
+           (setq unread-command-events
+                 (mapcar
+                  (lambda (x) (if (>= x 128) (list 'meta (- x 128)) x))
+                  key))
+           (setq key (read-key-sequence "Describe key: "))))
        (describe-key-briefly key insert))
     (describe-key-briefly key insert)))
 
@@ -4891,21 +4964,18 @@ If given a prefix, show the hidden text instead."
                     "\C-c\C-w" gnus-article-edit-mode-map)
     "f" gnus-article-edit-full-stops))
 
-(defun gnus-article-edit-mode ()
+(define-derived-mode gnus-article-edit-mode text-mode "Article Edit"
   "Major mode for editing articles.
 This is an extended text-mode.
 
 \\{gnus-article-edit-mode-map}"
-  (interactive)
-  (setq major-mode 'gnus-article-edit-mode)
-  (setq mode-name "Article Edit")
-  (use-local-map gnus-article-edit-mode-map)
   (make-local-variable 'gnus-article-edit-done-function)
   (make-local-variable 'gnus-prev-winconf)
+  (set (make-local-variable 'font-lock-defaults)
+       '(message-font-lock-keywords t))
   (setq buffer-read-only nil)
   (buffer-enable-undo)
-  (widen)
-  (gnus-run-hooks 'text-mode-hook 'gnus-article-edit-mode-hook))
+  (widen))
 
 (defun gnus-article-edit (&optional force)
   "Edit the current article.
@@ -4931,12 +5001,13 @@ groups."
     (set-buffer gnus-article-buffer)
     (gnus-article-edit-mode)
     (funcall start-func)
+    (set-buffer-modified-p nil)
     (gnus-configure-windows 'edit-article)
     (setq gnus-article-edit-done-function exit-func)
     (setq gnus-prev-winconf winconf)
     (when gnus-article-edit-article-setup-function
       (funcall gnus-article-edit-article-setup-function))
-    (gnus-message 6 "C-c C-c to end edits")))
+    (gnus-message 6 "C-c C-c to end edits; C-c C-k to exit")))
 
 (defun gnus-article-edit-done (&optional arg)
   "Update the article edits and exit."
@@ -4946,7 +5017,20 @@ groups."
        (start (window-start)))
     (remove-hook 'gnus-article-mode-hook
                 'gnus-article-mime-edit-article-unwind)
-    (gnus-article-edit-exit)
+    ;; 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))))
     (save-excursion
       (set-buffer buf)
       (let ((buffer-read-only nil))
@@ -4970,21 +5054,22 @@ groups."
 (defun gnus-article-edit-exit ()
   "Exit the article editing without updating."
   (interactive)
-  ;; We remove all text props from the article buffer.
-  (let ((buf (buffer-substring-no-properties (point-min) (point-max)))
-       (curbuf (current-buffer))
-       (p (point))
-       (window-start (window-start)))
-    (erase-buffer)
-    (insert buf)
-    (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 curbuf)
-       (set-window-start (get-buffer-window (current-buffer)) window-start)
-       (goto-char p)))))
+  (when (or (not (buffer-modified-p))
+           (yes-or-no-p "Article modified; kill anyway? "))
+    (let ((curbuf (current-buffer))
+         (p (point))
+         (window-start (window-start)))
+      (erase-buffer)
+      (if (gnus-buffer-live-p gnus-original-article-buffer)
+         (insert-buffer gnus-original-article-buffer))
+      (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 curbuf)
+         (set-window-start (get-buffer-window (current-buffer)) window-start)
+         (goto-char p))))))
 
 (defun gnus-article-edit-full-stops ()
   "Interactively repair spacing at end of sentences."
@@ -5007,12 +5092,12 @@ groups."
 (defun gnus-article-mime-edit-article-unwind ()
   "Unwind `gnus-article-buffer' if article editing was given up."
   (remove-hook 'gnus-article-mode-hook 'gnus-article-mime-edit-article-unwind)
-  (when mime-edit-mode-flag
-    (mime-edit-exit 'nomime 'no-error)
-    (message ""))
   (when (featurep 'font-lock)
     (setq font-lock-defaults nil)
-    (font-lock-mode 0)))
+    (font-lock-mode -1))
+  (when mime-edit-mode-flag
+    (mime-edit-exit 'nomime 'no-error)
+    (message "")))
 
 (defun gnus-article-mime-edit-article-setup ()
   "Convert current buffer to MIME-Edit buffer and turn on MIME-Edit mode
@@ -5021,7 +5106,8 @@ after replacing with the original article."
   (setq gnus-article-edit-done-function
        `(lambda (&rest args)
           (when mime-edit-mode-flag
-            (mime-edit-exit)
+            (let (mime-edit-insert-user-agent-field)
+              (mime-edit-exit))
             (message ""))
           (goto-char (point-min))
           (let (case-fold-search)
@@ -5029,53 +5115,79 @@ after replacing with the original article."
                    (format "^%s$" (regexp-quote mail-header-separator))
                    nil t)
               (replace-match "")))
-          (when (featurep 'font-lock)
-            (setq font-lock-defaults nil)
-            (font-lock-mode 0))
           (apply ,gnus-article-edit-done-function args)
-          (set-buffer gnus-original-article-buffer)
-          (erase-buffer)
-          (insert-buffer gnus-article-buffer)
+          (insert
+           (prog1
+               (buffer-substring-no-properties (point-min) (point-max))
+             (set-buffer (get-buffer-create gnus-original-article-buffer))
+             (erase-buffer)))
           (setq gnus-current-headers (gnus-article-make-full-mail-header))
+          (set-buffer gnus-article-buffer)
           (gnus-article-prepare-display)))
-  (substitute-key-definition
-   'gnus-article-edit-exit 'gnus-article-mime-edit-exit
-   gnus-article-edit-mode-map)
+  (substitute-key-definition 'gnus-article-edit-done
+                            'gnus-article-mime-edit-done
+                            gnus-article-edit-mode-map)
+  (substitute-key-definition 'gnus-article-edit-exit
+                            'gnus-article-mime-edit-exit
+                            gnus-article-edit-mode-map)
   (erase-buffer)
   (insert-buffer gnus-original-article-buffer)
-  (mime-edit-again)
+  (let ((ofn (symbol-function 'mime-edit-decode-single-part-in-buffer)))
+    (fset 'mime-edit-decode-single-part-in-buffer
+         (lambda (&rest args)
+           (if (let ((content-type (car args)))
+                 (and (eq 'message (mime-content-type-primary-type
+                                    content-type))
+                      (eq 'rfc822 (mime-content-type-subtype content-type))))
+               (setcar (cdr args) 'not-decode-text))
+           (apply ofn args)))
+    (unwind-protect
+       (mime-edit-again)
+      (fset 'mime-edit-decode-single-part-in-buffer ofn)))
   (when (featurep 'font-lock)
     (set (make-local-variable 'font-lock-defaults)
         '(message-font-lock-keywords t))
     (font-lock-set-defaults)
     (turn-on-font-lock))
+  (set-buffer-modified-p nil)
+  (delete-other-windows)
   (add-hook 'gnus-article-mode-hook 'gnus-article-mime-edit-article-unwind)
   (gnus-run-hooks 'gnus-article-mime-edit-article-setup-hook))
 
+(defun gnus-article-mime-edit-done (&optional arg)
+  "Update the article MIME edits and exit."
+  (interactive "P")
+  (when (featurep 'font-lock)
+    (setq font-lock-defaults nil)
+    (font-lock-mode -1))
+  (gnus-article-edit-done arg))
+
 (defun gnus-article-mime-edit-exit ()
   "Exit the article MIME editing without updating."
   (interactive)
-  (let ((winconf gnus-prev-winconf)
-       buf)
+  (when (or (not (buffer-modified-p))
+           (yes-or-no-p "Article modified; kill anyway? "))
+    (when (featurep 'font-lock)
+      (setq font-lock-defaults nil)
+      (font-lock-mode -1))
     (when mime-edit-mode-flag
-      (mime-edit-exit)
+      (let (mime-edit-insert-user-agent-field)
+       (mime-edit-exit))
       (message ""))
     (goto-char (point-min))
     (let (case-fold-search)
       (when (re-search-forward
             (format "^%s$" (regexp-quote mail-header-separator)) nil t)
        (replace-match "")))
-    (when (featurep 'font-lock)
-      (setq font-lock-defaults nil)
-      (font-lock-mode 0))
-    ;; We remove all text props from the article buffer.
-    (setq buf (buffer-substring-no-properties (point-min) (point-max)))
-    (set-buffer (get-buffer-create gnus-original-article-buffer))
-    (erase-buffer)
-    (insert buf)
-    (setq gnus-current-headers (gnus-article-make-full-mail-header))
-    (gnus-article-prepare-display)
-    (set-window-configuration winconf)))
+    (let ((winconf gnus-prev-winconf))
+      (insert (prog1
+                 (buffer-substring-no-properties (point-min) (point-max))
+               (set-buffer (get-buffer-create gnus-original-article-buffer))
+               (erase-buffer)))
+      (setq gnus-current-headers (gnus-article-make-full-mail-header))
+      (set-buffer gnus-article-buffer)
+      (gnus-article-prepare-display)
+      (set-window-configuration winconf))))
 
 ;;;
 ;;; Article highlights
@@ -5091,9 +5203,10 @@ after replacing with the original article."
   :type 'regexp)
 
 (defcustom gnus-button-alist
-  `(("<\\(url:[>\n\t ]*?\\)?news:[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>"
-     0 t gnus-button-message-id 2)
-    ("\\bnews:\\([^>\n\t ]*@[^>)!;:,\n\t ]*\\)" 0 t gnus-button-message-id 1)
+  `(("<\\(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)
     ("\\(\\b<\\(url:[>\n\t ]*\\)?news:[>\n\t ]*\\(//\\)?\\([^>\n\t ]*\\)>\\)"
      1 t
      gnus-button-fetch-group 4)
@@ -5175,7 +5288,7 @@ call it with the value of the `gnus-data' text property."
   (interactive "e")
   (set-buffer (window-buffer (posn-window (event-start event))))
   (let* ((pos (posn-point (event-start event)))
-         (data (get-text-property pos 'gnus-data))
+        (data (get-text-property pos 'gnus-data))
         (fun (get-text-property pos 'gnus-callback)))
     (goto-char pos)
     (when fun
@@ -5479,6 +5592,45 @@ specified by `gnus-button-alist'."
        (gnus-message 1 "You must define `%S' to use this button"
                      (cons fun args)))))))
 
+(defun gnus-parse-news-url (url)
+  (let (scheme server group message-id articles)
+    (with-temp-buffer
+      (insert url)
+      (goto-char (point-min))
+      (when (looking-at "\\([A-Za-z]+\\):")
+       (setq scheme (match-string 1))
+       (goto-char (match-end 0)))
+      (when (looking-at "//\\([^/]+\\)/")
+       (setq server (match-string 1))
+       (goto-char (match-end 0)))
+
+      (cond
+       ((looking-at "\\(.*@.*\\)")
+       (setq message-id (match-string 1)))
+       ((looking-at "\\([^/]+\\)/\\([-0-9]+\\)")
+       (setq group (match-string 1)
+             articles (split-string (match-string 2) "-")))
+       ((looking-at "\\([^/]+\\)/?")
+       (setq group (match-string 1)))
+       (t
+       (error "Unknown news URL syntax"))))
+    (list scheme server group message-id articles)))
+
+(defun gnus-button-handle-news (url)
+  "Fetch a news URL."
+  (destructuring-bind (scheme server group message-id articles)
+      (gnus-parse-news-url url)
+    (cond
+     (message-id
+      (save-excursion
+       (set-buffer gnus-summary-buffer)
+       (if server
+           (let ((gnus-refer-article-method (list (list 'nntp server))))
+             (gnus-summary-refer-article message-id))
+         (gnus-summary-refer-article message-id))))
+     (group
+      (gnus-button-fetch-group url)))))
+
 (defun gnus-button-message-id (message-id)
   "Fetch MESSAGE-ID."
   (save-excursion
@@ -5506,24 +5658,24 @@ specified by `gnus-button-alist'."
     (setq pairs (split-string query "&"))
     (while pairs
       (setq cur (car pairs)
-            pairs (cdr pairs))
+           pairs (cdr pairs))
       (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)))
-        (if downcase
-            (setq key (downcase key)))
-        (setq cur (assoc key retval))
-        (if cur
-            (setcdr cur (cons val (cdr cur)))
-          (setq retval (cons (list key val) retval)))))
+         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)))
+       (if downcase
+           (setq key (downcase key)))
+       (setq cur (assoc key retval))
+       (if cur
+           (setcdr cur (cons val (cdr cur)))
+         (setq retval (cons (list key val) retval)))))
     retval))
 
 (defun gnus-url-unhex (x)
   (if (> x ?9)
       (if (>= x ?a)
-          (+ 10 (- x ?a))
-        (+ 10 (- x ?A)))
+         (+ 10 (- x ?a))
+       (+ 10 (- x ?A)))
     (- x ?0)))
 
 (defun gnus-url-unhex-string (str &optional allow-newlines)
@@ -5533,21 +5685,21 @@ decoding of carriage returns and line feeds in the string, which is normally
 forbidden in URL encoding."
   (setq str (or str ""))
   (let ((tmp "")
-        (case-fold-search t))
+       (case-fold-search t))
     (while (string-match "%[0-9a-f][0-9a-f]" str)
       (let* ((start (match-beginning 0))
-             (ch1 (gnus-url-unhex (elt str (+ start 1))))
-             (code (+ (* 16 ch1)
-                      (gnus-url-unhex (elt str (+ start 2))))))
-        (setq tmp (concat
-                   tmp (substring str 0 start)
-                   (cond
-                    (allow-newlines
-                     (char-to-string code))
-                    ((or (= code ?\n) (= code ?\r))
-                     " ")
-                    (t (char-to-string code))))
-              str (substring str (match-end 0)))))
+            (ch1 (gnus-url-unhex (elt str (+ start 1))))
+            (code (+ (* 16 ch1)
+                     (gnus-url-unhex (elt str (+ start 2))))))
+       (setq tmp (concat
+                  tmp (substring str 0 start)
+                  (cond
+                   (allow-newlines
+                    (char-to-string code))
+                   ((or (= code ?\n) (= code ?\r))
+                    " ")
+                   (t (char-to-string code))))
+             str (substring str (match-end 0)))))
     (setq tmp (concat tmp str))
     tmp))
 
@@ -5557,22 +5709,22 @@ forbidden in URL encoding."
     (setq url (substring url (match-beginning 1) nil)))
   (let (to args subject func)
     (if (string-match (regexp-quote "?") url)
-        (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
-              args (gnus-url-parse-query-string
-                    (substring url (match-end 0) nil) t))
+       (setq to (gnus-url-unhex-string (substring url 0 (match-beginning 0)))
+             args (gnus-url-parse-query-string
+                   (substring url (match-end 0) nil) t))
       (setq to (gnus-url-unhex-string url)))
     (setq args (cons (list "to" to) args)
-          subject (cdr-safe (assoc "subject" args)))
+         subject (cdr-safe (assoc "subject" args)))
     (gnus-msg-mail)
     (while args
       (setq func (intern-soft (concat "message-goto-" (downcase (caar args)))))
       (if (fboundp func)
-          (funcall func)
-        (message-position-on-field (caar args)))
+         (funcall func)
+       (message-position-on-field (caar args)))
       (insert (mapconcat 'identity (cdar args) ", "))
       (setq args (cdr args)))
     (if subject
-        (message-goto-body)
+       (message-goto-body)
       (message-goto-subject))))
 
 (defun gnus-button-embedded-url (address)
@@ -5705,7 +5857,7 @@ For example:
                         (string-match (car x) gnus-newsgroup-name))
                    (nconc gnus-decode-header-methods-cache
                           (list (cdr x))))))
-         gnus-decode-header-methods))
+           gnus-decode-header-methods))
   (let ((xlist gnus-decode-header-methods-cache))
     (pop xlist)
     (save-restriction
@@ -5819,9 +5971,9 @@ For example:
     (unless func
       (error (format "Can't find the encrypt protocol %s" protocol)))
     (if (equal gnus-newsgroup-name "nndraft:drafts")
-       (error "Can't encrypt the article in group nndraft:drafts."))
+       (error "Can't encrypt the article in group nndraft:drafts"))
     (if (equal gnus-newsgroup-name "nndraft:queue")
-       (error "Don't encrypt the article in group nndraft:queue."))
+       (error "Don't encrypt the article in group nndraft:queue"))
     (gnus-summary-iterate n
       (save-excursion
        (set-buffer gnus-summary-buffer)
@@ -5834,7 +5986,7 @@ For example:
            (error "The current newsgroup does not support article encrypt"))
          (gnus-summary-show-article t)
          (setq references
-             (or (mail-header-references gnus-current-headers) ""))
+               (or (mail-header-references gnus-current-headers) ""))
          (set-buffer gnus-article-buffer)
          (let* ((buffer-read-only nil)
                 (headers
@@ -5940,7 +6092,7 @@ For example:
            (let ((gnus-mime-security-button-pressed t)
                  (gnus-mime-security-button-line-format
                   (get-text-property (point) 'gnus-line-format))
-               buffer-read-only)
+                 buffer-read-only)
              (forward-char -1)
              (while (eq (get-text-property (point) 'gnus-line-format)
                         gnus-mime-security-button-line-format)
@@ -5949,8 +6101,8 @@ For example:
              (delete-region (point)
                             (or (text-property-not-all
                                  (point) (point-max)
-                               'gnus-line-format
-                               gnus-mime-security-button-line-format)
+                                 'gnus-line-format
+                                 gnus-mime-security-button-line-format)
                                 (point-max)))
              (gnus-insert-mime-security-button handle))
          (if (gnus-buffer-live-p gnus-mime-security-details-buffer)