(mime-edit-normalize-body): Don't use the `(replace-match "\\1\r\n")' form
[elisp/semi.git] / mime-edit.el
index 66ede32..18263bf 100644 (file)
@@ -1,10 +1,11 @@
 ;;; mime-edit.el --- Simple MIME Composer for GNU Emacs
 
-;; Copyright (C) 1993,1994,1995,1996,1997,1998 Free Software Foundation, Inc.
+;; Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,03
+;;   Free Software Foundation, Inc.
 
 ;; Author: UMEDA Masanobu <umerin@mse.kyutech.ac.jp>
-;;         MORIOKA Tomohiko <morioka@jaist.ac.jp>
-;; Maintainer: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;;     MORIOKA Tomohiko <tomo@kanji.zinbun.kyoto-u.ac.jp>
+;;     Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
 ;; Created: 1994/08/21 renamed from mime.el
 ;;     Renamed: 1997/2/21 from tm-edit.el
 ;; Keywords: MIME, multimedia, multilingual, mail, news
 
 ;;; Code:
 
-(require 'emu)
 (require 'sendmail)
 (require 'mail-utils)
 (require 'mel)
 (require 'mime-view)
 (require 'signature)
 (require 'alist)
+(require 'invisible)
+(require 'pgg-def)
+(require 'pgg-parse)
+
+(autoload 'pgg-encrypt-region "pgg"
+  "PGP encryption of current region." t)
+(autoload 'pgg-sign-region "pgg"
+  "PGP signature of current region." t)
+(autoload 'pgg-insert-key "pgg"
+  "Insert PGP public key at point." t)
+(autoload 'smime-encrypt-region "smime"
+  "S/MIME encryption of current region.")
+(autoload 'smime-sign-region "smime"
+  "S/MIME signature of current region.")
+(defvar smime-output-buffer)
+(defvar smime-errors-buffer)
 
 
 ;;; @ version
 ;;;
 
-(defconst mime-edit-version-string
-  `,(concat (car mime-user-interface-version) " "
-           (mapconcat #'number-to-string
-                      (cddr mime-user-interface-version) ".")
-           " - \"" (cadr mime-user-interface-version) "\""))
+(eval-and-compile
+  (defconst mime-edit-version
+    (concat
+     (mime-product-name mime-user-interface-product) " "
+     (mapconcat #'number-to-string
+               (mime-product-version mime-user-interface-product) ".")
+     " - \"" (mime-product-code-name mime-user-interface-product) "\"")))
 
 
 ;;; @ variables
@@ -185,11 +203,11 @@ To insert a signature file automatically, call the function
       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
       )
      ("enriched")
-     ("x-latex")
      ("html")
      ("css") ; rfc2318
      ("xml") ; rfc2376
-     ("x-rot13-47-48")
+     ("x-latex")
+     ;; ("x-rot13-47-48")
      )
     ("message"
      ("external-body"
@@ -218,6 +236,7 @@ To insert a signature file automatically, call the function
     ("application"
      ("octet-stream" ("type" "" "tar" "shar"))
      ("postscript")
+     ("vnd.ms-powerpoint")
      ("x-kiss" ("x-cnf")))
     ("image"
      ("gif")
@@ -235,30 +254,93 @@ To insert a signature file automatically, call the function
   "*Alist of content-type, subtype, parameters and its values.")
 
 (defcustom mime-file-types
-  '(("\\.txt$"
+  '(
+
+    ;; Programming languages
+
+    ("\\.cc$"
+     "application" "octet-stream" (("type" . "C++"))
+     "7bit"
+     "attachment"      (("filename" . file))
+     )
+
+    ("\\.el$"
+     "application" "octet-stream" (("type" . "emacs-lisp"))
+     "7bit"
+     "attachment"      (("filename" . file))
+     )
+
+    ("\\.lsp$"
+     "application" "octet-stream" (("type" . "common-lisp"))
+     "7bit"
+     "attachment"      (("filename" . file))
+     )
+
+    ("\\.pl$"
+     "application" "octet-stream" (("type" . "perl"))
+     "7bit"
+     "attachment"      (("filename" . file))
+     )
+
+    ;; Text or translated text
+
+    ("\\.txt$"
      "text"    "plain"         nil
      nil
      "inline"          (("filename" . file))
      )
-    ("\\.pln$"
+
+     ;; .rc : procmail modules pm-xxxx.rc
+     ;; *rc : other resource files
+
+    ("\\.\\(rc\\|lst\\|log\\|sql\\|mak\\)$\\|\\..*rc$"
      "text"    "plain"         nil
      nil
-     "inline"          (("filename" . file))
+     "attachment"      (("filename" . file))
      )
-    ("\\.rtf$"
-     "text"    "richtext"      nil
-     nil
-     nil               nil)
+
     ("\\.html$"
      "text"    "html"          nil
      nil
      nil               nil)
+
+    ("\\.diff$\\|\\.patch$"
+     "application" "octet-stream" (("type" . "patch"))
+     nil
+     "attachment"      (("filename" . file))
+     )
+
+    ("\\.signature"
+     "text"    "plain"         nil     nil     nil     nil)
+
+
+    ;;  Octect binary text
+
+    ("\\.doc$"                         ;MS Word
+     "application" "msword" nil
+     "base64"
+     "attachment" (("filename" . file))
+     )
+    ("\\.ppt$"                         ; MS Power Point
+     "application" "vnd.ms-powerpoint" nil
+     "base64"
+     "attachment" (("filename" . file))
+     )
+
+    ("\\.pln$"
+     "text"    "plain"         nil
+     nil
+     "inline"          (("filename" . file))
+     )
     ("\\.ps$"
      "application" "postscript"        nil
      "quoted-printable"
      "attachment"      (("filename" . file))
      )
-    ("\\.jpg$"
+
+    ;;  Pure binary
+
+    ("\\.jpg$\\|\\.jpeg$"
      "image"   "jpeg"          nil
      "base64"
      "inline"          (("filename" . file))
@@ -308,16 +390,6 @@ To insert a signature file automatically, call the function
      "base64"
      "attachment"      (("filename" . file))
      )
-    ("\\.el$"
-     "application" "octet-stream" (("type" . "emacs-lisp"))
-     "7bit"
-     "attachment"      (("filename" . file))
-     )
-    ("\\.lsp$"
-     "application" "octet-stream" (("type" . "common-lisp"))
-     "7bit"
-     "attachment"      (("filename" . file))
-     )
     ("\\.tar\\.gz$"
      "application" "octet-stream" (("type" . "tar+gzip"))
      "base64"
@@ -358,18 +430,9 @@ To insert a signature file automatically, call the function
      "base64"
      "attachment"      (("filename" . file))
      )
-    ("\\.diff$"
-     "application" "octet-stream" (("type" . "patch"))
-     nil
-     "attachment"      (("filename" . file))
-     )
-    ("\\.patch$"
-     "application" "octet-stream" (("type" . "patch"))
-     nil
-     "attachment"      (("filename" . file))
-     )
-    ("\\.signature"
-     "text"    "plain"         nil     nil     nil     nil)
+
+    ;; Rest
+
     (".*"
      "application" "octet-stream" nil
      nil
@@ -405,9 +468,9 @@ If encoding is nil, it is determined from its contents."
                        ,@(cons
                           '(const nil)
                           (mapcar (lambda (cell)
-                                    (list 'item (car cell))
+                                    (list 'item cell)
                                     )
-                                  mime-file-encoding-method-alist)))
+                                  (mime-encoding-list))))
                ;; disposition-type
                (choice :tag "Disposition-Type"
                        (item nil)
@@ -435,14 +498,18 @@ If encoding is nil, it is determined from its contents."
     (iso-8859-7                8 "quoted-printable")
     (iso-8859-8                8 "quoted-printable")
     (iso-8859-9                8 "quoted-printable")
+    (iso-8859-14       8 "quoted-printable")
+    (iso-8859-15       8 "quoted-printable")
     (iso-2022-jp       7 "base64")
+    (iso-2022-jp-3     7 "base64")
     (iso-2022-kr       7 "base64")
     (euc-kr            8 "base64")
-    (cn-gb2312         8 "base64")
+    (cn-gb             8 "base64")
     (gb2312            8 "base64")
     (cn-big5           8 "base64")
     (big5              8 "base64")
     (shift_jis         8 "base64")
+    (tis-620           8 "base64")
     (iso-2022-jp-2     7 "base64")
     (iso-2022-int-1    7 "base64")
     ))
@@ -462,6 +529,10 @@ If encoding is nil, it is determined from its contents."
   "A string formatted version of mime-transfer-level")
 (make-variable-buffer-local 'mime-transfer-level-string)
 
+;;; @@ about content transfer encoding
+
+(defvar mime-content-transfer-encoding-priority-list
+  '(nil "8bit" "binary"))
 
 ;;; @@ about message inserting
 ;;;
@@ -504,7 +575,7 @@ If it is not specified for a major-mode,
   :type 'list)
 
 (defconst mime-edit-split-ignored-field-regexp
-  "\\(^Content-\\|^Subject:\\|^Mime-Version:\\|Message-Id:\\)")
+  "\\(^Content-\\|^Subject:\\|^Mime-Version:\\|^Message-Id:\\)")
 
 (defcustom mime-edit-split-blind-field-regexp
   "\\(^[BDFbdf]cc:\\|^cc:[ \t]*$\\)"
@@ -565,35 +636,62 @@ If it is not specified for a major-mode,
   "*If non-nil, insert User-Agent header field.")
 
 (defvar mime-edit-user-agent-value
-  (concat (car mime-user-interface-version)
+  (concat (mime-product-name mime-user-interface-product)
          "/"
          (mapconcat #'number-to-string
-                    (cddr mime-user-interface-version) ".")
+                    (mime-product-version mime-user-interface-product) ".")
          " ("
-         (cadr mime-user-interface-version)
+         (mime-product-code-name mime-user-interface-product)
          ") "
-         (car mime-library-version)
+         (mime-product-name mime-library-product)
          "/"
          (mapconcat #'number-to-string
-                    (cddr mime-library-version) ".")
+                    (mime-product-version mime-library-product) ".")
          " ("
-         (cadr mime-library-version)
+         (mime-product-code-name mime-library-product)
          ") "
+         (if (fboundp 'apel-version)
+             (concat (apel-version) " "))
          (if (featurep 'xemacs)
-             (concat "XEmacs"
-                     (if (string-match "\\s +\\\"" emacs-version)
-                         (concat "/"
-                                 (substring emacs-version 0
-                                            (match-beginning 0))
-                                 " (" xemacs-codename ")")
-                       " (" emacs-version ")")
-                     (if (featurep 'mule) " MULE"))
+             (concat (cond ((and (featurep 'chise)
+                                 (boundp 'xemacs-chise-version))
+                            (concat "CHISE-MULE/" xemacs-chise-version))
+                           ((featurep 'utf-2000)
+                            (concat "UTF-2000-MULE/" utf-2000-version))
+                           ((featurep 'mule) "MULE"))
+                     " XEmacs"
+                     (if (string-match "^[0-9]+\\(\\.[0-9]+\\)" emacs-version)
+                         (concat
+                          "/"
+                          (substring emacs-version 0 (match-end 0))
+                          (cond ((and (boundp 'xemacs-betaname)
+                                      xemacs-betaname)
+                                 ;; It does not exist in XEmacs
+                                 ;; versions prior to 20.3.
+                                 (concat " " xemacs-betaname))
+                                ((and (boundp 'emacs-patch-level)
+                                      emacs-patch-level)
+                                 ;; It does not exist in FSF Emacs or in
+                                 ;; XEmacs versions earlier than 21.1.1.
+                                 (format " (patch %d)" emacs-patch-level))
+                                (t ""))
+                          " (" xemacs-codename ")"
+                          ;; `xemacs-extra-name' has appeared in the
+                          ;; development version of XEmacs 21.5-b8.
+                          (if (and (boundp 'xemacs-extra-name)
+                                   (symbol-value 'xemacs-extra-name))
+                              (concat " " (symbol-value 'xemacs-extra-name))
+                            "")
+                          " ("
+                          system-configuration ")")
+                       " (" emacs-version ")"))
            (let ((ver (if (string-match "\\.[0-9]+$" emacs-version)
                           (substring emacs-version 0 (match-beginning 0))
                         emacs-version)))
              (if (featurep 'mule)
                  (if (boundp 'enable-multibyte-characters)
                      (concat "Emacs/" ver
+                             " (" system-configuration ")"
                              (if enable-multibyte-characters
                                  (concat " MULE/" mule-version)
                                " (with unibyte mode)")
@@ -606,7 +704,7 @@ If it is not specified for a major-mode,
                                      ))))
                    (concat "MULE/" mule-version
                            " (based on Emacs " ver ")"))
-               ver))))
+               (concat "Emacs/" ver " (" system-configuration ")")))))
   "Body of User-Agent field.
 If variable `mime-edit-insert-user-agent-field' is not nil, it is
 inserted into message header.")
@@ -620,11 +718,14 @@ inserted into message header.")
 Tspecials means any character that matches with it in header must be quoted.")
 
 (defconst mime-edit-mime-version-value
-  (concat "1.0 (generated by " mime-edit-version-string ")")
+  (concat "1.0 (generated by " mime-edit-version ")")
   "MIME version number.")
 
 (defconst mime-edit-mime-version-field-for-message/partial
-  (concat "MIME-Version: 1.0 (split by " mime-edit-version-string ")\n")
+  (concat "MIME-Version:"
+         (mime-encode-field-body
+          (concat " 1.0 (split by " mime-edit-version ")\n")
+          "MIME-Version:"))
   "MIME version field for message/partial.")
 
 
@@ -709,15 +810,15 @@ Tspecials means any character that matches with it in header must be quoted.")
     (encrypted "Enclose as encrypted"  mime-edit-enclose-pgp-encrypted-region)
     (quote     "Verbatim region"       mime-edit-enclose-quote-region)
     (key       "Insert Public Key"     mime-edit-insert-key)
-    (split     "About split"           mime-edit-set-split)
-    (sign      "About sign"            mime-edit-set-sign)
-    (encrypt   "About encryption"      mime-edit-set-encrypt)
+    (split     "Set splitting"         mime-edit-set-split)
+    (sign      "PGP sign"              mime-edit-set-sign)
+    (encrypt   "PGP encrypt"           mime-edit-set-encrypt)
     (preview   "Preview Message"       mime-edit-preview-message)
     (level     "Toggle transfer-level" mime-edit-toggle-transfer-level)
     )
   "MIME-edit menubar entry.")
 
-(cond (running-xemacs
+(cond ((featurep 'xemacs)
        ;; modified by Pekka Marjola <pema@iki.fi>
        ;;      1995/9/5 (c.f. [tm-en:69])
        (defun mime-edit-define-menu-for-xemacs ()
@@ -915,7 +1016,7 @@ User customizable variables (not documented all of them):
       )))
 
 
-(cond (running-xemacs
+(cond ((featurep 'xemacs)
        (add-minor-mode 'mime-edit-mode-flag
                       '((" MIME-Edit "  mime-transfer-level-string))
                       mime-edit-mode-map
@@ -947,7 +1048,7 @@ User customizable variables (not documented all of them):
     (force-mode-line-update)
 
     ;; Define menu for XEmacs.
-    (if running-xemacs
+    (if (featurep 'xemacs)
        (mime-edit-define-menu-for-xemacs)
       )
 
@@ -962,6 +1063,7 @@ User customizable variables (not documented all of them):
                     paragraph-separate))
     (run-hooks 'mime-edit-mode-hook)
     (message
+     "%s"
      (substitute-command-keys
       "Type \\[mime-edit-exit] to exit MIME mode, and type \\[mime-edit-help] to get help."))
     ))
@@ -985,7 +1087,7 @@ just return to previous mode."
          (mime-edit-translate-buffer)))
     ;; Restore previous state.
     (setq mime-edit-mode-flag nil)
-    (if (and running-xemacs
+    (if (and (featurep 'xemacs)
             (featurep 'menubar))
        (delete-menu-item (list mime-edit-menu-title))
       )
@@ -1022,9 +1124,8 @@ If optional argument SUBTYPE is not nil, text/SUBTYPE tag is inserted."
            (insert "\n")
            (forward-char -1)
            ))
-      (if (and (member (cadr ret) '("enriched" "richtext"))
-              (fboundp 'enriched-mode)
-              )
+      (if (and (member (cadr ret) '("enriched"))
+              (fboundp 'enriched-mode))
          (enriched-mode t)
        (if (boundp 'enriched-mode)
            (enriched-mode -1)
@@ -1111,7 +1212,7 @@ If optional argument SUBTYPE is not nil, text/SUBTYPE tag is inserted."
   (let ((encoding
         (completing-read
          "What transfer encoding: "
-         mime-file-encoding-method-alist nil t nil)))
+         (mime-encoding-alist) nil t nil)))
     (mime-edit-insert-tag "audio" "basic" nil)
     (mime-edit-define-encoding encoding)
     (save-restriction
@@ -1314,7 +1415,11 @@ Optional argument ENCODING specifies an encoding method such as base64."
           (mime-create-tag
            (mime-edit-set-parameter
             (mime-edit-get-contype tag)
-            "charset" (upcase (symbol-name charset)))
+            "charset"
+            (let ((comment (get charset 'mime-charset-comment)))
+              (if comment
+                  (concat (upcase (symbol-name charset)) " (" comment ")")
+                (upcase (symbol-name charset)))))
            (mime-edit-get-encoding tag)))
          ))))
 
@@ -1404,7 +1509,7 @@ Nil if no such parameter."
        ;; Change value
        (concat (substring ctype 0 (match-beginning 1))
                parameter "=" value
-               (substring contype (match-end 1))
+               (substring ctype (match-end 1))
                opt-fields)
       (concat ctype "; " parameter "=" value opt-fields)
       )))
@@ -1502,7 +1607,7 @@ Optional DELIMITER specifies parameter delimiter (';' by default)."
 
 (defun mime-prompt-for-parameter (parameter)
   "Ask for PARAMETER.
-Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
+Parameter must be '(PROMPT CHOICE1 (CHOICE2...))."
   (let* ((prompt (car parameter))
         (choices (mapcar (function
                           (lambda (e)
@@ -1540,7 +1645,7 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
            (setq encoding
                  (completing-read
                   "What transfer encoding: "
-                  mime-file-encoding-method-alist nil t default)
+                  (mime-encoding-alist) nil t default)
                  )
            ""))
     encoding))
@@ -1556,13 +1661,13 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
 
 (defun mime-edit-translate-header ()
   "Encode the message header into network representation."
-  (eword-encode-header 'code-conversion)
-  (run-hooks 'mime-edit-translate-header-hook)
-  )
+  (mime-encode-header-in-buffer 'code-conversion)
+  (run-hooks 'mime-edit-translate-header-hook))
 
 (defun mime-edit-translate-buffer ()
   "Encode the tagged MIME message in current buffer in MIME compliant message."
   (interactive)
+  (undo-boundary)
   (if (catch 'mime-edit-error
        (save-excursion
          (run-hooks 'mime-edit-translate-buffer-hook)
@@ -1633,6 +1738,12 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
                ((string-equal type "kazu-encrypted")
                 (mime-edit-encrypt-pgp-kazu bb eb boundary)
                 )
+               ((string-equal type "smime-signed")
+                (mime-edit-sign-smime bb eb boundary)
+                )
+               ((string-equal type "smime-encrypted")
+                (mime-edit-encrypt-smime bb eb boundary)
+                )
                (t
                 (setq boundary
                       (nth 2 (mime-edit-translate-region bb eb
@@ -1666,26 +1777,57 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
          (replace-match (concat "-" (substring tag 2)))
          )))))
 
+(defvar mime-edit-pgp-user-id nil)
+
 (defun mime-edit-sign-pgp-mime (beg end boundary)
   (save-excursion
     (save-restriction
-      (narrow-to-region beg end)
-      (let* ((ret
-             (mime-edit-translate-region beg end boundary))
+      (let* ((from (std11-field-body "From" mail-header-separator))
+            (ret (progn 
+                   (narrow-to-region beg end)
+                   (mime-edit-translate-region beg end boundary)))
             (ctype    (car ret))
             (encoding (nth 1 ret))
-            (pgp-boundary (concat "pgp-sign-" boundary)))
+            (pgp-boundary (concat "pgp-sign-" boundary))
+            micalg)
        (goto-char beg)
        (insert (format "Content-Type: %s\n" ctype))
        (if encoding
            (insert (format "Content-Transfer-Encoding: %s\n" encoding))
          )
        (insert "\n")
-       (or (as-binary-process
-            (funcall (pgp-function 'mime-sign)
-                     (point-min)(point-max) nil nil pgp-boundary))
+       (or (let ((pgg-default-user-id 
+                  (or mime-edit-pgp-user-id
+                      (if from 
+                          (nth 1 (std11-extract-address-components from))
+                        pgg-default-user-id))))
+             (pgg-sign-region (point-min)(point-max)))
            (throw 'mime-edit-error 'pgp-error)
            )
+       (setq micalg
+             (cdr (assq 'hash-algorithm
+                        (cdar (with-current-buffer pgg-output-buffer
+                                (pgg-parse-armor-region 
+                                 (point-min)(point-max))))))
+             micalg 
+             (if micalg
+                 (concat "; micalg=pgp-" (downcase (symbol-name micalg)))
+               ""))
+       (goto-char beg)
+       (insert (format "--[[multipart/signed;
+ boundary=\"%s\"%s;
+ protocol=\"application/pgp-signature\"][7bit]]
+--%s
+" pgp-boundary micalg pgp-boundary))
+       (goto-char (point-max))
+       (insert (format "\n--%s
+Content-Type: application/pgp-signature
+Content-Transfer-Encoding: 7bit
+
+" pgp-boundary))
+       (insert-buffer-substring pgg-output-buffer)
+       (goto-char (point-max))
+       (insert (format "\n--%s--\n" pgp-boundary))
        ))))
 
 (defvar mime-edit-encrypt-recipient-fields-list '("To" "cc"))
@@ -1726,28 +1868,41 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
   (save-excursion
     (save-restriction
       (let (from recipients header)
-       (let ((ret (mime-edit-make-encrypt-recipient-header)))
-         (setq from (aref ret 0)
-               recipients (aref ret 1)
-               header (aref ret 2))
+        (let ((ret (mime-edit-make-encrypt-recipient-header)))
+          (setq from (aref ret 0)
+                recipients (aref ret 1)
+                header (aref ret 2))
          )
-       (narrow-to-region beg end)
-       (let* ((ret
-               (mime-edit-translate-region beg end boundary))
-              (ctype    (car ret))
-              (encoding (nth 1 ret))
-              (pgp-boundary (concat "pgp-" boundary)))
-         (goto-char beg)
-         (insert header)
-         (insert (format "Content-Type: %s\n" ctype))
-         (if encoding
-             (insert (format "Content-Transfer-Encoding: %s\n" encoding))
-           )
-         (insert "\n")
-         (or (funcall (pgp-function 'encrypt)
-                      recipients (point-min) (point-max) from)
+        (narrow-to-region beg end)
+        (let* ((ret
+                (mime-edit-translate-region beg end boundary))
+               (ctype    (car ret))
+               (encoding (nth 1 ret))
+               (pgp-boundary (concat "pgp-" boundary)))
+          (goto-char beg)
+          (insert header)
+          (insert (format "Content-Type: %s\n" ctype))
+          (if encoding
+              (insert (format "Content-Transfer-Encoding: %s\n" encoding))
+            )
+          (insert "\n")
+         (mime-encode-header-in-buffer)
+         (or (let ((pgg-default-user-id 
+                    (or mime-edit-pgp-user-id
+                        (if from 
+                            (nth 1 (std11-extract-address-components from))
+                          pgg-default-user-id))))                   
+               (pgg-encrypt-region 
+                (point-min) (point-max) 
+                (mapcar (lambda (recipient)
+                          (nth 1 (std11-extract-address-components
+                                  recipient)))
+                        (split-string recipients 
+                                      "\\([ \t\n]*,[ \t\n]*\\)+")))
+               )
              (throw 'mime-edit-error 'pgp-error)
              )
+         (delete-region (point-min)(point-max))
          (goto-char beg)
          (insert (format "--[[multipart/encrypted;
  boundary=\"%s\";
@@ -1760,6 +1915,7 @@ Content-Type: application/octet-stream
 Content-Transfer-Encoding: 7bit
 
 " pgp-boundary pgp-boundary pgp-boundary))
+         (insert-buffer-substring pgg-output-buffer)
          (goto-char (point-max))
          (insert (format "\n--%s--\n" pgp-boundary))
          )))))
@@ -1778,9 +1934,7 @@ Content-Transfer-Encoding: 7bit
            (insert (format "Content-Transfer-Encoding: %s\n" encoding))
          )
        (insert "\n")
-       (or (as-binary-process
-            (funcall (pgp-function 'traditional-sign)
-                     beg (point-max)))
+       (or (pgg-sign-region beg (point-max) 'clearsign)
            (throw 'mime-edit-error 'pgp-error)
            )
        (goto-char beg)
@@ -1809,10 +1963,7 @@ Content-Transfer-Encoding: 7bit
              (insert (format "Content-Transfer-Encoding: %s\n" encoding))
            )
          (insert "\n")
-         (or (as-binary-process
-              (funcall (pgp-function 'encrypt)
-                       recipients beg (point-max) nil 'maybe)
-              )
+         (or (pgg-encrypt-region beg (point-max) recipients)
              (throw 'mime-edit-error 'pgp-error)
              )
          (goto-char beg)
@@ -1821,6 +1972,78 @@ Content-Transfer-Encoding: 7bit
          ))
       )))
 
+(defun mime-edit-sign-smime (beg end boundary)
+  (save-excursion
+    (save-restriction
+      (let* ((ret (progn 
+                   (narrow-to-region beg end)
+                   (mime-edit-translate-region beg end boundary)))
+            (ctype    (car ret))
+            (encoding (nth 1 ret))
+            (smime-boundary (concat "smime-sign-" boundary)))
+       (goto-char beg)
+       (insert (format "Content-Type: %s\n" ctype))
+       (if encoding
+           (insert (format "Content-Transfer-Encoding: %s\n" encoding))
+         )
+       (insert "\n")
+       (let (buffer-undo-list)
+         (goto-char (point-min))
+         (while (progn (end-of-line) (not (eobp)))
+           (insert "\r")
+           (forward-line 1))
+         (or (prog1 (smime-sign-region (point-min)(point-max))
+               (push nil buffer-undo-list)
+               (ignore-errors (undo)))
+             (throw 'mime-edit-error 'pgp-error)
+             ))
+       (goto-char beg)
+       (insert (format "--[[multipart/signed;
+ boundary=\"%s\"; micalg=sha1;
+ protocol=\"application/pkcs7-signature\"][7bit]]
+--%s
+" smime-boundary smime-boundary))
+       (goto-char (point-max))
+       (insert (format "\n--%s
+Content-Type: application/pkcs7-signature; name=\"smime.p7s\"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=\"smime.p7s\"
+Content-Description: S/MIME Cryptographic Signature
+
+"  smime-boundary))
+       (insert-buffer-substring smime-output-buffer)
+       (goto-char (point-max))
+       (insert (format "\n--%s--\n" smime-boundary))
+       ))))
+
+(defun mime-edit-encrypt-smime (beg end boundary)
+  (save-excursion
+    (save-restriction
+      (let* ((ret (progn 
+                   (narrow-to-region beg end)
+                   (mime-edit-translate-region beg end boundary)))
+            (ctype    (car ret))
+            (encoding (nth 1 ret)))
+       (goto-char beg)
+       (insert (format "Content-Type: %s\n" ctype))
+       (if encoding
+           (insert (format "Content-Transfer-Encoding: %s\n" encoding))
+         )
+       (insert "\n")
+       (goto-char (point-min))
+       (while (progn (end-of-line) (not (eobp)))
+         (insert "\r")
+         (forward-line 1))
+       (or (smime-encrypt-region (point-min)(point-max))
+           (throw 'mime-edit-error 'pgp-error)
+           )
+       (delete-region (point-min)(point-max))
+       (insert "--[[application/pkcs7-mime; name=\"smime.p7m\"
+Content-Disposition: attachment; filename=\"smime.p7m\"
+Content-Description: S/MIME Encrypted Message][base64]]\n")
+       (insert-buffer-substring smime-output-buffer)
+       ))))
+
 (defsubst replace-space-with-underline (str)
   (mapconcat (function
              (lambda (arg)
@@ -1911,9 +2134,12 @@ Content-Transfer-Encoding: 7bit
            (insert "Content-Type: " contype "\n")
            (if encoding
                (insert "Content-Transfer-Encoding: " encoding "\n"))
-           (eword-encode-header)
-           ))
-       t)))
+           (mime-encode-header-in-buffer))
+         (cons (and contype
+                    (downcase contype))
+               (and encoding
+                    (downcase encoding))))
+       )))
 
 (defun mime-edit-translate-region (beg end &optional boundary multipart)
   (or boundary
@@ -1949,22 +2175,26 @@ Content-Transfer-Encoding: 7bit
         (t
          ;; It's a multipart message.
          (goto-char (point-min))
-         (and (mime-edit-translate-single-part-tag boundary)
-              (while (mime-edit-translate-single-part-tag boundary "\n")))
-         ;; Define Content-Type as "multipart/mixed".
-         (setq contype
-               (concat "multipart/mixed;\n boundary=\"" boundary "\""))
-         ;; Content-Transfer-Encoding must be "7bit".
-         ;; The following encoding can be `nil', but is
-         ;; specified as is since there is no way that a user
-         ;; specifies it.
-         (setq encoding "7bit")
-         ;; Insert the trailer.
-         (goto-char (point-max))
-         (insert "\n--" boundary "--\n")
-         ))
-       (list contype encoding boundary nparts)
-       ))))
+         (let ((prio mime-content-transfer-encoding-priority-list)
+               part-info nprio)
+           (when (setq part-info
+                       (mime-edit-translate-single-part-tag boundary))
+             (and (setq nprio (member (cdr part-info) prio))
+                  (setq prio nprio))
+             (while (setq part-info
+                          (mime-edit-translate-single-part-tag boundary "\n"))
+               (and (setq nprio (member (cdr part-info) prio))
+                    (setq prio nprio))))
+           ;; Define Content-Type as "multipart/mixed".
+           (setq contype
+                 (concat "multipart/mixed;\n boundary=\"" boundary "\""))
+           (setq encoding (car prio))
+           ;; Insert the trailer.
+           (goto-char (point-max))
+           (insert "\n--" boundary "--\n")
+           )))
+        (list contype encoding boundary nparts)
+        ))))
 
 (defun mime-edit-normalize-body ()
   "Normalize the body part by inserting appropriate message tags."
@@ -2026,7 +2256,7 @@ Content-Transfer-Encoding: 7bit
                    ;;                        (point)
                    ;;                        'hard t)))
                   ;; End patch for hard newlines
-                  (enriched-encode beg end)
+                  (enriched-encode beg end nil)
                   (goto-char beg)
                   (if (search-forward "\n\n")
                       (delete-region beg (match-end 0))
@@ -2072,9 +2302,15 @@ Content-Transfer-Encoding: 7bit
                    (narrow-to-region beg (mime-edit-content-end))
                    (goto-char beg)
                    (while (re-search-forward "\\(\\=\\|[^\r]\\)\n" nil t)
-                     (replace-match "\\1\r\n"))))
+                     ;; Don't use this in the multibyte buffer since it may
+                     ;; convert the unibyte string into multibyte.
+                     ;;;;(replace-match "\\1\r\n"))))
+                     (backward-char 1)
+                     (insert "\r")
+                     (forward-char 1))))
              (goto-char beg)
