🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.emacs.sources
Article #352

Emacs MIME tools (Emacs で MIME メッセージを読み書きするためのツール群 )

#352
From: Masanobu UMEDA
Date: Mon, 05 Jul 1993 15:19
1397 lines
49276 bytes
Following shell archive is a set of emacs tools that are useful for
reading and composing MIME messages.  The archive contains the
following elisp packages:

mime.el		MIME message composer
rmailmime.el	Functions for reading MIME messages from Rmail
metamail.el	Functions to use metamail from Emacs

metamail package is required for using these tools.
----------------------------------------------------------------------
: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract:
: metamail.el mime.el rmailmime.el
echo x metamail.el
sed 's/^X//' > metamail.el << '*-*-END-of-metamail.el-*-*'
X;;; Metamail interface for GNU Emacs
X;; Copyright (C) 1993 Masanobu UMEDA
X
X;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
X;; Version: $Header: metamail.el,v 1.3 93/06/21 15:37:28 umerin Exp $
X;; Keywords: mail, news, mime, multimedia
X
X;; This file is part of GNU Emacs.
X
X;; GNU Emacs is free software; you can redistribute it and/or modify
X;; it under the terms of the GNU General Public License as published by
X;; the Free Software Foundation; either version 2, or (at your option)
X;; any later version.
X
X;; GNU Emacs is distributed in the hope that it will be useful,
X;; but WITHOUT ANY WARRANTY; without even the implied warranty of
X;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X;; GNU General Public License for more details.
X
X;; You should have received a copy of the GNU General Public License
X;; along with GNU Emacs; see the file COPYING.  If not, write to
X;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
X
X;;; Commentary:
X
X;; LCD Archive Entry:
X;; metamail|Masanobu UMEDA|umerin@mse.kyutech.ac.jp|
X;; Metamail interface for GNU Emacs|
X;; $Date: 93/06/21 15:37:28 $|$Revision: 1.3 $|~/misc/metamail.el.Z|
X
X;; Note: Metamail does not have all options which is compatible with
X;; the environment variables.  For that reason, matamail.el have to
X;; hack the environment variables.  In addition, there is no way to
X;; display all header fields without extra informative body messages
X;; which is suppressed by "-q" option.
X
X;; The idea of using metamail to process MIME messages is from
X;; gnus-mime.el by Spike <Spike@world.std.com>.
X
X;;; Code:
X
X(defvar metamail-program-name "metamail"
X  "*Metamail program name.")
X
X(defvar metamail-environment "KEYHEADS='*';export KEYHEADS;"
X  "*Environment variables for Metamail.
XIt must be an emtpy string or a string terminated with ';'.")
X
X(defvar metamail-switches '("-m" "emacs" "-x" "-d" "-z")
X  "*Switches for Metamail program.
X-z is required to remove zap file.")
X
X(defun metamail-buffer (&optional buffer)
X  "Process current buffer through 'metamail'.
XOptional argument BUFFER specifies a buffer to be filled (nil means current)."
X  (interactive)
X  (metamail-region (point-min) (point-max) buffer))
X
X(defun metamail-region (beg end &optional buffer)
X  "Process current region through 'metamail'.
XOptional argument BUFFER specifies a buffer to be filled (nil means current)."
X  (interactive "r")
X  (let ((curbuf (current-buffer))
X	(buffer-read-only nil)
X	(metafile (make-temp-name "/tmp/metamail")))
X    (save-excursion
X      ;; Gee!  Metamail does not ouput to stdout if input comes from
X      ;; stdin.
X      (write-region beg end metafile nil 'nomessage)
X      (if buffer
X	  (set-buffer buffer))
X      (setq buffer-read-only nil)
X      ;; Clear destination buffer.
X      (if (eq curbuf (current-buffer))
X	  (delete-region beg end)
X	(delete-region (point-min) (point-max)))
X      ;; We have to pass the environment variable KEYHEADS to /bin/sh
X      ;; to display all header fields.  Metamail should have an
X      ;; optional argument to pass such information directly.
X      (apply (function call-process)
X	     "/bin/sh"
X	     nil
X	     t				;Output to current buffer
X	     t				;Force redisplay
X	     (list "-c"
X		   ;; Construct environment and the command.
X		   (concat
X		    metamail-environment
X		    metamail-program-name
X		    " "
X		    (mapconcat (function identity) metamail-switches " ")
X		    " "
X		    metafile
X		    )))
X      )))
X
X;(defun metamail-region (beg end &optional buffer)
X;  "Process current region through 'metamail'.
X;Optional argument BUFFER specifies a buffer to be filled (nil means current)."
X;  (interactive "r")
X;  (let ((curbuf (current-buffer))
X;	(buffer-read-only nil)
X;	(metafile (make-temp-name "/tmp/metamail")))
X;    (save-excursion
X;      (write-region (point-min) (point-max) metafile nil 'nomessage)
X;      (if (eq curbuf
X;	      (if buffer (get-buffer buffer) (current-buffer)))
X;	  (delete-region (point-min) (point-max)))
X;      (apply (function call-process)
X;	     metamail-program-name
X;	     nil
X;	     (or buffer t)		;BUFFER or current buffer
X;	     nil			;don't redisplay
X;	     (append metamail-switches (list metafile)))
X;      )))
X
X(provide 'metamail)
X
X;;; metamail.el ends here
*-*-END-of-metamail.el-*-*
echo x mime.el
sed 's/^X//' > mime.el << '*-*-END-of-mime.el-*-*'
X;;; Poorman's Simple MIME Composer for Emacs
X;; Copyright (C) 1993 Masanobu UMEDA
X
X;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
X;; Version: $Header: mime.el,v 1.19 93/07/05 21:33:36 umerin Locked $
X;; Keywords: mail, news, mime
X
X;; This file is part of GNU Emacs.
X
X;; GNU Emacs is free software; you can redistribute it and/or modify
X;; it under the terms of the GNU General Public License as published by
X;; the Free Software Foundation; either version 2, or (at your option)
X;; any later version.
X
X;; GNU Emacs is distributed in the hope that it will be useful,
X;; but WITHOUT ANY WARRANTY; without even the implied warranty of
X;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X;; GNU General Public License for more details.
X
X;; You should have received a copy of the GNU General Public License
X;; along with GNU Emacs; see the file COPYING.  If not, write to
X;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
X
X;;; Commentary:
X
X;; LCD Archive Entry:
X;; mime|Masanobu UMEDA|umerin@mse.kyutech.ac.jp|
X;; Simple MIME Composer|
X;; $Date: 93/07/05 21:33:36 $|$Revision: 1.19 $|~/misc/mime.el.Z|
X
X;; This is an Emacs minor mode for editing Internet multimedia
X;; messages encoded in MIME (RFC1341 and RFC1342).  All messages in
X;; this mode are composed in the tagged MIME format, that are
X;; described in the following examples.  The messages in the tagged
X;; MIME format are automatically translated into a MIME compliant
X;; message when exiting the mode.
X
X;; Content-Type Tag:
X;;	--[[TYPE/SUBTYPE; OPTIONS]]
X;;
X;; The tagged MIME message examples:
X;;
X;; This is a conventional plain text.  It should be translated into
X;; text/plain.
X;; 
X;;--[[text/plain]]
X;; This is also a plain text.  But, it is explicitly specified as is.
X;;
X;;--[[text/plain; charset=ISO-2022-JP]]
X;; これは charset を ISO-2022-JP に指定した日本語の plain テキストです.
X;;
X;;--[[text/richtext]]
X;; <center>This is a richtext.</center>
X;;
X;;--[[image/gif]]^MContent-Transfer-Encoding: base64^M...image comes here...
X;;
X;;--[[audio/basic]]^MContent-Transfer-Encoding: base64^M...audio comes here...
X
X;;; Code:
X
X(require 'sendmail)
X(require 'mail-utils)
X
X(autoload 'metamail-buffer "metamail"
X	  "Process current buffer through 'metamail'." t)
X
X(defvar mime-prefix "\C-c\C-x"
X  "*Keymap prefix for MIME commands.")
X
X(defvar mime-ignore-preceding-spaces nil
X  "*Ignore preceding white spaces if non-nil.")
X
X(defvar mime-ignore-trailing-spaces nil
X  "*Ignore trailing white spaces if non-nil.")
X
X(defvar mime-auto-fill-header t
X  "*Fill header fields that contain encoded-words.")
X
X(defvar mime-content-types
X  '(("text"
X     ("plain"
X      ("charset" "ISO-2022-JP" "US-ASCII"))
X     ("richtext"
X      ("charset" "ISO-2022-JP" "US-ASCII")))
X    ("message"
X     ("external-body"
X      ("access-type"
X       ("anon-ftp"
X	("site" "wnoc-fuk.wide.ad.jp" "nic.karrn.ad.jp")
X	("directory")
X	("name")
X	("mode" "binary" "ascii"))
X       ("ftp"
X	("site")
X	("directory")
X	("name")
X	("mode" "binary" "ascii"))
X       ("tftp"
X	("site")
X	("name"))
X       ("afs"
X	("site")
X	("name"))
X       ("local-file"
X	("site")
X	("name"))
X       ("mail-server"
X	("server"))))
X     ("rfc822"))
X    ("application"
X     ("postscript")
X     ("octet-stream"
X      ("name")
X      ("type" "" "tar" "shar")
X      ("conversions")
X      ))
X    ("image"
X     ("gif")
X     ("jpeg")
X     ("x-xwd")
X     ("x-xbm"))
X    ("audio"
X     ("basic"))
X    ("video"
X     ("mpeg")))
X  "*Alist of content-type, subtype, options and its values.")
X
X(defvar mime-file-types
X  '(("\\.ps$"	"application"	"postscript"	nil)
X    ("\\.gif$"	"image"		"gif"	nil)
X    ("\\.xwd$"	"image"		"x-xwd"	nil)
X    ("\\.xbm$"	"image"		"x-xbm"	nil)
X    ("\\.jpg$"	"image"		"jpeg"	nil)
X    ("\\.au$"	"audio"		"basic"	nil)
X    ("\\.mpg$"	"video"		"mpeg"	nil))
X  "*Alist of file name, types and options.")
X
X(defvar mime-message-encoder
X  '(("base64"			"mmencode"	"mmencode -u")
X    ("b"			"mmencode"	"mmencode -u") ;in header
X    ("quoted-printable"		"mmencode -q"	"mmencode -q -u")
X    ("q"			"mmencode -q"	"mmencode -q -u") ;in header
X    ("7bit"			nil nil) ;Default
X    ("8bit"			nil nil)
X    ("binary"			nil nil))
X  "*Alist of encoding, encoder, and decoder.
XEncoder and decoder is a command string, function symbol or lambda
Xlist which take two arguments.  If it is nil, no conversion is done.")
X
X(defvar mime-message-handler
X  '(("text/richtext"		t)
X    ("text/plain"		t)
X    (t				mime-run-metamail))
X  "*Alist of Content-type and its preview method.
XThe method can be a function symbol or a lambda list that takes a
Xregion, nil or t.  nil means no handler is defined.  t means what you
Xsee is what you get.  If content-type is t, it is a default.")
X
X(defvar mime-charset-chooser
X  (function mime-charset-chooser-for-nemacs)
X  "*Function that identify charset of a text in a given region.")
X
X(defvar mime-header-encoding-chooser
X  (function mime-header-encoding-chooser-for-nemacs)
X  "*Function to identify encoding method of a header in a give region.
XThe method is a form of (CHARSET . ENCODING), where ENCODING is either
X'B' or 'Q'.  Nil means no encoding is necessary.")
X
X(defvar mime-header-string-encoder
X  (function mime-header-string-encoder-for-nemacs)
X  "*Function to encode string for using in header for given encoding method.")
X
X(defvar mime-voice-recorder
X  (function mime-voice-recorder-for-sun)
X  "*Function to record voice message.")
X
X(defvar mime-max-header-length 76
X  "*Any header should not exceed this value.")
X
X(defvar mime-tspecials-regexp "[][()<>@,;:\\\"/?.= \t]"
X  "*Specify MIME tspecials.
XTspecials means any character that matches with it must be quoted.")
X
X(defvar mime-tag-regexp "^--[[][[]\\([^]]*\\)]]"
X  "*Regexp of Content-Type tag in the text.")
X
X(defvar mime-tag-format "--[[%s]]"
X  "*Control-string generating a Content-Type tag.")
X
X(defvar mime-multipart-boundary "Multipart"
X  "*Boundary of a multipart message.")
X
X
X(defconst mime-version-number "1.0"
X  "MIME version number.")
X
X(defvar mime-mode-flag nil)
X(make-variable-buffer-local 'mime-mode-flag)
X
X(or (assq 'mime-mode-flag minor-mode-alist)
X    (setq minor-mode-alist
X	  (cons (list 'mime-mode-flag " MIME") minor-mode-alist)))
X
X(defun mime-define-keymap (keymap)
X  "Add MIME commands to KEYMAP."
X  (if (not (keymapp keymap))
X      nil
X    (define-key keymap "\C-t" 'mime-insert-text)
X    (define-key keymap "\C-v" 'mime-insert-voice)
X    (define-key keymap "\C-e" 'mime-insert-external)
X    (define-key keymap "\C-i" 'mime-include-file)
X    (define-key keymap "\C-p" 'mime-preview-content)
X    (define-key keymap "\C-z" 'mime-mode-exit)
X    (define-key keymap "?" 'help-mime-mode)))
X
X;;;###autoload
X(defun mime-mode ()
X  "Minor mode for editing the tagged MIME message.
X
XIn this mode, basically, the message should be composed in the tagged
XMIME format.  The message tag looks like:
X
X	'--[[text/plain; charset=ISO-2022-JP]]'.
X
XThe tag specifies the content-type, subtype, and options of the
Xmessage following the tag in terms of MIME.  Messages without any tag
Xare treated as text/plain by default.  Binary messages such as audio
Xand image are usually hidden in this mode using selective-display
Xfacility.  The messages in the tagged MIME format are automatically
Xtranslated into a MIME compliant message when exiting the mode.
X
XCommands with a prefix (specified by the variable mime-prefix):
XC-t	mime-insert-text	insert text message
XC-v	mime-insert-voice	insert voice message
XC-e	mime-insert-external	insert reference to external body
XC-i	mime-include-file	insert from a (binary) file
XC-p	mime-preview-content	preview an included content
XC-z	mime-mode-exit		Convert into MIME
X?	help-mime-mode		show this message
X
XAdditional commands:
XC-c C-s	mime-mode-exit-and-run	Convert into MIME and run original command
XC-c C-c	mime-mode-exit-and-run	Convert into MIME and run original command
X
XThe following is a message example in the tagged MIME format (TABs at
Xthe beginning of the line are not a part of the message):
X
X	This is a conventional plain text.  It should be translated
X	into text/plain.
X	--[[text/plain]]
X	This is also a plain text.  But, it is explicitly specified as
X	is.
X	--[[text/plain; charset=ISO-2022-JP]]
X	これは charset を ISO-2022-JP に指定した日本語の plain テキス
X	トです.
X	--[[text/richtext]]
X	<center>This is a richtext.</center>
X	--[[image/gif]]^MContent-Transfer-Encoding: base64^M...image here...
X	--[[audio/basic]]^Montent-Transfer-Encoding: base64^M...audio here...
X
XTurning on MIME mode calls the value of mime-mode-hook, if they are
Xnon-nil."
X  (interactive)
X  (if mime-mode-flag
X      (error "You are already editing a MIME.")
X    (setq mime-mode-flag t)
X    ;; Remember old key bindings.
X    (make-local-variable 'mime-mode-old-local-map)
X    (setq mime-mode-old-local-map (current-local-map))
X    ;; Add MIME commands to current local map.
X    (use-local-map (copy-keymap (current-local-map)))
X    (if (not (lookup-key (current-local-map) mime-prefix))
X	(define-key (current-local-map) mime-prefix (make-sparse-keymap)))
X    (mime-define-keymap (lookup-key (current-local-map) mime-prefix))
X    ;; These are useful to avoid sending before conversion into
X    ;; MIME in Mail mode and News mode.
X    (define-key (current-local-map) "\C-c\C-c" 'mime-mode-exit-and-run)
X    (define-key (current-local-map) "\C-c\C-s" 'mime-mode-exit-and-run)
X    ;; Remember old selective-display.
X    (make-local-variable 'mime-mode-old-selective-display)
X    (setq mime-mode-old-selective-display selective-display)
X    (setq selective-display t)
X    ;; I don't care about saving these.
X    (setq paragraph-start
X	  (concat mime-tag-regexp "\\|" paragraph-start))
X    (setq paragraph-separate
X	  (concat mime-tag-regexp "\\|" paragraph-separate))
X    (run-hooks 'mime-mode-hook)
X    (message
X     (substitute-command-keys
X      "Type \\[mime-mode-exit] in this buffer to exit MIME mode."))
X    ))
X
X;;;###autoload
X(fset 'edit-mime 'mime-mode)		; for convenience
X
X(defun mime-mode-exit (&optional nomime)
X  "Convert the tagged MIME message into MIME compliant message.
XWith no argument encode a message in the buffer into MIME, otherwise
Xjust return to previous mode."
X  (interactive "P")
X  (if (not mime-mode-flag)
X      (error "You aren't editing a MIME.")
X    (if (not nomime)
X	(mime-convert-buffer))
X    (setq mime-mode-flag nil)
X    ;; Restore previous state.
X    (use-local-map mime-mode-old-local-map)
X    (setq selective-display mime-mode-old-selective-display)
X    (set-buffer-modified-p (buffer-modified-p))
X    (message "Exit MIME mode.")
X    ))
X
X(defun mime-mode-exit-and-run ()
X  "Run a command bound on the same key in old keymap after the conversion."
X  (interactive)
X  (let ((cmd (lookup-key mime-mode-old-local-map (this-command-keys))))
X    (mime-mode-exit)
X    (if cmd
X	(call-interactively cmd))))
X
X(defun help-mime-mode ()
X  "Show help message about MIME mode."
X  (interactive)
X  (with-output-to-temp-buffer "*Help*"
X    (princ "Edit MIME Mode:\n")
X    (princ (documentation 'mime-mode))
X    (print-help-return-message)))
X
X(defun mime-insert-text ()
X  "Insert text message."
X  (interactive)
X  (if (and (mime-insert-message "text" nil nil)
X	   (looking-at mime-tag-regexp))
X      (progn
X	;; Make a space between the following message.
X	(insert "\n")
X	(forward-char -1))))
X
X(defun mime-insert-voice ()
X  "Insert voice message."
X  (interactive)
X  (mime-insert-message "audio" "basic" nil)
X  (let ((buffer (funcall mime-voice-recorder)))
X    (unwind-protect
X	(mime-insert-binary-buffer buffer "base64")
X      (kill-buffer buffer)
X      )))
X
X(defun mime-insert-external ()
X  "Insert reference to external body."
X  (interactive)
X  (mime-insert-message "message" "external-body" nil ";\n\t")
X  ;;(forward-char -1)
X  ;;(insert "Content-description: " (read-string "Content-description: ") "\n")
X  ;;(forward-line 1)
X  (let* ((pritype (mime-prompt-for-type))
X	 (subtype (mime-prompt-for-subtype pritype))
X	 (options (mime-prompt-for-options pritype subtype ";\n\t")))
X    (and pritype
X	 subtype
X	 (insert "Content-type: " pritype "/" subtype (or options "") "\n")))
X  (if (and (not (eobp))
X	   (not (looking-at mime-tag-regexp)))
X      (insert (mime-make-text-tag) "\n")))
X
X(defun mime-include-file (file)
X  "Insert message from a file."
X  (interactive "fInclude file: ")
X  (let*  ((guess (mime-find-file-type file))
X	  (pritype (nth 0 guess))
X	  (subtype (nth 1 guess))
X	  (options (nth 2 guess)))
X    (mime-insert-message pritype subtype options)
X    (mime-insert-binary-file file "base64")))
X
X(defun mime-preview-content ()
X  "Preview an included message content around point through metamail."
X  (interactive)
X  (save-excursion
X    ;; Search for the beginning of the tagged MIME message.
X    (if (looking-at mime-tag-regexp)
X	nil
X      ;; At first, go to the end.
X      (if (re-search-forward mime-tag-regexp nil t)
X	  (progn
X	    (forward-line -1)
X	    (end-of-line))
X	(goto-char (point-max)))
X      ;; Then search for the beginning. 
X      (re-search-backward mime-tag-regexp nil t)
X      (beginning-of-line))
X    (if (looking-at mime-tag-regexp)
X	(let* ((handler
X		(mime-find-handler
X		 (mime-strip-options
X		  (buffer-substring (match-beginning 1) (match-end 1)))))
X	       (beg (point))
X	       (end (save-excursion
X		      (forward-line 1)
X		      (re-search-forward mime-tag-regexp nil 'move)
X		      (point))))
X	  (cond ((eq handler t)		;As is.
X		 (message "Nothing to do.  You are seeing as is."))
X		((or (symbolp handler) (consp handler))
X		 (funcall handler beg end))
X		(t
X		 (ding) (message "No message handler defined."))
X		))
X      (ding) (message "No messages to preview around here.")
X      )))
X
X
X;; Additional commands
X
X(defun mime-encode-region (encoding begin end)
X  "Encode current buffer using ENCODING from BEGIN to END."
X  (interactive
X   (list (completing-read "Encoding: " mime-message-encoder nil 'req)
X	 (region-beginning) (region-end)))
X  (let* ((kanji-flag nil)
X	 (encoding (or encoding "base64"))
X	 (encoder (mime-find-encoder encoding)))
X    (cond ((stringp encoder)
X	   (shell-command-on-region begin end encoder t))
X	  (encoder
X	   (funcall encoder begin end))
X	  )))
X
X(defun mime-decode-region (encoding begin end)
X  "Decode current buffer using ENCODING from BEGIN to END."
X  (interactive
X   (list (completing-read "Encoding: " mime-message-encoder nil 'req)
X	 (region-beginning) (region-end)))
X  (let* ((kanji-flag nil)
X	 (encoding (or encoding "base64"))
X	 (decoder (mime-find-decoder encoding)))
X    (cond ((stringp decoder)
X	   (shell-command-on-region begin end decoder t))
X	  (decoder
X	   (funcall decoder begin end))
X	  )))
X
X
X;; Insert new MIME tag at around point.
X
X(defun mime-insert-message (&optional pritype subtype options delimiter)
X  "Insert new MIME message tag.
XIf nothing is inserted, return nil."
X  (let ((oldtag nil)
X	(newtag nil)
X	(current (point)))
X    (setq pritype
X	  (or pritype (mime-prompt-for-type)))
X    (setq subtype
X	  (or subtype (mime-prompt-for-subtype pritype)))
X    (setq options
X	  (or options (mime-prompt-for-options pritype subtype delimiter)))
X    ;; Make a new MIME tag.
X    (setq newtag (mime-make-tag pritype subtype options))
X    ;; Find an old MIME tag.
X    (setq oldtag
X	  (save-excursion
X	    (end-of-line)
X	    (if (re-search-backward mime-tag-regexp nil t)
X		(buffer-substring (match-beginning 0) (match-end 0)))))
X    ;; We are only interested in TEXT.
X    (if (and oldtag
X	     ;;(not (string-match "[^a-zA-Z0-9]text/" oldtag))
X	     (not (mime-text-tag-p oldtag)))
X	(setq oldtag nil))
X    ;; Copy the tag for a message at current point if necessary.
X    (if (save-excursion
X	  (forward-line -1)
X	  (and (looking-at mime-tag-regexp)
X	       (progn
X		 (goto-char (match-end 0))
X		 (not (= (following-char) ?\^M)))))
X	(forward-line -1))
X    (beginning-of-line)
X    (if (and oldtag
X	     (not (eobp))
X	     (not (looking-at mime-tag-regexp))
X	     (not (string-equal oldtag newtag)))
X	(save-excursion
X	  (insert oldtag "\n")))
X    ;; Make a new tag.
X    (if (or (not oldtag)
X	    (not (string-equal oldtag newtag)))
X	(progn
X	  (insert newtag "\n")
X	  t				;New entry is created.
X	  )
X      ;; Restore previous point.
X      (goto-char current)
X      nil				;Nothing is created.
X      )
X    ))
X
X;; Insert the content of binary file after MIME tag.
X
X(defun mime-insert-binary-file (file &optional encoding)
X  "Insert binary FILE at point.
XOptional argument specifies an encoding method such as base64 (default)."
X  (let* ((encoding (or encoding "base64")))
X    (save-restriction
X      (narrow-to-region (1- (point)) (point))
X      (insert "Content-Transfer-Encoding: " encoding "\n\n")
X      (let ((start (point))
X	    (kanji-flag nil))		;NEmacs hack.
X	(insert-file-contents file)
X	;; Encode binary message if necessary.
X	(mime-encode-region encoding start (point-max)))
X      (mime-flag-region (point-min) (1- (point-max)) ?\^M)
X      (goto-char (point-max))
X      )))
X
X(defun mime-insert-binary-buffer (buffer &optional encoding)
X  "Insert binary BUFFER at point.
XOptional argument specifies an encoding method such as base64 (default)."
X  (let* ((encoding (or encoding "base64")))
X    (save-restriction
X      (narrow-to-region (1- (point)) (point))
X      (insert "Content-Transfer-Encoding: " encoding "\n\n")
X      (let ((start (point))
X	    (kanji-flag nil))		;NEmacs hack.
X	(insert-buffer-substring buffer)
X	;; Encode binary message if necessary.
X	(mime-encode-region encoding start (point-max)))
X      (mime-flag-region (point-min) (1- (point-max)) ?\^M)
X      (goto-char (point-max))
X      )))
X
X(defun mime-run-metamail (begin end)
X  "Run metamail on current tagged MIME message from BEGIN to END."
X  (save-excursion
X    (let ((tmpbuf (get-buffer-create " *MIME preview*")))
X      (copy-to-buffer tmpbuf begin end)
X      (set-buffer tmpbuf)
X      ;; Mock Mail mode buffer.
X      (goto-char (point-min))
X      (insert "From: PreviewTheContent\n"
X	      mail-header-separator "\n")
X      ;; Then convert it into MIME. 
X      (mime-convert-body)
X      (goto-char (point-min))
X      (if (search-forward (concat "\n" mail-header-separator "\n") nil t)
X	  (replace-match "\n\n"))
X      ;; Preview the content using metamail.
X      (metamail-buffer)
X      (kill-buffer tmpbuf)
X      )))
X
X(defun mime-encode-string (encoding string)
X  "Using ENCODING encode a STRING."
X  (save-excursion
X    (set-buffer (get-buffer-create " *MIME encoding*"))
X    (erase-buffer)
X    (insert string)
X    (mime-encode-region encoding (point-min) (point-max))
X    ;; Unfold lines since mmencode breaks long lines.
X    (goto-char (point-min))
X    (while (re-search-forward "\n" nil t)
X      (replace-match ""))
X    (prog1
X	(buffer-substring (point-min) (point-max))
X      (kill-buffer (current-buffer)))))
X
X(defun mime-decode-string (encoding string)
X  "Using ENCODING decode a STRING."
X  (save-excursion
X    (set-buffer (get-buffer-create " *MIME decoding*"))
X    (erase-buffer)
X    (insert string)
X    (mime-decode-region encoding (point-min) (point-max))
X    (prog1
X	(buffer-substring (point-min) (point-max))
X      (kill-buffer (current-buffer)))))
X
X(defun mime-find-encoder (encoding)
X  "Return encoder of message for ENCODING."
X  (and encoding
X       (nth 1 (assoc (downcase encoding) mime-message-encoder))))
X
X(defun mime-find-decoder (encoding)
X  "Return decoder of message for ENCODING."
X  (and encoding
X       (nth 2 (assoc (downcase encoding) mime-message-encoder))))
X
X(defun mime-find-file-type (file)
X  "Guess Content-Type, subtype, and options from FILE."
X  (let ((guess nil)
X	(guesses mime-file-types))
X    (while (and (not guess) guesses)
X      (if (string-match (car (car guesses)) file)
X	  (setq guess (cdr (car guesses))))
X      (setq guesses (cdr guesses)))
X    guess
X    ))
X
X(defun mime-find-handler (type)
X  "Return message handler for Content-type TYPE."
X  (and type
X       (let ((pair (assoc (downcase type) mime-message-handler)))
X	 (if pair
X	     (nth 1 pair)
X	   ;; Search default if no entry.
X	   (nth 1 (assoc t mime-message-handler))))))
X
X(defun mime-strip-options (content-type)
X  "Return content-type and subtype without options."
X  (if (string-match "^[ \t]*\\([^; \t\n]*\\)" content-type)
X      (substring content-type (match-beginning 1) (match-end 1)) nil))
X
X(defun mime-prompt-for-type ()
X  "Ask for Content-type."
X  (completing-read "Content-Type: "
X		   mime-content-types
X		   nil
X		   t
X		   nil
X		   ))
X
X(defun mime-prompt-for-subtype (pritype)
X  "Ask for Content-type subtype for Content-Type PRITYPE."
X  (let* ((default (car (car (cdr (assoc pritype mime-content-types)))))
X	 (answer
X	  (completing-read (if default
X			       (concat
X				"Content subtype: (default " default ") ")
X			     "Content subtype: ")
X			   (cdr (assoc pritype mime-content-types))
X			   nil
X			   t
X			   ""
X			   )))
X    (if (string-equal answer "") default answer)))
X
X(defun mime-prompt-for-options (pritype subtype &optional delimiter)
X  "Ask for Content-type options for Content-Type PRITYPE and SUBTYPE.
XOptional DELIMITER specifies option delimiter (';' by default)."
X  (let* ((delimiter (or delimiter "; "))
X	 (options
X	  (mapconcat
X	   (function identity)
X	   (delq nil
X		 (mime-prompt-for-options-1
X		  (cdr (assoc subtype
X			      (cdr (assoc pritype mime-content-types))))))
X	   delimiter
X	   )))
X    (if (and (stringp options)
X	     (not (string-equal options "")))
X	(concat delimiter options)
X      ""				;"" if no options
X      )))
X
X(defun mime-prompt-for-options-1 (optlist)
X  (apply (function append)
X	 (mapcar (function mime-prompt-for-option) optlist)))
X
X(defun mime-prompt-for-option (option)
X  "Ask for OPTION.
XOption must be '(PROMPT CHOICE1 (CHOISE2 ...))."
X  (let* ((prompt (car option))
X	 (choices (mapcar (function
X			   (lambda (e)
X			     (if (consp e) e (list e))))
X			  (cdr option)))
X	 (default (car (car choices)))
X	 (answer nil))
X    (if choices
X	(progn
X	  (setq answer
X		(completing-read
X		 (concat prompt
X			 ": (default "
X			 (if (string-equal default "") "\"\"" default)
X			 ") ")
X		 choices nil nil ""))
X	  ;; If nothing is selected, use default.
X	  (if (string-equal answer "")
X	      (setq answer default)))
X      (setq answer
X	    (read-string (concat prompt ": "))))
X    (cons (if (and answer
X		   (not (string-equal answer "")))
X	      (concat prompt "="
X		      ;; Note: control characters ignored!
X		      (if (string-match mime-tspecials-regexp answer)
X			  (concat "\"" answer "\"") answer)))
X	  (mime-prompt-for-options-1 (cdr (assoc answer (cdr option)))))
X    ))
X
X(defun mime-make-tag (pritype subtype &optional options)
X  "Make a tag of MIME message of PRITYPE, SUBTYPE and optional OPTIONS."
X  (format mime-tag-format
X	  (concat (or pritype "") "/" (or subtype "") (or options ""))))
X
X(defun mime-make-text-tag ()
X  "Make a tag for a text.
XContent-type is 'text' and its subtype is obtained from mime-content-types.
XCharset is inferenced from the message content."
X  (save-excursion
X    (let* ((pritype "text")
X	   (subtype (car (car (cdr (assoc pritype mime-content-types)))))
X	   (begin (point)))
X      ;; Move to the end of this text.
X      (if (re-search-forward mime-tag-regexp nil 'move)
X	  (beginning-of-line))
X      (mime-make-tag pritype subtype
X		     (concat "; charset="
X			     (funcall mime-charset-chooser begin (point))))
X      )))
X
X(defun mime-text-tag-p (tag)
X  "Non-nil if TAG is a kind of text content-type."
X  (and (string-match mime-tag-regexp tag)
X       (string-match "^text\\(/\\|$\\)"
X		     (substring tag (match-beginning 1) (match-end 1)))))
X
X(defun mime-flag-region (from to flag)
X  "Hides or shows lines from FROM to TO, according to FLAG.
XIf FLAG is `\\n' (newline character) then text is shown,
Xwhile if FLAG is `\\^M' (control-M) the text is hidden."
X  (let ((buffer-read-only nil)		;Okay even if write protected.
X	(modp (buffer-modified-p)))
X    (unwind-protect
X        (subst-char-in-region from to
X			      (if (= flag ?\n) ?\^M ?\n)
X			      flag t)
X      (set-buffer-modified-p modp))))
X
X;;(defun mime-default-options (pritype subtype)
X;;  "Return default options for content-type PRITYPE and SUBTYPE."
X;;  (mapconcat
X;;   (function
X;;    (lambda (optlist)
X;;      (concat (car optlist)
X;;	      "="
X;;	      (car (cdr optlist)))))
X;;   (cdr (assoc subtype (cdr (assoc pritype mime-content-types))))
X;;   "; "
X;;   ))
X
X
X;; Translate the tagged MIME messages into a MIME compliant message.
X
X(defun mime-convert-buffer ()
X  "Encode the tagged MIME message in current buffer in MIME compliant message."
X  (interactive)
X  (mime-convert-header)
X  (mime-convert-body))
X
X(defun mime-convert-header ()
X  "Encode headers in MIME compliant message headers."
X  (interactive)
X  (save-excursion
X    (save-restriction
X      (goto-char (point-min))
X      (search-forward (concat "\n" mail-header-separator "\n") nil t)
X      (narrow-to-region (point-min) (point))
X      (goto-char (point-min))
X      (while (re-search-forward "^[^ \t\n:]+:[ \t]*" nil t)
X	(let* ((beg (point))
X	       (end (progn
X		      (while (progn (forward-line 1) (looking-at "[ \t]")))
X		      (1- (point)))))
X	  (if (funcall mime-header-encoding-chooser beg end)
X	      (let* ((string (buffer-substring beg end))
X		     (newstr (mime-convert-header-string string))
X		     (fill-column mime-max-header-length)
X		     (fill-prefix " "))
X		(if (not (string-equal string newstr))
X		    (save-excursion
X		      (goto-char beg)
X		      (delete-region beg end)
X		      (insert newstr)
X		      ;; Fill header fields.
X		      (if mime-auto-fill-header
X			  ;; The region must end with a newline to
X			  ;; fill the region without inserting extra
X			  ;; newline.
X			  (fill-region-as-paragraph beg (1+ (point))))
X		      ))))
X	  ))
X      )))
X
X(defun mime-convert-header-string (string)
X  "Encode STRING suitable for using in header."
X  (save-excursion
X    (let* ((poslist nil)		;Possible break points.
X	   (last-encoding nil)		;last chunk encoding
X	   (this-encoding nil)		;this chunk encoding
X	   (start nil)			;Chunk start point
X	   (chunk nil)
X	   (saved nil)			;Saved last line.
X	   (separator nil)
X	   (result ""))
X      (set-buffer (get-buffer-create " *MIME header*"))
X      (erase-buffer)
X      (insert string)
X      ;; Replace white spaces for continuation line with a space.
X      (goto-char (point-min))
X      (while (re-search-forward "\n[ \t]*" nil t)
X	(replace-match " "))
X      ;; Encode string
X      (goto-char (point-min))
X      (while (not (eobp))
X	(setq start (point))
X	;; Set initial code.
X	(setq last-encoding this-encoding) 
X	(setq this-encoding
X	      (funcall mime-header-encoding-chooser
X		       start
X		       (save-excursion
X			 (forward-char 1) (point))))
X	(setq poslist (mime-search-for-code-boundary))
X	(if (not this-encoding)
X	    (setq chunk (buffer-substring start (point)))
X	  ;; Break line if too long in terms of RFC1342.
X	  (let ((repeat t))
X	    (while repeat
X	      (setq chunk
X		    (funcall mime-header-string-encoder
X			     this-encoding
X			     (buffer-substring start (point))))
X	      (if (<= (length chunk) mime-max-header-length)
X		  (setq repeat nil)
X		;; Must break since too long.
X		(setq poslist (cdr poslist))
X		(if poslist
X		    ;; There is a break point candidate.
X		    (progn
X		      (goto-char (car poslist))
X		      (skip-chars-backward " \t"))
X		  ;; Still too long, so insert a newline.
X		  (backward-char
X		   (max 1
X			(/ (* (- (point) start)
X			      (- (length chunk) mime-max-header-length))
X			   (- (length chunk)
X			      (length (car this-encoding))
X			      (length (cdr this-encoding)) 6))))
X		  ))
X	      ))
X	  )
X	;; Fold line if necessary.
X	;; BUG: An extra space may be inserted after a white space
X	;; followed by non-ascii characters.
X	(cond ((string-equal result "")
X	       (setq saved chunk)
X	       (setq separator ""))
X	      ((and (or last-encoding this-encoding)
X		    (> (length (concat saved chunk))
X		       mime-max-header-length))
X	       (setq saved (concat chunk " "))
X	       (setq separator "\n "))
X	      ;; (not (equal last-encoding this-encoding))
X	      ((and last-encoding (not this-encoding)
X		    (> (length (concat saved " " chunk))
X		       mime-max-header-length))
X	       (setq saved (concat chunk " "))
X	       (setq separator "\n "))
X	      ;; (not (equal last-encoding this-encoding))
X	      ((and last-encoding (not this-encoding)
X		    (string-match "^[^ \t]" chunk))
X	       (setq saved (concat saved " " chunk))
X	       (setq separator " "))
X	      (t
X	       (setq saved (concat saved chunk))
X	       (setq separator "")))
X	(setq result (concat result separator chunk)))
X      (kill-buffer (current-buffer))
X      result
X      )))
X
X(defun mime-search-for-code-boundary ()
X  "Search for code boundary starting from current point and return points."
X  (let ((repeat t)
X	(lastwhite nil)
X	(poslist nil)			;possible boundary points
X	(encoding (and (not (eobp))
X		       (funcall mime-header-encoding-chooser
X				(point)
X				(save-excursion
X				  (forward-char 1) (point))))))
X    (while repeat
X      (while (and (not (eobp))
X		  (equal encoding
X			 (funcall mime-header-encoding-chooser
X				  (point)
X				  (save-excursion
X				    (forward-char 1) (point)))))
X	(setq lastwhite nil)
X	(forward-char 1))
X      ;; Remember the candidate.
X      (if (not lastwhite)
X	  (setq poslist (cons (point) poslist)))
X      ;; Iterate if the next of the next whitespace is the same.
X      (if (looking-at "[ \t]")
X	  (skip-chars-forward " \t")
X	(setq repeat nil))
X      (setq lastwhite t)
X      )
X    ;; Goto the last point.
X    (goto-char (car poslist))
X    poslist
X    ))
X
X(defun mime-convert-body ()
X  "Encode the tagged MIME body in current buffer in MIME compliant message."
X  (interactive)
X  (save-excursion
X    (let ((boundary
X	   (concat mime-multipart-boundary " " (current-time-string)))
X	  (ctype nil)			;Content type
X	  (fields nil)			;Some additional fields
X	  (npart 0))			;Number of body part
X      (save-restriction
X	;; We are interested in message body.
X	(let* ((beg
X		(progn
X		  (goto-char (point-min))
X		  (re-search-forward
X		   (concat "\n" mail-header-separator
X			   (if mime-ignore-preceding-spaces
X			       "[ \t\n]*\n" "\n")) nil 'move)
X		  (point)))
X	       (end
X		(progn
X		  (goto-char (point-max))
X		  (and mime-ignore-trailing-spaces
X		       (re-search-backward "[^ \t\n]\n" beg t)
X		       (forward-char 1))
X		  (point))))
X	  (narrow-to-region beg end))
X	;; Counting the number of Content-Type.
X	(goto-char (point-min))
X	(while (re-search-forward mime-tag-regexp nil t)
X	  (setq npart (1+ npart)))
X	;; Normalize the body.
X	(goto-char (point-min))
X	;; Insert the first MIME tags if necessary.
X	(if (not (looking-at mime-tag-regexp))
X	    (progn
X	      (setq npart (1+ npart))
X	      (insert (mime-make-text-tag) "\n")
X	      ))
X	;; Insert MIME tags after mmencoded messages.
X	(while (re-search-forward mime-tag-regexp nil t)
X	  (if (= (following-char) ?\^M)
X	      (progn
X		(forward-line 1)
X		(if (and (not (eobp))
X			 (not (looking-at mime-tag-regexp)))
X		    (progn
X		      (setq npart (1+ npart))
X		      (insert (mime-make-text-tag) "\n")))
X		))
X	  )
X	;; Begin translation.
X	(cond ((<= npart 1)
X	       ;; It's a singular message.
X	       (goto-char (point-min))
X	       (while (re-search-forward mime-tag-regexp nil t)
X		 (setq ctype
X		       (buffer-substring (match-beginning 1) (match-end 1)))
X		 (delete-region (match-beginning 0)
X				(match-end 0))
X		 (if (= (following-char) ?\^M)
X		     (save-restriction
X		       (narrow-to-region (point)
X					 (save-excursion
X					   (end-of-line) (point)))
X		       ;; Show the text hiden with selective display.
X		       (mime-flag-region (point-min) (point-max) ?\n)
X		       (goto-char (point-min))
X		       (if (search-forward "\n\n" nil t)
X			   (progn
X			     (setq fields
X				   (buffer-substring (point-min)
X						     (- (point) 2)))
X			     (delete-region (point-min) (point)))))
X		   ;; Delete the following newline.
X		   (delete-char 1))
X		 ))
X	      (t
X	       ;; It's a multipart message.
X	       (goto-char (point-min))
X	       (while (re-search-forward mime-tag-regexp nil t)
X		 (setq ctype
X		       (buffer-substring (match-beginning 1) (match-end 1)))
X		 (delete-region (match-beginning 0) (match-end 0))
X		 (insert "--" boundary "\n")
X		 (insert "Content-Type: " ctype)
X		 ;; Show the text hiden with selective display.
X		 (if (= (following-char) ?\^M)
X		     (mime-flag-region (progn (beginning-of-line) (point))
X				       (progn (end-of-line) (point))
X				       ?\n)
X		   (insert "\n"))
X		 )
X	       ;; Insert the trailer.
X	       (goto-char (point-max))
X	       (if (not (= (preceding-char) ?\n))
X		   ;; Boundary must start with a newline.
X		   (insert "\n"))
X	       (insert "--" boundary "--\n"))
X	      )
X	)
X      ;; Make primary MIME headers.
X      (or (mail-position-on-field "Mime-Version")
X	  (insert mime-version-number))
X      ;; Remove old Content-Type and other fields.
X      (save-restriction
X	(goto-char (point-min))
X	(search-forward (concat "\n" mail-header-separator "\n") nil t)
X	(narrow-to-region (point-min) (point))
X	(goto-char (point-min))
X	(mime-delete-field "Content-Type")
X	(mime-delete-field "Content-Transfer-Encoding"))
X      ;; Then, insert new Content-Type field.
X      (cond ((<= npart 1)
X	     (mail-position-on-field "Content-Type")
X	     (insert ctype)
X	     ;; Insert additional fields if exists.
X	     (if fields
X		 (insert fields)))
X	    (t
X	     (mail-position-on-field "Content-Type")
X	     (insert "multipart/mixed; boundary=\"" boundary "\""))
X	    )
X      )))
X
X(defun mime-delete-field (field)
X  "Delete header FIELD."
X  (let ((regexp (format "^%s:[ \t]*" field)))
X    (goto-char (point-min))
X    (while (re-search-forward regexp nil t)
X      (delete-region (match-beginning 0)
X		     (progn (forward-line 1) (point)))
X      )))
X
X
X;;;
X;;; Platform dependents functions
X;;;
X
X(defun mime-charset-chooser-for-nemacs (begin end)
X  "Identify charset of a message in a given region (NEmacs only)."
X  (cond ((and (fboundp 'check-region-kanji-code) ;In case of NEmacs.
X	      (check-region-kanji-code begin end))
X	 "ISO-2022-JP")
X	(t "us-ascii")			;Default charset of MIME.
X	))
X
X(defun mime-header-encoding-chooser-for-nemacs (begin end)
X  "Return header encoding method for a given region (NEmacs only)."
X  (cond ((and (fboundp 'check-region-kanji-code) ;In case of NEmacs.
X	      (check-region-kanji-code begin end))
X	 '("ISO-2022-JP" . "B"))
X	(t nil)				;No encoding is necessary.
X	))
X
X(defun mime-header-string-encoder-for-nemacs (method string)
X  "For given encoding METHOD encode STRING for using in header (NEmacs only)."
X  (let ((charset (car method))
X	(encoding (cdr method)))
X    (concat "=?" charset "?" encoding "?"
X	    (mime-encode-string
X	     encoding
X	     (if (fboundp 'convert-string-kanji-code) ;In case of NEmacs.
X		 ;; Convert internal (EUC) to JIS code.
X		 (convert-string-kanji-code string 3 2) string)
X	     )
X	    "?="
X	    )))
X
X(defun mime-voice-recorder-for-sun ()
X  "Record voice in a buffer using Sun audio device, and return the buffer."
X  (let ((buffer (get-buffer-create " *MIME audio*")))
X    (message "Type C-g to finish recording...")
X    (save-excursion
X      (set-buffer buffer)
X      (erase-buffer)
X      (condition-case errorcode
X	  (call-process "cat"
X			"/dev/audio"
X			buffer
X			nil
X			)
X	(quit (message "Type C-g to finish recording... done.")
X	      buffer			;Return the buffer
X	      )))))
X
X
X;;;
X;;; Other useful commands.
X;;;
X
X;; Message forwarding commands as content-type "message/rfc822".
X;; Usages are as follows:
X;;
X;;(setq rmail-mode-hook
X;;      '(lambda ()
X;;	 ;; Forward mail using MIME.
X;;	 (require 'mime)
X;;	 (substitute-key-definition 'rmail-forward
X;;				    'mime-forward-from-rmail-using-mail
X;;				    (current-local-map))
X;;	 ))
X;;
X;;(setq gnus-mail-forward-method 'mime-forward-from-gnus-using-mail)
X;;(setq gnus-summary-mode-hook
X;;      '(lambda ()
X;;	 ;; Forward article using MIME.
X;;	 (require 'mime)
X;;	 ))
X
X(defun mime-forward-from-rmail-using-mail ()
X  "Forward current message in message/rfc822 content-type message from rmail."
X  (interactive)
X  ;;>> this gets set even if we abort. Can't do anything about it, though.
X  (rmail-set-attribute "forwarded" t)
X  (let ((forward-buffer (current-buffer))
X	(subject (concat "["
X			 (mail-strip-quoted-names (mail-fetch-field "From"))
X			 ": " (or (mail-fetch-field "Subject") "") "]")))
X    ;; If only one window, use it for the mail buffer.
X    ;; Otherwise, use another window for the mail buffer
X    ;; so that the Rmail buffer remains visible
X    ;; and sending the mail will get back to it.
X    (if (if (one-window-p t)
X	    (mail nil nil subject)
X	  (mail-other-window nil nil subject))
X	(save-excursion
X	  (goto-char (point-max))
X	  (forward-line 1)
X	  (mime-insert-message "message" "rfc822")
X	  (insert-buffer forward-buffer)))))
X
X(defun mime-forward-from-gnus-using-mail ()
X  "Forward current article in message/rfc822 content-type message from GNUS."
X  (let ((forward-buffer (current-buffer))
X	(subject
X	 (concat "[" gnus-newsgroup-name "] "
X		 ;;(mail-strip-quoted-names (gnus-fetch-field "From")) ": "
X		 (or (gnus-fetch-field "Subject") ""))))
X    ;; If only one window, use it for the mail buffer.
X    ;; Otherwise, use another window for the mail buffer
X    ;; so that the Rmail buffer remains visible
X    ;; and sending the mail will get back to it.
X    (if (if (one-window-p t)
X	    (mail nil nil subject)
X	  (mail-other-window nil nil subject))
X	(save-excursion
X	  (goto-char (point-max))
X	  (mime-insert-message "message" "rfc822")
X	  (insert-buffer forward-buffer)
X	  ;; You have a chance to arrange the message.
X	  (run-hooks 'gnus-mail-forward-hook)
X	  ))))
X
X(provide 'mime)
X
X;;; mime.el ends here
*-*-END-of-mime.el-*-*
echo x rmailmime.el
sed 's/^X//' > rmailmime.el << '*-*-END-of-rmailmime.el-*-*'
X;;; rmailmime.el --- Rmail: MIME message support.
X
X;; Copyright (C) 1993 Masanobu UMEDA
X
X;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
X;; Version: $Header: rmailmime.el,v 1.1 93/07/02 12:16:19 umerin Locked $
X;; Keywords: mail, mime
X
X;; This file is part of GNU Emacs.
X
X;; GNU Emacs is free software; you can redistribute it and/or modify
X;; it under the terms of the GNU General Public License as published by
X;; the Free Software Foundation; either version 2, or (at your option)
X;; any later version.
X
X;; GNU Emacs is distributed in the hope that it will be useful,
X;; but WITHOUT ANY WARRANTY; without even the implied warranty of
X;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X;; GNU General Public License for more details.
X
X;; You should have received a copy of the GNU General Public License
X;; along with GNU Emacs; see the file COPYING.  If not, write to
X;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
X
X;;; Commentary:
X
X;; LCD Archive Entry:
X;; rmailmime|Masanobu UMEDA|umerin@mse.kyutech.ac.jp|
X;; Rmail: MIME message support.|
X;; $Date: 93/07/02 12:16:19 $|$Revision: 1.1 $|~/misc/rmailmime.el.Z|
X
X;; Usage examples:
X;; 
X;; To convert MIME headers into readable form automatically, set the
X;; variable rmail-message-filter to the function
X;; rmail-convert-mime-header as follows:
X;;	(setq rmail-message-filter 'rmail-convert-mime-header)
X;;
X;; To show MIME messages using metamail program, bind the command
X;; rmail-show-mime to some key in rmail mode.  The following example
X;; binds it to the key '!'.
X;;	(setq rmail-mode-hook
X;;	      '(lambda ()
X;;		 (local-set-key "!" 'rmail-show-mime)
X;;		 ))
X
X;;; Code:
X
X(require 'metamail)
X
X(defun rmail-show-mime ()
X  "Show MIME messages using temporary buffer in View mode."
X  (interactive)
X  (let ((tmpbuf (get-buffer-create "*metamail*")))
X    (metamail-region
X     (point-min) (point-max) tmpbuf)
X    (switch-to-buffer tmpbuf)
X    (view-buffer tmpbuf)
X    (goto-char (point-min))))
X
X(defun rmail-convert-mime-header ()
X  "Convert MIME headers of current message into readable form.
XOriginal headers are preserved.
XIt is expected to be used as rmail-message-filter."
X  (save-excursion
X    (let ((end (progn
X		 (goto-char (point-min))
X		 (search-forward "\n\n" nil t)
X		 (point))))
X      (if (save-restriction
X	    (narrow-to-region (point-min) end)
X	    (mail-fetch-field "Mime-Version"))
X	  (progn
X	    (metamail-region (point-min) end)
X	    ;; Remove an extra newline inserted by metamail.
X	    (goto-char (point-min))
X	    (if (search-forward "\n\n\n" nil t)
X		(delete-char -1))))
X      )))
X
X(provide 'rmailmime)
X
X;;; rmailsort.el ends here
*-*-END-of-rmailmime.el-*-*
exit 0
--
Masanobu UMEDA
umerin@mse.kyutech.ac.jp
Faculty of Computer Science and System Engineering
Kyushu Institute of Technology
Technical Details
Message-ID: <UMERIN.93Jul6001941@orchid.mse.kyutech.ac.jp>
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!howland.reston.ans.net!agate!ames!koriel!sh.wide!wnoc-kyo!kyu-cs!wnoc-fukuoka-news!shiwasu!shiwasu!umerin

Show Full Headers
Complete Article Headers
X-Google-Language: Japanese,JIS
X-Google-Thread: ff358,cc6b65fce96484b2,start
X-Google-Attributes: gidff358,public
X-Google-Thread: 10381e,cc6b65fce96484b2,start
X-Google-Attributes: gid10381e,public
X-Google-Thread: 107729,cc6b65fce96484b2,start
X-Google-Attributes: gid107729,public
X-Google-ArrivalTime: 1993-07-05 08:45:22 PST
Newsgroups: gnu.emacs.sources,fj.editor.emacs,comp.mail.mime
Path: arc1-ca.pugleaf.net!gmd.de!xlink.net!howland.reston.ans.net!agate!ames!koriel!sh.wide!wnoc-kyo!kyu-cs!wnoc-fukuoka-news!shiwasu!shiwasu!umerin
From: umerin@mse.kyutech.ac.jp (Masanobu UMEDA)
Subject: Emacs MIME tools (Emacs で MIME
 メッセージを読み書きするためのツール群 )
Content-Type: text/plain; charset=ISO-2022-JP
Sender: news@shiwasu.isci.kyutech.ac.jp
Mime-Version: 1.0
Organization: Department of Mechanical System Engineering, Kyutech, Japan
Date: Mon, 5 Jul 1993 15:19:41 GMT
To: ip-connection@nic.ad.jp
Message-ID: <UMERIN.93Jul6001941@orchid.mse.kyutech.ac.jp>
Reply-To: umerin@mse.kyutech.ac.jp
Lines: 1397