updated.
[elisp/semi.git] / mime-edit.el
index 0fc6949..f526fbb 100644 (file)
@@ -7,7 +7,7 @@
 ;; Maintainer: MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;; Created: 1994/08/21 renamed from mime.el
 ;;     Renamed: 1997/2/21 from tm-edit.el
-;; Version: $Revision: 0.40 $
+;; Version: $Revision: 0.85 $
 ;; Keywords: MIME, multimedia, multilingual, mail, news
 
 ;; This file is part of SEMI (SEMI is Emacs MIME Interfaces).
 ;; composed in the tagged MIME format are automatically translated
 ;; into a MIME compliant message when exiting the mode.
 
-;; Mule (a multilingual extension to Emacs 18 and 19) has a capability
-;; of handling multilingual text in limited ISO-2022 manner that is
-;; based on early experiences in Japanese Internet community and
-;; resulted in RFC 1468 (ISO-2022-JP charset for MIME).  In order to
-;; enable multilingual capability in single text message in MIME,
-;; charset of multilingual text written in Mule is declared as either
-;; `ISO-2022-JP-2' [RFC 1554].  Mule is required for reading the such
-;; messages.
+;; Mule (multilingual feature of Emacs 20 and multilingual extension
+;; for XEmacs 20) has a capability of handling multilingual text in
+;; limited ISO-2022 manner that is based on early experiences in
+;; Japanese Internet community and resulted in RFC 1468 (ISO-2022-JP
+;; charset for MIME).  In order to enable multilingual capability in
+;; single text message in MIME, charset of multilingual text written
+;; in Mule is declared as either `ISO-2022-JP-2' [RFC 1554].  Mule is
+;; required for reading the such messages.
 
 ;; This MIME composer can work with Mail mode, mh-e letter Mode, and
 ;; News mode.  First of all, you need the following autoload
 ;; definition to load mime-edit-mode automatically:
 ;;