-             (mime-encode-region beg (mime-edit-content-end) encoding)
+             (mime-encode-region beg (mime-edit-content-end)
+                                 (or encoding "7bit"))
              (mime-edit-define-encoding encoding)
              ))
        (goto-char (mime-edit-content-end))
@@ -2098,8 +2334,7 @@ Content-Transfer-Encoding: 7bit
     (goto-char (point-min))
     (while (re-search-forward regexp nil t)
       (delete-region (match-beginning 0)
-                    (progn (forward-line 1) (point)))
-      )))
+                    (1+ (std11-field-end))))))
 
 \f
 ;;;
@@ -2230,13 +2465,25 @@ and insert data encoded as ENCODING."
   (mime-edit-enclose-region-internal 'kazu-encrypted beg end)
   )
 
+(defun mime-edit-enclose-smime-signed-region (beg end)
+  (interactive "*r")
+  (mime-edit-enclose-region-internal 'smime-signed beg end)
+  )
+
+(defun mime-edit-enclose-smime-encrypted-region (beg end)
+  (interactive "*r")
+  (mime-edit-enclose-region-internal 'smime-encrypted beg end)
+  )
+
 (defun mime-edit-insert-key (&optional arg)
   "Insert a pgp public key."
   (interactive "P")
   (mime-edit-insert-tag "application" "pgp-keys")
   (mime-edit-define-encoding "7bit")
-  (funcall (pgp-function 'insert-key))
-  )
+  (pgg-insert-key)
+  (if (and (not (eobp))
+          (not (looking-at mime-edit-single-part-tag-regexp)))
+      (insert (mime-make-text-tag) "\n")))
 
 
 ;;; @ flag setting
@@ -2295,12 +2542,14 @@ Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8."
     ))
   (if arg
       (progn
-       (setq mime-edit-pgp-processing 'sign)
+       (or (memq 'sign mime-edit-pgp-processing)
+           (setq mime-edit-pgp-processing 
+                 (nconc mime-edit-pgp-processing 
+                        (copy-sequence '(sign)))))
        (message "This message will be signed.")
        )
-    (if (eq mime-edit-pgp-processing 'sign)
-       (setq mime-edit-pgp-processing nil)
-      )
+    (setq mime-edit-pgp-processing 
+         (delq 'sign mime-edit-pgp-processing))
     (message "This message will not be signed.")
     ))
 
@@ -2311,12 +2560,14 @@ Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8."
     ))
   (if arg
       (progn
-       (setq mime-edit-pgp-processing 'encrypt)
+       (or (memq 'encrypt mime-edit-pgp-processing)
+           (setq mime-edit-pgp-processing 
+                 (nconc mime-edit-pgp-processing 
+                        (copy-sequence '(encrypt)))))
        (message "This message will be encrypt.")
        )
-    (if (eq mime-edit-pgp-processing 'encrypt)
-       (setq mime-edit-pgp-processing nil)
-      )
+    (setq mime-edit-pgp-processing
+         (delq 'encrypt mime-edit-pgp-processing))
     (message "This message will not be encrypt.")
     ))
 
@@ -2326,15 +2577,18 @@ Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8."
               (if (search-forward (concat "\n" mail-header-separator "\n"))
                   (match-end 0)
                 )))
-       (end (point-max))
        )
     (if beg
-       (cond ((eq mime-edit-pgp-processing 'sign)
-              (mime-edit-enclose-pgp-signed-region beg end)
-              )
-             ((eq mime-edit-pgp-processing 'encrypt)
-              (mime-edit-enclose-pgp-encrypted-region beg end)
-              ))
+       (dolist (pgp-processing mime-edit-pgp-processing)
+         (case pgp-processing
+           (sign
+            (mime-edit-enclose-pgp-signed-region 
+             beg (point-max))
+            )
+           (encrypt
+            (mime-edit-enclose-pgp-encrypted-region 
+             beg (point-max))
+            )))
       )))
 
 
@@ -2363,11 +2617,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
            (or (cdr (assq major-mode mime-edit-message-max-lines-alist))
                mime-edit-message-default-max-lines))
       )
-  (let* ((mime-edit-draft-file-name
-         (or (buffer-file-name)
-             (make-temp-name
-              (expand-file-name "mime-draft" mime-temp-directory))))
-        (separator mail-header-separator)
+  (let* ((separator mail-header-separator)
         (id (concat "\""
                     (replace-space-with-underline (current-time-string))
                     "@" (system-name) "\"")))
@@ -2428,7 +2678,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
          (message (format "Sending %d/%d..."
                           mime-edit-partial-number total))
          (call-interactively command)
-         (message (format "Sending %d/%d... done"
+         (message (format "Sending %d/%d...done"
                           mime-edit-partial-number total))
          )
        (setq mime-edit-partial-number
@@ -2446,7 +2696,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
       (save-excursion
        (message (format "Sending %d/%d..."
                         mime-edit-partial-number total))
-       (message (format "Sending %d/%d... done"
+       (message (format "Sending %d/%d...done"
                         mime-edit-partial-number total))
        )
       )))
@@ -2479,6 +2729,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
         (buf-name (buffer-name))
         (temp-buf-name (concat "*temp-article:" buf-name "*"))
         (buf (get-buffer temp-buf-name))
+        (pgp-processing mime-edit-pgp-processing)
         )
     (if buf
        (progn
@@ -2494,6 +2745,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
     (setq mail-header-separator separator)
     (make-local-variable 'mime-edit-buffer)
     (setq mime-edit-buffer the-buf)
+    (setq mime-edit-pgp-processing pgp-processing)
 
     (run-hooks 'mime-edit-translate-hook)
     (mime-edit-translate-buffer)
@@ -2503,18 +2755,18 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
        (replace-match "")
       )
     (mime-view-buffer)
-    ))
+    (make-local-variable 'mime-edit-temp-message-buffer)
+    (setq mime-edit-temp-message-buffer buf)))
 
 (defun mime-edit-quitting-method ()
   "Quitting method for mime-view."
-  (let ((temp mime-raw-buffer)
-       buf)
+  (let* ((temp mime-edit-temp-message-buffer)
+        buf)
     (mime-preview-kill-buffer)
     (set-buffer temp)
     (setq buf mime-edit-buffer)
     (kill-buffer temp)
-    (switch-to-buffer buf)
-    ))
+    (switch-to-buffer buf)))
 
 (set-alist 'mime-preview-quitting-method-alist
           'mime-temp-message-mode
@@ -2530,140 +2782,243 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
          "\\):")
   "Regexp for deleted header fields when `mime-edit-again' is called.")
 
-(defun mime-edit-decode-buffer (not-decode-text)
+(defsubst eliminate-top-spaces (string)
+  "Eliminate top sequence of space or tab in STRING."
+  (if (string-match "^[ \t]+" string)
+      (substring string (match-end 0))
+    string))
+
+(defun mime-edit-decode-multipart-in-buffer (content-type not-decode-text)
+  (let* ((subtype
+         (or
+          (cdr (assoc (mime-content-type-parameter content-type "protocol")
+                      '(("application/pgp-encrypted" . pgp-encrypted)
+                        ("application/pgp-signature" . pgp-signed))))
+          (mime-content-type-subtype content-type)))
+        (boundary (mime-content-type-parameter content-type "boundary"))
+        (boundary-pat (concat "\n--" (regexp-quote boundary) "[ \t]*\n")))
+    (re-search-forward boundary-pat nil t)
+    (let ((bb (match-beginning 0)) eb tag)
+      (setq tag (format "\n--<<%s>>-{\n" subtype))
+      (goto-char bb)
+      (insert tag)
+      (setq bb (+ bb (length tag)))
+      (re-search-forward
+       (concat "\n--" (regexp-quote boundary) "--[ \t]*\n")
+       nil t)
+      (setq eb (match-beginning 0))
+      (replace-match (format "--}-<<%s>>\n" subtype))
+      (save-restriction
+       (narrow-to-region bb eb)
+       (goto-char (point-min))
+       (while (re-search-forward boundary-pat nil t)
+         (let ((beg (match-beginning 0))
+               end)
+           (delete-region beg (match-end 0))
+           (save-excursion
+             (if (re-search-forward boundary-pat nil t)
+                 (setq end (match-beginning 0))
+               (setq end (point-max))
+               )
+             (save-restriction
+               (narrow-to-region beg end)
+               (cond
+                ((eq subtype 'pgp-encrypted)
+                 (when (and
+                        (progn
+                          (goto-char (point-min))
+                          (re-search-forward "^-+BEGIN PGP MESSAGE-+$"
+                                             nil t))
+                        (prog1 
+                            (save-window-excursion
+                              (pgg-decrypt-region (match-beginning 0)
+                                                  (point-max)))
+                          (delete-region (point-min)(point-max))))
+                   (insert-buffer-substring pgg-output-buffer)
+                   (mime-edit-decode-message-in-buffer 
+                    nil not-decode-text)
+                   (delete-region (goto-char (point-min))
+                                  (if (search-forward "\n\n" nil t)
+                                      (match-end 0)
+                                    (point-min)))
+                   (goto-char (point-max))
+                   ))
+                (t 
+                 (mime-edit-decode-message-in-buffer
+                  (if (eq subtype 'digest)
+                      (eval-when-compile
+                        (make-mime-content-type 'message 'rfc822))
+                    )
+                  not-decode-text)
+                 (goto-char (point-max))
+                 ))
+               ))))
+       ))
+    (goto-char (point-min))
+    (or (= (point-min) 1)
+       (delete-region (point-min)
+                      (if (search-forward "\n\n" nil t)
+                          (match-end 0)
+                        (point-min)
+                        )))
+    ))
+
+(defun mime-edit-decode-single-part-in-buffer
+  (content-type not-decode-text &optional content-disposition)
+  (let* ((type (mime-content-type-primary-type content-type))
+        (subtype (mime-content-type-subtype content-type))
+        (ctype (format "%s/%s" type subtype))
+        charset
+        (pstr (let ((bytes (+ 14 (length ctype))))
+                (mapconcat (function
+                            (lambda (attr)
+                              (if (string= (car attr) "charset")
+                                  (progn
+                                    (setq charset (cdr attr))
+                                    "")
+                                (let* ((str (concat (car attr)
+                                                    "=" (cdr attr)))
+                                       (bs (length str)))
+                                  (setq bytes (+ bytes bs 2))
+                                  (if (< bytes 76)
+                                      (concat "; " str)
+                                    (setq bytes (+ bs 1))
+                                    (concat ";\n " str)
+                                    )
+                                  ))))
+                           (mime-content-type-parameters content-type) "")))
+        encoding
+        encoded
+        (limit (save-excursion
+                 (if (search-forward "\n\n" nil t)
+                     (1- (point)))))
+        (disposition-type
+         (mime-content-disposition-type content-disposition))
+        (disposition-str
+         (if disposition-type
+             (let ((bytes (+ 21 (length (format "%s" disposition-type)))))
+               (mapconcat (function
+                           (lambda (attr)
+                             (let* ((str (concat
+                                          (car attr)
+                                          "="
+                                          (if (string-equal "filename"
+                                                            (car attr))
+                                              (std11-wrap-as-quoted-string
+                                               (cdr attr))
+                                            (cdr attr))))
+                                    (bs (length str)))
+                               (setq bytes (+ bytes bs 2))
+                               (if (< bytes 76)
+                                   (concat "; " str)
+                                 (setq bytes (+ bs 1))
+                                 (concat ";\n " str)
+                                 )
+                               )))
+                          (mime-content-disposition-parameters
+                           content-disposition)
+                          ""))))
+        )
+    (if disposition-type
+       (setq pstr (format "%s\nContent-Disposition: %s%s"
+                          pstr disposition-type disposition-str))
+      )
+    (save-excursion
+      (if (re-search-forward
+          "^Content-Transfer-Encoding:" limit t)
+         (let ((beg (match-beginning 0))
+               (hbeg (match-end 0))
+               (end (std11-field-end limit)))
+           (setq encoding
+                 (downcase
+                  (eliminate-top-spaces
+                   (std11-unfold-string
+                    (buffer-substring hbeg end)))))
+           (if (or charset (eq type 'text))
+               (progn
+                 (delete-region beg (1+ end))
+                 (goto-char (point-min))
+                 (if (search-forward "\n\n" nil t)
+                     (progn
+                       (mime-decode-region
+                        (match-end 0)(point-max) encoding)
+                       (setq encoded t
+                             encoding nil)
+                       )))))))
+    (if (and (eq type 'text)
+            (or encoded (not not-decode-text)))
+       (progn
+         (save-excursion
+           (goto-char (point-min))
+           (while (re-search-forward "\r\n" nil t)
+             (replace-match "\n")
+             ))
+         (decode-mime-charset-region (point-min)(point-max)
+                                     (or charset default-mime-charset))
+         ))
+    (let ((he (if (re-search-forward "^$" nil t)
+                 (match-end 0)
+               (point-min)
+               )))
+      (if (and (eq type 'text)
+              (eq subtype 'x-rot13-47-48))
+         (mule-caesar-region he (point-max))
+       )
+      (if (= (point-min) 1)
+         (progn
+           (goto-char he)
+           (insert
+            (concat "\n"
+                    (mime-create-tag
+                     (format "%s/%s%s" type subtype pstr)
+                     encoding)))
+           )
+       (delete-region (point-min) he)
+       (insert
+        (mime-create-tag (format "%s/%s%s" type subtype pstr)
+                         encoding))
+       ))
+    ))
+
+;;;###autoload
+(defun mime-edit-decode-message-in-buffer (&optional default-content-type
+                                                    not-decode-text)
   (save-excursion
     (goto-char (point-min))
-    (let ((ctl (mime-read-Content-Type)))
+    (let ((ctl (or (mime-read-Content-Type)
+                  default-content-type)))
       (if ctl
-         (let ((type (mime-content-type-primary-type ctl))
-               (stype (mime-content-type-subtype ctl))
-               (params (mime-content-type-parameters ctl)))
+         (let ((type (mime-content-type-primary-type ctl)))
            (cond
-            ((and (eq type 'application)(eq stype 'pgp-signature))
+            ((and (eq type 'application)
+                  (eq (mime-content-type-subtype ctl) 'pgp-signature))
              (delete-region (point-min)(point-max))
              )
             ((eq type 'multipart)
-             (let* ((boundary (cdr (assoc "boundary" params)))
-                    (boundary-pat
-                     (concat "\n--" (regexp-quote boundary) "[ \t]*\n"))
-                    )
-               (re-search-forward boundary-pat nil t)
-               (let ((bb (match-beginning 0)) eb tag)
-                 (setq tag (format "\n--<<%s>>-{\n" stype))
-                 (goto-char bb)
-                 (insert tag)
-                 (setq bb (+ bb (length tag)))
-                 (re-search-forward
-                  (concat "\n--" (regexp-quote boundary) "--[ \t]*\n")
-                  nil t)
-                 (setq eb (match-beginning 0))
-                 (replace-match (format "--}-<<%s>>\n" stype))
-                 (save-restriction
-                   (narrow-to-region bb eb)
-                   (goto-char (point-min))
-                   (while (re-search-forward boundary-pat nil t)
-                     (let ((beg (match-beginning 0))
-                           end)
-                       (delete-region beg (match-end 0))
-                       (save-excursion
-                         (if (re-search-forward boundary-pat nil t)
-                             (setq end (match-beginning 0))
-                           (setq end (point-max))
-                           )
-                         (save-restriction
-                           (narrow-to-region beg end)
-                           (mime-edit-decode-buffer not-decode-text)
-                           (goto-char (point-max))
-                           ))))
-                   ))
-               (goto-char (point-min))
-               (or (= (point-min) 1)
-                   (delete-region (point-min)
-                                  (if (search-forward "\n\n" nil t)
-                                      (match-end 0)
-                                    (point-min)
-                                    )))
-               ))
+             (mime-edit-decode-multipart-in-buffer ctl not-decode-text)
+             )
             (t
-             (let* ((ctype (format "%s/%s" type stype))
-                    charset
-                    (pstr
-                     (let ((bytes (+ 14 (length ctype))))
-                       (mapconcat (function
-                                   (lambda (attr)
-                                     (if (string= (car attr) "charset")
-                                         (progn
-                                           (setq charset (cdr attr))
-                                           "")
-                                       (let* ((str
-                                               (concat (car attr)
-                                                       "=" (cdr attr))
-                                               )
-                                              (bs (length str))
-                                              )
-                                         (setq bytes (+ bytes bs 2))
-                                         (if (< bytes 76)
-                                             (concat "; " str)
-                                           (setq bytes (+ bs 1))
-                                           (concat ";\n " str)
-                                           )
-                                         ))))
-                                  params "")))
-                    encoding
-                    encoded)
-               (save-excursion
-                 (if (re-search-forward
-                      "Content-Transfer-Encoding:" nil t)
-                     (let ((beg (match-beginning 0))
-                           (hbeg (match-end 0))
-                           (end (std11-field-end)))
-                       (setq encoding
-                             (eliminate-top-spaces
-                              (std11-unfold-string
-                               (buffer-substring hbeg end))))
-                       (if (or charset (eq type 'text))
-                           (progn
-                             (delete-region beg (1+ end))
-                             (goto-char (point-min))
-                             (if (search-forward "\n\n" nil t)
-                                 (progn
-                                   (mime-decode-region
-                                    (match-end 0)(point-max) encoding)
-                                   (setq encoded t
-                                         encoding nil)
-                                   )))))))
-               (if (or encoded (not not-decode-text))
-                   (decode-mime-charset-region
-                    (point-min)(point-max)
-                    (or charset default-mime-charset))
-                 )
-               (let ((he
-                      (if (re-search-forward "^$" nil t)
-                          (match-end 0)
-                        (point-min)
-                        )))
-                 (if (= (point-min) 1)
-                     (progn
-                       (goto-char he)
-                       (insert
-                        (concat "\n"
-                                (mime-create-tag
-                                 (format "%s/%s%s" type stype pstr)
-                                 encoding)))
-                       )
-                   (delete-region (point-min) he)
-                   (insert
-                    (mime-create-tag
-                     (format "%s/%s%s" type stype pstr)
-                     encoding))
-                   ))
-               ))))
+             (mime-edit-decode-single-part-in-buffer
+              ctl not-decode-text (mime-read-Content-Disposition))
+             )))
        (or not-decode-text
            (decode-mime-charset-region (point-min) (point-max)
-                                       default-mime-charset)
-           )
-       ))))
+                                       default-mime-charset))
+       )
+      (if (= (point-min) 1)
+         (progn
+           (save-restriction
+             (std11-narrow-to-header)
+             (goto-char (point-min))
+             (while (re-search-forward
+                     mime-edit-again-ignored-field-regexp nil t)
+               (delete-region (match-beginning 0) (1+ (std11-field-end)))
+               ))
+           (mime-decode-header-in-buffer (not not-decode-text))
+           ))
+      )))
 
+;;;###autoload
 (defun mime-edit-again (&optional not-decode-text no-separator not-turn-on)
   "Convert current buffer to MIME-Edit buffer and turn on MIME-Edit mode.
 Content-Type and Content-Transfer-Encoding header fields will be
@@ -2675,14 +3030,8 @@ converted to MIME-Edit tags."
        nil t)
       (replace-match "\n\n")
     )
-  (mime-edit-decode-buffer not-decode-text)
+  (mime-edit-decode-message-in-buffer nil not-decode-text)
   (goto-char (point-min))
-  (save-restriction
-    (std11-narrow-to-header)
-    (goto-char (point-min))
-    (while (re-search-forward mime-edit-again-ignored-field-regexp nil t)
-      (delete-region (match-beginning 0) (1+ (std11-field-end)))
-      ))
   (or no-separator
       (and (re-search-forward "^$")
           (replace-match mail-header-separator)