diff lisp/tm/tm-edit.el @ 4:b82b59fe008d r19-15b3

Import from CVS: tag r19-15b3
author cvs
date Mon, 13 Aug 2007 08:46:56 +0200
parents
children 4b173ad71786
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/tm/tm-edit.el	Mon Aug 13 08:46:56 2007 +0200
@@ -0,0 +1,2581 @@
+;;; tm-edit.el --- Simple MIME Composer for GNU Emacs
+
+;; Copyright (C) 1993 .. 1996 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>
+;; Created: 1994/08/21 renamed from mime.el
+;; Version: $Revision: 1.1.1.1 $
+;; Keywords: mail, news, MIME, multimedia, multilingual
+
+;; This file is part of tm (Tools for MIME).
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This is an Emacs minor mode for editing Internet multimedia
+;; messages formatted in MIME (RFC 2045, 2046, 2047, 2048 and 2049).
+;; All messages in this mode are composed in the tagged MIME format,
+;; that are described in the following examples.  The messages
+;; 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] or `ISO-2022-INT-1'.  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/editor-mode automatically:
+;;
+;; (autoload 'mime/editor-mode "tm-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/editor-mode)
+;; (add-hook 'mail-send-hook 'mime-editor/maybe-translate)
+;;
+;; In case of MH-E, you need the following hook definition:
+;;
+;; (add-hook 'mh-letter-mode-hook
+;;           (function
+;;            (lambda ()
+;;              (mime/editor-mode)
+;;              (make-local-variable 'mail-header-separator)
+;;              (setq mail-header-separator "--------")
+;;              ))))
+;; (add-hook 'mh-before-send-letter-hook 'mime-editor/maybe-translate)
+;;
+;; In case of News mode, you need the following hook definition:
+;;
+;; (add-hook 'news-reply-mode-hook 'mime/editor-mode)
+;; (add-hook 'news-inews-hook 'mime-editor/maybe-translate)
+;;
+;; In case of Emacs 19, it is possible to emphasize the message tags
+;; using font-lock mode as follows:
+;;
+;; (add-hook 'mime/editor-mode-hook
+;;           (function
+;;            (lambda ()
+;;              (font-lock-mode 1)
+;;              (setq font-lock-keywords (list mime-editor/tag-regexp))
+;;              ))))
+
+;; The message tag looks like:
+;;
+;;	--[[TYPE/SUBTYPE;PARAMETERS][ENCODING]]
+;;
+;; The tagged MIME message examples:
+;;
+;; This is a conventional plain text.  It should be translated into
+;; text/plain.
+;; 
+;;--[[text/plain]]
+;; This is also a plain text.  But, it is explicitly specified as is.
+;;
+;;--[[text/plain; charset=ISO-2022-JP]]
+;; これは charset を ISO-2022-JP に指定した日本語の plain テキストです.
+;;
+;;--[[text/richtext]]
+;; <center>This is a richtext.</center>
+;;
+;;--[[image/gif][base64]]^M...image encoded in base64 comes here...
+;;
+;;--[[audio/basic][base64]]^M...audio encoded in base64 comes here...
+
+;;; Code:
+
+(require 'sendmail)
+(require 'mail-utils)
+(require 'mel)
+(require 'tl-822)
+(require 'tl-list)
+(require 'tm-view)
+(require 'tm-ew-e)
+(require 'signature)
+
+
+;;; @ version
+;;;
+
+(defconst mime-editor/RCS-ID
+  "$Id: tm-edit.el,v 1.1.1.1 1996/12/18 03:55:31 steve Exp $")
+
+(defconst mime-editor/version (get-version-string mime-editor/RCS-ID))
+
+(defconst mime-editor/version-name
+  (concat "tm-edit " mime-editor/version))
+
+
+;;; @ 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.")
+
+(defvar mime-ignore-trailing-spaces nil
+  "*Ignore trailing white spaces if non-nil.")
+
+(defvar mime-ignore-same-text-tag t
+  "*Ignore preceding text content-type tag that is same with new one.
+If non-nil, the text tag is not inserted unless something different.")
+
+(defvar mime-auto-hide-body t
+  "*Hide non-textual body encoded in base64 after insertion if non-nil.")
+
+(defvar mime-editor/voice-recorder
+  (function mime-editor/voice-recorder-for-sun)
+  "*Function to record a voice message and encode it. [tm-edit.el]")
+
+(defvar mime/editor-mode-hook nil
+  "*Hook called when enter MIME mode.")
+
+(defvar mime-editor/translate-hook nil
+  "*Hook called before translating into a MIME compliant message.
+To insert a signature file automatically, call the function
+`mime-editor/insert-signature' from this hook.")
+
+(defvar mime-editor/exit-hook nil
+  "*Hook called when exit MIME mode.")
+
+(defvar mime-content-types
+  '(("text"
+     ;; Charset parameter need not to be specified, since it is
+     ;; defined automatically while translation.
+     ("plain"
+      ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
+      )
+     ("richtext"
+      ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
+      )
+     ("enriched"
+      ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
+      )
+     ("x-latex"
+      ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
+      )
+     ("html"
+      ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
+      )
+     ("x-rot13-47")
+     )
+    ("message"
+     ("external-body"
+      ("access-type"
+       ("anon-ftp"
+	("site" "ftp.jaist.ac.jp" "wnoc-fuk.wide.ad.jp" "nic.karrn.ad.jp")
+	("directory" "/pub/GNU/elisp/mime")
+	("name")
+	("mode" "image" "ascii" "local8"))
+       ("ftp"
+	("site")
+	("directory")
+	("name")
+	("mode" "image" "ascii" "local8"))
+       ("tftp"        ("site") ("name"))
+       ("afs"         ("site") ("name"))
+       ("local-file"  ("site") ("name"))
+       ("mail-server" ("server" "ftpmail@nic.karrn.ad.jp"))
+       ))
+     ("rfc822")
+     )
+    ("application"
+     ("octet-stream" ("type" "" "tar" "shar"))
+     ("postscript")
+     ("x-kiss" ("x-cnf")))
+    ("image"
+     ("gif")
+     ("jpeg")
+     ("tiff")
+     ("x-pic")
+     ("x-mag")
+     ("x-xwd")
+     ("x-xbm")
+     )
+    ("audio" ("basic"))
+    ("video" ("mpeg"))
+    )
+  "*Alist of content-type, subtype, parameters and its values.")
+
+(defvar mime-file-types
+  '(("\\.rtf$"
+     "text"	"richtext"	nil
+     nil
+     nil		nil)
+    ("\\.html$"
+     "text"	"html"		nil
+     nil
+     nil		nil)
+    ("\\.ps$"
+     "application" "postscript"	nil
+     "quoted-printable"
+     "attachment"	(("filename" . file))
+     )
+    ("\\.jpg$"
+     "image"	"jpeg"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.gif$"
+     "image"	"gif"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.tiff$"
+     "image"	"tiff"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.pic$"
+     "image"	"x-pic"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.mag$"
+     "image"	"x-mag"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.xbm$"
+     "image"	"x-xbm"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.xwd$"
+     "image"	"x-xwd"		nil
+     "base64"
+     "inline"		(("filename" . file))
+     )
+    ("\\.au$"
+     "audio"	"basic"		nil
+     "base64"
+     "attachment"		(("filename" . file))
+     )
+    ("\\.mpg$"
+     "video"	"mpeg"		nil
+     "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"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.tgz$"
+     "application" "octet-stream" (("type" . "tar+gzip"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.tar\\.Z$"
+     "application" "octet-stream" (("type" . "tar+compress"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.taz$"
+     "application" "octet-stream" (("type" . "tar+compress"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.gz$"
+     "application" "octet-stream" (("type" . "gzip"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.Z$"
+     "application" "octet-stream" (("type" . "compress"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.lzh$"
+     "application" "octet-stream" (("type" . "lha"))
+     nil
+     "attachment"	(("filename" . file))
+     )
+    ("\\.zip$"
+     "application" "zip" nil
+     nil
+     "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)
+    (".*"
+     "application" "octet-stream" nil
+     nil
+     "attachment"	(("filename" . file))
+     )
+    )
+  "*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-editor/transfer-level 7
+  "*A number of network transfer level. It should be bigger than 7.")
+(make-variable-buffer-local 'mime-editor/transfer-level)
+
+(defvar mime-editor/transfer-level-string
+  (mime/encoding-name mime-editor/transfer-level 'not-omit)
+  "*A string formatted version of mime/defaul-transfer-level")
+(make-variable-buffer-local 'mime-editor/transfer-level-string)
+
+(defun mime-editor/make-charset-default-encoding-alist (transfer-level)
+  (mapcar (function
+	   (lambda (charset-type)
+	     (let ((charset  (car charset-type))
+		   (type     (nth 1 charset-type))
+		   (encoding (nth 2 charset-type))
+		   )
+	       (if (<= type transfer-level)
+		   (cons charset (mime/encoding-name type))
+		 (cons charset encoding)
+		 ))))
+	  mime-charset-type-list))
+
+(defvar mime-editor/charset-default-encoding-alist
+  (mime-editor/make-charset-default-encoding-alist mime-editor/transfer-level))
+(make-variable-buffer-local 'mime-editor/charset-default-encoding-alist)
+
+;;; @@ about message inserting
+;;;
+
+(defvar mime-editor/yank-ignored-field-list
+  '("Received" "Approved" "Path" "Replied" "Status"
+    "Xref" "X-UIDL" "X-Filter" "X-Gnus-.*" "X-VM-.*")
+  "Delete these fields from original message when it is inserted
+as message/rfc822 part.
+Each elements are regexp of field-name. [tm-edit.el]")
+
+(defvar mime-editor/yank-ignored-field-regexp
+  (concat "^"
+	  (apply (function regexp-or) mime-editor/yank-ignored-field-list)
+	  ":"))
+
+(defvar mime-editor/message-inserter-alist nil)
+(defvar mime-editor/mail-inserter-alist nil)
+
+;;; @@ about message splitting
+;;;
+
+(defvar mime-editor/split-message t
+  "*Split large message if it is non-nil. [tm-edit.el]")
+
+(defvar mime-editor/message-default-max-lines 1000
+  "*Default maximum lines of a message. [tm-edit.el]")
+
+(defvar mime-editor/message-max-lines-alist
+  '((news-reply-mode . 500))
+  "Alist of major-mode vs maximum lines of a message.
+If it is not specified for a major-mode,
+`mime-editor/message-default-max-lines' is used. [tm-edit.el]")
+
+(defconst mime-editor/split-ignored-field-regexp
+  "\\(^Content-\\|^Subject:\\|^Mime-Version:\\)")
+
+(defvar mime-editor/split-blind-field-regexp
+  "\\(^[BDFbdf]cc:\\|^cc:[ \t]*$\\)")
+
+(defvar mime-editor/split-message-sender-alist nil)
+
+(defvar mime-editor/news-reply-mode-server-running nil)
+
+
+;;; @@ about PGP
+;;;
+
+(defvar mime-editor/signing-type 'pgp-elkins
+  "*PGP signing type (pgp-elkins, pgp-kazu or nil). [tm-edit.el]")
+
+(defvar mime-editor/encrypting-type 'pgp-elkins
+  "*PGP encrypting type (pgp-elkins, pgp-kazu or nil). [tm-edit.el]")
+
+(defvar mime-editor/pgp-sign-function 'tm:mc-pgp-sign-region)
+(defvar mime-editor/pgp-encrypt-function 'tm:mc-pgp-encrypt-region)
+(defvar mime-editor/traditional-pgp-sign-function 'mc-pgp-sign-region)
+(defvar mime-editor/pgp-insert-public-key-function 'mc-insert-public-key)
+
+(autoload mime-editor/pgp-sign-function "tm-edit-mc")
+(autoload mime-editor/pgp-encrypt-function "tm-edit-mc")
+(autoload mime-editor/traditional-pgp-sign-function "mc-pgp")
+(autoload mime-editor/pgp-insert-public-key-function "mc-toplev")
+
+
+;;; @@ about tag
+;;;
+
+(defconst mime-editor/single-part-tag-regexp
+  "--[[][[]\\([^]]*\\)]\\([[]\\([^]]*\\)]\\|\\)]"
+  "*Regexp of MIME tag in the form of [[CONTENT-TYPE][ENCODING]].")
+
+(defconst mime-editor/quoted-single-part-tag-regexp
+  (concat "- " (substring mime-editor/single-part-tag-regexp 1)))
+
+(defconst mime-editor/multipart-beginning-regexp "--<<\\([^<>]+\\)>>-{\n")
+
+(defconst mime-editor/multipart-end-regexp "--}-<<\\([^<>]+\\)>>\n")
+
+(defconst mime-editor/beginning-tag-regexp
+  (regexp-or mime-editor/single-part-tag-regexp
+	     mime-editor/multipart-beginning-regexp))
+
+(defconst mime-editor/end-tag-regexp
+  (regexp-or mime-editor/single-part-tag-regexp
+	     mime-editor/multipart-end-regexp))
+
+(defconst mime-editor/tag-regexp
+  (regexp-or mime-editor/single-part-tag-regexp
+	     mime-editor/multipart-beginning-regexp
+	     mime-editor/multipart-end-regexp))
+
+(defvar mime-tag-format "--[[%s]]"
+  "*Control-string making a MIME tag.")
+
+(defvar mime-tag-format-with-encoding "--[[%s][%s]]"
+  "*Control-string making a MIME tag with encoding.")
+
+;;; @@ multipart boundary
+;;;
+
+(defvar mime-multipart-boundary "Multipart"
+  "*Boundary of a multipart message.")
+
+
+;;; @@ buffer local variables
+;;;
+
+(defvar mime/editor-mode-old-local-map nil)
+(defvar mime/editing-buffer nil)
+
+
+;;; @ constants
+;;;
+
+(defconst mime-tspecials-regexp "[][()<>@,;:\\\"/?.= \t]"
+  "*Specify MIME tspecials.
+Tspecials means any character that matches with it in header must be quoted.")
+
+(defconst mime-editor/mime-version-value
+  (concat "1.0 (generated by " mime-editor/version-name ")")
+  "MIME version number.")
+
+(defconst mime-editor/mime-map (make-sparse-keymap)
+  "Keymap for MIME commands.")
+
+;;; @ keymap and menu
+;;;
+
+(defvar mime/editor-mode-flag nil)
+(make-variable-buffer-local 'mime/editor-mode-flag)
+
+(defun mime-editor/define-keymap (keymap)
+  "Add mime-editor commands to KEYMAP."
+  (if (not (keymapp keymap))
+      nil
+    (define-key keymap "\C-t" 'mime-editor/insert-text)
+    (define-key keymap "\C-i" 'mime-editor/insert-file)
+    (define-key keymap "\C-e" 'mime-editor/insert-external)
+    (define-key keymap "\C-v" 'mime-editor/insert-voice)
+    (define-key keymap "\C-y" 'mime-editor/insert-message)
+    (define-key keymap "\C-m" 'mime-editor/insert-mail)
+    (define-key keymap "\C-w" 'mime-editor/insert-signature)
+    (define-key keymap "\C-s" 'mime-editor/insert-signature)
+    (define-key keymap "\C-k" 'mime-editor/insert-key)
+    (define-key keymap "t"    'mime-editor/insert-tag)
+    (define-key keymap "a"    'mime-editor/enclose-alternative-region)
+    (define-key keymap "p"    'mime-editor/enclose-parallel-region)
+    (define-key keymap "m"    'mime-editor/enclose-mixed-region)
+    (define-key keymap "d"    'mime-editor/enclose-digest-region)
+    (define-key keymap "s"    'mime-editor/enclose-signed-region)
+    (define-key keymap "e"    'mime-editor/enclose-encrypted-region)
+    (define-key keymap "q"    'mime-editor/enclose-quote-region)
+    (define-key keymap "7"    'mime-editor/set-transfer-level-7bit)
+    (define-key keymap "8"    'mime-editor/set-transfer-level-8bit)
+    (define-key keymap "/"    'mime-editor/set-split)
+    (define-key keymap "v"    'mime-editor/set-sign)
+    (define-key keymap "h"    'mime-editor/set-encrypt)
+    (define-key keymap "\C-p" 'mime-editor/preview-message)
+    (define-key keymap "\C-z" 'mime-editor/exit)
+    (define-key keymap "?"    'mime-editor/help)
+    ))
+
+(mime-editor/define-keymap mime-editor/mime-map)
+
+(defun mime-editor/toggle-mode ()
+  (interactive)
+  (if mime/editor-mode-flag
+      (mime-editor/exit 'nomime)
+    (mime/editor-mode)
+    ))
+
+(cond (running-xemacs
+       (defconst mime-editor/minor-mime-map nil "Keymap for MIME commands.")
+       (or mime-editor/minor-mime-map
+	   (progn
+	     (setq mime-editor/minor-mime-map 
+		   (make-sparse-keymap 'mime-editor/minor-mime-map))
+	     (define-key
+	       mime-editor/minor-mime-map mime-prefix mime-editor/mime-map)
+	     ))
+       (add-minor-mode 'mime/editor-mode-flag
+		       '((" MIME-Edit "  mime-editor/transfer-level-string))
+		       mime-editor/minor-mime-map
+		       nil
+		       'mime-editor/toggle-mode)
+       )
+      (t
+       (set-alist 'minor-mode-alist
+		  'mime/editor-mode-flag
+		  '((" MIME-Edit "  mime-editor/transfer-level-string))))
+      )
+
+(defconst mime-editor/menu-title "MIME-Edit")
+
+(defconst mime-editor/menu-list
+  '((mime-help	"Describe MIME editor mode" mime-editor/help)
+    (file	"Insert File"		mime-editor/insert-file)
+    (external	"Insert External"	mime-editor/insert-external)
+    (voice	"Insert Voice"		mime-editor/insert-voice)
+    (message	"Insert Message"	mime-editor/insert-message)
+    (mail	"Insert Mail"		mime-editor/insert-mail)
+    (signature	"Insert Signature"	mime-editor/insert-signature)
+    (text	"Insert Text"		mime-editor/insert-text)
+    (tag	"Insert Tag"		mime-editor/insert-tag)
+    (alternative "Enclose as alternative"
+		 mime-editor/enclose-alternative-region)
+    (parallel	"Enclose as parallel"	mime-editor/enclose-parallel-region)
+    (mixed	"Enclose as serial"	mime-editor/enclose-mixed-region)
+    (digest	"Enclose as digest"	mime-editor/enclose-digest-region)
+    (signed	"Enclose as signed"	mime-editor/enclose-signed-region)
+    (encrypted	"Enclose as encrypted"	mime-editor/enclose-encrypted-region)
+    (quote	"Verbatim region"	mime-editor/enclose-quote-region)
+    (key	"Insert Public Key"	mime-editor/insert-key)
+    (split	"About split"           mime-editor/set-split)
+    (sign	"About sign"		mime-editor/set-sign)
+    (encrypt	"About encryption"	mime-editor/set-encrypt)
+    (preview	"Preview Message"	mime-editor/preview-message)
+    (level	"Toggle transfer-level"	mime-editor/toggle-transfer-level)
+    )
+  "MIME-edit menubar entry.")
+
+(defun mime-editor/define-menu-for-emacs19 ()
+  "Define menu for Emacs 19."
+  (define-key (current-local-map) [menu-bar mime-edit]
+    (cons mime-editor/menu-title
+	  (make-sparse-keymap mime-editor/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))
+	       )
+	     ))
+	  (reverse mime-editor/menu-list)
+	  ))
+
+;;; modified by Pekka Marjola <pema@iki.fi>
+;;;	1995/9/5 (c.f. [tm-en:69])
+(defun mime-editor/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-editor/menu-title
+			    (mapcar (function
+				     (lambda (item)
+				       (vector (nth 1 item)(nth 2 item)
+					       mime/editor-mode-flag)
+				       ))
+				    mime-editor/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-editor/popup-menu-for-xemacs)))
+    (setq mime-editor/popup-menu-for-xemacs
+	  (append '("MIME Commands" "---")
+		  (mapcar (function (lambda (item)
+				      (vector (nth 1 item)
+					      (nth 2 item)
+					      t)))
+			  mime-editor/menu-list)))
+  )
+;;; end
+
+
+;;; @ functions
+;;;
+
+;;;###autoload
+(defun mime/editor-mode ()
+  "MIME minor mode for editing the tagged MIME message.
+
+In this mode, basically, the message is composed in the tagged MIME
+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
+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.
+
+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.
+
+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
+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 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
+which key is MIME charset and value is coding-system.
+
+Following commands are available in addition to major mode commands:
+\\[mime-editor/insert-text]	insert a text message.
+\\[mime-editor/insert-file]	insert a (binary) file.
+\\[mime-editor/insert-external]	insert a reference to external body.
+\\[mime-editor/insert-voice]	insert a voice message.
+\\[mime-editor/insert-message]	insert a mail or news message.
+\\[mime-editor/insert-mail]	insert a mail message.
+\\[mime-editor/insert-signature]	insert a signature file at end.
+\\[mime-editor/insert-tag]	insert a new MIME tag.
+\\[mime-editor/enclose-alternative-region]	enclose as multipart/alternative.
+\\[mime-editor/enclose-parallel-region]	enclose as multipart/parallel.
+\\[mime-editor/enclose-mixed-region]	enclose as multipart/mixed.
+\\[mime-editor/enclose-digest-region]	enclose as multipart/digest.
+\\[mime-editor/enclose-signed-region]	enclose as PGP signed.
+\\[mime-editor/enclose-encrypted-region]	enclose as PGP encrypted.
+\\[mime-editor/insert-key]	insert PGP public key.
+\\[mime-editor/preview-message]	preview editing MIME message.
+\\[mime-editor/exit]	exit and translate into a MIME compliant message.
+\\[mime-editor/maybe-translate]	exit and translate if in MIME mode, then split.
+\\[mime-editor/help]	show this help.
+
+Additional commands are available in some major modes:
+C-c C-c		exit, translate and run the original command.
+C-c C-s		exit, translate and run the original command.
+
+The following is a message example written in the tagged MIME format.
+TABs at the beginning of the line are not a part of the message:
+
+	This is a conventional plain text.  It should be translated
+	into text/plain.
+	--[[text/plain]]
+	This is also a plain text.  But, it is explicitly specified as
+	is.
+	--[[text/plain; charset=ISO-2022-JP]]
+	これは charset を ISO-2022-JP に指定した日本語の plain テキス
+	トです.
+	--[[text/richtext]]
+	<center>This is a richtext.</center>
+	--[[image/gif][base64]]^M...image encoded in base64 here...
+	--[[audio/basic][base64]]^M...audio encoded in base64 here...
+
+User customizable variables (not documented all of them):
+ mime-prefix
+    Specifies a key prefix for MIME minor mode commands.
+
+ mime-ignore-preceding-spaces
+    Preceding white spaces in a message body are ignored if non-nil.
+
+ mime-ignore-trailing-spaces
+    Trailing white spaces in a message body are ignored if non-nil.
+
+ mime-auto-fill-header
+    Fill header fields that contain encoded-words if non-nil.
+
+ mime-auto-hide-body
+    Hide a non-textual body message encoded in base64 after insertion
+    if non-nil.
+
+ mime-editor/voice-recorder
+    Specifies a function to record a voice message and encode it.
+    The function `mime-editor/voice-recorder-for-sun' is for Sun
+    SparcStations.
+
+ mime/editor-mode-hook
+    Turning on MIME mode calls the value of mime/editor-mode-hook, if
+    it is non-nil.
+
+ mime-editor/translate-hook
+    The value of mime-editor/translate-hook is called just before translating
+    the tagged MIME format into a MIME compliant message if it is
+    non-nil.  If the hook call the function mime-editor/insert-signature,
+    the signature file will be inserted automatically.
+
+ mime-editor/exit-hook
+    Turning off MIME mode calls the value of mime-editor/exit-hook, if it is
+    non-nil."
+  (interactive)
+  (if mime/editor-mode-flag
+      (error "You are already editing a MIME message.")
+    (setq mime/editor-mode-flag t)
+    ;; Remember old key bindings.
+    (if running-xemacs
+	(use-local-map (or (current-local-map) (make-sparse-keymap)))
+      (make-local-variable 'mime/editor-mode-old-local-map)
+      (setq mime/editor-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-editor/mime-map))
+
+    ;; Set transfer level into mode line
+    ;;
+    (setq mime-editor/transfer-level-string
+ 	  (mime/encoding-name mime-editor/transfer-level 'not-omit))
+    (force-mode-line-update)
+    
+    ;; Define menu.  Menus for other emacs implementations are
+    ;; welcome.
+    (cond (running-xemacs
+	   (mime-editor/define-menu-for-xemacs))
+	  ((>= emacs-major-version 19)
+	   (mime-editor/define-menu-for-emacs19)
+	   ))
+    ;; end
+    
+    (enable-invisible)
+    
+    ;; I don't care about saving these.
+    (setq paragraph-start
+	  (regexp-or mime-editor/single-part-tag-regexp
+		     paragraph-start))
+    (setq paragraph-separate
+	  (regexp-or mime-editor/single-part-tag-regexp
+		     paragraph-separate))
+    (run-hooks 'mime/editor-mode-hook)
+    (message
+     (substitute-command-keys
+      "Type \\[mime-editor/exit] to exit MIME mode, and type \\[mime-editor/help] to get help."))
+    ))
+
+;;;###autoload
+(defalias 'edit-mime 'mime/editor-mode)		; for convenience
+(defalias 'mime-mode 'mime/editor-mode)		; for convenience
+
+(defun mime-editor/exit (&optional nomime no-error)
+  "Translate the tagged MIME message into a MIME compliant message.
+With no argument encode a message in the buffer into MIME, otherwise
+just return to previous mode."
+  (interactive "P")
+  (if (not mime/editor-mode-flag)
+      (if (null no-error)
+	  (error "You aren't editing a MIME message.")
+	)
+    (if (not nomime)
+	(progn
+	  (run-hooks 'mime-editor/translate-hook)
+	  (mime-editor/translate-buffer)))
+    ;; Restore previous state.
+    (setq mime/editor-mode-flag nil)
+    (cond (running-xemacs
+	   (delete-menu-item (list mime-editor/menu-title)))
+	  (t
+	   (use-local-map mime/editor-mode-old-local-map)))
+    
+    (end-of-invisible)
+    (set-buffer-modified-p (buffer-modified-p))
+    (run-hooks 'mime-editor/exit-hook)
+    (message "Exit MIME editor mode.")
+    ))
+
+(defun mime-editor/maybe-translate ()
+  (interactive)
+  (mime-editor/exit nil t)
+  (call-interactively 'mime-editor/maybe-split-and-send)
+  )
+
+(defun mime-editor/help ()
+  "Show help message about MIME mode."
+  (interactive)
+  (with-output-to-temp-buffer "*Help*"
+    (princ "MIME editor mode:\n")
+    (princ (documentation 'mime/editor-mode))
+    (print-help-return-message)))
+
+(defun mime-editor/insert-text ()
+  "Insert a text message.
+Charset is automatically obtained from the `mime/lc-charset-alist'."
+  (interactive)
+  (let ((ret (mime-editor/insert-tag "text" nil nil)))
+  (if ret
+      (progn
+	(if (looking-at mime-editor/single-part-tag-regexp)
+	    (progn
+	      ;; Make a space between the following message.
+	      (insert "\n")
+	      (forward-char -1)
+	      ))
+	(if (and (member (second ret) '("enriched" "richtext"))
+		 (fboundp 'enriched-mode)
+		 )
+	    (enriched-mode t)
+	  (if (boundp 'enriched-mode)
+	      (enriched-mode nil)
+	    ))))))
+
+(defun mime-editor/insert-file (file)
+  "Insert a message from a file."
+  (interactive "fInsert file as MIME message: ")
+  (let*  ((guess (mime-find-file-type file))
+	  (pritype (nth 0 guess))
+	  (subtype (nth 1 guess))
+	  (parameters (nth 2 guess))
+	  (default (nth 3 guess))	;Guess encoding from its file name.
+	  (disposition-type (nth 4 guess))
+	  (disposition-params (nth 5 guess))
+	  (encoding
+	   (if (not (interactive-p))
+	       default
+	     (completing-read
+	      (concat "What transfer encoding"
+		      (if default
+			  (concat " (default "
+				  (if (string-equal default "")
+				      "\"\""
+				    default)
+				  ")"
+				  ))
+		      ": ")
+	      mime-file-encoding-method-alist nil t nil))))
+    (if (string-equal encoding "")
+	(setq encoding default))
+    (if (or (consp parameters) (stringp disposition-type))
+	(let ((rest parameters) cell attribute value)
+	  (setq parameters "")
+	  (while rest
+	    (setq cell (car rest))
+	    (setq attribute (car cell))
+	    (setq value (cdr cell))
+	    (if (eq value 'file)
+		(setq value (std11-wrap-as-quoted-string
+			     (file-name-nondirectory file)))
+	      )
+	    (setq parameters (concat parameters "; " attribute "=" value))
+	    (setq rest (cdr rest))
+	    )
+	  (if disposition-type
+	      (progn
+		(setq parameters
+		      (concat parameters "\n"
+			      "Content-Disposition: " disposition-type))
+		(setq rest disposition-params)
+		(while rest
+		  (setq cell (car rest))
+		  (setq attribute (car cell))
+		  (setq value (cdr cell))
+		  (if (eq value 'file)
+		      (setq value (std11-wrap-as-quoted-string
+				   (file-name-nondirectory file)))
+		    )
+		  (setq parameters
+			(concat parameters "; " attribute "=" value))
+		  (setq rest (cdr rest))
+		  )
+		))
+	  ))
+    (mime-editor/insert-tag pritype subtype parameters)
+    (mime-editor/insert-binary-file file encoding)
+    ))
+
+(defun mime-editor/insert-external ()
+  "Insert a reference to external body."
+  (interactive)
+  (mime-editor/insert-tag "message" "external-body" nil ";\n\t")
+  ;;(forward-char -1)
+  ;;(insert "Content-Description: " (read-string "Content-Description: ") "\n")
+  ;;(forward-line 1)
+  (let* ((pritype (mime-prompt-for-type))
+	 (subtype (mime-prompt-for-subtype pritype))
+	 (parameters (mime-prompt-for-parameters pritype subtype ";\n\t")))
+    (and pritype
+	 subtype
+	 (insert "Content-Type: "
+		 pritype "/" subtype (or parameters "") "\n")))
+  (if (and (not (eobp))
+	   (not (looking-at mime-editor/single-part-tag-regexp)))
+      (insert (mime-make-text-tag) "\n")))
+
+(defun mime-editor/insert-voice ()
+  "Insert a voice message."
+  (interactive)
+  (let ((encoding
+	 (completing-read
+	  "What transfer encoding: "
+	  mime-file-encoding-method-alist nil t nil)))
+    (mime-editor/insert-tag "audio" "basic" nil)
+    (mime-editor/define-encoding encoding)
+    (save-restriction
+      (narrow-to-region (1- (point))(point))
+      (unwind-protect
+	  (funcall mime-editor/voice-recorder encoding)
+	(progn
+	  (insert "\n")
+	  (invisible-region (point-min)(point-max))
+	  (goto-char (point-max))
+	  )))))
+
+(defun mime-editor/insert-signature (&optional arg)
+  "Insert a signature file."
+  (interactive "P")
+  (let ((signature-insert-hook
+         (function
+          (lambda ()
+            (apply (function mime-editor/insert-tag)
+                   (mime-find-file-type signature-file-name))
+            )))
+        )
+    (insert-signature arg)
+    ))
+
+
+;; Insert a new tag around a point.
+
+(defun mime-editor/insert-tag (&optional pritype subtype parameters delimiter)
+  "Insert new MIME tag and return a list of PRITYPE, SUBTYPE, and PARAMETERS.
+If nothing is inserted, return nil."
+  (interactive)
+  (let ((p (point)))
+    (mime-editor/goto-tag)
+    (if (and (re-search-forward mime-editor/tag-regexp nil t)
+	     (< (match-beginning 0) p)
+	     (< p (match-end 0))
+	     )
+	(goto-char (match-beginning 0))
+      (goto-char p)
+      ))
+  (let ((oldtag nil)
+	(newtag nil)
+	(current (point))
+	)
+    (setq pritype
+	  (or pritype
+	      (mime-prompt-for-type)))
+    (setq subtype
+	  (or subtype
+	      (mime-prompt-for-subtype pritype)))
+    (setq parameters
+	  (or parameters
+	      (mime-prompt-for-parameters pritype subtype delimiter)))
+    ;; Make a new MIME tag.
+    (setq newtag (mime-make-tag pritype subtype parameters))
+    ;; Find an current MIME tag.
+    (setq oldtag
+	  (save-excursion
+	    (if (mime-editor/goto-tag)
+		(buffer-substring (match-beginning 0) (match-end 0))
+	      ;; Assume content type is 'text/plan'.
+	      (mime-make-tag "text" "plain")
+	      )))
+    ;; We are only interested in TEXT.
+    (if (and oldtag
+	     (not (mime-test-content-type
+		   (mime-editor/get-contype oldtag) "text")))
+	(setq oldtag nil))
+    ;; Make a new tag.
+    (if (or (not oldtag)		;Not text
+	    (or mime-ignore-same-text-tag
+		(not (string-equal oldtag newtag))))
+	(progn
+	  ;; Mark the beginning of the tag for convenience.
+	  (push-mark (point) 'nomsg)
+	  (insert newtag "\n")
+	  (list pritype subtype parameters) ;New tag is created.
+	  )
+      ;; Restore previous point.
+      (goto-char current)
+      nil				;Nothing is created.
+      )
+    ))
+
+(defun mime-editor/insert-binary-file (file &optional encoding)
+  "Insert binary FILE at point.
+Optional argument ENCODING specifies an encoding method such as base64."
+  (let* ((tagend (1- (point)))		;End of the tag
+	 (hide-p (and mime-auto-hide-body
+		      (stringp encoding)
+		      (not
+		       (let ((en (downcase encoding)))
+			 (or (string-equal en "7bit")
+			     (string-equal en "8bit")
+			     (string-equal en "binary")
+			     )))))
+	 )
+    (save-restriction
+      (narrow-to-region tagend (point))
+      (mime-insert-encoded-file file encoding)
+      (if hide-p
+	  (progn
+	    (invisible-region (point-min) (point-max))
+	    (goto-char (point-max))
+	    )
+	(goto-char (point-max))
+	))
+    (or hide-p
+	(looking-at mime-editor/tag-regexp)
+	(= (point)(point-max))
+	(mime-editor/insert-tag "text" "plain")
+	)
+    ;; Define encoding even if it is 7bit.
+    (if (stringp encoding)
+	(save-excursion
+	  (goto-char tagend) ; Make sure which line the tag is on.
+	  (mime-editor/define-encoding encoding)
+	  ))
+    ))
+
+
+;; Commands work on a current message flagment.
+
+(defun mime-editor/goto-tag ()
+  "Search for the beginning of the tagged MIME message."
+  (let ((current (point)) multipart)
+    (if (looking-at mime-editor/tag-regexp)
+	t
+      ;; At first, go to the end.
+      (cond ((re-search-forward mime-editor/beginning-tag-regexp nil t)
+	     (goto-char (1- (match-beginning 0))) ;For multiline tag
+	     )
+	    (t
+	     (goto-char (point-max))
+	     ))
+      ;; Then search for the beginning. 
+      (re-search-backward mime-editor/end-tag-regexp nil t)
+      (or (looking-at mime-editor/beginning-tag-regexp)
+	  ;; Restore previous point.
+	  (progn
+	    (goto-char current)
+	    nil
+	    ))
+      )))
+
+(defun mime-editor/content-beginning ()
+  "Return the point of the beginning of content."
+  (save-excursion
+    (let ((beg (save-excursion
+		 (beginning-of-line) (point))))
+      (if (mime-editor/goto-tag)
+	  (let ((top (point)))
+	    (goto-char (match-end 0))
+	    (if (and (= beg top)
+		     (= (following-char) ?\^M))
+		(point)
+	      (forward-line 1)
+	      (point)))
+	;; Default text/plain tag.
+	(goto-char (point-min))
+	(re-search-forward
+	 (concat "\n" (regexp-quote mail-header-separator)
+		 (if mime-ignore-preceding-spaces
+		     "[ \t\n]*\n" "\n")) nil 'move)
+	(point))
+      )))
+
+(defun mime-editor/content-end ()
+  "Return the point of the end of content."
+  (save-excursion
+    (let ((beg (point)))
+      (if (mime-editor/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-editor/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-editor/content-beginning))
+	(if (re-search-forward mime-editor/tag-regexp nil 'move)
+	    ;; Don't forget a multiline tag.
+	    (goto-char (match-beginning 0)))
+	(point))
+      )))
+
+(defun mime-editor/define-charset (charset)
+  "Set charset of current tag to CHARSET."
+  (save-excursion
+    (if (mime-editor/goto-tag)
+	(let ((tag (buffer-substring (match-beginning 0) (match-end 0))))
+	  (delete-region (match-beginning 0) (match-end 0))
+	  (insert
+	   (mime-create-tag
+	    (mime-editor/set-parameter
+	     (mime-editor/get-contype tag)
+	     "charset" (upcase (symbol-name charset)))
+	    (mime-editor/get-encoding tag)))
+	  ))))
+
+(defun mime-editor/define-encoding (encoding)
+  "Set encoding of current tag to ENCODING."
+  (save-excursion
+    (if (mime-editor/goto-tag)
+	(let ((tag (buffer-substring (match-beginning 0) (match-end 0))))
+	  (delete-region (match-beginning 0) (match-end 0))
+	  (insert (mime-create-tag (mime-editor/get-contype tag) encoding)))
+      )))
+
+(defun mime-editor/choose-charset ()
+  "Choose charset of a text following current point."
+  (detect-mime-charset-region (point) (mime-editor/content-end))
+  )
+
+(defun mime-make-text-tag (&optional subtype)
+  "Make a tag for a text after current point.
+Subtype of text type can be specified by an optional argument SUBTYPE.
+Otherwise, it is obtained from mime-content-types."
+  (let* ((pritype "text")
+	 (subtype (or subtype
+		      (car (car (cdr (assoc pritype mime-content-types)))))))
+    ;; Charset should be defined later.
+    (mime-make-tag pritype subtype)))
+
+
+;; Tag handling functions
+
+(defun mime-make-tag (pritype subtype &optional parameters encoding)
+  "Make a tag of MIME message of PRITYPE, SUBTYPE and optional PARAMETERS."
+  (mime-create-tag (concat (or pritype "") "/" (or subtype "")
+			   (or parameters ""))
+		   encoding))
+
+(defun mime-create-tag (contype &optional encoding)
+  "Make a tag with CONTENT-TYPE and optional ENCODING."
+  (format (if encoding mime-tag-format-with-encoding mime-tag-format)
+	  contype encoding))
+
+(defun mime-editor/get-contype (tag)
+  "Return Content-Type (including parameters) of TAG."
+  (and (stringp tag)
+       (or (string-match mime-editor/single-part-tag-regexp tag)
+	   (string-match mime-editor/multipart-beginning-regexp tag)
+	   (string-match mime-editor/multipart-end-regexp tag)
+	   )
+       (substring tag (match-beginning 1) (match-end 1))
+       ))
+
+(defun mime-editor/get-encoding (tag)
+  "Return encoding of TAG."
+  (and (stringp tag)
+       (string-match mime-editor/single-part-tag-regexp tag)
+       (match-beginning 3)
+       (not (= (match-beginning 3) (match-end 3)))
+       (substring tag (match-beginning 3) (match-end 3))))
+
+(defun mime-get-parameter (contype parameter)
+  "For given CONTYPE return value for PARAMETER.
+Nil if no such parameter."
+  (if (string-match
+       (concat
+	";[ \t\n]*"
+	(regexp-quote parameter)
+	"[ \t\n]*=[ \t\n]*\\([^\" \t\n;]*\\|\"[^\"]*\"\\)\\([ \t\n]*;\\|$\\)")
+       contype)
+      (substring contype (match-beginning 1) (match-end 1))
+    nil					;No such parameter
+    ))
+
+(defun mime-editor/set-parameter (contype parameter value)
+  "For given CONTYPE set PARAMETER to VALUE."
+  (let (ctype opt-fields)
+    (if (string-match "\n[^ \t\n\r]+:" contype)
+	(setq ctype (substring contype 0 (match-beginning 0))
+	      opt-fields (substring contype (match-beginning 0)))
+      (setq ctype contype)
+      )
+    (if (string-match
+	 (concat
+	  ";[ \t\n]*\\("
+	  (regexp-quote parameter)
+	  "[ \t\n]*=[ \t\n]*\\([^\" \t\n;]*\\|\"[^\"]*\"\\)\\)[ \t\n]*\\(;\\|$\\)")
+	 ctype)
+	;; Change value
+	(concat (substring ctype 0 (match-beginning 1))
+		parameter "=" value
+		(substring contype (match-end 1))
+		opt-fields)
+      (concat ctype "; " parameter "=" value opt-fields)
+      )))
+
+(defun mime-strip-parameters (contype)
+  "Return primary content-type and subtype without parameters for CONTYPE."
+  (if (string-match "^[ \t]*\\([^; \t\n]*\\)" contype)
+      (substring contype (match-beginning 1) (match-end 1)) nil))
+
+(defun mime-test-content-type (contype type &optional subtype)
+  "Test if CONTYPE is a TYPE and an optional SUBTYPE."
+  (and (stringp contype)
+       (stringp type)
+       (string-match
+	(concat "^[ \t]*" (downcase type) "/" (downcase (or subtype "")))
+	(downcase contype))))
+
+
+;; Basic functions
+
+(defun mime-find-file-type (file)
+  "Guess Content-Type, subtype, and parameters from FILE."
+  (let ((guess nil)
+	(guesses mime-file-types))
+    (while (and (not guess) guesses)
+      (if (string-match (car (car guesses)) file)
+	  (setq guess (cdr (car guesses))))
+      (setq guesses (cdr guesses)))
+    guess
+    ))
+
+(defun mime-prompt-for-type ()
+  "Ask for Content-type."
+  (let ((type ""))
+    ;; Repeat until primary content type is specified.
+    (while (string-equal type "")
+      (setq type
+	    (completing-read "What content type: "
+			     mime-content-types
+			     nil
+			     'require-match ;Type must be specified.
+			     nil
+			     ))
+      (if (string-equal type "")
+	  (progn
+	    (message "Content type is required.")
+	    (beep)
+	    (sit-for 1)
+	    ))
+      )
+    type
+    ))
+
+(defun mime-prompt-for-subtype (pritype)
+  "Ask for Content-type subtype of Content-Type PRITYPE."
+  (let* ((default (car (car (cdr (assoc pritype mime-content-types)))))
+	 (answer
+	  (completing-read
+	   (if default
+	       (concat
+		"What content subtype: (default " default ") ")
+	     "What content subtype: ")
+	   (cdr (assoc pritype mime-content-types))
+	   nil
+	   'require-match		;Subtype must be specified.
+	   nil
+	   )))
+    (if (string-equal answer "") default answer)))
+
+(defun mime-prompt-for-parameters (pritype subtype &optional delimiter)
+  "Ask for Content-type parameters of Content-Type PRITYPE and SUBTYPE.
+Optional DELIMITER specifies parameter delimiter (';' by default)."
+  (let* ((delimiter (or delimiter "; "))
+	 (parameters
+	  (mapconcat
+	   (function identity)
+	   (delq nil
+		 (mime-prompt-for-parameters-1
+		  (cdr (assoc subtype
+			      (cdr (assoc pritype mime-content-types))))))
+	   delimiter
+	   )))
+    (if (and (stringp parameters)
+	     (not (string-equal parameters "")))
+	(concat delimiter parameters)
+      ""				;"" if no parameters
+      )))
+
+(defun mime-prompt-for-parameters-1 (optlist)
+  (apply (function append)
+	 (mapcar (function mime-prompt-for-parameter) optlist)))
+
+(defun mime-prompt-for-parameter (parameter)
+  "Ask for PARAMETER.
+Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
+  (let* ((prompt (car parameter))
+	 (choices (mapcar (function
+			   (lambda (e)
+			     (if (consp e) e (list e))))
+			  (cdr parameter)))
+	 (default (car (car choices)))
+	 (answer nil))
+    (if choices
+	(progn
+	  (setq answer
+		(completing-read
+		 (concat "What " prompt
+			 ": (default "
+			 (if (string-equal default "") "\"\"" default)
+			 ") ")
+		 choices nil nil ""))
+	  ;; If nothing is selected, use default.
+	  (if (string-equal answer "")
+	      (setq answer default)))
+      (setq answer
+	    (read-string (concat "What " prompt ": "))))
+    (cons (if (and answer
+		   (not (string-equal answer "")))
+	      (concat prompt "="
+		      ;; Note: control characters ignored!
+		      (if (string-match mime-tspecials-regexp answer)
+			  (concat "\"" answer "\"") answer)))
+	  (mime-prompt-for-parameters-1 (cdr (assoc answer (cdr parameter)))))
+    ))
+
+(defun mime-flag-region (from to flag)
+  "Hides or shows lines from FROM to TO, according to FLAG.
+If FLAG is `\\n' (newline character) then text is shown,
+while if FLAG is `\\^M' (control-M) the text is hidden."
+  (let ((buffer-read-only nil)		;Okay even if write protected.
+	(modp (buffer-modified-p)))
+    (unwind-protect
+        (subst-char-in-region from to
+			      (if (= flag ?\n) ?\^M ?\n)
+			      flag t)
+      (set-buffer-modified-p modp))))
+
+
+;;; @ Translate the tagged MIME messages into a MIME compliant message.
+;;;
+
+(defvar mime-editor/translate-buffer-hook
+  '(mime-editor/pgp-enclose-buffer
+    mime-editor/translate-header
+    mime-editor/translate-body))
+
+(defun mime-editor/translate-header ()
+  "Encode the message header into network representation."
+  (mime/encode-message-header 'code-conversion)
+  (run-hooks 'mime-editor/translate-header-hook)
+  )
+
+(defun mime-editor/translate-buffer ()
+  "Encode the tagged MIME message in current buffer in MIME compliant message."
+  (interactive)
+  (if (catch 'mime-editor/error
+	(save-excursion
+	  (run-hooks 'mime-editor/translate-buffer-hook)
+	  ))
+      (progn
+	(undo)
+	(error "Translation error!")
+	)))
+
+(defun mime-editor/find-inmost ()
+  (goto-char (point-min))
+  (if (re-search-forward mime-editor/multipart-beginning-regexp nil t)
+      (let ((bb (match-beginning 0))
+	    (be (match-end 0))
+	    (type (buffer-substring (match-beginning 1)(match-end 1)))
+	    end-exp eb ee)
+	(setq end-exp (format "--}-<<%s>>\n" type))
+	(widen)
+	(if (re-search-forward end-exp nil t)
+	    (progn
+	      (setq eb (match-beginning 0))
+	      (setq ee (match-end 0))
+	      )
+	  (setq eb (point-max))
+	  (setq ee (point-max))
+	  )
+	(narrow-to-region be eb)
+	(goto-char be)
+	(if (re-search-forward mime-editor/multipart-beginning-regexp nil t)
+	    (let (ret)
+	      (narrow-to-region (match-beginning 0)(point-max))
+	      (mime-editor/find-inmost)
+	      )
+	  (widen)
+	  (list type bb be eb)
+	  ))))
+
+(defun mime-editor/process-multipart-1 (boundary)
+  (let ((ret (mime-editor/find-inmost)))
+    (if ret
+	(let ((type (car ret))
+	      (bb (nth 1 ret))(be (nth 2 ret))
+	      (eb (nth 3 ret))
+	      )
+	  (narrow-to-region bb eb)
+	  (delete-region bb be)
+	  (setq bb (point-min))
+	  (setq eb (point-max))
+	  (widen)
+	  (goto-char eb)
+	  (if (looking-at mime-editor/multipart-end-regexp)
+	      (let ((beg (match-beginning 0))
+		    (end (match-end 0))
+		    )
+		(delete-region beg end)
+		(or (looking-at mime-editor/beginning-tag-regexp)
+		    (eobp)
+		    (insert (concat (mime-make-text-tag) "\n"))
+		    )))
+	  (cond ((string-equal type "quote")
+		 (mime-editor/enquote-region bb eb)
+		 )
+		((string-equal type "signed")
+		 (cond ((eq mime-editor/signing-type 'pgp-elkins)
+			(mime-editor/sign-pgp-elkins bb eb boundary)
+			)
+		       ((eq mime-editor/signing-type 'pgp-kazu)
+			(mime-editor/sign-pgp-kazu bb eb boundary)
+			))
+		 )
+		((string-equal type "encrypted")
+		 (cond ((eq mime-editor/encrypting-type 'pgp-elkins)
+			(mime-editor/encrypt-pgp-elkins bb eb boundary)
+			)
+		       ((eq mime-editor/encrypting-type 'pgp-kazu)
+			(mime-editor/encrypt-pgp-kazu bb eb boundary)
+			)))
+		(t
+		 (setq boundary
+		       (nth 2 (mime-editor/translate-region bb eb
+							    boundary t)))
+		 (goto-char bb)
+		 (insert
+		  (format "--[[multipart/%s;
+ boundary=\"%s\"][7bit]]\n"
+			  type boundary))
+		 ))
+	  boundary))))
+
+(defun mime-editor/enquote-region (beg end)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char beg)
+      (while (re-search-forward mime-editor/single-part-tag-regexp nil t)
+	(let ((tag (buffer-substring (match-beginning 0)(match-end 0))))
+	  (replace-match (concat "- " (substring tag 1)))
+	  )))))
+
+(defun mime-editor/dequote-region (beg end)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char beg)
+      (while (re-search-forward
+	      mime-editor/quoted-single-part-tag-regexp nil t)
+	(let ((tag (buffer-substring (match-beginning 0)(match-end 0))))
+	  (replace-match (concat "-" (substring tag 2)))
+	  )))))
+
+(defun mime-editor/sign-pgp-elkins (beg end boundary)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (let* ((ret
+	      (mime-editor/translate-region beg end boundary))
+	     (ctype    (car ret))
+	     (encoding (nth 1 ret))
+	     (parts    (nth 3 ret))
+	     (pgp-boundary (concat "pgp-sign-" boundary))
+	     )
+	(goto-char beg)
+	(insert (format "Content-Type: %s\n" ctype))
+	(if encoding
+	    (insert (format "Content-Transfer-Encoding: %s\n" encoding))
+	  )
+	(insert "\n")
+	(or (funcall mime-editor/pgp-sign-function
+		     (point-min)(point-max) nil nil pgp-boundary)
+	    (throw 'mime-editor/error 'pgp-error)
+	    )
+	))))
+
+(defvar mime-editor/encrypt-recipient-fields-list '("To" "cc"))
+
+(defun mime-editor/make-encrypt-recipient-header ()
+  (let* ((names mime-editor/encrypt-recipient-fields-list)
+	 (values
+	  (std11-field-bodies (cons "From" names)
+			      nil mail-header-separator))
+	 (from (prog1
+		   (car values)
+		 (setq values (cdr values))))
+	 (header (and (stringp from)
+		      (if (string-equal from "")
+			  ""
+			(format "From: %s\n" from)
+			)))
+	 recipients)
+    (while (and names values)
+      (let ((name (car names))
+	    (value (car values))
+	    )
+	(and (stringp value)
+	     (or (string-equal value "")
+		 (progn
+		   (setq header (concat header name ": " value "\n")
+			 recipients (if recipients
+					(concat recipients " ," value)
+				      value))
+		   ))))
+      (setq names (cdr names)
+	    values (cdr values))
+      )
+    (vector from recipients header)
+    ))
+
+(defun mime-editor/encrypt-pgp-elkins (beg end boundary)
+  (save-excursion
+    (save-restriction
+      (let (from recipients header)
+	(let ((ret (mime-editor/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-editor/translate-region beg end boundary))
+	       (ctype    (car ret))
+	       (encoding (nth 1 ret))
+	       (parts    (nth 3 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 mime-editor/pgp-encrypt-function
+		       recipients (point-min) (point-max) from)
+	      (throw 'mime-editor/error 'pgp-error)
+	      )
+	  (goto-char beg)
+	  (insert (format "--[[multipart/encrypted;
+ boundary=\"%s\";
+ protocol=\"application/pgp-encrypted\"][7bit]]
+--%s
+Content-Type: application/pgp-encrypted
+
+--%s
+Content-Type: application/octet-stream
+Content-Transfer-Encoding: 7bit
+
+" pgp-boundary pgp-boundary pgp-boundary))
+	  (goto-char (point-max))
+	  (insert (format "\n--%s--\n" pgp-boundary))
+	  )))))
+
+(defun mime-editor/sign-pgp-kazu (beg end boundary)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (let* ((ret
+	      (mime-editor/translate-region beg end boundary))
+	     (ctype    (car ret))
+	     (encoding (nth 1 ret))
+	     (parts    (nth 3 ret))
+	     )
+	(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 mime-editor/traditional-pgp-sign-function
+		      beg (point-max)))
+	    (throw 'mime-editor/error 'pgp-error)
+	    )
+	(goto-char beg)
+	(insert
+	 "--[[application/pgp; format=mime][7bit]]\n")
+	))
+    ))
+
+(defun mime-editor/encrypt-pgp-kazu (beg end boundary)
+  (save-excursion
+    (let (from recipients header)
+      (let ((ret (mime-editor/make-encrypt-recipient-header)))
+	(setq from (aref ret 0)
+	      recipients (aref ret 1)
+	      header (aref ret 2))
+	)
+      (save-restriction
+	(narrow-to-region beg end)
+	(let* ((ret
+		(mime-editor/translate-region beg end boundary))
+	       (ctype    (car ret))
+	       (encoding (nth 1 ret))
+	       (parts    (nth 3 ret))
+	       )
+	  (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 (as-binary-process
+	       (funcall mime-editor/pgp-encrypt-function
+			recipients beg (point-max) nil 'maybe)
+	       )
+	      (throw 'mime-editor/error 'pgp-error)
+	      )
+	  (goto-char beg)
+	  (insert
+	   "--[[application/pgp; format=mime][7bit]]\n")
+	  ))
+      )))
+
+(defun mime-editor/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))
+		   ))
+	  (i 1)
+	  ret)
+      (while (mime-editor/process-multipart-1
+	      (format "%s-%d" boundary i))
+	(setq i (1+ i))
+	)
+      (save-restriction
+	;; We are interested in message body.
+	(let* ((beg
+		(progn
+		  (goto-char (point-min))
+		  (re-search-forward
+		   (concat "\n" (regexp-quote mail-header-separator)
+			   (if mime-ignore-preceding-spaces
+			       "[ \t\n]*\n" "\n")) nil 'move)
+		  (point)))
+	       (end
+		(progn
+		  (goto-char (point-max))
+		  (and mime-ignore-trailing-spaces
+		       (re-search-backward "[^ \t\n]\n" beg t)
+		       (forward-char 1))
+		  (point))))
+	  (setq ret (mime-editor/translate-region
+		     beg end
+		     (format "%s-%d" boundary i)))
+	  ))
+      (mime-editor/dequote-region (point-min)(point-max))
+      (let ((contype (car ret))		;Content-Type
+	    (encoding (nth 1 ret))	;Content-Transfer-Encoding
+	    )
+	;; Make primary MIME headers.
+	(or (mail-position-on-field "Mime-Version")
+	    (insert mime-editor/mime-version-value))
+	;; Remove old Content-Type and other fields.
+	(save-restriction
+	  (goto-char (point-min))
+	  (search-forward (concat "\n" mail-header-separator "\n") nil t)
+	  (narrow-to-region (point-min) (point))
+	  (goto-char (point-min))
+	  (mime-delete-field "Content-Type")
+	  (mime-delete-field "Content-Transfer-Encoding"))
+	;; Then, insert Content-Type and Content-Transfer-Encoding fields.
+	(mail-position-on-field "Content-Type")
+	(insert contype)
+	(if encoding
+	    (progn
+	      (mail-position-on-field "Content-Transfer-Encoding")
+	      (insert encoding)))
+	))))
+
+(defun mime-editor/translate-single-part-tag (&optional prefix)
+  (if (re-search-forward mime-editor/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-editor/get-contype tag))
+	(setq encoding (mime-editor/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)
+	  )
+	t)))
+
+(defun mime-editor/translate-region (beg end &optional boundary multipart)
+  (if (null boundary)
+      (setq boundary
+	    (concat mime-multipart-boundary "_"
+		    (replace-space-with-underline (current-time-string))))
+    )
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (let ((tag nil)			;MIME tag
+	    (contype nil)		;Content-Type
+	    (encoding nil)		;Content-Transfer-Encoding
+	    (nparts 0))			;Number of body parts
+	;; Normalize the body part by inserting appropriate message
+	;; tags for every message contents.
+	(mime-editor/normalize-body)
+	;; Counting the number of Content-Type.
+	(goto-char (point-min))
+	(while (re-search-forward mime-editor/single-part-tag-regexp nil t)
+	  (setq nparts (1+ nparts)))
+	;; Begin translation.
+	(cond
+	 ((and (<= nparts 1)(not multipart))
+	  ;; It's a singular message.
+	  (goto-char (point-min))
+	  (while (re-search-forward
+		  mime-editor/single-part-tag-regexp nil t)
+	    (setq tag
+		  (buffer-substring (match-beginning 0) (match-end 0)))
+	    (delete-region (match-beginning 0) (1+ (match-end 0)))
+	    (setq contype (mime-editor/get-contype tag))
+	    (setq encoding (mime-editor/get-encoding tag))
+	    ))
+	 (t
+	  ;; It's a multipart message.
+	  (goto-char (point-min))
+	  (and (mime-editor/translate-single-part-tag)
+	       (while (mime-editor/translate-single-part-tag "\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)
+	))))
+
+(defun mime-editor/normalize-body ()
+  "Normalize the body part by inserting appropriate message tags."
+  ;; Insert the first MIME tags if necessary.
+  (goto-char (point-min))
+  (if (not (looking-at mime-editor/single-part-tag-regexp))
+      (insert (mime-make-text-tag) "\n"))
+  ;; Check each tag, and add new tag or correct it if necessary.
+  (goto-char (point-min))
+  (while (re-search-forward mime-editor/single-part-tag-regexp nil t)
+    (let* ((tag (buffer-substring (match-beginning 0) (match-end 0)))
+	   (contype (mime-editor/get-contype tag))
+	   (charset (mime-get-parameter contype "charset"))
+	   (encoding (mime-editor/get-encoding tag)))
+      ;; Remove extra whitespaces after the tag.
+      (if (looking-at "[ \t]+$")
+	  (delete-region (match-beginning 0) (match-end 0)))
+      (let ((beg (point))
+	    (end (mime-editor/content-end))
+	    )
+	(if (= end (point-max))
+	    nil
+	  (goto-char end)
+	  (or (looking-at mime-editor/beginning-tag-regexp)
+	      (eobp)
+	      (insert (mime-make-text-tag) "\n")
+	      ))
+	(visible-region beg end)
+	(goto-char beg)
+	)
+      (cond
+       ((mime-test-content-type contype "message")
+	;; Content-type "message" should be sent as is.
+	(forward-line 1)
+	)
+       ((mime-test-content-type contype "text")
+	;; Define charset for text if necessary.
+	(setq charset (if charset
+			  (intern (downcase charset))
+			(mime-editor/choose-charset)))
+	(mime-editor/define-charset charset)
+	(cond ((string-equal contype "text/x-rot13-47")
+	       (save-excursion
+		 (forward-line)
+		 (set-mark (point))
+		 (goto-char (mime-editor/content-end))
+		 (tm:caesar-region)
+		 ))
+	      ((string-equal contype "text/enriched")
+	       (save-excursion
+		 (let ((beg (progn
+			      (forward-line)
+			      (point)))
+		       (end (mime-editor/content-end))
+		       )
+		   ;; Patch for hard newlines
+                   ;; (save-excursion
+                   ;;   (goto-char beg)
+                   ;;   (while (search-forward "\n" end t)
+                   ;;     (put-text-property (match-beginning 0)
+                   ;;                        (point)
+                   ;;                        'hard t)))
+		   ;; End patch for hard newlines
+		   (enriched-encode beg end)
+		   (goto-char beg)
+		   (if (search-forward "\n\n")
+		       (delete-region beg (match-end 0))
+		     )
+		   ))))
+	;; Point is now on current tag.
+	;; Define encoding and encode text if necessary.
+	(or encoding	;Encoding is not specified.
+	    (let* ((encoding
+		    (cdr
+		     (assq charset
+			   mime-editor/charset-default-encoding-alist)
+		     ))
+		   (beg (mime-editor/content-beginning))
+		   )
+	      (encode-mime-charset-region beg (mime-editor/content-end)
+					  charset)
+	      (mime-encode-region beg (mime-editor/content-end) encoding)
+	      (mime-editor/define-encoding encoding)
+	      ))
+	(goto-char (mime-editor/content-end))
+	)
+       ((null encoding)		;Encoding is not specified.
+	;; Application, image, audio, video, and any other
+	;; unknown content-type without encoding should be
+	;; encoded.
+	(let* ((encoding "base64")	;Encode in BASE64 by default.
+	       (beg (mime-editor/content-beginning))
+	       (end (mime-editor/content-end))
+	       (body (buffer-substring beg end))
+	       )
+	  (mime-encode-region beg end encoding)
+	  (mime-editor/define-encoding encoding))
+	(forward-line 1)
+	))
+      )))
+
+(defun mime-delete-field (field)
+  "Delete header FIELD."
+  (let ((regexp (format "^%s:[ \t]*" field)))
+    (goto-char (point-min))
+    (while (re-search-forward regexp nil t)
+      (delete-region (match-beginning 0)
+		     (progn (forward-line 1) (point)))
+      )))
+
+
+;;;
+;;; Platform dependent functions
+;;;
+
+;; Sun implementations
+
+(defun mime-editor/voice-recorder-for-sun (encoding)
+  "Record voice in a buffer using Sun audio device,
+and insert data encoded as ENCODING. [tm-edit.el]"
+  (message "Start the recording on %s.  Type C-g to finish the recording..."
+	   (system-name))
+  (mime-insert-encoded-file "/dev/audio" encoding)
+  )
+
+
+;;; @ Other useful commands.
+;;;
+
+;; Message forwarding commands as content-type "message/rfc822".
+
+(defun mime-editor/insert-message (&optional message)
+  (interactive)
+  (let ((inserter (assoc-value major-mode mime-editor/message-inserter-alist)))
+    (if (and inserter (fboundp inserter))
+	(progn
+	  (mime-editor/insert-tag "message" "rfc822")
+	  (funcall inserter message)
+	  )
+      (message "Sorry, I don't have message inserter for your MUA.")
+      )))
+
+(defun mime-editor/insert-mail (&optional message)
+  (interactive)
+  (let ((inserter (assoc-value major-mode mime-editor/mail-inserter-alist)))
+    (if (and inserter (fboundp inserter))
+	(progn
+	  (mime-editor/insert-tag "message" "rfc822")
+	  (funcall inserter message)
+	  )
+      (message "Sorry, I don't have mail inserter for your MUA.")
+      )))
+
+(defun mime-editor/inserted-message-filter ()
+  (save-excursion
+    (save-restriction
+      (let ((header-start (point))
+	    (case-fold-search t)
+	    beg end)
+	;; for Emacs 18
+	;; (if (re-search-forward "^$" (marker-position (mark-marker)))
+	(if (re-search-forward "^$" (mark t))
+	    (narrow-to-region header-start (match-beginning 0))
+	  )
+	(goto-char header-start)
+	(while (and (re-search-forward
+		     mime-editor/yank-ignored-field-regexp nil t)
+		    (setq beg (match-beginning 0))
+		    (setq end (1+ (std11-field-end)))
+		    )
+	  (delete-region beg end)
+	  )
+	))))
+
+
+;;; @ multipart enclosure
+;;;
+
+(defun mime-editor/enclose-region (type beg end)
+  (save-excursion
+    (goto-char beg)
+    (let ((current (point)))
+      (save-restriction
+	(narrow-to-region beg end)
+	(insert (format "--<<%s>>-{\n" type))
+	(goto-char (point-max))
+	(insert (format "--}-<<%s>>\n" type))
+	(goto-char (point-max))
+	)
+      (or (looking-at mime-editor/beginning-tag-regexp)
+	  (eobp)
+	  (insert (mime-make-text-tag) "\n")
+	  )
+      )))
+
+(defun mime-editor/enclose-quote-region (beg end)
+  (interactive "*r")
+  (mime-editor/enclose-region "quote" beg end)
+  )
+
+(defun mime-editor/enclose-mixed-region (beg end)
+  (interactive "*r")
+  (mime-editor/enclose-region "mixed" beg end)
+  )
+
+(defun mime-editor/enclose-parallel-region (beg end)
+  (interactive "*r")
+  (mime-editor/enclose-region "parallel" beg end)
+  )
+
+(defun mime-editor/enclose-digest-region (beg end)
+  (interactive "*r")
+  (mime-editor/enclose-region "digest" beg end)
+  )
+
+(defun mime-editor/enclose-alternative-region (beg end)
+  (interactive "*r")
+  (mime-editor/enclose-region "alternative" beg end)
+  )
+
+(defun mime-editor/enclose-signed-region (beg end)
+  (interactive "*r")
+  (if mime-editor/signing-type
+      (mime-editor/enclose-region "signed" beg end)
+    (message "Please specify signing type.")
+    ))
+
+(defun mime-editor/enclose-encrypted-region (beg end)
+  (interactive "*r")
+  (if mime-editor/signing-type
+      (mime-editor/enclose-region "encrypted" beg end)
+    (message "Please specify encrypting type.")
+    ))
+
+(defun mime-editor/insert-key (&optional arg)
+  "Insert a pgp public key."
+  (interactive "P")
+  (mime-editor/insert-tag "application" "pgp-keys")
+  (mime-editor/define-encoding "7bit")
+  (funcall mime-editor/pgp-insert-public-key-function)
+  )
+
+
+;;; @ flag setting
+;;;
+
+(defun mime-editor/set-split (arg)
+  (interactive
+   (list
+    (y-or-n-p "Do you want to enable split?")
+    ))
+  (setq mime-editor/split-message arg)
+  (if arg
+      (message "This message is enabled to split.")
+    (message "This message is not enabled to split.")
+    ))
+
+(defun mime-editor/toggle-transfer-level (&optional transfer-level)
+  "Toggle transfer-level is 7bit or 8bit through.
+
+Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8."
+  (interactive)
+  (if (numberp transfer-level)
+      (setq mime-editor/transfer-level transfer-level)
+    (if (< mime-editor/transfer-level 8)
+	(setq mime-editor/transfer-level 8)
+      (setq mime-editor/transfer-level 7)
+      ))
+  (setq mime-editor/charset-default-encoding-alist
+	(mime-editor/make-charset-default-encoding-alist
+	 mime-editor/transfer-level))
+  (message (format "Current transfer-level is %d bit"
+		   mime-editor/transfer-level))
+  (setq mime-editor/transfer-level-string
+	(mime/encoding-name mime-editor/transfer-level 'not-omit))
+  (force-mode-line-update)
+  )
+
+(defun mime-editor/set-transfer-level-7bit ()
+  (interactive)
+  (mime-editor/toggle-transfer-level 7)
+  )
+
+(defun mime-editor/set-transfer-level-8bit ()
+  (interactive)
+  (mime-editor/toggle-transfer-level 8)
+  )
+
+
+;;; @ pgp
+;;;
+
+(defun mime-editor/set-sign (arg)
+  (interactive
+   (list
+    (y-or-n-p "Do you want to sign?")
+    ))
+  (if arg
+      (if mime-editor/signing-type
+	  (progn
+	    (setq mime-editor/pgp-processing 'sign)
+	    (message "This message will be signed.")
+	    )
+	(message "Please specify signing type.")
+	)
+    (if (eq mime-editor/pgp-processing 'sign)
+	(setq mime-editor/pgp-processing nil)
+      )
+    (message "This message will not be signed.")
+    ))
+
+(defun mime-editor/set-encrypt (arg)
+  (interactive
+   (list
+    (y-or-n-p "Do you want to encrypt?")
+    ))
+  (if arg
+      (if mime-editor/encrypting-type
+	  (progn
+	    (setq mime-editor/pgp-processing 'encrypt)
+	    (message "This message will be encrypt.")
+	    )
+	(message "Please specify encrypting type.")
+	)
+    (if (eq mime-editor/pgp-processing 'encrypt)
+	(setq mime-editor/pgp-processing nil)
+      )
+    (message "This message will not be encrypt.")
+    ))
+
+(defvar mime-editor/pgp-processing nil)
+(make-variable-buffer-local 'mime-editor/pgp-processing)
+
+(defun mime-editor/pgp-enclose-buffer ()
+  (let ((beg (save-excursion
+	       (goto-char (point-min))
+	       (if (search-forward (concat "\n" mail-header-separator "\n"))
+		   (match-end 0)
+		 )))
+	(end (point-max))
+	)
+    (if beg
+	(cond ((eq mime-editor/pgp-processing 'sign)
+	       (mime-editor/enclose-signed-region beg end)
+	       )
+	      ((eq mime-editor/pgp-processing 'encrypt)
+	       (mime-editor/enclose-encrypted-region beg end)
+	       ))
+      )))
+
+
+;;; @ split
+;;;
+
+(defun mime-editor/insert-partial-header
+  (fields subject id number total separator)
+  (insert fields)
+  (insert (format "Subject: %s (%d/%d)\n" subject number total))
+  (insert (format "Mime-Version: 1.0 (split by %s)\n"
+		  mime-editor/version-name))
+  (insert (format "\
+Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
+		  id number total separator))
+  )
+
+(defun mime-editor/split-and-send
+  (&optional cmd lines mime-editor/message-max-length)
+  (interactive)
+  (or lines
+      (setq lines
+	    (count-lines (point-min) (point-max)))
+      )
+  (or mime-editor/message-max-length
+      (setq mime-editor/message-max-length
+	    (or (cdr (assq major-mode mime-editor/message-max-lines-alist))
+		mime-editor/message-default-max-lines))
+      )
+  (let* ((mime-editor/draft-file-name 
+	  (or (buffer-file-name)
+	      (make-temp-name
+	       (expand-file-name "tm-draft" mime/tmp-dir))))
+	 (separator mail-header-separator)
+	 (id (concat "\""
+		     (replace-space-with-underline (current-time-string))
+		     "@" (system-name) "\"")))
+    (run-hooks 'mime-editor/before-split-hook)
+    (let ((the-buf (current-buffer))
+	  (copy-buf (get-buffer-create " *Original Message*"))
+	  (header (std11-header-string-except
+		   mime-editor/split-ignored-field-regexp separator))
+	  (subject (mail-fetch-field "subject"))
+	  (total (+ (/ lines mime-editor/message-max-length)
+		    (if (> (mod lines mime-editor/message-max-length) 0)
+			1)))
+	  (command
+	   (or cmd
+	       (cdr
+		(assq major-mode
+		      mime-editor/split-message-sender-alist))
+	       (function
+		(lambda ()
+		  (interactive)
+		  (error "Split sender is not specified for `%s'." major-mode)
+		  ))
+	       ))
+	  (mime-editor/partial-number 1)
+	  data)
+      (save-excursion
+	(set-buffer copy-buf)
+	(erase-buffer)
+	(insert-buffer the-buf)
+	(save-restriction
+	  (if (re-search-forward
+	       (concat "^" (regexp-quote separator) "$") nil t)
+	      (let ((he (match-beginning 0)))
+		(replace-match "")
+		(narrow-to-region (point-min) he)
+		))
+	  (goto-char (point-min))
+	  (while (re-search-forward mime-editor/split-blind-field-regexp nil t)
+	    (delete-region (match-beginning 0)
+			   (1+ (std11-field-end)))
+	    )))
+      (while (< mime-editor/partial-number total)
+	(erase-buffer)
+	(save-excursion
+	  (set-buffer copy-buf)
+	  (setq data (buffer-substring
+		      (point-min)
+		      (progn
+			(goto-line mime-editor/message-max-length)
+			(point))
+		      ))
+	  (delete-region (point-min)(point))
+	  )
+	(mime-editor/insert-partial-header
+	 header subject id mime-editor/partial-number total separator)
+	(insert data)
+	(save-excursion
+	  (message (format "Sending %d/%d..."
+			   mime-editor/partial-number total))
+	  (call-interactively command)
+	  (message (format "Sending %d/%d... done"
+			   mime-editor/partial-number total))
+	  )
+	(setq mime-editor/partial-number
+	      (1+ mime-editor/partial-number))
+	)
+      (erase-buffer)
+      (save-excursion
+	(set-buffer copy-buf)
+	(setq data (buffer-string))
+	(erase-buffer)
+	)
+      (mime-editor/insert-partial-header
+       header subject id mime-editor/partial-number total separator)
+      (insert data)
+      (save-excursion
+	(message (format "Sending %d/%d..."
+			 mime-editor/partial-number total))
+	(message (format "Sending %d/%d... done"
+			 mime-editor/partial-number total))
+	)
+      )))
+
+(defun mime-editor/maybe-split-and-send (&optional cmd)
+  (interactive)
+  (run-hooks 'mime-editor/before-send-hook)
+  (let ((mime-editor/message-max-length
+	 (or (cdr (assq major-mode mime-editor/message-max-lines-alist))
+	     mime-editor/message-default-max-lines))
+	(lines (count-lines (point-min) (point-max)))
+	)
+    (if (and (> lines mime-editor/message-max-length)
+	     mime-editor/split-message)
+	(mime-editor/split-and-send cmd lines mime-editor/message-max-length)
+      )))
+
+
+;;; @ preview message
+;;;
+
+(defun mime-editor/preview-message ()
+  "preview editing MIME message. [tm-edit.el]"
+  (interactive)
+  (let* ((str (buffer-string))
+	 (separator mail-header-separator)
+	 (the-buf (current-buffer))
+	 (buf-name (buffer-name))
+	 (temp-buf-name (concat "*temp-article:" buf-name "*"))
+	 (buf (get-buffer temp-buf-name))
+	 )
+    (if buf
+	(progn
+	  (switch-to-buffer buf)
+	  (erase-buffer)
+	  )
+      (setq buf (get-buffer-create temp-buf-name))
+      (switch-to-buffer buf)
+      )
+    (insert str)
+    (setq major-mode 'mime/temporary-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)
+    
+    (run-hooks 'mime-editor/translate-hook)
+    (mime-editor/translate-buffer)
+    (goto-char (point-min))
+    (if (re-search-forward
+	 (concat "^" (regexp-quote separator) "$"))
+	(replace-match "")
+      )
+    (mime/viewer-mode)
+    ))
+
+(defun mime-editor/quitting-method ()
+  (let ((temp mime::preview/article-buffer)
+	buf)
+    (mime-viewer/kill-buffer)
+    (set-buffer temp)
+    (setq buf mime/editing-buffer)
+    (kill-buffer temp)
+    (switch-to-buffer buf)
+    ))
+
+(set-alist 'mime-viewer/quitting-method-alist
+	   'mime/temporary-message-mode
+	   (function mime-editor/quitting-method)
+	   )
+
+
+;;; @ draft preview
+;;; 
+;; by "OKABE Yasuo <okabe@kudpc.kyoto-u.ac.jp>
+;;	 Mon, 10 Apr 1995 20:03:07 +0900
+
+(defvar mime-editor/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-editor/draft-preview ()
+  (interactive)
+  (let ((sep (cdr (assq major-mode mime-editor/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/viewer-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-viewer/kill-buffer)
+    (pop-to-buffer mother)
+    ))
+
+(set-alist 'mime-viewer/quitting-method-alist
+	   'mh-letter-mode
+	   (function mime-viewer::quitting-method/draft-preview)
+	   )
+
+(set-alist 'mime-viewer/quitting-method-alist
+	   'news-reply-mode
+	   (function mime-viewer::quitting-method/draft-preview)
+	   )
+
+
+;;; @ edit again
+;;;
+
+(defun mime-editor::edit-again (code-conversion)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((ctl (mime/Content-Type)))
+      (if ctl
+	  (let ((ctype (car ctl))
+		(params (cdr ctl))
+		type stype)
+	    (if (string-match "/" ctype)
+		(progn
+		  (setq type (substring ctype 0 (match-beginning 0)))
+		  (setq stype (substring ctype (match-end 0)))
+		  )
+	      (setq type ctype)
+	      )
+	    (cond
+	     ((string-equal type "multipart")
+	      (let* ((boundary (assoc-value "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-editor::edit-again code-conversion)
+			    (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)
+				     )))
+		))
+	     (t
+	      (let* (charset
+		     (pstr
+		      (mapconcat (function
+				  (lambda (attr)
+				    (if (string-equal (car attr)
+						      "charset")
+					(progn
+					  (setq charset (cdr attr))
+					  "")
+				      (concat ";" (car attr)
+					      "=" (cdr attr))
+				      )
+				    ))
+				 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 (string-equal 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 code-conversion encoded)
+		    (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
+				  (concat type "/" stype pstr) encoding)))
+			)
+		    (delete-region (point-min) he)
+		    (insert
+		     (mime-create-tag
+		      (concat type "/" stype pstr) encoding))
+		    ))
+		))))
+	(if code-conversion
+	    (decode-mime-charset-region (point-min) (point-max)
+					default-mime-charset)
+	  )
+	))))
+
+(defun mime/edit-again (&optional code-conversion no-separator no-mode)
+  (interactive)
+  (mime-editor::edit-again code-conversion)
+  (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)
+       ))
+    (goto-char (point-min))
+    (while (re-search-forward
+	    "^\\(Content-.*\\|Mime-Version\\):" 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/editor-mode)
+      ))
+
+
+;;; @ end
+;;;
+
+(provide 'tm-edit)
+
+(run-hooks 'tm-edit-load-hook)
+
+;;; tm-edit.el ends here