-;; (autoload 'mime-edit-mode "mime-edit"
+;; (autoload 'turn-on-mime-edit "mime-edit"
 ;;           "Minor mode for editing MIME message." t)
 ;;
 ;; In case of Mail mode (includes VM mode), you need the following
 ;; hook definition:
 ;;
-;; (add-hook 'mail-mode-hook 'mime-edit-mode)
+;; (add-hook 'mail-mode-hook 'turn-on-mime-edit)
 ;; (add-hook 'mail-send-hook 'mime-edit-maybe-translate)
 ;;
 ;; In case of MH-E, you need the following hook definition:
@@ -63,7 +63,7 @@
 ;; (add-hook 'mh-letter-mode-hook
 ;;           (function
 ;;            (lambda ()
-;;              (mime-edit-mode)
+;;              (turn-on-mime-edit)
 ;;              (make-local-variable 'mail-header-separator)
 ;;              (setq mail-header-separator "--------")
 ;;              ))))
@@ -71,7 +71,7 @@
 ;;
 ;; In case of News mode, you need the following hook definition:
 ;;
-;; (add-hook 'news-reply-mode-hook 'mime-edit-mode)
+;; (add-hook 'news-reply-mode-hook 'turn-on-mime-edit)
 ;; (add-hook 'news-inews-hook 'mime-edit-maybe-translate)
 ;;
 ;; In case of Emacs 19, it is possible to emphasize the message tags
 
 ;;; Code:
 
+(require 'emu)
 (require 'sendmail)
 (require 'mail-utils)
 (require 'mel)
-(require 'tl-list)
 (require 'mime-view)
-(require 'tm-ew-e)
+(require 'eword-encode)
 (require 'signature)
+(require 'alist)
 
 
 ;;; @ version
 ;;;
 
 (defconst mime-edit-RCS-ID
-  "$Id: mime-edit.el,v 0.40 1997-02-21 07:02:52 tmorioka Exp $")
+  "$Id: mime-edit.el,v 0.85 1997-07-05 17:18:02 morioka Exp $")
 
-(defconst mime-edit-version (get-version-string mime-edit-RCS-ID))
+(defconst mime-edit-version `,(get-version-string mime-edit-RCS-ID))
 
 (defconst mime-edit-version-name
-  (concat "SEMI MIME-Edit " mime-edit-version))
+  `,(concat "SEMI MIME-Edit " mime-edit-version
+           " \"" semi-version-name "\""))
 
 
 ;;; @ variables
 ;;;
 
-(defvar mime-prefix "\C-c\C-x"
-  "*Keymap prefix for MIME commands.")
-
 (defvar mime-ignore-preceding-spaces nil
   "*Ignore preceding white spaces if non-nil.")
 
@@ -182,7 +181,7 @@ To insert a signature file automatically, call the function
      ("html"
       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
       )
-     ("x-rot13-47")
+     ("x-rot13-47-48")
      )
     ("message"
      ("external-body"
@@ -211,6 +210,7 @@ To insert a signature file automatically, call the function
     ("image"
      ("gif")
      ("jpeg")
+     ("png")
      ("tiff")
      ("x-pic")
      ("x-mag")
@@ -246,6 +246,11 @@ To insert a signature file automatically, call the function
      "base64"
      "inline"          (("filename" . file))
      )
+    ("\\.png$"
+     "image"   "png"           nil
+     "base64"
+     "inline"          (("filename" . file))
+     )
     ("\\.tiff$"
      "image"   "tiff"          nil
      "base64"
@@ -352,19 +357,48 @@ To insert a signature file automatically, call the function
   "*Alist of file name, types, parameters, and default encoding.
 If encoding is nil, it is determined from its contents.")
 
+
 ;;; @@ about charset, encoding and transfer-level
 ;;;
 
-(defvar mime-edit-transfer-level 7
+(defvar mime-charset-type-list
+  '((us-ascii          7 nil)
+    (iso-8859-1                8 "quoted-printable")
+    (iso-8859-2                8 "quoted-printable")
+    (iso-8859-3                8 "quoted-printable")
+    (iso-8859-4                8 "quoted-printable")
+    (iso-8859-5                8 "quoted-printable")
+    (koi8-r            8 "quoted-printable")
+    (iso-8859-7                8 "quoted-printable")
+    (iso-8859-8                8 "quoted-printable")
+    (iso-8859-9                8 "quoted-printable")
+    (iso-2022-jp       7 "base64")
+    (iso-2022-kr       7 "base64")
+    (euc-kr            8 "base64")
+    (cn-gb2312         8 "quoted-printable")
+    (cn-big5           8 "base64")
+    (gb2312            8 "quoted-printable")
+    (big5              8 "base64")
+    (iso-2022-jp-2     7 "base64")
+    (iso-2022-int-1    7 "base64")
+    ))
+
+(defvar mime-transfer-level 7
   "*A number of network transfer level.  It should be bigger than 7.")
-(make-variable-buffer-local 'mime-edit-transfer-level)
+(make-variable-buffer-local 'mime-transfer-level)
 
-(defvar mime-edit-transfer-level-string
-  (mime/encoding-name mime-edit-transfer-level 'not-omit)
-  "*A string formatted version of mime/defaul-transfer-level")
-(make-variable-buffer-local 'mime-edit-transfer-level-string)
+(defsubst mime-encoding-name (transfer-level &optional not-omit)
+  (cond ((> transfer-level 8) "binary")
+       ((= transfer-level 8) "8bit")
+       (not-omit "7bit")
+       ))
 
-(defun mime-edit-make-charset-default-encoding-alist (transfer-level)
+(defvar mime-transfer-level-string
+  (mime-encoding-name mime-transfer-level 'not-omit)
+  "A string formatted version of mime-transfer-level")
+(make-variable-buffer-local 'mime-transfer-level-string)
+
+(defun mime-make-charset-default-encoding-alist (transfer-level)
   (mapcar (function
           (lambda (charset-type)
             (let ((charset  (car charset-type))
@@ -372,15 +406,16 @@ If encoding is nil, it is determined from its contents.")
                   (encoding (nth 2 charset-type))
                   )
               (if (<= type transfer-level)
-                  (cons charset (mime/encoding-name type))
+                  (cons charset (mime-encoding-name type))
                 (cons charset encoding)
                 ))))
          mime-charset-type-list))
 
 (defvar mime-edit-charset-default-encoding-alist
-  (mime-edit-make-charset-default-encoding-alist mime-edit-transfer-level))
+  (mime-make-charset-default-encoding-alist mime-transfer-level))
 (make-variable-buffer-local 'mime-edit-charset-default-encoding-alist)
 
+
 ;;; @@ about message inserting
 ;;;
 
@@ -399,6 +434,7 @@ Each elements are regexp of field-name. [mime-edit.el]")
 (defvar mime-edit-message-inserter-alist nil)
 (defvar mime-edit-mail-inserter-alist nil)
 
+
 ;;; @@ about message splitting
 ;;;
 
@@ -468,6 +504,7 @@ If it is not specified for a major-mode,
 (defvar mime-tag-format-with-encoding "--[[%s][%s]]"
   "*Control-string making a MIME tag with encoding.")
 
+
 ;;; @@ multipart boundary
 ;;;
 
@@ -475,11 +512,24 @@ If it is not specified for a major-mode,
   "*Boundary of a multipart message.")
 
 
-;;; @@ buffer local variables
+;;; @@ optional header fields
 ;;;
 
-(defvar mime-edit-mode-old-local-map nil)
-(defvar mime/editing-buffer nil)
+(defvar mime-edit-insert-x-emacs-field t
+  "*If non-nil, insert X-Emacs header field.")
+
+(defvar mime-edit-x-emacs-value
+  (if running-xemacs
+      (concat emacs-version
+             (if (featurep 'mule)
+                 " with mule"
+               " without mule"))
+    (let ((ver (if (string-match "\\.[0-9]+$" emacs-version)
+                  (substring emacs-version 0 (match-beginning 0))
+                emacs-version)))
+      (if (featurep 'mule)
+         (concat "Emacs " ver ", MULE " mule-version)
+       ver))))
 
 \f
 ;;; @ constants
@@ -493,8 +543,6 @@ Tspecials means any character that matches with it in header must be quoted.")
   (concat "1.0 (generated by " mime-edit-version-name ")")
   "MIME version number.")
 
-(defconst mime-edit-mime-map (make-sparse-keymap)
-  "Keymap for MIME commands.")
 
 ;;; @ keymap and menu
 ;;;
@@ -502,66 +550,65 @@ Tspecials means any character that matches with it in header must be quoted.")
 (defvar mime-edit-mode-flag nil)
 (make-variable-buffer-local 'mime-edit-mode-flag)
 
-(defun mime-edit-define-keymap (keymap)
-  "Add mime-editor commands to KEYMAP."
-  (if (not (keymapp keymap))
-      nil
-    (define-key keymap "\C-t" 'mime-edit-insert-text)
-    (define-key keymap "\C-i" 'mime-edit-insert-file)
-    (define-key keymap "\C-e" 'mime-edit-insert-external)
-    (define-key keymap "\C-v" 'mime-edit-insert-voice)
-    (define-key keymap "\C-y" 'mime-edit-insert-message)
-    (define-key keymap "\C-m" 'mime-edit-insert-mail)
-    (define-key keymap "\C-w" 'mime-edit-insert-signature)
-    (define-key keymap "\C-s" 'mime-edit-insert-signature)
-    (define-key keymap "\C-k" 'mime-edit-insert-key)
-    (define-key keymap "t"    'mime-edit-insert-tag)
-    (define-key keymap "a"    'mime-edit-enclose-alternative-region)
-    (define-key keymap "p"    'mime-edit-enclose-parallel-region)
-    (define-key keymap "m"    'mime-edit-enclose-mixed-region)
-    (define-key keymap "d"    'mime-edit-enclose-digest-region)
-    (define-key keymap "s"    'mime-edit-enclose-signed-region)
-    (define-key keymap "e"    'mime-edit-enclose-encrypted-region)
-    (define-key keymap "q"    'mime-edit-enclose-quote-region)
-    (define-key keymap "7"    'mime-edit-set-transfer-level-7bit)
-    (define-key keymap "8"    'mime-edit-set-transfer-level-8bit)
-    (define-key keymap "/"    'mime-edit-set-split)
-    (define-key keymap "v"    'mime-edit-set-sign)
-    (define-key keymap "h"    'mime-edit-set-encrypt)
-    (define-key keymap "\C-p" 'mime-edit-preview-message)
-    (define-key keymap "\C-z" 'mime-edit-exit)
-    (define-key keymap "?"    'mime-edit-help)
-    ))
-
-(mime-edit-define-keymap mime-edit-mime-map)
-
-(defun mime-edit-toggle-mode ()
-  (interactive)
-  (if mime-edit-mode-flag
-      (mime-edit-exit 'nomime)
-    (mime-edit-mode)
-    ))
-
-(cond (running-xemacs
-       (defconst mime-edit-minor-mime-map nil "Keymap for MIME commands.")
-       (or mime-edit-minor-mime-map
-          (progn
-            (setq mime-edit-minor-mime-map 
-                  (make-sparse-keymap 'mime-edit-minor-mime-map))
-            (define-key
-              mime-edit-minor-mime-map mime-prefix mime-edit-mime-map)
-            ))
-       (add-minor-mode 'mime-edit-mode-flag
-                      '((" MIME-Edit "  mime-edit-transfer-level-string))
-                      mime-edit-minor-mime-map
-                      nil
-                      'mime-edit-toggle-mode)
-       )
-      (t
-       (set-alist 'minor-mode-alist
-                 'mime-edit-mode-flag
-                 '((" MIME-Edit "  mime-edit-transfer-level-string))))
-      )
+(defvar mime-edit-mode-map (make-sparse-keymap)
+  "Keymap for MIME-Edit mode commands.")
+
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-t"       'mime-edit-insert-text)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-i"       'mime-edit-insert-file)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-e"       'mime-edit-insert-external)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-v"       'mime-edit-insert-voice)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-y"       'mime-edit-insert-message)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-m"       'mime-edit-insert-mail)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-w"       'mime-edit-insert-signature)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-s"       'mime-edit-insert-signature)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-k"       'mime-edit-insert-key)
+(define-key mime-edit-mode-map
+  "\C-c\C-xt"          'mime-edit-insert-tag)
+
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-a"       'mime-edit-enclose-alternative-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-p"       'mime-edit-enclose-parallel-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-m"       'mime-edit-enclose-mixed-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-d"       'mime-edit-enclose-digest-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-s"       'mime-edit-enclose-signed-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-e"       'mime-edit-enclose-encrypted-region)
+(define-key mime-edit-mode-map
+  "\C-c\C-m\C-q"       'mime-edit-enclose-quote-region)
+
+(define-key mime-edit-mode-map
+  "\C-c\C-x7"          'mime-edit-set-transfer-level-7bit)
+(define-key mime-edit-mode-map
+  "\C-c\C-x8"          'mime-edit-set-transfer-level-8bit)
+(define-key mime-edit-mode-map
+  "\C-c\C-x/"          'mime-edit-set-split)
+(define-key mime-edit-mode-map
+  "\C-c\C-xs"          'mime-edit-set-sign)
+(define-key mime-edit-mode-map
+  "\C-c\C-xv"          'mime-edit-set-sign)
+(define-key mime-edit-mode-map
+  "\C-c\C-xe"          'mime-edit-set-encrypt)
+(define-key mime-edit-mode-map
+  "\C-c\C-xh"          'mime-edit-set-encrypt)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-p"       'mime-edit-preview-message)
+(define-key mime-edit-mode-map
+  "\C-c\C-x\C-z"       'mime-edit-exit)
+(define-key mime-edit-mode-map
+  "\C-c\C-x?"          'mime-edit-help)
 
 (defconst mime-edit-menu-title "MIME-Edit")
 
@@ -592,50 +639,51 @@ Tspecials means any character that matches with it in header must be quoted.")
     )
   "MIME-edit menubar entry.")
 
-(defun mime-edit-define-menu-for-emacs19 ()
-  "Define menu for Emacs 19."
-  (define-key (current-local-map) [menu-bar mime-edit]
-    (cons mime-edit-menu-title
-         (make-sparse-keymap mime-edit-menu-title)))
-  (mapcar (function
-          (lambda (item)
-            (define-key (current-local-map)
-              (vector 'menu-bar 'mime-edit (car item))
-              (cons (nth 1 item)(nth 2 item))
+(cond (running-xemacs
+       ;; modified by Pekka Marjola <pema@iki.fi>
+       ;;      1995/9/5 (c.f. [tm-en:69])
+       (defun mime-edit-define-menu-for-xemacs ()
+        "Define menu for Emacs 19."
+        (cond ((featurep 'menubar)
+               (make-local-variable 'current-menubar)
+               (set-buffer-menubar current-menubar)
+               (add-submenu
+                nil
+                (cons mime-edit-menu-title
+                      (mapcar (function
+                               (lambda (item)
+                                 (vector (nth 1 item)(nth 2 item)
+                                         mime-edit-mode-flag)
+                                 ))
+                              mime-edit-menu-list)))
+               )))
+       
+       ;; modified by Steven L. Baur <steve@miranova.com>
+       ;;      1995/12/6 (c.f. [tm-en:209])
+       (or (boundp 'mime-edit-popup-menu-for-xemacs)
+          (setq mime-edit-popup-menu-for-xemacs
+                (append '("MIME Commands" "---")
+                        (mapcar (function (lambda (item)
+                                            (vector (nth 1 item)
+                                                    (nth 2 item)
+                                                    t)))
+                                mime-edit-menu-list)))
+          )
+       )
+      ((>= emacs-major-version 19)
+       (define-key mime-edit-mode-map [menu-bar mime-edit]
+        (cons mime-edit-menu-title
+              (make-sparse-keymap mime-edit-menu-title)))
+       (mapcar (function
+               (lambda (item)
+                 (define-key mime-edit-mode-map
+                   (vector 'menu-bar 'mime-edit (car item))
+                   (cons (nth 1 item)(nth 2 item))
+                   )
+                 ))
+              (reverse mime-edit-menu-list)
               )
-            ))
-         (reverse mime-edit-menu-list)
-         ))
-
-;;; modified by Pekka Marjola <pema@iki.fi>
-;;;    1995/9/5 (c.f. [tm-en:69])
-(defun mime-edit-define-menu-for-xemacs ()
-  "Define menu for Emacs 19."
-  (cond ((featurep 'menubar)
-        (make-local-variable 'current-menubar)
-        (set-buffer-menubar current-menubar)
-        (add-submenu nil
-                     (cons mime-edit-menu-title
-                           (mapcar (function
-                                    (lambda (item)
-                                      (vector (nth 1 item)(nth 2 item)
-                                              mime-edit-mode-flag)
-                                      ))
-                                   mime-edit-menu-list)))
-        )))
-
-;;; modified by Steven L. Baur <steve@miranova.com>
-;;;    1995/12/6 (c.f. [tm-en:209])
-(if (and running-xemacs (not (boundp 'mime-edit-popup-menu-for-xemacs)))
-    (setq mime-edit-popup-menu-for-xemacs
-         (append '("MIME Commands" "---")
-                 (mapcar (function (lambda (item)
-                                     (vector (nth 1 item)
-                                             (nth 2 item)
-                                             t)))
-                         mime-edit-menu-list)))
-  )
-;;; end
+       ))
 
 
 ;;; @ functions
@@ -651,40 +699,35 @@ format. The message tag looks like:
        --[[text/plain; charset=ISO-2022-JP][7bit]]
 
 The tag specifies the MIME content type, subtype, optional parameters
-and transfer encoding of the message following the tag. Messages
-without any tag are treated as `text/plain' by default. Charset and
+and transfer encoding of the message following the tag.  Messages
+without any tag are treated as `text/plain' by default.  Charset and
 transfer encoding are automatically defined unless explicitly
-specified. Binary messages such as audio and image are usually hidden.
-The messages in the tagged MIME format are automatically translated
-into a MIME compliant message when exiting this mode.
+specified.  Binary messages such as audio and image are usually
+hidden.  The messages in the tagged MIME format are automatically
+translated into a MIME compliant message when exiting this mode.
 
-Available charsets depend on Emacs version being used. The following
+Available charsets depend on Emacs version being used.  The following
 lists the available charsets of each emacs.
 
-EMACS 18:      US-ASCII is only available.
-NEmacs:                US-ASCII and ISO-2022-JP are available.
-EMACS 19:      US-ASCII and ISO-8859-1 (or other charset) are available.
-XEmacs 19:     US-ASCII and ISO-8859-1 (or other charset) are available.
-Mule:          US-ASCII, ISO-8859-* (except for ISO-8859-5), KOI8-R,
-               ISO-2022-JP, ISO-2022-JP-2, ISO-2022-KR, BIG5 and
-               ISO-2022-INT-1 are available.
+Without mule:  US-ASCII and ISO-8859-1 (or other charset) are available.
+With mule:     US-ASCII, ISO-8859-* (except for ISO-8859-5), KOI8-R,
+               ISO-2022-JP, ISO-2022-JP-2, EUC-KR, CN-GB-2312,
+               CN-BIG5 and ISO-2022-INT-1 are available.
 
 ISO-2022-JP-2 and ISO-2022-INT-1 charsets used in mule is expected to
-be used to represent multilingual text in intermixed manner. Any
+be used to represent multilingual text in intermixed manner.  Any
 languages that has no registered charset are represented as either
 ISO-2022-JP-2 or ISO-2022-INT-1 in mule.
 
-If you want to use non-ISO-8859-1 charset in EMACS 19 or XEmacs 19,
-please set variable `default-mime-charset'. This variable must be
-symbol of which name is a MIME charset.
+If you want to use non-ISO-8859-1 charset in Emacs 19 or XEmacs
+without mule, please set variable `default-mime-charset'.  This
+variable must be symbol of which name is a MIME charset.
 
 If you want to add more charsets in mule, please set variable
-`charsets-mime-charset-alist'. This variable must be alist of which
-key is list of leading-char/charset and value is symbol of MIME
-charset. (leading-char is a term of MULE 1.* and 2.*. charset is a
-term of XEmacs/mule, mule merged EMACS and MULE 3.*) If name of
-coding-system is different as MIME charset, please set variable
-`mime-charset-coding-system-alist'. This variable must be alist of
+`charsets-mime-charset-alist'.  This variable must be alist of which
+key is list of charset and value is symbol of MIME charset.  If name
+of coding-system is different as MIME charset, please set variable
+`mime-charset-coding-system-alist'.  This variable must be alist of
 which key is MIME charset and value is coding-system.
 
 Following commands are available in addition to major mode commands:
@@ -743,7 +786,7 @@ TABs at the beginning of the line are not a part of the message:
        --[[audio/basic][base64]]...audio encoded in base64 here...
 
 User customizable variables (not documented all of them):
- mime-prefix
+ mime-edit-prefix
     Specifies a key prefix for MIME minor mode commands.
 
  mime-ignore-preceding-spaces
@@ -756,7 +799,7 @@ User customizable variables (not documented all of them):
     Hide a non-textual body message encoded in base64 after insertion
     if non-nil.
 
- mime-edit-transfer-level
+ mime-transfer-level
     A number of network transfer level.  It should be bigger than 7.
     If you are in 8bit-through environment, please set 8.
 
@@ -780,34 +823,51 @@ User customizable variables (not documented all of them):
     non-nil."
   (interactive)
   (if mime-edit-mode-flag
+      (mime-edit-exit)
+    (if (and (boundp 'mime-edit-touched-flag)
+            mime-edit-touched-flag)
+       (mime-edit-again)
+      (make-local-variable 'mime-edit-touched-flag)
+      (setq mime-edit-touched-flag t)
+      (turn-on-mime-edit)
+      )))
+
+
+(cond (running-xemacs
+       (add-minor-mode 'mime-edit-mode-flag
+                      '((" MIME-Edit "  mime-transfer-level-string))
+                      mime-edit-mode-map
+                      nil
+                      'mime-edit-mode)
+       )
+      (t
+       (set-alist 'minor-mode-alist
+                 'mime-edit-mode-flag
+                 '((" MIME-Edit "  mime-transfer-level-string)))
+       (set-alist 'minor-mode-map-alist
+                 'mime-edit-mode-flag
+                 mime-edit-mode-map)
+       ))
+
+
+;;;###autoload
+(defun turn-on-mime-edit ()
+  "Unconditionally turn on MIME-Edit mode."
+  (interactive)
+  (if mime-edit-mode-flag
       (error "You are already editing a MIME message.")
     (setq mime-edit-mode-flag t)
-    ;; Remember old key bindings.
-    (if running-xemacs
-       (use-local-map (or (current-local-map) (make-sparse-keymap)))
-      (make-local-variable 'mime-edit-mode-old-local-map)
-      (setq mime-edit-mode-old-local-map (current-local-map))
-      ;; Add MIME commands to current local map.
-      (use-local-map (copy-keymap (or (current-local-map)
-                                     (make-sparse-keymap))))
-      )
-    (if (not (lookup-key (current-local-map) mime-prefix))
-       (define-key (current-local-map) mime-prefix mime-edit-mime-map))
-
+    
     ;; Set transfer level into mode line
     ;;
-    (setq mime-edit-transfer-level-string
-         (mime/encoding-name mime-edit-transfer-level 'not-omit))
+    (setq mime-transfer-level-string
+         (mime-encoding-name mime-transfer-level 'not-omit))
     (force-mode-line-update)
     
-    ;; Define menu.  Menus for other emacs implementations are
-    ;; welcome.
-    (cond (running-xemacs
-          (mime-edit-define-menu-for-xemacs))
-         ((>= emacs-major-version 19)
-          (mime-edit-define-menu-for-emacs19)
-          ))
-    ;; end
+    ;; Define menu for XEmacs.
+    (if running-xemacs
+       (mime-edit-define-menu-for-xemacs)
+      )
     
     (enable-invisible)
     
@@ -825,8 +885,8 @@ User customizable variables (not documented all of them):
     ))
 
 ;;;###autoload
-(defalias 'edit-mime 'mime-edit-mode)          ; for convenience
-(defalias 'mime-mode 'mime-edit-mode)          ; for convenience
+(defalias 'edit-mime 'turn-on-mime-edit) ; for convenience
+
 
 (defun mime-edit-exit (&optional nomime no-error)
   "Translate the tagged MIME message into a MIME compliant message.
@@ -843,12 +903,10 @@ just return to previous mode."
          (mime-edit-translate-buffer)))
     ;; Restore previous state.
     (setq mime-edit-mode-flag nil)
-    (cond (running-xemacs
-          (if (featurep 'menubar) 
-              (delete-menu-item (list mime-edit-menu-title))))
-         (t
-          (use-local-map mime-edit-mode-old-local-map)))
-    
+    (if (and running-xemacs
+            (featurep 'menubar))
+       (delete-menu-item (list mime-edit-menu-title))
+      )
     (end-of-invisible)
     (set-buffer-modified-p (buffer-modified-p))
     (run-hooks 'mime-edit-exit-hook)
@@ -1097,7 +1155,7 @@ Optional argument ENCODING specifies an encoding method such as base64."
 
 (defun mime-edit-goto-tag ()
   "Search for the beginning of the tagged MIME message."
-  (let ((current (point)) multipart)
+  (let ((current (point)))
     (if (looking-at mime-edit-tag-regexp)
        t
       ;; At first, go to the end.
@@ -1142,26 +1200,25 @@ Optional argument ENCODING specifies an encoding method such as base64."
 (defun mime-edit-content-end ()
   "Return the point of the end of content."
   (save-excursion
-    (let ((beg (point)))
-      (if (mime-edit-goto-tag)
-         (let ((top (point)))
-           (goto-char (match-end 0))
-           (if (invisible-p (point))
-               (next-visible-point (point))
-             ;; Move to the end of this text.
-             (if (re-search-forward mime-edit-tag-regexp nil 'move)
-                 ;; Don't forget a multiline tag.
-                 (goto-char (match-beginning 0))
-               )
-             (point)
-             ))
-       ;; Assume the message begins with text/plain.
-       (goto-char (mime-edit-content-beginning))
-       (if (re-search-forward mime-edit-tag-regexp nil 'move)
-           ;; Don't forget a multiline tag.
-           (goto-char (match-beginning 0)))
-       (point))
-      )))
+    (if (mime-edit-goto-tag)
+       (progn
+         (goto-char (match-end 0))
+         (if (invisible-p (point))
+             (next-visible-point (point))
+           ;; Move to the end of this text.
+           (if (re-search-forward mime-edit-tag-regexp nil 'move)
+               ;; Don't forget a multiline tag.
+               (goto-char (match-beginning 0))
+             )
+           (point)
+           ))
+      ;; Assume the message begins with text/plain.
+      (goto-char (mime-edit-content-beginning))
+      (if (re-search-forward mime-edit-tag-regexp nil 'move)
+         ;; Don't forget a multiline tag.
+         (goto-char (match-beginning 0)))
+      (point))
+    ))
 
 (defun mime-edit-define-charset (charset)
   "Set charset of current tag to CHARSET."
@@ -1410,12 +1467,12 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
 
 (defvar mime-edit-translate-buffer-hook
   '(mime-edit-pgp-enclose-buffer
-    mime-edit-translate-header
-    mime-edit-translate-body))
+    mime-edit-translate-body
+    mime-edit-translate-header))
 
 (defun mime-edit-translate-header ()
   "Encode the message header into network representation."
-  (mime/encode-message-header 'code-conversion)
+  (eword-encode-header 'code-conversion)
   (run-hooks 'mime-edit-translate-header-hook)
   )
 
@@ -1549,8 +1606,9 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
            (insert (format "Content-Transfer-Encoding: %s\n" encoding))
          )
        (insert "\n")
-       (or (funcall (pgp-function 'mime-sign)
-                    (point-min)(point-max) nil nil pgp-boundary)
+       (or (as-binary-process
+            (funcall (pgp-function 'mime-sign)
+                     (point-min)(point-max) nil nil pgp-boundary))
            (throw 'mime-edit-error 'pgp-error)
            )
        ))))
@@ -1695,14 +1753,25 @@ Content-Transfer-Encoding: 7bit
          ))
       )))
 
+(defsubst replace-space-with-underline (str)
+  (mapconcat (function
+             (lambda (arg)
+               (char-to-string
+                (if (eq arg ?\ )
+                    ?_
+                  arg)))) str "")
+  )
+
+(defun mime-edit-make-boundary ()
+  (concat mime-multipart-boundary "_"
+         (replace-space-with-underline (current-time-string))
+         ))
+
 (defun mime-edit-translate-body ()
   "Encode the tagged MIME body in current buffer in MIME compliant message."
   (interactive)
   (save-excursion
-    (let ((boundary
-          (concat mime-multipart-boundary "_"
-                  (replace-space-with-underline (current-time-string))
-                  ))
+    (let ((boundary (mime-edit-make-boundary))
          (i 1)
          ret)
       (while (mime-edit-process-multipart-1
@@ -1734,6 +1803,11 @@ Content-Transfer-Encoding: 7bit
       (let ((contype (car ret))                ;Content-Type
            (encoding (nth 1 ret))      ;Content-Transfer-Encoding
            )
+       ;; Insert X-Emacs field
+       (and mime-edit-insert-x-emacs-field
+            (or (mail-position-on-field "X-Emacs")
+                (insert mime-edit-x-emacs-value)
+                ))
        ;; Make primary MIME headers.
        (or (mail-position-on-field "Mime-Version")
            (insert mime-edit-mime-version-value))
@@ -1755,30 +1829,30 @@ Content-Transfer-Encoding: 7bit
        ))))
 
 (defun mime-edit-translate-single-part-tag (&optional prefix)
+  "Translate single-part-tag to MIME header."
   (if (re-search-forward mime-edit-single-part-tag-regexp nil t)
       (let* ((beg (match-beginning 0))
             (end (match-end 0))
             (tag (buffer-substring beg end))
             )
        (delete-region beg end)
-       (setq contype (mime-edit-get-contype tag))
-       (setq encoding (mime-edit-get-encoding tag))
-       (insert (concat prefix "--" boundary "\n"))
-       (save-restriction
-         (narrow-to-region (point)(point))
-         (insert "Content-Type: " contype "\n")
-         (if encoding
-             (insert "Content-Transfer-Encoding: " encoding "\n"))
-         (mime/encode-message-header)
-         )
+       (let ((contype (mime-edit-get-contype tag))
+             (encoding (mime-edit-get-encoding tag))
+             )
+         (insert (concat prefix "--" boundary "\n"))
+         (save-restriction
+           (narrow-to-region (point)(point))
+           (insert "Content-Type: " contype "\n")
+           (if encoding
+               (insert "Content-Transfer-Encoding: " encoding "\n"))
+           (eword-encode-header)
+           ))
        t)))
 
 (defun mime-edit-translate-region (beg end &optional boundary multipart)
-  (if (null boundary)
-      (setq boundary
-           (concat mime-multipart-boundary "_"
-                   (replace-space-with-underline (current-time-string))))
-    )
+  (or boundary
+      (setq boundary (mime-edit-make-boundary))
+      )
   (save-excursion
     (save-restriction
       (narrow-to-region beg end)
@@ -1867,12 +1941,10 @@ Content-Transfer-Encoding: 7bit
                          (intern (downcase charset))
                        (mime-edit-choose-charset)))
        (mime-edit-define-charset charset)
-       (cond ((string-equal contype "text/x-rot13-47")
+       (cond ((string-equal contype "text/x-rot13-47-48")
               (save-excursion
                 (forward-line)
-                (set-mark (point))
-                (goto-char (mime-edit-content-end))
-                (tm:caesar-region)
+                (mule-caesar-region (point) (mime-edit-content-end))
                 ))
              ((string-equal contype "text/enriched")
               (save-excursion
@@ -1907,6 +1979,33 @@ Content-Transfer-Encoding: 7bit
                   )
              (encode-mime-charset-region beg (mime-edit-content-end)
                                          charset)
+             ;; Protect "From " in beginning of line
+             (save-restriction
+               (narrow-to-region beg (mime-edit-content-end))
+               (goto-char beg)
+               (if (re-search-forward "^From " nil t)
+                   (unless encoding
+                     (if (memq charset '(iso-2022-jp
+                                         iso-2022-jp-2
+                                         iso-2022-int-1
+                                         x-ctext))
+                         (while (progn
+                                  (replace-match "\e(BFrom ")
+                                  (re-search-forward "^From " nil t)
+                                  ))
+                       (setq encoding "quoted-printable")
+                       ))))
+             ;; canonicalize line break code
+             (or (member encoding '(nil "7bit" "8bit" "quoted-printable"))
+                 (save-restriction
+                   (narrow-to-region beg (mime-edit-content-end))
+                   (goto-char beg)
+                   (while (re-search-forward "\\([^\r]\\)\n" nil t)
+                     (replace-match
+                      (concat (buffer-substring (match-beginning 0)
+                                                (match-end 1)) "\r\n"))
+                     )))
+             (goto-char beg)
              (mime-encode-region beg (mime-edit-content-end) encoding)
              (mime-edit-define-encoding encoding)
              ))
@@ -1959,7 +2058,7 @@ and insert data encoded as ENCODING. [mime-edit.el]"
 
 (defun mime-edit-insert-message (&optional message)
   (interactive)
-  (let ((inserter (assoc-value major-mode mime-edit-message-inserter-alist)))
+  (let ((inserter (cdr (assq major-mode mime-edit-message-inserter-alist))))
     (if (and inserter (fboundp inserter))
        (progn
          (mime-edit-insert-tag "message" "rfc822")
@@ -1970,7 +2069,7 @@ and insert data encoded as ENCODING. [mime-edit.el]"
 
 (defun mime-edit-insert-mail (&optional message)
   (interactive)
-  (let ((inserter (assoc-value major-mode mime-edit-mail-inserter-alist)))
+  (let ((inserter (cdr (assq major-mode mime-edit-mail-inserter-alist))))
     (if (and inserter (fboundp inserter))
        (progn
          (mime-edit-insert-tag "message" "rfc822")
@@ -2089,18 +2188,17 @@ and insert data encoded as ENCODING. [mime-edit.el]"
 Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8."
   (interactive)
   (if (numberp transfer-level)
-      (setq mime-edit-transfer-level transfer-level)
-    (if (< mime-edit-transfer-level 8)
-       (setq mime-edit-transfer-level 8)
-      (setq mime-edit-transfer-level 7)
+      (setq mime-transfer-level transfer-level)
+    (if (< mime-transfer-level 8)
+       (setq mime-transfer-level 8)
+      (setq mime-transfer-level 7)
       ))
   (setq mime-edit-charset-default-encoding-alist
-       (mime-edit-make-charset-default-encoding-alist
-        mime-edit-transfer-level))
+       (mime-make-charset-default-encoding-alist mime-transfer-level))
   (message (format "Current transfer-level is %d bit"
-                  mime-edit-transfer-level))
-  (setq mime-edit-transfer-level-string
-       (mime/encoding-name mime-edit-transfer-level 'not-omit))
+                  mime-transfer-level))
+  (setq mime-transfer-level-string
+       (mime-encoding-name mime-transfer-level 'not-omit))
   (force-mode-line-update)
   )
 
@@ -2206,7 +2304,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
   (let* ((mime-edit-draft-file-name 
          (or (buffer-file-name)
              (make-temp-name
-              (expand-file-name "mime-draft" mime/tmp-dir))))
+              (expand-file-name "mime-draft" mime-temp-directory))))
         (separator mail-header-separator)
         (id (concat "\""
                     (replace-space-with-underline (current-time-string))
@@ -2308,6 +2406,8 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
 ;;; @ preview message
 ;;;
 
+(defvar mime-edit-buffer nil) ; buffer local variable
+
 (defun mime-edit-preview-message ()
   "preview editing MIME message. [mime-edit.el]"
   (interactive)
@@ -2327,11 +2427,11 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
       (switch-to-buffer buf)
       )
     (insert str)
-    (setq major-mode 'mime/temporary-message-mode)
+    (setq major-mode 'mime-temp-message-mode)
     (make-local-variable 'mail-header-separator)
     (setq mail-header-separator separator)
-    (make-local-variable 'mime/editing-buffer)
-    (setq mime/editing-buffer the-buf)
+    (make-local-variable 'mime-edit-buffer)
+    (setq mime-edit-buffer the-buf)
     
     (run-hooks 'mime-edit-translate-hook)
     (mime-edit-translate-buffer)
@@ -2344,82 +2444,32 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
     ))
 
 (defun mime-edit-quitting-method ()
-  (let ((temp mime::preview/article-buffer)
+  "Quitting method for mime-view."
+  (let ((temp mime-raw-buffer)
        buf)
     (mime-view-kill-buffer)
     (set-buffer temp)
-    (setq buf mime/editing-buffer)
+    (setq buf mime-edit-buffer)
     (kill-buffer temp)
     (switch-to-buffer buf)
     ))
 
 (set-alist 'mime-view-quitting-method-alist
-          'mime/temporary-message-mode
+          'mime-temp-message-mode
           (function mime-edit-quitting-method)
           )
 
 
-;;; @ draft preview
-;;; 
-;; by "OKABE Yasuo <okabe@kudpc.kyoto-u.ac.jp>
-;;      Mon, 10 Apr 1995 20:03:07 +0900
-
-(defvar mime-edit-draft-header-separator-alist
-  '((news-reply-mode . mail-header-separator)
-    (mh-letter-mode . mail-header-separator)
-    ))
-
-(defvar mime::article/draft-header-separator nil)
-
-(defun mime-edit-draft-preview ()
-  (interactive)
-  (let ((sep (cdr (assq major-mode mime-edit-draft-header-separator-alist))))
-    (or (stringp sep) (setq sep (eval sep)))
-    (make-variable-buffer-local 'mime::article/draft-header-separator)
-    (goto-char (point-min))
-    (re-search-forward
-     (concat "^\\(" (regexp-quote sep) "\\)?$"))
-    (setq mime::article/draft-header-separator
-         (buffer-substring (match-beginning 0) (match-end 0)))
-    (replace-match "")
-    (mime-view-mode (current-buffer))
-    (pop-to-buffer (current-buffer))
-    ))
-
-(defun mime-viewer::quitting-method/draft-preview ()
-  (let ((mother mime::preview/mother-buffer))
-    (save-excursion
-      (switch-to-buffer mother)
-      (goto-char (point-min))
-      (if (and
-          (re-search-forward
-           (concat "^\\("
-                   (regexp-quote mime::article/draft-header-separator)
-                   "\\)?$") nil t)
-          (bolp))
-         (progn
-           (insert mime::article/draft-header-separator)
-           (set-buffer-modified-p (buffer-modified-p))
-           )))
-    (mime-view-kill-buffer)
-    (pop-to-buffer mother)
-    ))
-
-(set-alist 'mime-view-quitting-method-alist
-          'mh-letter-mode
-          (function mime-viewer::quitting-method/draft-preview)
-          )
-
-(set-alist 'mime-view-quitting-method-alist
-          'news-reply-mode
-          (function mime-viewer::quitting-method/draft-preview)
-          )
-
-
 ;;; @ edit again
 ;;;
 
-(defun mime-editor::edit-again (code-conversion)
+(defvar mime-edit-again-ignored-field-regexp
+  (concat "^\\(" "Content-.*\\|Mime-Version"
+         (if mime-edit-insert-x-emacs-field "\\|X-Emacs")
+         "\\):")
+  "Regexp for deleted header fields when `mime-edit-again' is called.")
+
+(defun mime-edit-decode-buffer (not-decode-text)
   (save-excursion
     (goto-char (point-min))
     (let ((ctl (mime/Content-Type)))
@@ -2439,7 +2489,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
              (delete-region (point-min)(point-max))
              )
             ((string= type "multipart")
-             (let* ((boundary (assoc-value "boundary" params))
+             (let* ((boundary (cdr (assoc "boundary" params)))
                     (boundary-pat
                      (concat "\n--" (regexp-quote boundary) "[ \t]*\n"))
                     )
@@ -2468,7 +2518,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
                            )
                          (save-restriction
                            (narrow-to-region beg end)
-                           (mime-editor::edit-again code-conversion)
+                           (mime-edit-decode-buffer not-decode-text)
                            (goto-char (point-max))
                            ))))
                    ))
@@ -2527,7 +2577,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
                                    (setq encoded t
                                          encoding nil)
                                    )))))))
-               (if (or code-conversion encoded)
+               (if (or encoded (not not-decode-text))
                    (decode-mime-charset-region
                     (point-min)(point-max)
                     (or charset default-mime-charset))
@@ -2551,36 +2601,37 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
                      (concat type "/" stype pstr) encoding))
                    ))
                ))))
-       (if code-conversion
+       (or not-decode-text
            (decode-mime-charset-region (point-min) (point-max)
                                        default-mime-charset)
-         )
+           )
        ))))
 
-(defun mime/edit-again (&optional code-conversion no-separator no-mode)
+(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
+converted to MIME-Edit tags."
   (interactive)
-  (mime-editor::edit-again code-conversion)
+  (goto-char (point-min))
+  (if (search-forward
+       (concat "\n" (regexp-quote mail-header-separator) "\n")
+       nil t)
+      (replace-match "\n\n")
+    )
+  (mime-edit-decode-buffer not-decode-text)
   (goto-char (point-min))
   (save-restriction
-    (narrow-to-region
-     (point-min)
-     (if (re-search-forward
-         (concat "^\\(" (regexp-quote mail-header-separator) "\\)?$")
-         nil t)
-        (match-end 0)
-       (point-max)
-       ))
+    (std11-narrow-to-header)
     (goto-char (point-min))
-    (while (re-search-forward
-           "^\\(Content-.*\\|Mime-Version\\):" nil t)
+    (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)
           ))
-  (or no-mode
-      (mime-edit-mode)
+  (or not-turn-on
+      (turn-on-mime-edit)
       ))