e79cd70b65388f861a5616982ee7fd66b8303152
[elisp/tm.git] / tm-edit.el
1 ;;;
2 ;;; tm-edit.el --- Simple MIME Composer for GNU Emacs
3 ;;;
4 ;;; Copyright (C) 1993 UMEDA Masanobu
5 ;;; Copyright (C) 1994,1995 MORIOKA Tomohiko
6 ;;;
7 ;;; Author: UMEDA Masanobu <umerin@mse.kyutech.ac.jp>
8 ;;;         MORIOKA Tomohiko <morioka@jaist.ac.jp>
9 ;;; Maintainer: MORIOKA Tomohiko <morioka@jaist.ac.jp>
10 ;;; Created: 1994/08/21 renamed from mime.el
11 ;;; Version: $Revision: 7.40 $
12 ;;; Keywords: mail, news, MIME, multimedia, multilingual
13 ;;;
14 ;;; This file is part of tm (Tools for MIME).
15 ;;;
16 ;;; This program is free software; you can redistribute it and/or
17 ;;; modify it under the terms of the GNU General Public License as
18 ;;; published by the Free Software Foundation; either version 2, or
19 ;;; (at your option) any later version.
20 ;;;
21 ;;; This program is distributed in the hope that it will be useful,
22 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24 ;;; General Public License for more details.
25 ;;;
26 ;;; You should have received a copy of the GNU General Public License
27 ;;; along with This program.  If not, write to the Free Software
28 ;;; Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29
30 ;;; Commentary:
31
32 ;; This is an Emacs minor mode for editing Internet multimedia
33 ;; messages formatted in MIME (RFC 1521 and RFC 1522). All messages in
34 ;; this mode are composed in the tagged MIME format, that are
35 ;; described in the following examples. The messages composed in the
36 ;; tagged MIME format are automatically translated into a MIME
37 ;; compliant message when exiting the mode.
38
39 ;; Mule (a multilingual extension to Emacs 18 and 19) has a capability
40 ;; of handling multilingual text in limited ISO-2022 manner that is
41 ;; based on early experiences in Japanese Internet community and
42 ;; resulted in RFC 1468 (ISO-2022-JP charset for MIME). In order to
43 ;; enable multilingual capability in single text message in MIME,
44 ;; charset of multilingual text written in Mule is declared as either
45 ;; `ISO-2022-JP-2' [RFC 1554] or `ISO-2022-INT-1'. Mule is required
46 ;; for reading the such messages.
47
48 ;; This MIME composer can work with Mail mode, mh-e letter Mode, and
49 ;; News mode.  First of all, you need the following autoload
50 ;; definition to load mime/editor-mode automatically:
51 ;;
52 ;; (autoload 'mime/editor-mode "tm-edit"
53 ;;           "Minor mode for editing MIME message." t)
54 ;;
55 ;; In case of Mail mode (includes VM mode), you need the following
56 ;; hook definition:
57 ;;
58 ;; (add-hook 'mail-mode-hook 'mime/editor-mode)
59 ;; (add-hook 'mail-send-hook 'mime-editor/maybe-translate)
60 ;;
61 ;; In case of MH-E, you need the following hook definition:
62 ;;
63 ;; (add-hook 'mh-letter-mode-hook
64 ;;           (function
65 ;;            (lambda ()
66 ;;              (mime/editor-mode)
67 ;;              (make-local-variable 'mail-header-separator)
68 ;;              (setq mail-header-separator "--------")
69 ;;              ))))
70 ;; (add-hook 'mh-before-send-letter-hook 'mime-editor/maybe-translate)
71 ;;
72 ;; In case of News mode, you need the following hook definition:
73 ;;
74 ;; (add-hook 'news-reply-mode-hook 'mime/editor-mode)
75 ;; (add-hook 'news-inews-hook 'mime-editor/maybe-translate)
76 ;;
77 ;; In case of Emacs 19, it is possible to emphasize the message tags
78 ;; using font-lock mode as follows:
79 ;;
80 ;; (add-hook 'mime/editor-mode-hook
81 ;;           (function
82 ;;            (lambda ()
83 ;;              (font-lock-mode 1)
84 ;;              (setq font-lock-keywords (list mime-editor/tag-regexp))
85 ;;              ))))
86
87 ;; The message tag looks like:
88 ;;
89 ;;      --[[TYPE/SUBTYPE;PARAMETERS][ENCODING]]
90 ;;
91 ;; The tagged MIME message examples:
92 ;;
93 ;; This is a conventional plain text.  It should be translated into
94 ;; text/plain.
95 ;; 
96 ;;--[[text/plain]]
97 ;; This is also a plain text.  But, it is explicitly specified as is.
98 ;;
99 ;;--[[text/plain; charset=ISO-2022-JP]]
100 ;; \e$B$3$l$O\e(B charset \e$B$r\e(B ISO-2022-JP \e$B$K;XDj$7$?F|K\8l$N\e(B plain \e$B%F%-%9%H$G$9\e(B.
101 ;;
102 ;;--[[text/richtext]]
103 ;; <center>This is a richtext.</center>
104 ;;
105 ;;--[[image/gif][base64]]^M...image encoded in base64 comes here...
106 ;;
107 ;;--[[audio/basic][base64]]^M...audio encoded in base64 comes here...
108
109 ;;; Code:
110
111 (require 'sendmail)
112 (require 'mail-utils)
113 (require 'mel)
114 (require 'tl-822)
115 (require 'tl-list)
116 (require 'tm-view)
117 (require 'tm-ew-e)
118 (require 'signature)
119
120
121 ;;; @ version
122 ;;;
123
124 (defconst mime-editor/RCS-ID
125   "$Id: tm-edit.el,v 7.40 1996/01/14 05:52:49 morioka Exp $")
126
127 (defconst mime-editor/version (get-version-string mime-editor/RCS-ID))
128
129
130 ;;; @ variables
131 ;;;
132
133 (defvar mime-prefix "\C-c\C-x"
134   "*Keymap prefix for MIME commands.")
135
136 (defvar mime-signature-file "~/.signature.rtf"
137   "*Signature file to be included as a part of a multipart message.")
138
139 (defvar mime-ignore-preceding-spaces nil
140   "*Ignore preceding white spaces if non-nil.")
141
142 (defvar mime-ignore-trailing-spaces nil
143   "*Ignore trailing white spaces if non-nil.")
144
145 (defvar mime-ignore-same-text-tag t
146   "*Ignore preceding text content-type tag that is same with new one.
147 If non-nil, the text tag is not inserted unless something different.")
148
149 (defvar mime-auto-hide-body t
150   "*Hide non-textual body encoded in base64 after insertion if non-nil.")
151
152 (defvar mime-string-encoder
153   (cond ((boundp 'NEMACS)
154          (function mime-string-encoder-for-nemacs))
155         ((featurep 'mule)
156          (function mime-string-encoder-for-mule))
157         ((string-match "^19\\." emacs-version)
158          (function mime-string-encoder-for-emacs19))
159         (t                              ;ASCII only emacs
160          (function mime-string-encoder-for-emacs18)))
161   "*Function to encode a string for given encoding method.
162 The method is a form of (CHARSET . ENCODING).")
163
164 (defvar mime-voice-recorder
165   (function mime-voice-recorder-for-sun)
166   "*Function to record a voice message and return a buffer that contains it.")
167
168 (defvar mime/editor-mode-hook nil
169   "*Hook called when enter MIME mode.")
170
171 (defvar mime-editor/translate-hook nil
172   "*Hook called before translating into a MIME compliant message.
173 To insert a signature file specified by mime-signature-file
174 (`.signature.rtf' by default) automatically, call the function
175 `mime-editor/insert-signature' from this hook.")
176
177 (defvar mime-editor/exit-hook nil
178   "*Hook called when exit MIME mode.")
179
180 (defvar mime-content-types
181   '(("text"
182      ;; Charset parameter need not to be specified, since it is
183      ;; defined automatically while translation.
184      ("plain"
185       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
186       )
187      ("richtext"
188       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
189       )
190      ("enriched"
191       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
192       )
193      ("x-latex"
194       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
195       )
196      ("html"
197       ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8")
198       )
199      ("x-rot13-47")
200      )
201     ("message"
202      ("external-body"
203       ("access-type"
204        ("anon-ftp"
205         ("site" "ftp.jaist.ac.jp" "wnoc-fuk.wide.ad.jp" "nic.karrn.ad.jp")
206         ("directory" "/pub/GNU/elisp/mime")
207         ("name")
208         ("mode" "image" "ascii" "local8"))
209        ("ftp"
210         ("site")
211         ("directory")
212         ("name")
213         ("mode" "image" "ascii" "local8"))
214        ("tftp"        ("site") ("name"))
215        ("afs"         ("site") ("name"))
216        ("local-file"  ("site") ("name"))
217        ("mail-server" ("server" "ftpmail@nic.karrn.ad.jp"))
218        ))
219      ("rfc822")
220      )
221     ("application"
222      ("octet-stream" ("type" "" "tar" "shar"))
223      ("postscript")
224      ("x-kiss" ("x-cnf")))
225     ("image"
226      ("gif")
227      ("jpeg")
228      ("tiff")
229      ("x-pic")
230      ("x-mag")
231      ("x-xwd")
232      ("x-xbm")
233      )
234     ("audio" ("basic"))
235     ("video" ("mpeg"))
236     )
237   "*Alist of content-type, subtype, parameters and its values.")
238
239 (defvar mime-file-types
240   '(("\\.rtf$"
241      "text"     "richtext"      nil
242      nil
243      nil                nil)
244     ("\\.html$"
245      "text"     "html"          nil
246      nil
247      nil                nil)
248     ("\\.ps$"
249      "application" "postscript" nil
250      "quoted-printable"
251      "attachment"       (("filename" . file))
252      )
253     ("\\.jpg$"
254      "image"    "jpeg"          nil
255      "base64"
256      "inline"           (("filename" . file))
257      )
258     ("\\.gif$"
259      "image"    "gif"           nil
260      "base64"
261      "inline"           (("filename" . file))
262      )
263     ("\\.tiff$"
264      "image"    "tiff"          nil
265      "base64"
266      "inline"           (("filename" . file))
267      )
268     ("\\.pic$"
269      "image"    "x-pic"         nil
270      "base64"
271      "inline"           (("filename" . file))
272      )
273     ("\\.mag$"
274      "image"    "x-mag"         nil
275      "base64"
276      "inline"           (("filename" . file))
277      )
278     ("\\.xbm$"
279      "image"    "x-xbm"         nil
280      "base64"
281      "inline"           (("filename" . file))
282      )
283     ("\\.xwd$"
284      "image"    "x-xwd"         nil
285      "base64"
286      "inline"           (("filename" . file))
287      )
288     ("\\.au$"
289      "audio"    "basic"         nil
290      "base64"
291      "attachment"               (("filename" . file))
292      )
293     ("\\.mpg$"
294      "video"    "mpeg"          nil
295      "base64"
296      "attachment"       (("filename" . file))
297      )
298     ("\\.el$"
299      "application" "octet-stream" (("type" . "emacs-lisp"))
300      "7bit"
301      "attachment"       (("filename" . file))
302      )
303     ("\\.lsp$"
304      "application" "octet-stream" (("type" . "common-lisp"))
305      "7bit"
306      "attachment"       (("filename" . file))
307      )
308     ("\\.tar.gz$"
309      "application" "octet-stream" (("type" . "tar+gzip"))
310      nil
311      "attachment"       (("filename" . file))
312      )
313     ("\\.diff$"
314      "application" "octet-stream" (("type" . "patch"))
315      nil
316      "attachment"       (("filename" . file))
317      )
318     ("\\.signature"
319      "text"     "plain"         nil     nil)
320     (".*"       nil             nil     nil     nil)
321     )
322   "*Alist of file name, types, parameters, and default encoding.
323 If encoding is nil, it is determined from its contents.")
324
325 ;;; @@ about message inserting
326 ;;;
327
328 (defvar mime-editor/yank-ignored-field-list
329   '("Received" "Sender" "Approved" "Path" "Status" "X-VM-.*" "X-UIDL")
330   "Delete these fields from original message when it is inserted
331 as message/rfc822 part.
332 Each elements are regexp of field-name. [tm-edit.el]")
333
334 (defvar mime-editor/yank-ignored-field-regexp
335   (concat "^"
336           (apply (function regexp-or) mime-editor/yank-ignored-field-list)
337           ":"))
338
339 (defvar mime-editor/message-inserter-alist nil)
340 (defvar mime-editor/mail-inserter-alist nil)
341
342 ;;; @@ about message splitting
343 ;;;
344
345 (defvar mime-editor/split-message t
346   "*Split large message if it is non-nil. [tm-edit.el]")
347
348 (defvar mime-editor/message-default-max-length 1000
349   "*Default maximum size of a message. [tm-edit.el]")
350
351 (defvar mime-editor/message-max-length-alist
352   '((news-reply-mode . 500)))
353
354 (defconst mime-editor/split-ignored-field-regexp
355   "\\(^Content-\\|^Subject:\\|^Mime-Version:\\)")
356
357 (defvar mime-editor/split-blind-field-regexp
358   "\\(^[BDFbdf]cc:\\|^cc:[ \t]*$\\)")
359
360 (defvar mime-editor/message-default-sender-alist
361   '((mail-mode . mail-send-and-exit)
362     (mh-letter-mode . mh-send-letter)
363     (news-reply-mode . gnus-inews-news)
364     ))
365
366 (defvar mime-editor/split-message-sender-alist
367   '((mail-mode
368      . (lambda ()
369          (interactive)
370          (sendmail-send-it)
371          ))
372     (mh-letter-mode
373      . (lambda (&optional arg)
374          (interactive "P")
375          (write-region (point-min) (point-max)
376                        mime-editor/draft-file-name nil 'no-message)
377          (cond (arg
378                 (pop-to-buffer "MH mail delivery")
379                 (erase-buffer)
380                 (mh-exec-cmd-output mh-send-prog t "-watch" "-nopush"
381                                     "-nodraftfolder"
382                                     mh-send-args mime-editor/draft-file-name)
383                 (goto-char (point-max)) ; show the interesting part
384                 (recenter -1)
385                 (sit-for 1))
386                (t
387                 (apply 'mh-exec-cmd-quiet t mh-send-prog 
388                        (mh-list-to-string
389                         (list "-nopush" "-nodraftfolder"
390                               "-noverbose" "-nowatch"
391                               mh-send-args mime-editor/draft-file-name)))))
392          ))
393     ))
394
395 (defvar mime-editor/window-config-alist
396   '((mail-mode       . nil)
397     (mh-letter-mode  . mh-previous-window-config)
398     (news-reply-mode . (cond ((boundp 'gnus-winconf-post-news)
399                               (prog1
400                                   gnus-winconf-post-news
401                                 (setq gnus-winconf-post-news nil)
402                                 ))
403                              ((boundp 'gnus-prev-winconf)
404                               (prog1
405                                   gnus-prev-winconf
406                                 (setq gnus-prev-winconf nil)
407                                 ))
408                              ))
409     ))
410
411 (defvar mime-editor/news-reply-mode-server-running nil)
412
413
414 ;;; @@ about PGP
415 ;;;
416
417 (defvar mime-editor/signing-type nil
418   "*PGP signing type (pgp-elkins, pgp-kazu or nil). [tm-edit.el]")
419
420 (defvar mime-editor/encrypting-type nil
421   "*PGP encrypting type (pgp-elkins, pgp-kazu or nil). [tm-edit.el]")
422
423 (if (or mime-editor/signing-type mime-editor/encrypting-type)
424     (require 'mailcrypt)
425   )
426
427
428 ;;; @@ about tag
429 ;;;
430
431 (defconst mime-editor/single-part-tag-regexp
432   "^--[[][[]\\([^]]*\\)]\\([[]\\([^]]*\\)]\\|\\)]"
433   "*Regexp of MIME tag in the form of [[CONTENT-TYPE][ENCODING]].")
434
435 (defconst mime-editor/multipart-beginning-regexp "^--<<\\([^<>]+\\)>>-{\n")
436
437 (defconst mime-editor/multipart-end-regexp "^--}-<<\\([^<>]+\\)>>\n")
438
439 (defconst mime-editor/beginning-tag-regexp
440   (regexp-or mime-editor/single-part-tag-regexp
441              mime-editor/multipart-beginning-regexp))
442
443 (defconst mime-editor/end-tag-regexp
444   (regexp-or mime-editor/single-part-tag-regexp
445              mime-editor/multipart-end-regexp))
446
447 (defconst mime-editor/tag-regexp
448   (regexp-or mime-editor/single-part-tag-regexp
449              mime-editor/multipart-beginning-regexp
450              mime-editor/multipart-end-regexp))
451
452 (defvar mime-tag-format "--[[%s]]"
453   "*Control-string making a MIME tag.")
454
455 (defvar mime-tag-format-with-encoding "--[[%s][%s]]"
456   "*Control-string making a MIME tag with encoding.")
457
458 ;;; @@ multipart boundary
459 ;;;
460
461 (defvar mime-multipart-boundary "Multipart"
462   "*Boundary of a multipart message.")
463
464
465 ;;; @@ buffer local variables
466 ;;;
467
468 (defvar mime/editor-mode-old-local-map nil)
469 (defvar mime/editor-mode-old-selective-display nil)
470 (defvar mime/editing-buffer nil)
471
472 \f
473 ;;; @ constants
474 ;;;
475
476 (defconst mime-tspecials-regexp "[][()<>@,;:\\\"/?.= \t]"
477   "*Specify MIME tspecials.
478 Tspecials means any character that matches with it in header must be quoted.")
479
480 (defconst mime-editor/mime-version-value
481   (format "1.0 (generated by tm-edit %s)" mime-editor/version)
482   "MIME version number.")
483
484
485 ;;; @ keymap and menu
486 ;;;
487
488 (defvar mime/editor-mode-flag nil)
489 (make-variable-buffer-local 'mime/editor-mode-flag)
490
491 (set-alist 'minor-mode-alist 'mime/editor-mode-flag '(" MIME-Edit"))
492
493 (defun mime-editor/define-keymap (keymap)
494   "Add mime-editor commands to KEYMAP."
495   (if (not (keymapp keymap))
496       nil
497     (define-key keymap "\C-t" 'mime-editor/insert-text)
498     (define-key keymap "\C-i" 'mime-editor/insert-file)
499     (define-key keymap "\C-e" 'mime-editor/insert-external)
500     (define-key keymap "\C-v" 'mime-editor/insert-voice)
501     (define-key keymap "\C-y" 'mime-editor/insert-message)
502     (define-key keymap "\C-m" 'mime-editor/insert-mail)
503     (define-key keymap "\C-w" 'mime-editor/insert-signature)
504     (define-key keymap "\C-s" 'mime-editor/insert-signature)
505     (define-key keymap "\C-k" 'mime-editor/insert-key)
506     (define-key keymap "t"    'mime-editor/insert-tag)
507     (define-key keymap "a"    'mime-editor/enclose-alternative-region)
508     (define-key keymap "p"    'mime-editor/enclose-parallel-region)
509     (define-key keymap "m"    'mime-editor/enclose-mixed-region)
510     (define-key keymap "d"    'mime-editor/enclose-digest-region)
511     (define-key keymap "s"    'mime-editor/enclose-signed-region)
512     (define-key keymap "e"    'mime-editor/enclose-encrypted-region)
513     (define-key keymap "\C-p" 'mime-editor/preview-message)
514     (define-key keymap "\C-z" 'mime-editor/exit)
515     (define-key keymap "?"    'mime-editor/help)
516     ))
517
518 (defconst mime-editor/menu-title "MIME-Edit")
519
520 (defconst mime-editor/menu-list
521   (nconc
522    '((mime-help "Describe MIME editor mode" mime-editor/help)
523      (file      "Insert File"           mime-editor/insert-file)
524      (external  "Insert External"       mime-editor/insert-external)
525      (voice     "Insert Voice"          mime-editor/insert-voice)
526      (message   "Insert Message"        mime-editor/insert-message)
527      (mail      "Insert Mail"           mime-editor/insert-mail)
528      (signature "Insert Signature"      mime-editor/insert-signature)
529      (text      "Insert Text"           mime-editor/insert-text)
530      (tag       "Insert Tag"            mime-editor/insert-tag)
531      (alternative "Enclose as alternative"
532                   mime-editor/enclose-alternative-region)
533      (parallel  "Enclose as parallel"   mime-editor/enclose-parallel-region)
534      (mixed     "Enclose as serial"     mime-editor/enclose-mixed-region)
535      (digest    "Enclose as digest"     mime-editor/enclose-digest-region)
536      (signed    "Enclose as signed"     mime-editor/enclose-signed-region)
537      (encrypted "Enclose as encrypted"  mime-editor/enclose-encrypted-region)
538      (key       "Insert Public Key"     mime-editor/insert-key)
539      (split     "About split"           mime-editor/set-split)
540      )
541    (if (and (featurep 'mailcrypt)
542             (not (or mime-editor/signing-type mime-editor/encrypting-type)))
543        '((sign    "About sign"       mime-editor/set-sign)
544          (encrypt "About encryption" mime-editor/set-encrypt)
545          ))
546    '((preview   "Preview Message"       mime-editor/preview-message))
547    )
548   "MIME-edit menubar entry.")
549
550 (defun mime-editor/define-menu-for-emacs19 ()
551   "Define menu for Emacs 19."
552   (define-key (current-local-map) [menu-bar mime-edit]
553     (cons mime-editor/menu-title
554           (make-sparse-keymap mime-editor/menu-title)))
555   (mapcar (function
556            (lambda (item)
557              (define-key (current-local-map)
558                (vector 'menu-bar 'mime-edit (car item))
559                (cons (nth 1 item)(nth 2 item))
560                )
561              ))
562           (reverse mime-editor/menu-list)
563           ))
564
565 ;;; modified by Pekka Marjola <pema@niksula.hut.fi>
566 ;;;     1995/9/5 (c.f. [tm-en:69])
567 (defun mime-editor/define-menu-for-xemacs ()
568   "Define menu for Emacs 19."
569   (cond ((featurep 'menubar)
570          (make-local-variable 'current-menubar)
571          (set-buffer-menubar current-menubar)
572          (add-submenu nil
573                       (cons mime-editor/menu-title
574                             (mapcar (function
575                                      (lambda (item)
576                                        (vector (nth 1 item)(nth 2 item)
577                                                mime/editor-mode-flag)
578                                        ))
579                                     mime-editor/menu-list)))
580          )))
581
582 ;;; modified by Steven L. Baur <steve@miranova.com>
583 ;;;     1995/12/6 (c.f. [tm-en:209])
584 (if (and (string-match "XEmacs\\|Lucid" emacs-version)
585          (not (boundp 'mime-editor/popup-menu-for-xemacs)))
586     (setq mime-editor/popup-menu-for-xemacs
587           (append '("MIME Commands" "---")
588                   (mapcar (function (lambda (item)
589                                       (vector (nth 1 item)
590                                               (nth 2 item)
591                                               t)))
592                           mime-editor/menu-list)))
593   )
594 ;;; end
595
596
597 ;;; @ functions
598 ;;;
599
600 ;;;###autoload
601 (defun mime/editor-mode ()
602   "MIME minor mode for editing the tagged MIME message.
603
604 In this mode, basically, the message is composed in the tagged MIME
605 format.  The message tag looks like:
606
607         `--[[text/plain; charset=ISO-2022-JP][7bit]]'.
608
609 The tag specifies the MIME content type, subtype, optional parameters
610 and transfer encoding of the message following the tag.  Messages
611 without any tag are treated as `text/plain' by default.  Charset and
612 transfer encoding are automatically defined unless explicitly
613 specified.  Binary messages such as audio and image are usually hidden
614 using selective-display facility.  The messages in the tagged MIME
615 format are automatically translated into a MIME compliant message when
616 exiting this mode.
617
618 Available charsets depend on Emacs version being used.  The following
619 lists the available charsets of each emacs.
620
621 Emacs18:        US-ASCII is only available.
622 NEmacs:         US-ASCII and ISO-2022-JP are available.
623 Emacs19:        US-ASCII and ISO-8859-1 are available.
624 Mule:           US-ASCII, ISO-8859-* (except for ISO-8859-6),
625                 ISO-2022-JP, ISO-2022-JP-2 and ISO-2022-INT-1 are available.
626
627 ISO-2022-JP-2 and ISO-2022-INT-1 charsets used in Mule is expected to
628 be used to represent multilingual text in intermixed manner.  Any
629 languages that has no registered charset are represented as either
630 ISO-2022-JP-2 or ISO-2022-INT-1 in Mule.
631
632 Following commands are available in addition to major mode commands:
633 \\[mime-editor/insert-text]     insert a text message.
634 \\[mime-editor/insert-file]     insert a (binary) file.
635 \\[mime-editor/insert-external] insert a reference to external body.
636 \\[mime-editor/insert-voice]    insert a voice message.
637 \\[mime-editor/insert-message]  insert a mail or news message.
638 \\[mime-editor/insert-mail]     insert a mail message.
639 \\[mime-editor/insert-signature]        insert a signature file at end.
640 \\[mime-editor/insert-tag]      insert a new MIME tag.
641 \\[mime-editor/enclose-alternative-region]      enclose as multipart/alternative.
642 \\[mime-editor/enclose-parallel-region] enclose as multipart/parallel.
643 \\[mime-editor/enclose-mixed-region]    enclose as multipart/mixed.
644 \\[mime-editor/enclose-digest-region]   enclose as multipart/digest.
645 \\[mime-editor/enclose-signed-region]   enclose as PGP signed.
646 \\[mime-editor/enclose-encrypted-region]        enclose as PGP encrypted.
647 \\[mime-editor/insert-key]      insert PGP public key.
648 \\[mime-editor/preview-message] preview editing MIME message.
649 \\[mime-editor/exit]    exit and translate into a MIME compliant message.
650 \\[mime-editor/maybe-translate] exit, translate and run the original command.
651 \\[mime-editor/help]    show this help.
652
653 Additional commands are available in some major modes:
654 C-c C-c         exit, translate and run the original command.
655 C-c C-s         exit, translate and run the original command.
656
657 The following is a message example written in the tagged MIME format.
658 TABs at the beginning of the line are not a part of the message:
659
660         This is a conventional plain text.  It should be translated
661         into text/plain.
662         --[[text/plain]]
663         This is also a plain text.  But, it is explicitly specified as
664         is.
665         --[[text/plain; charset=ISO-2022-JP]]
666         \e$B$3$l$O\e(B charset \e$B$r\e(B ISO-2022-JP \e$B$K;XDj$7$?F|K\8l$N\e(B plain \e$B%F%-%9\e(B
667         \e$B%H$G$9\e(B.
668         --[[text/richtext]]
669         <center>This is a richtext.</center>
670         --[[image/gif][base64]]^M...image encoded in base64 here...
671         --[[audio/basic][base64]]^M...audio encoded in base64 here...
672
673 User customizable variables (not documented all of them):
674  mime-prefix
675     Specifies a key prefix for MIME minor mode commands.
676
677  mime-signature-file
678     Specifies a signature file to be included as part of a multipart
679     message.
680
681  mime-ignore-preceding-spaces
682     Preceding white spaces in a message body are ignored if non-nil.
683
684  mime-ignore-trailing-spaces
685     Trailing white spaces in a message body are ignored if non-nil.
686
687  mime-auto-fill-header
688     Fill header fields that contain encoded-words if non-nil.
689
690  mime-auto-hide-body
691     Hide a non-textual body message encoded in base64 after insertion
692     if non-nil.
693
694  mime-string-encoder
695     Specifies a function to encode a string for given encoding method.
696     The method is a form of (CHARSET . ENCODING).
697
698  mime-voice-recorder
699     Specifies a function to record a voice message and return a buffer
700     that contains it.  The function mime-voice-recorder-for-sun is for
701     Sun SparcStations.
702
703  mime/editor-mode-hook
704     Turning on MIME mode calls the value of mime/editor-mode-hook, if
705     it is non-nil.
706
707  mime-editor/translate-hook
708     The value of mime-editor/translate-hook is called just before translating
709     the tagged MIME format into a MIME compliant message if it is
710     non-nil.  If the hook call the function mime-editor/insert-signature,
711     the signature file will be inserted automatically.
712
713  mime-editor/exit-hook
714     Turning off MIME mode calls the value of mime-editor/exit-hook, if it is
715     non-nil."
716   (interactive)
717   (if mime/editor-mode-flag
718       (error "You are already editing a MIME message.")
719     (setq mime/editor-mode-flag t)
720     ;; Remember old key bindings.
721     (make-local-variable 'mime/editor-mode-old-local-map)
722     (setq mime/editor-mode-old-local-map (current-local-map))
723     ;; Add MIME commands to current local map.
724     (use-local-map (copy-keymap (current-local-map)))
725     (if (not (lookup-key (current-local-map) mime-prefix))
726         (define-key (current-local-map) mime-prefix (make-sparse-keymap)))
727     (mime-editor/define-keymap (lookup-key (current-local-map) mime-prefix))
728     
729     ;; Define menu.  Menus for other emacs implementations are
730     ;; welcome.
731     ;;  modified by Pekka Marjola <pema@niksula.hut.fi>
732     ;;          1995/9/5 (c.f. [tm-eng:69])
733     (cond ((string-match "XEmacs\\|Lucid" emacs-version)
734            (mime-editor/define-menu-for-xemacs))
735           ((string-match "^19\\." emacs-version)
736            (mime-editor/define-menu-for-emacs19)
737            ))
738     ;; end
739     
740     ;; Remember old selective-display.
741     (make-local-variable 'mime/editor-mode-old-selective-display)
742     (setq mime/editor-mode-old-selective-display selective-display)
743     (setq selective-display t)
744     ;; I don't care about saving these.
745     (setq paragraph-start
746           (regexp-or mime-editor/single-part-tag-regexp
747                      paragraph-start))
748     (setq paragraph-separate
749           (regexp-or mime-editor/single-part-tag-regexp
750                      paragraph-separate))
751     (run-hooks 'mime/editor-mode-hook)
752     (message
753      (substitute-command-keys
754       "Type \\[mime-editor/exit] to exit MIME mode, and type \\[mime-editor/help] to get help."))
755     ))
756
757 ;;;###autoload
758 (defalias 'edit-mime 'mime/editor-mode)         ; for convenience
759 (defalias 'mime-mode 'mime/editor-mode)         ; for convenience
760
761 (defun mime-editor/exit (&optional nomime no-error)
762   "Translate the tagged MIME message into a MIME compliant message.
763 With no argument encode a message in the buffer into MIME, otherwise
764 just return to previous mode."
765   (interactive "P")
766   (if (not mime/editor-mode-flag)
767       (if (null no-error)
768           (error "You aren't editing a MIME message.")
769         )
770     (if (not nomime)
771         (progn
772           (run-hooks 'mime-editor/translate-hook)
773           (mime-editor/translate-buffer)))
774     ;; Restore previous state.
775     (setq mime/editor-mode-flag nil)
776     (use-local-map mime/editor-mode-old-local-map)
777     
778     ;; modified by Pekka Marjola <pema@niksula.hut.fi>
779     ;;  1995/9/5 (c.f. [tm-eng:69])
780     (if (string-match "XEmacs\\|Lucid" emacs-version)
781         (progn
782           (delete-menu-item (list mime-editor/menu-title))
783                                         ; should rather be const
784           ;; (while mime-editor/xemacs-old-bindings
785           ;;   (eval (pop mime-editor/xemacs-old-bindings)))
786           (local-unset-key mime-prefix)))
787     ;; end
788     
789     (setq selective-display mime/editor-mode-old-selective-display)
790     (set-buffer-modified-p (buffer-modified-p))
791     (run-hooks 'mime-editor/exit-hook)
792     (message "Exit MIME editor mode.")
793     ))
794
795 (defun mime-editor/maybe-translate ()
796   (interactive)
797   (mime-editor/exit nil t)
798   (call-interactively 'mime-editor/maybe-split-and-send)
799   )
800
801 (defun mime-editor/help ()
802   "Show help message about MIME mode."
803   (interactive)
804   (with-output-to-temp-buffer "*Help*"
805     (princ "MIME editor mode:\n")
806     (princ (documentation 'mime/editor-mode))
807     (print-help-return-message)))
808
809 (defun mime-editor/insert-text ()
810   "Insert a text message.
811 Charset is automatically obtained from the `mime/lc-charset-alist'."
812   (interactive)
813   (if (and (mime-editor/insert-tag "text" nil nil)
814            (looking-at mime-editor/single-part-tag-regexp))
815       (progn
816         ;; Make a space between the following message.
817         (insert "\n")
818         (forward-char -1)
819         )))
820
821 (defun mime-editor/insert-file (file)
822   "Insert a message from a file."
823   (interactive "fInsert file as MIME message: ")
824   (let*  ((guess (mime-find-file-type file))
825           (pritype (nth 0 guess))
826           (subtype (nth 1 guess))
827           (parameters (nth 2 guess))
828           (default (nth 3 guess))       ;Guess encoding from its file name.
829           (disposition-type (nth 4 guess))
830           (disposition-params (nth 5 guess))
831           (encoding
832            (if (not (interactive-p))
833                default
834              (completing-read
835               (concat "What transfer encoding"
836                       (if default
837                           (concat " (default "
838                                   (if (string-equal default "")
839                                       "\"\""
840                                     default)
841                                   ")"
842                                   ))
843                       ": ")
844               mime-encoding-method-alist nil t nil))))
845     (if (string-equal encoding "")
846         (setq encoding default))
847     (if (or (consp parameters) (stringp disposition-type))
848         (let ((rest parameters) cell attribute value)
849           (setq parameters "")
850           (while rest
851             (setq cell (car rest))
852             (setq attribute (car cell))
853             (setq value (cdr cell))
854             (if (eq value 'file)
855                 (setq value (file-name-nondirectory file))
856               )
857             (setq parameters (concat parameters "; " attribute "=" value))
858             (setq rest (cdr rest))
859             )
860           (if disposition-type
861               (progn
862                 (setq parameters
863                       (concat parameters "\n"
864                               "Content-Disposition: " disposition-type))
865                 (setq rest disposition-params)
866                 (while rest
867                   (setq cell (car rest))
868                   (setq attribute (car cell))
869                   (setq value (cdr cell))
870                   (if (eq value 'file)
871                       (setq value (file-name-nondirectory file))
872                     )
873                   (setq parameters
874                         (concat parameters "; " attribute "=" value))
875                   (setq rest (cdr rest))
876                   )
877                 ))
878           ))
879     (mime-editor/insert-tag pritype subtype parameters)
880     (mime-editor/insert-binary-file file encoding)
881     ))
882
883 (defun mime-editor/insert-external ()
884   "Insert a reference to external body."
885   (interactive)
886   (mime-editor/insert-tag "message" "external-body" nil ";\n\t")
887   ;;(forward-char -1)
888   ;;(insert "Content-Description: " (read-string "Content-Description: ") "\n")
889   ;;(forward-line 1)
890   (let* ((pritype (mime-prompt-for-type))
891          (subtype (mime-prompt-for-subtype pritype))
892          (parameters (mime-prompt-for-parameters pritype subtype ";\n\t")))
893     (and pritype
894          subtype
895          (insert "Content-Type: "
896                  pritype "/" subtype (or parameters "") "\n")))
897   (if (and (not (eobp))
898            (not (looking-at mime-editor/single-part-tag-regexp)))
899       (insert (mime-make-text-tag) "\n")))
900
901 (defun mime-editor/insert-voice ()
902   "Insert a voice message."
903   (interactive)
904   (mime-editor/insert-tag "audio" "basic" nil)
905   (let ((buffer (funcall mime-voice-recorder)))
906     (unwind-protect
907         (mime-editor/insert-binary-buffer buffer "base64")
908       (kill-buffer buffer)
909       )))
910
911 (defun mime-editor/insert-signature (&optional arg)
912   "Insert a signature file specified by mime-signature-file."
913   (interactive "P")
914   (let ((signature
915          (expand-file-name
916           (if arg
917               (read-file-name "Insert your signature: "
918                               (concat signature-file-name "-")
919                               signature-file-name
920                               nil)
921             (signature/get-signature-file-name))))
922         )
923     (if signature-insert-at-eof
924         (goto-char (point-max))
925       )
926     (apply (function mime-editor/insert-tag)
927            (mime-find-file-type signature))
928     (if (file-readable-p signature)
929         (progn
930           (goto-char (point-max))
931           (if (not (bolp))
932               (insert "\n"))
933           (delete-blank-lines)
934           (insert-file-contents signature)
935           (set-buffer-modified-p (buffer-modified-p))
936                                         ; force mode line update
937           ))))
938
939 \f
940 ;; Insert a new tag around a point.
941
942 (defun mime-editor/insert-tag (&optional pritype subtype parameters delimiter)
943   "Insert new MIME tag and return a list of PRITYPE, SUBTYPE, and PARAMETERS.
944 If nothing is inserted, return nil."
945   (interactive)
946   (let ((oldtag nil)
947         (newtag nil)
948         (current (point))
949         exist-prev-tag exist-next-tag)
950     (setq pritype
951           (or pritype
952               (mime-prompt-for-type)))
953     (setq subtype
954           (or subtype
955               (mime-prompt-for-subtype pritype)))
956     (setq parameters
957           (or parameters
958               (mime-prompt-for-parameters pritype subtype delimiter)))
959     ;; Make a new MIME tag.
960     (setq newtag (mime-make-tag pritype subtype parameters))
961     ;; Find an current MIME tag.
962     (setq oldtag
963           (save-excursion
964             (if (mime-editor/goto-tag)
965                 (progn
966                   (if (eq current (match-beginning 0))
967                       (setq exist-next-tag t)
968                     (setq exist-prev-tag t)
969                     )
970                   (buffer-substring (match-beginning 0) (match-end 0))
971                   )
972               ;; Assume content type is 'text/plan'.
973               (mime-make-tag "text" "plain")
974               )))
975     ;; We are only interested in TEXT.
976     (if (and oldtag
977              (not (mime-test-content-type
978                    (mime-editor/get-contype oldtag) "text")))
979         (setq oldtag nil))
980     (cond (exist-prev-tag (insert "\n"))
981           (exist-next-tag (save-excursion
982                             (insert "\n")
983                             )))
984     ;; (beginning-of-line)
985     ;; (cond ((and oldtag                  ;Text
986     ;;             (not (eobp))
987     ;;             (save-excursion
988     ;;               (forward-line -1)
989     ;;               (looking-at mime-editor/beginning-tag-regexp)
990     ;;               )
991     ;;             (or mime-ignore-same-text-tag
992     ;;                 (not (string-equal oldtag newtag))))
993     ;;        ;; If point is at the next of current tag, move to the
994     ;;        ;; beginning of the tag to disable insertion of extra tag.
995     ;;        (forward-line -1))
996     ;;       ((and oldtag                  ;Text
997     ;;             (not (eobp))
998     ;;             (not (looking-at mime-editor/tag-regexp))
999     ;;             (or mime-ignore-same-text-tag
1000     ;;                 (not (string-equal oldtag newtag))))
1001     ;;        ;; Copy current tag to break a text into two.
1002     ;;        (save-excursion
1003     ;;          (insert oldtag "\n")))
1004     ;;       ((and (null oldtag)           ;Not text
1005     ;;             (not (looking-at mime-editor/tag-regexp)))
1006     ;;        ;; Adjust insertion point.  In the middle of text, it is
1007     ;;        ;; okay to break the text into two.  However, it should not
1008     ;;        ;; be broken into two, if otherwise.
1009     ;;        (goto-char (mime-editor/content-end))
1010     ;;        (if (eolp)
1011     ;;            (forward-line 1))
1012     ;;        (if (not (bolp))
1013     ;;            (insert "\n"))
1014     ;;        ))
1015     (if (not (bolp))
1016         (if exist-prev-tag
1017             (forward-line 1)
1018           (insert "\n")
1019           ))
1020     ;; Make a new tag.
1021     (if (or (not oldtag)                ;Not text
1022             (or mime-ignore-same-text-tag
1023                 (not (string-equal oldtag newtag))))
1024         (progn
1025           ;; Mark the beginning of the tag for convenience.
1026           (push-mark (point) 'nomsg)
1027           (insert newtag "\n")
1028           (list pritype subtype parameters) ;New tag is created.
1029           )
1030       ;; Restore previous point.
1031       (goto-char current)
1032       nil                               ;Nothing is created.
1033       )
1034     ))
1035
1036 ;; Insert the binary content after MIME tag.
1037 ;;      modified by MORITA Masahiro <hiro@isl.ntt.JP>
1038 ;;      for x-uue
1039 (defun mime-editor/insert-binary-file (file &optional encoding)
1040   "Insert binary FILE at point.
1041 Optional argument ENCODING specifies an encoding method such as base64."
1042   (let ((tmpbuf (get-buffer-create " *MIME insert*")))
1043     (save-excursion
1044       (set-buffer tmpbuf)
1045       (erase-buffer)
1046       (let ((mc-flag nil)               ;Mule
1047             (file-coding-system-for-read
1048              (if (featurep 'mule) *noconv*))
1049             (kanji-flag nil)            ;NEmacs
1050             (emx-binary-mode t)         ;Stop CRLF to LF conversion in OS/2
1051             )
1052         (let (jka-compr-compression-info-list
1053               jam-zcat-filename-list)
1054           (insert-file-contents file))))
1055     (prog1
1056         (if (and (stringp encoding)
1057                  (string-equal (downcase encoding) "x-uue"))
1058             (progn
1059               (require 'mel-u)
1060               (let ((uuencode-external-encoder
1061                      (cons (car uuencode-external-encoder)
1062                            (list (file-name-nondirectory file))
1063                            )))
1064                 (mime-editor/insert-binary-buffer tmpbuf encoding)
1065                 ))
1066           (mime-editor/insert-binary-buffer tmpbuf encoding))
1067       (kill-buffer tmpbuf))))
1068
1069 ;; Insert the binary content after MIME tag.
1070 ;;      modified by MORITA Masahiro <hiro@isl.ntt.JP>
1071 ;;      for x-uue
1072 (defun mime-editor/insert-binary-buffer (buffer &optional encoding)
1073   "Insert binary BUFFER at point.
1074 Optional argument ENCODING specifies an encoding method such as base64."
1075   (let* ((tagend (1- (point)))          ;End of the tag
1076          (hide-p (and mime-auto-hide-body
1077                       (stringp encoding)
1078                       (let ((en (downcase encoding)))
1079                         (or (string-equal en "base64")
1080                             (string-equal en "x-uue")
1081                             ))))
1082          )
1083     (save-restriction
1084       (narrow-to-region (1- (point)) (point))
1085       (let ((start (point))
1086             (emx-binary-mode t))        ;Stop LF to CRLF conversion in OS/2
1087         (insert-buffer-substring buffer)
1088         ;; Encode binary message if necessary.
1089         (if encoding
1090             (mime-encode-region encoding start (point-max))))
1091       (if hide-p
1092           (progn
1093             (mime-flag-region (point-min) (1- (point-max)) ?\^M)
1094             (goto-char (point-max)))
1095         ))
1096     ;; Define encoding even if it is 7bit.
1097     (if (stringp encoding)
1098         (save-excursion
1099           (goto-char tagend)            ;Make sure which line the tag is on.
1100           (mime-editor/define-encoding encoding)))
1101     ))
1102
1103 \f
1104 ;; Commands work on a current message flagment.
1105
1106 (defun mime-editor/goto-tag ()
1107   "Search for the beginning of the tagged MIME message."
1108   (let ((current (point)) multipart)
1109     (if (looking-at mime-editor/tag-regexp)
1110         t
1111       ;; At first, go to the end.
1112       (cond ((re-search-forward mime-editor/beginning-tag-regexp nil t)
1113              (goto-char (match-beginning 0)) ;For multiline tag
1114              (forward-line -1)
1115              (end-of-line)
1116              )
1117             (t
1118              (goto-char (point-max))
1119              ))
1120       ;; Then search for the beginning. 
1121       (re-search-backward mime-editor/end-tag-regexp nil t)
1122       (beginning-of-line)
1123       (or (looking-at mime-editor/beginning-tag-regexp)
1124           ;; Restore previous point.
1125           (progn
1126             (goto-char current)
1127             nil
1128             ))
1129       )))
1130
1131 (defun mime-editor/content-beginning ()
1132   "Return the point of the beginning of content."
1133   (save-excursion
1134     (let ((beg (save-excursion
1135                  (beginning-of-line) (point))))
1136       (if (mime-editor/goto-tag)
1137           (let ((top (point)))
1138             (goto-char (match-end 0))
1139             (if (and (= beg top)
1140                      (= (following-char) ?\^M))
1141                 (point)
1142               (forward-line 1)
1143               (point)))
1144         ;; Default text/plain tag.
1145         (goto-char (point-min))
1146         (re-search-forward
1147          (concat "\n" (regexp-quote mail-header-separator)
1148                  (if mime-ignore-preceding-spaces
1149                      "[ \t\n]*\n" "\n")) nil 'move)
1150         (point))
1151       )))
1152
1153 (defun mime-editor/content-end ()
1154   "Return the point of the end of content."
1155   (save-excursion
1156     (let ((beg (save-excursion
1157                  (beginning-of-line) (point))))
1158       (if (mime-editor/goto-tag)
1159           (let ((top (point)))
1160             (goto-char (match-end 0))
1161             (if (and (= beg top)        ;Must be on the same line.
1162                      (= (following-char) ?\^M))
1163                 (progn
1164                   (end-of-line)
1165                   (point))
1166               ;; Move to the end of this text.
1167               (if (re-search-forward mime-editor/tag-regexp nil 'move)
1168                   ;; Don't forget a multiline tag.
1169                   (goto-char (match-beginning 0)))
1170               (point)
1171               ))
1172         ;; Assume the message begins with text/plain.
1173         (goto-char (mime-editor/content-beginning))
1174         (if (re-search-forward mime-editor/tag-regexp nil 'move)
1175             ;; Don't forget a multiline tag.
1176             (goto-char (match-beginning 0)))
1177         (point))
1178       )))
1179
1180 (defun mime-editor/define-charset (charset)
1181   "Set charset of current tag to CHARSET."
1182   (save-excursion
1183     (if (mime-editor/goto-tag)
1184         (let ((tag (buffer-substring (match-beginning 0) (match-end 0))))
1185           (delete-region (match-beginning 0) (match-end 0))
1186           (insert
1187            (mime-create-tag (mime-set-parameter
1188                              (mime-editor/get-contype tag) "charset" charset)
1189                             (mime-editor/get-encoding tag))))
1190       )))
1191
1192 (defun mime-editor/define-encoding (encoding)
1193   "Set encoding of current tag to ENCODING."
1194   (save-excursion
1195     (if (mime-editor/goto-tag)
1196         (let ((tag (buffer-substring (match-beginning 0) (match-end 0))))
1197           (delete-region (match-beginning 0) (match-end 0))
1198           (insert (mime-create-tag (mime-editor/get-contype tag) encoding)))
1199       )))
1200
1201 (defun mime-editor/choose-charset ()
1202   "Choose charset of a text following current point."
1203   (mime/find-charset-region (point) (mime-editor/content-end))
1204   )
1205
1206 (defun mime-make-text-tag (&optional subtype)
1207   "Make a tag for a text after current point.
1208 Subtype of text type can be specified by an optional argument SUBTYPE.
1209 Otherwise, it is obtained from mime-content-types."
1210   (let* ((pritype "text")
1211          (subtype (or subtype
1212                       (car (car (cdr (assoc pritype mime-content-types)))))))
1213     ;; Charset should be defined later.
1214     (mime-make-tag pritype subtype)))
1215
1216 \f
1217 ;; Tag handling functions
1218
1219 (defun mime-make-tag (pritype subtype &optional parameters encoding)
1220   "Make a tag of MIME message of PRITYPE, SUBTYPE and optional PARAMETERS."
1221   (mime-create-tag (concat (or pritype "") "/" (or subtype "")
1222                            (or parameters ""))
1223                    encoding))
1224
1225 (defun mime-create-tag (contype &optional encoding)
1226   "Make a tag with CONTENT-TYPE and optional ENCODING."
1227   (format (if encoding mime-tag-format-with-encoding mime-tag-format)
1228           contype encoding))
1229
1230 (defun mime-editor/get-contype (tag)
1231   "Return Content-Type (including parameters) of TAG."
1232   (and (stringp tag)
1233        (or (string-match mime-editor/single-part-tag-regexp tag)
1234            (string-match mime-editor/multipart-beginning-regexp tag)
1235            (string-match mime-editor/multipart-end-regexp tag)
1236            )
1237        (substring tag (match-beginning 1) (match-end 1))
1238        ))
1239
1240 (defun mime-editor/get-encoding (tag)
1241   "Return encoding of TAG."
1242   (and (stringp tag)
1243        (string-match mime-editor/single-part-tag-regexp tag)
1244        (match-beginning 3)
1245        (not (= (match-beginning 3) (match-end 3)))
1246        (substring tag (match-beginning 3) (match-end 3))))
1247
1248 (defun mime-get-parameter (contype parameter)
1249   "For given CONTYPE return value for PARAMETER.
1250 Nil if no such parameter."
1251   (if (string-match
1252        (concat
1253         ";[ \t\n]*"
1254         (regexp-quote parameter)
1255         "[ \t\n]*=[ \t\n]*\\([^\" \t\n;]*\\|\"[^\"]*\"\\)\\([ \t\n]*;\\|$\\)")
1256        contype)
1257       (substring contype (match-beginning 1) (match-end 1))
1258     nil                                 ;No such parameter
1259     ))
1260
1261 (defun mime-set-parameter (contype parameter value)
1262   "For given CONTYPE set PARAMETER to VALUE."
1263   (if (string-match
1264        (concat
1265         ";[ \t\n]*\\("
1266         (regexp-quote parameter)
1267         "[ \t\n]*=[ \t\n]*\\([^\" \t\n;]*\\|\"[^\"]*\"\\)\\)[ \t\n]*\\(;\\|$\\)")
1268        contype)
1269       ;; Change value
1270       (concat (substring contype 0 (match-beginning 1))
1271               parameter "=" value
1272               (substring contype (match-end 1)))
1273     (concat contype "; " parameter "=" value)))
1274
1275 (defun mime-strip-parameters (contype)
1276   "Return primary content-type and subtype without parameters for CONTYPE."
1277   (if (string-match "^[ \t]*\\([^; \t\n]*\\)" contype)
1278       (substring contype (match-beginning 1) (match-end 1)) nil))
1279
1280 (defun mime-test-content-type (contype type &optional subtype)
1281   "Test if CONTYPE is a TYPE and an optional SUBTYPE."
1282   (and (stringp contype)
1283        (stringp type)
1284        (string-match
1285         (concat "^[ \t]*" (downcase type) "/" (downcase (or subtype "")))
1286         (downcase contype))))
1287
1288 \f
1289 ;; Basic functions
1290
1291 (defun mime-find-file-type (file)
1292   "Guess Content-Type, subtype, and parameters from FILE."
1293   (let ((guess nil)
1294         (guesses mime-file-types))
1295     (while (and (not guess) guesses)
1296       (if (string-match (car (car guesses)) file)
1297           (setq guess (cdr (car guesses))))
1298       (setq guesses (cdr guesses)))
1299     guess
1300     ))
1301
1302 (defun mime-prompt-for-type ()
1303   "Ask for Content-type."
1304   (let ((type ""))
1305     ;; Repeat until primary content type is specified.
1306     (while (string-equal type "")
1307       (setq type
1308             (completing-read "What content type: "
1309                              mime-content-types
1310                              nil
1311                              'require-match ;Type must be specified.
1312                              nil
1313                              ))
1314       (if (string-equal type "")
1315           (progn
1316             (message "Content type is required.")
1317             (beep)
1318             (sit-for 1)
1319             ))
1320       )
1321     type
1322     ))
1323
1324 (defun mime-prompt-for-subtype (pritype)
1325   "Ask for Content-type subtype of Content-Type PRITYPE."
1326   (let* ((default (car (car (cdr (assoc pritype mime-content-types)))))
1327          (answer
1328           (completing-read
1329            (if default
1330                (concat
1331                 "What content subtype: (default " default ") ")
1332              "What content subtype: ")
1333            (cdr (assoc pritype mime-content-types))
1334            nil
1335            'require-match               ;Subtype must be specified.
1336            nil
1337            )))
1338     (if (string-equal answer "") default answer)))
1339
1340 (defun mime-prompt-for-parameters (pritype subtype &optional delimiter)
1341   "Ask for Content-type parameters of Content-Type PRITYPE and SUBTYPE.
1342 Optional DELIMITER specifies parameter delimiter (';' by default)."
1343   (let* ((delimiter (or delimiter "; "))
1344          (parameters
1345           (mapconcat
1346            (function identity)
1347            (delq nil
1348                  (mime-prompt-for-parameters-1
1349                   (cdr (assoc subtype
1350                               (cdr (assoc pritype mime-content-types))))))
1351            delimiter
1352            )))
1353     (if (and (stringp parameters)
1354              (not (string-equal parameters "")))
1355         (concat delimiter parameters)
1356       ""                                ;"" if no parameters
1357       )))
1358
1359 (defun mime-prompt-for-parameters-1 (optlist)
1360   (apply (function append)
1361          (mapcar (function mime-prompt-for-parameter) optlist)))
1362
1363 (defun mime-prompt-for-parameter (parameter)
1364   "Ask for PARAMETER.
1365 Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
1366   (let* ((prompt (car parameter))
1367          (choices (mapcar (function
1368                            (lambda (e)
1369                              (if (consp e) e (list e))))
1370                           (cdr parameter)))
1371          (default (car (car choices)))
1372          (answer nil))
1373     (if choices
1374         (progn
1375           (setq answer
1376                 (completing-read
1377                  (concat "What " prompt
1378                          ": (default "
1379                          (if (string-equal default "") "\"\"" default)
1380                          ") ")
1381                  choices nil nil ""))
1382           ;; If nothing is selected, use default.
1383           (if (string-equal answer "")
1384               (setq answer default)))
1385       (setq answer
1386             (read-string (concat "What " prompt ": "))))
1387     (cons (if (and answer
1388                    (not (string-equal answer "")))
1389               (concat prompt "="
1390                       ;; Note: control characters ignored!
1391                       (if (string-match mime-tspecials-regexp answer)
1392                           (concat "\"" answer "\"") answer)))
1393           (mime-prompt-for-parameters-1 (cdr (assoc answer (cdr parameter)))))
1394     ))
1395
1396 (defun mime-encode-string (encoding string)
1397   "Using ENCODING encode a STRING.
1398 If the STRING is too long, the encoded string may be broken into
1399 several lines."
1400   (save-excursion
1401     (set-buffer (get-buffer-create " *MIME encoding*"))
1402     (erase-buffer)
1403     (insert string)
1404     (mime-encode-region encoding (point-min) (point-max))
1405     (prog1
1406         (buffer-substring (point-min) (point-max))
1407       (kill-buffer (current-buffer)))))
1408
1409 (defun mime-decode-string (encoding string)
1410   "Using ENCODING decode a STRING."
1411   (save-excursion
1412     (set-buffer (get-buffer-create " *MIME decoding*"))
1413     (erase-buffer)
1414     (insert string)
1415     (mime-decode-region encoding (point-min) (point-max))
1416     (prog1
1417         (buffer-substring (point-min) (point-max))
1418       (kill-buffer (current-buffer)))))
1419
1420 (defun mime-flag-region (from to flag)
1421   "Hides or shows lines from FROM to TO, according to FLAG.
1422 If FLAG is `\\n' (newline character) then text is shown,
1423 while if FLAG is `\\^M' (control-M) the text is hidden."
1424   (let ((buffer-read-only nil)          ;Okay even if write protected.
1425         (modp (buffer-modified-p)))
1426     (unwind-protect
1427         (subst-char-in-region from to
1428                               (if (= flag ?\n) ?\^M ?\n)
1429                               flag t)
1430       (set-buffer-modified-p modp))))
1431
1432 \f
1433 ;;; @ Translate the tagged MIME messages into a MIME compliant message.
1434 ;;;
1435
1436 (defun mime-editor/translate-buffer ()
1437   "Encode the tagged MIME message in current buffer in MIME compliant message."
1438   (interactive)
1439   (if (catch 'mime-editor/error
1440         (save-excursion
1441           (mime/encode-message-header)
1442           (mime-editor/translate-body)
1443           (mime-editor/pgp-processing)
1444           ))
1445       (progn
1446         (undo)
1447         (error "Translation error!")
1448         )))
1449
1450 (defun mime-editor/find-inmost ()
1451   (goto-char (point-min))
1452   (if (re-search-forward mime-editor/multipart-beginning-regexp nil t)
1453       (let ((bb (match-beginning 0))
1454             (be (match-end 0))
1455             (type (buffer-substring (match-beginning 1)(match-end 1)))
1456             end-exp eb ee)
1457         (setq end-exp (format "^--}-<<%s>>\n" type))
1458         (widen)
1459         (if (re-search-forward end-exp nil t)
1460             (progn
1461               (setq eb (match-beginning 0))
1462               (setq ee (match-end 0))
1463               )
1464           (setq eb (point-max))
1465           (setq ee (point-max))
1466           )
1467         (narrow-to-region be eb)
1468         (goto-char be)
1469         (if (re-search-forward mime-editor/multipart-beginning-regexp nil t)
1470             (let (ret)
1471               (narrow-to-region (match-beginning 0)(point-max))
1472               (mime-editor/find-inmost)
1473               )
1474           (widen)
1475           ;;(delete-region eb ee)
1476           (list type bb be eb)
1477           ))))
1478
1479 (defun mime-editor/process-multipart-1 (boundary)
1480   (let ((ret (mime-editor/find-inmost)))
1481     (if ret
1482         (let ((type (car ret))
1483               (bb (nth 1 ret))(be (nth 2 ret))
1484               (eb (nth 3 ret))
1485               )
1486           (narrow-to-region bb eb)
1487           (delete-region bb be)
1488           (setq bb (point-min))
1489           (setq eb (point-max))
1490           (widen)
1491           (goto-char eb)
1492           (if (looking-at mime-editor/multipart-end-regexp)
1493               (let ((beg (match-beginning 0))
1494                     (end (match-end 0))
1495                     )
1496                 (delete-region beg end)
1497                 (if (and (not (looking-at mime-editor/single-part-tag-regexp))
1498                          (not (eobp)))
1499                     (insert (concat (mime-make-text-tag) "\n"))
1500                   )))
1501           (cond ((string= type "signed")
1502                  (cond ((eq mime-editor/signing-type 'pgp-elkins)
1503                         (mime-editor/sign-pgp-elkins bb eb boundary)
1504                         )
1505                        ((eq mime-editor/signing-type 'pgp-kazu)
1506                         (mime-editor/process-pgp-kazu 'mc-sign
1507                                                       bb eb boundary)
1508                         )
1509                        ))
1510                 ((string= type "encrypted")
1511                  (cond ((eq mime-editor/signing-type 'pgp-elkins)
1512                         (mime-editor/encrypt-pgp-elkins bb eb boundary)
1513                         )
1514                        ((eq mime-editor/signing-type 'pgp-kazu)
1515                         (mime-editor/process-pgp-kazu 'mc-encrypt
1516                                                       bb eb boundary)
1517                         )))
1518                 (t
1519                  (setq boundary
1520                        (nth 2 (mime-editor/translate-region bb eb
1521                                                             boundary t)))
1522                  (goto-char bb)
1523                  (insert
1524                   (format "--[[multipart/%s;
1525  boundary=\"%s\"][7bit]]\n"
1526                           type boundary))
1527                  ))
1528           boundary))))
1529
1530 (defun tm:mc-pgp-generic-parser (result)
1531   (let ((ret (mc-pgp-generic-parser result)))
1532     (if (consp ret)
1533         (vector (car ret)(cdr ret))
1534       )))
1535
1536 (autoload 'mc-pgp-lookup-key "mc-pgp")
1537
1538 (defun tm:mc-process-region
1539   (beg end passwd program args parser &optional buffer boundary)
1540   (let ((obuf (current-buffer))
1541         (process-connection-type nil)
1542         mybuf result rgn proc)
1543     (unwind-protect
1544         (progn
1545           (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
1546           (set-buffer mybuf)
1547           (erase-buffer)
1548           (set-buffer obuf)
1549           (buffer-disable-undo mybuf)
1550           (setq proc
1551                 (apply 'start-process "*PGP*" mybuf program args))
1552           (if passwd
1553               (progn
1554                 (process-send-string proc (concat passwd "\n"))
1555                 (or mc-passwd-timeout (mc-deactivate-passwd t))))
1556           (process-send-region proc beg end)
1557           (process-send-eof proc)
1558           (while (eq 'run (process-status proc))
1559             (accept-process-output proc 5))
1560           (setq result (process-exit-status proc))
1561           ;; Hack to force a status_notify() in Emacs 19.29
1562           (delete-process proc)
1563           (set-buffer mybuf)
1564           (goto-char (point-max))
1565           (if (re-search-backward "\nProcess \\*PGP.*\n\\'" nil t)
1566               (delete-region (match-beginning 0) (match-end 0)))
1567           (goto-char (point-min))
1568           ;; CRNL -> NL
1569           (while (search-forward "\r\n" nil t)
1570             (replace-match "\n"))
1571           ;; Hurm.  FIXME; must get better result codes.
1572           (if (stringp result)
1573               (error "%s exited abnormally: '%s'" program result)
1574             (setq rgn (funcall parser result))
1575             ;; If the parser found something, migrate it
1576             (if (consp rgn)
1577                 (progn
1578                   (set-buffer obuf)
1579                   (if boundary
1580                       (save-restriction
1581                         (narrow-to-region beg end)
1582                         (goto-char beg)
1583                         (insert (format "--%s\n" boundary))
1584                         (goto-char (point-max))
1585                         (insert (format "\n--%s
1586 Content-Type: application/pgp-signature
1587 Content-Transfer-Encoding: 7bit
1588
1589 " boundary))
1590                         (insert-buffer-substring mybuf (car rgn) (cdr rgn))
1591                         (goto-char (point-max))
1592                         (insert (format "\n--%s--\n" boundary))
1593                         )
1594                     (delete-region beg end)
1595                     (goto-char beg)
1596                     (insert-buffer-substring mybuf (car rgn) (cdr rgn))
1597                     )
1598                   (set-buffer mybuf)
1599                   (delete-region (car rgn) (cdr rgn)))))
1600           ;; Return nil on failure and exit code on success
1601           (if rgn result))
1602       ;; Cleanup even on nonlocal exit
1603       (if (and proc (eq 'run (process-status proc)))
1604           (interrupt-process proc))
1605       (set-buffer obuf)
1606       (or buffer (null mybuf) (kill-buffer mybuf)))))
1607
1608 (defun tm:mc-pgp-sign-region (start end &optional id unclear boundary)
1609   (if (not (boundp 'mc-pgp-user-id))
1610       (load "mc-pgp")
1611     )
1612   (let ((process-environment process-environment)
1613         (buffer (get-buffer-create mc-buffer-name))
1614         passwd args key
1615         (parser (function mc-pgp-generic-parser))
1616         (pgp-path mc-pgp-path)
1617         )
1618     (setq key (mc-pgp-lookup-key (or id mc-pgp-user-id)))
1619     (setq passwd
1620           (mc-activate-passwd
1621            (cdr key)
1622            (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
1623     (setenv "PGPPASSFD" "0")
1624     (setq args
1625           (cons
1626            (if boundary
1627                "-fbast"
1628              "-fast")
1629            (list "+verbose=1" "+language=en"
1630                  (format "+clearsig=%s" (if unclear "off" "on"))
1631                  "+batchmode" "-u" (cdr key))))
1632     (if mc-pgp-comment
1633         (setq args (cons (format "+comment=%s" mc-pgp-comment) args))
1634       )
1635     (message "Signing as %s ..." (car key))
1636     (if (tm:mc-process-region
1637          start end passwd pgp-path args parser buffer boundary)
1638         (progn
1639           (if boundary
1640               (progn
1641                 (goto-char (point-min))
1642                 (insert
1643                  (format "\
1644 --[[multipart/signed; protocol=\"application/pgp-signature\";
1645  boundary=\"%s\"; micalg=pgp-md5][7bit]]\n" boundary))
1646                 ))
1647           (message "Signing as %s ... Done." (car key))
1648           t)
1649       nil)))
1650
1651 (defun mime-editor/sign-pgp-elkins (beg end boundary)
1652   (save-excursion
1653     (save-restriction
1654       (narrow-to-region beg end)
1655       (let* ((ret
1656               (mime-editor/translate-region beg end boundary))
1657              (ctype    (car ret))
1658              (encoding (nth 1 ret))
1659              (parts    (nth 3 ret))
1660              (pgp-boundary (concat "pgp-sign-" boundary))
1661              )
1662         (goto-char beg)
1663         (insert (format "Content-Type: %s\n" ctype))
1664         (if encoding
1665             (insert (format "Content-Transfer-Encoding: %s\n" encoding))
1666           )
1667         (insert "\n")
1668         (or (tm:mc-pgp-sign-region (point-min)(point-max)
1669                                    nil nil pgp-boundary)
1670             (throw 'mime-editor/error 'pgp-error)
1671             )
1672         ))))
1673
1674 (defun mime-editor/encrypt-pgp-elkins (beg end boundary)
1675   (save-excursion
1676     (save-restriction
1677       (narrow-to-region beg end)
1678       (let* ((ret
1679               (mime-editor/translate-region beg end boundary))
1680              (ctype    (car ret))
1681              (encoding (nth 1 ret))
1682              (parts    (nth 3 ret))
1683              (pgp-boundary (concat "pgp-" boundary))
1684              )
1685         (goto-char beg)
1686         (insert (format "Content-Type: %s\n" ctype))
1687         (if encoding
1688             (insert (format "Content-Transfer-Encoding: %s\n" encoding))
1689           )
1690         (insert "\n")
1691         (if (null
1692              (progn
1693                (goto-char beg)
1694                (insert "=\n")
1695                (prog1
1696                    (let ((mail-header-separator "="))
1697                      (call-interactively 'mc-encrypt)
1698                      )
1699                  (goto-char beg)
1700                  (and (search-forward "=\n")
1701                       (replace-match ""))
1702                  )))
1703             (throw 'mime-editor/error 'pgp-error)
1704           )
1705         (goto-char beg)
1706         (insert (format "--[[multipart/encrypted;
1707  boundary=\"%s\";
1708  protocol=\"application/pgp-encrypted\"][7bit]]
1709 --%s
1710 Content-Type: application/pgp-encrypted
1711
1712 --%s
1713 Content-Type: application/octet-stream
1714 Content-Transfer-Encoding: 7bit
1715
1716 " pgp-boundary pgp-boundary pgp-boundary))
1717         (goto-char (point-max))
1718         (insert (format "\n--%s--\n" pgp-boundary))
1719         ))
1720     ))
1721
1722 (defun mime-editor/process-pgp-kazu (type beg end boundary)
1723   (save-excursion
1724     (save-restriction
1725       (narrow-to-region beg end)
1726       (let* ((ret
1727               (mime-editor/translate-region beg end boundary))
1728              (ctype    (car ret))
1729              (encoding (nth 1 ret))
1730              (parts    (nth 3 ret))
1731              )
1732         (goto-char beg)
1733         (insert (format "Content-Type: %s\n" ctype))
1734         (if encoding
1735             (insert (format "Content-Transfer-Encoding: %s\n" encoding))
1736           )
1737         (insert "\n")
1738         (if (null
1739              (progn
1740                (goto-char beg)
1741                (insert "=\n")
1742                (prog1
1743                    (let ((mail-header-separator "="))
1744                      (call-interactively type)
1745                      )
1746                  (goto-char beg)
1747                  (and (search-forward "=\n")
1748                       (replace-match ""))
1749                  )))
1750             (throw 'mime-editor/error 'pgp-error)
1751           )
1752         (goto-char beg)
1753         (insert
1754          "--[[application/pgp; format=mime][7bit]]\n")
1755         ))
1756     ))
1757
1758 (defun mime-editor/translate-body ()
1759   "Encode the tagged MIME body in current buffer in MIME compliant message."
1760   (interactive)
1761   (save-excursion
1762     (let ((boundary
1763            (concat mime-multipart-boundary "_"
1764                    (replace-space-with-underline (current-time-string))
1765                    ))
1766           (i 1)
1767           ret)
1768       (while (mime-editor/process-multipart-1
1769               (format "%s-%d" boundary i))
1770         (setq i (1+ i))
1771         )
1772       (save-restriction
1773         ;; We are interested in message body.
1774         (let* ((beg
1775                 (progn
1776                   (goto-char (point-min))
1777                   (re-search-forward
1778                    (concat "\n" (regexp-quote mail-header-separator)
1779                            (if mime-ignore-preceding-spaces
1780                                "[ \t\n]*\n" "\n")) nil 'move)
1781                   (point)))
1782                (end
1783                 (progn
1784                   (goto-char (point-max))
1785                   (and mime-ignore-trailing-spaces
1786                        (re-search-backward "[^ \t\n]\n" beg t)
1787                        (forward-char 1))
1788                   (point))))
1789           (setq ret (mime-editor/translate-region
1790                      beg end
1791                      (format "%s-%d" boundary i)))
1792           ))
1793       (let ((contype (car ret))         ;Content-Type
1794             (encoding (nth 1 ret))      ;Content-Transfer-Encoding
1795             )
1796         ;; Make primary MIME headers.
1797         (or (mail-position-on-field "Mime-Version")
1798             (insert mime-editor/mime-version-value))
1799         ;; Remove old Content-Type and other fields.
1800         (save-restriction
1801           (goto-char (point-min))
1802           (search-forward (concat "\n" mail-header-separator "\n") nil t)
1803           (narrow-to-region (point-min) (point))
1804           (goto-char (point-min))
1805           (mime-delete-field "Content-Type")
1806           (mime-delete-field "Content-Transfer-Encoding"))
1807         ;; Then, insert Content-Type and Content-Transfer-Encoding fields.
1808         (mail-position-on-field "Content-Type")
1809         (insert contype)
1810         (if encoding
1811             (progn
1812               (mail-position-on-field "Content-Transfer-Encoding")
1813               (insert encoding)))
1814         ))))
1815
1816 (defun mime-editor/translate-region (beg end &optional boundary multipart)
1817   (if (null boundary)
1818       (setq boundary
1819             (concat mime-multipart-boundary "_"
1820                     (replace-space-with-underline (current-time-string))))
1821     )
1822   (save-excursion
1823     (save-restriction
1824       (narrow-to-region beg end)
1825       (let ((tag nil)                   ;MIME tag
1826             (contype nil)               ;Content-Type
1827             (encoding nil)              ;Content-Transfer-Encoding
1828             (nparts 0))                 ;Number of body parts
1829         ;; Normalize the body part by inserting appropriate message
1830         ;; tags for every message contents.
1831         (mime-editor/normalize-body)
1832         ;; Counting the number of Content-Type.
1833         (goto-char (point-min))
1834         (while (re-search-forward mime-editor/single-part-tag-regexp nil t)
1835           (setq nparts (1+ nparts)))
1836         ;; Begin translation.
1837         (cond ((and (<= nparts 1)(not multipart))
1838                ;; It's a singular message.
1839                (goto-char (point-min))
1840                (while (re-search-forward
1841                        mime-editor/single-part-tag-regexp nil t)
1842                  (setq tag
1843                        (buffer-substring (match-beginning 0) (match-end 0)))
1844                  (delete-region (match-beginning 0) (1+ (match-end 0)))
1845                  (setq contype (mime-editor/get-contype tag))
1846                  (setq encoding (mime-editor/get-encoding tag))
1847                  ))
1848               (t
1849                ;; It's a multipart message.
1850                (goto-char (point-min))
1851                (while (re-search-forward
1852                        mime-editor/single-part-tag-regexp nil t)
1853                  (setq tag
1854                        (buffer-substring (match-beginning 0) (match-end 0)))
1855                  (delete-region (match-beginning 0) (match-end 0))
1856                  (setq contype (mime-editor/get-contype tag))
1857                  (setq encoding (mime-editor/get-encoding tag))
1858                  (insert "--" boundary "\n")
1859                  (insert "Content-Type: " contype "\n")
1860                  (if encoding
1861                      (insert "Content-Transfer-Encoding: " encoding "\n"))
1862                  )
1863                ;; Define Content-Type as "multipart/mixed".
1864                (setq contype
1865                      (concat "multipart/mixed;\n boundary=\"" boundary "\""))
1866                ;; Content-Transfer-Encoding must be "7bit".
1867                ;; The following encoding can be `nil', but is
1868                ;; specified as is since there is no way that a user
1869                ;; specifies it.
1870                (setq encoding "7bit")
1871                ;; Insert the trailer.
1872                (goto-char (point-max))
1873                (if multipart
1874                    (insert "--" boundary "--\n")
1875                  (insert "\n--" boundary "--\n")
1876                  )))
1877         (list contype encoding boundary nparts)
1878         ))))
1879
1880 (defun mime-editor/normalize-body ()
1881   "Normalize the body part by inserting appropriate message tags."
1882   ;; Insert the first MIME tags if necessary.
1883   (goto-char (point-min))
1884   (if (not (looking-at mime-editor/single-part-tag-regexp))
1885       (insert (mime-make-text-tag) "\n"))
1886   ;; Check each tag, and add new tag or correct it if necessary.
1887   (goto-char (point-min))
1888   (while (re-search-forward mime-editor/single-part-tag-regexp nil t)
1889     (let* ((tag (buffer-substring (match-beginning 0) (match-end 0)))
1890            (contype (mime-editor/get-contype tag))
1891            (charset (mime-get-parameter contype "charset"))
1892            (encoding (mime-editor/get-encoding tag)))
1893       ;; Remove extra whitespaces after the tag.
1894       (if (looking-at "[ \t]+$")
1895           (delete-region (match-beginning 0) (match-end 0)))
1896       (cond ((= (following-char) ?\^M)
1897              ;; It must be image, audio or video.
1898              (let ((beg (point))
1899                    (end (mime-editor/content-end)))
1900                ;; Insert explicit MIME tags after hidden messages.
1901                (forward-line 1)
1902                (if (and (not (eobp))
1903                         (not (looking-at mime-editor/single-part-tag-regexp)))
1904                    (progn
1905                      (insert (mime-make-text-tag) "\n")
1906                      (forward-line -1)  ;Process it again as text.
1907                      ))
1908                ;; Show a hidden message.  The point is not altered
1909                ;; after the conversion.
1910                (mime-flag-region beg end ?\n)))
1911             ((mime-test-content-type contype "message")
1912              ;; Content-type "message" should be sent as is.
1913              (forward-line 1))
1914             ((mime-test-content-type contype "text")
1915              ;; Define charset for text if necessary.
1916              (setq charset (or charset (mime-editor/choose-charset)))
1917              (mime-editor/define-charset charset)
1918              (if (string-equal contype "text/x-rot13-47")
1919                  (save-excursion
1920                    (forward-line)
1921                    (set-mark (point))
1922                    (goto-char (mime-editor/content-end))
1923                    (tm:caesar-region)
1924                    ))
1925              ;; Point is now on current tag.
1926              ;; Define encoding and encode text if necessary.
1927              (if (null encoding)        ;Encoding is not specified.
1928                  (let* ((encoding
1929                          (cdr
1930                           (assoc charset mime/charset-default-encoding-alist)
1931                           ))
1932                         (beg (mime-editor/content-beginning))
1933                         (end (mime-editor/content-end))
1934                         (body (buffer-substring beg end))
1935                         (encoded (funcall mime-string-encoder
1936                                           (cons charset encoding) body)))
1937                    (if (not (string-equal body encoded))
1938                        (progn
1939                          (goto-char beg)
1940                          (delete-region beg end)
1941                          (insert encoded)
1942                          (goto-char beg)))
1943                    (mime-editor/define-encoding encoding)))
1944              (forward-line 1))
1945             ((null encoding)            ;Encoding is not specified.
1946              ;; Application, image, audio, video, and any other
1947              ;; unknown content-type without encoding should be
1948              ;; encoded.
1949              (let* ((encoding "base64") ;Encode in BASE64 by default.
1950                     (beg (mime-editor/content-beginning))
1951                     (end (mime-editor/content-end))
1952                     (body (buffer-substring beg end))
1953                     (encoded (funcall mime-string-encoder
1954                                       (cons nil encoding) body)))
1955                (if (not (string-equal body encoded))
1956                    (progn
1957                      (goto-char beg)
1958                      (delete-region beg end)
1959                      (insert encoded)
1960                      (goto-char beg)))
1961                (mime-editor/define-encoding encoding))
1962              (forward-line 1))
1963             )
1964       )))
1965
1966 (defun mime-delete-field (field)
1967   "Delete header FIELD."
1968   (let ((regexp (format "^%s:[ \t]*" field)))
1969     (goto-char (point-min))
1970     (while (re-search-forward regexp nil t)
1971       (delete-region (match-beginning 0)
1972                      (progn (forward-line 1) (point)))
1973       )))
1974
1975 \f
1976 ;;;
1977 ;;; Platform dependent functions
1978 ;;;
1979
1980 ;; Emacs 18 implementations
1981
1982 (defun mime-string-encoder-for-emacs18 (method string)
1983   "For given METHOD that is a cons of charset and encoding, encode a STRING."
1984   (let ((charset (car method))
1985         (encoding (cdr method)))
1986     (cond ((stringp encoding)
1987            (mime-encode-string encoding string))
1988           ;; Return string without any encoding.
1989           (t string)
1990           )))
1991
1992 \f
1993 ;; Emacs 19 implementations
1994
1995 (defun mime-string-encoder-for-emacs19 (method string)
1996   "For given METHOD that is a cons of charset and encoding, encode a STRING."
1997   (let ((charset (car method))
1998         (encoding (cdr method)))
1999     (cond ((stringp encoding)
2000            (mime-encode-string encoding string))
2001           ;; Return string without any encoding.
2002           (t string)
2003           )))
2004
2005 \f
2006 ;; NEmacs implementations
2007
2008 (defun mime-string-encoder-for-nemacs (method string)
2009   "For given METHOD that is a cons of charset and encoding, encode a STRING.
2010 US-ASCII and ISO-2022-JP are supported on NEmacs."
2011   (let ((charset (car method))
2012         (encoding (cdr method)))
2013     (cond ((stringp encoding)
2014            (mime-encode-string encoding
2015                                ;; Convert internal (EUC) to JIS code.
2016                                (convert-string-kanji-code string 3 2)
2017                                ))
2018           ;; NEmacs can convert into ISO-2022-JP automatically,
2019           ;; but can do it myself as follows:
2020           ;;(t (convert-string-kanji-code string 3 2))
2021
2022           ;; Return string without any encoding.
2023           (t string)
2024           )))
2025
2026 \f
2027 ;; Mule implementations
2028 ;; Thanks to contributions by wkenji@flab.fujitsu.co.jp (Kenji
2029 ;; WAKAMIYA) and handa@etl.go.jp (Kenichi Handa).
2030
2031 (defun mime-string-encoder-for-mule (method string)
2032   "For given METHOD that is a cons of charset and encoding, encode a
2033 STRING.  US-ASCII, ISO-8859-* (except for ISO-8859-6), ISO-2022-JP,
2034 ISO-2022-JP-2 and ISO-2022-INT-1 are supported on Mule.  Either of
2035 charset ISO-2022-JP-2 or ISO-2022-INT-1 is used for multilingual
2036 text."
2037   (let* ((charset (car method))
2038          (encoding (cdr method))
2039          (coding-system
2040           (cdr (assoc (and (stringp charset) (upcase charset))
2041                       '(("ISO-8859-1" . *ctext*)
2042                         ("ISO-8859-2" . *iso-8859-2*)
2043                         ("ISO-8859-3" . *iso-8859-3*)
2044                         ("ISO-8859-4" . *iso-8859-4*)
2045                         ("ISO-8859-5" . *iso-8859-5*)
2046                         ;;("ISO-8859-6" . *iso-8859-6*)
2047                         ("ISO-8859-7" . *iso-8859-7*)
2048                         ("ISO-8859-8" . *iso-8859-8*)
2049                         ("ISO-8859-9" . *iso-8859-9*)
2050                         ("ISO-2022-JP" . *junet*)
2051                         ("ISO-2022-JP-2" . *iso-2022-ss2-7*)
2052                         ("ISO-2022-KR" . *korean-mail*)
2053                         ("ISO-2022-INT-1" . *iso-2022-int-1*)
2054                         )))))
2055     ;; In bilingual environment it may be unnecessary to convert the
2056     ;; coding system of the string unless transfer encoding is
2057     ;; required since such conversion may be performed by mule
2058     ;; automatically.
2059     (if (not (null coding-system))
2060         (setq string (code-convert-string string *internal* coding-system)))
2061     (if (stringp encoding)
2062         (setq string (mime-encode-string encoding string)))
2063     string
2064     ))
2065
2066 \f
2067 ;; Sun implementations
2068
2069 (defun mime-voice-recorder-for-sun ()
2070   "Record voice in a buffer using Sun audio device, and return the buffer.
2071 If the environment variable AUDIOHOST is defined, its value is used as
2072 a recording host instead of local host."
2073   (let ((buffer (get-buffer-create " *MIME audio*"))
2074         (host (getenv "AUDIOHOST")))
2075     (message "Start the recording on %s.  Type C-g to finish the recording..."
2076              (or host (system-name)))
2077     (save-excursion
2078       (set-buffer buffer)
2079       (erase-buffer)
2080       (condition-case errorcode
2081           (let ((selective-display nil) ;Disable ^M to nl translation.
2082                 (mc-flag nil)           ;Mule
2083                 (kanji-flag nil))       ;NEmacs
2084             ;; If AUDIOHOST is defined, use the value as recording host.
2085             (cond ((not (null host))
2086                    ;; Disable automatic conversion of coding system if Mule.
2087                    (if (featurep 'mule)
2088                        (define-program-coding-system nil "rsh" *noconv*))
2089                    (call-process "rsh"
2090                                  nil
2091                                  buffer
2092                                  nil
2093                                  host
2094                                  "cat"
2095                                  "/dev/audio"
2096                                  ))
2097                   (t
2098                    ;; Disable automatic conversion of coding system if Mule.
2099                    (if (featurep 'mule)
2100                        (define-program-coding-system nil "cat" *noconv*))
2101                    (call-process "cat"
2102                                  "/dev/audio"
2103                                  buffer
2104                                  nil
2105                                  ))))
2106         (quit (message "Type C-g to finish recording... done.")
2107               buffer                    ;Return the buffer
2108               )))))
2109
2110 \f
2111 ;;; @ Other useful commands.
2112 ;;;
2113
2114 ;; Message forwarding commands as content-type "message/rfc822".
2115
2116 (defun mime-editor/insert-message (&optional message)
2117   (interactive)
2118   (let ((inserter (assoc-value major-mode mime-editor/message-inserter-alist)))
2119     (if (and inserter (fboundp inserter))
2120         (progn
2121           (mime-editor/insert-tag "message" "rfc822")
2122           (funcall inserter message)
2123           )
2124       (message "Sorry, I don't have message inserter for your MUA.")
2125       )))
2126
2127 (defun mime-editor/insert-mail (&optional message)
2128   (interactive)
2129   (let ((inserter (assoc-value major-mode mime-editor/mail-inserter-alist)))
2130     (if (and inserter (fboundp inserter))
2131         (progn
2132           (mime-editor/insert-tag "message" "rfc822")
2133           (funcall inserter message)
2134           )
2135       (message "Sorry, I don't have mail inserter for your MUA.")
2136       )))
2137
2138 (defun mime-editor/inserted-message-filter ()
2139   (save-excursion
2140     (save-restriction
2141       (let ((header-start (point))
2142             (case-fold-search t)
2143             beg end)
2144         ;; for Emacs 18
2145         ;; (if (re-search-forward "^$" (marker-position (mark-marker)))
2146         (if (re-search-forward "^$" (mark t))
2147             (narrow-to-region header-start (match-beginning 0))
2148           )
2149         (goto-char header-start)
2150         (while (and (re-search-forward
2151                      mime-editor/yank-ignored-field-regexp nil t)
2152                     (setq beg (match-beginning 0))
2153                     (setq end (1+ (rfc822/field-end)))
2154                     )
2155           (delete-region beg end)
2156           )
2157         ))))
2158
2159
2160 ;;; @ multipart enclosure
2161 ;;;
2162
2163 (defun mime-editor/enclose-region (type beg end)
2164   (save-excursion
2165     (goto-char beg)
2166     (let ((current (point))
2167           exist-prev-tag)
2168       (save-excursion
2169         (if (mime-editor/goto-tag)
2170             (or (eq current (match-beginning 0))
2171                 (setq exist-prev-tag t)
2172                 )))
2173       (save-restriction
2174         (narrow-to-region beg end)
2175         (goto-char beg)
2176         (if exist-prev-tag
2177             (insert "\n")
2178           )
2179         (insert (format "--<<%s>>-{\n" type))
2180         (goto-char (point-max))
2181         (insert (format "\n--}-<<%s>>\n" type))
2182         (goto-char (point-max))
2183         )
2184       (if (and (not (looking-at mime-editor/single-part-tag-regexp))
2185                (not (eobp)))
2186           (insert (mime-make-text-tag) "\n")
2187         )
2188       )))
2189
2190 (defun mime-editor/enclose-mixed-region (beg end)
2191   (interactive "*r")
2192   (mime-editor/enclose-region "mixed" beg end)
2193   )
2194
2195 (defun mime-editor/enclose-parallel-region (beg end)
2196   (interactive "*r")
2197   (mime-editor/enclose-region "parallel" beg end)
2198   )
2199
2200 (defun mime-editor/enclose-digest-region (beg end)
2201   (interactive "*r")
2202   (mime-editor/enclose-region "digest" beg end)
2203   )
2204
2205 (defun mime-editor/enclose-alternative-region (beg end)
2206   (interactive "*r")
2207   (mime-editor/enclose-region "alternative" beg end)
2208   )
2209
2210 (defun mime-editor/enclose-signed-region (beg end)
2211   (interactive "*r")
2212   (if mime-editor/signing-type
2213       (mime-editor/enclose-region "signed" beg end)
2214     (message "Please specify signing type.")
2215     ))
2216
2217 (defun mime-editor/enclose-encrypted-region (beg end)
2218   (interactive "*r")
2219   (if mime-editor/signing-type
2220       (mime-editor/enclose-region "encrypted" beg end)
2221     (message "Please specify encrypting type.")
2222     ))
2223
2224 (defun mime-editor/insert-key (&optional arg)
2225   "Insert a pgp public key."
2226   (interactive "P")
2227   (mime-editor/insert-tag "application" "pgp-keys")
2228   (mime-editor/define-encoding "7bit")
2229   (mc-insert-public-key)
2230   )
2231
2232
2233 ;;; @ flag setting
2234 ;;;
2235
2236 (defun mime-editor/set-split (arg)
2237   (interactive
2238    (list
2239     (y-or-n-p "Do you want to enable split?")
2240     ))
2241   (setq mime-editor/split-message arg)
2242   (if arg
2243       (message "This message is enabled to split.")
2244     (message "This message is not enabled to split.")
2245     ))
2246
2247
2248 ;;; @ pgp
2249 ;;;
2250
2251 (defun mime-editor/set-sign (arg)
2252   (interactive
2253    (list
2254     (y-or-n-p "Do you want to sign?")
2255     ))
2256   (if arg
2257       (progn
2258         (setq mime-editor/pgp-processing 'sign)
2259         (message "This message will be signed.")
2260         )
2261     (if (eq mime-editor/pgp-processing 'sign)
2262         (setq mime-editor/pgp-processing nil)
2263       )
2264     (message "This message will not be signed.")
2265     ))
2266
2267 (defun mime-editor/set-encrypt (arg)
2268   (interactive
2269    (list
2270     (y-or-n-p "Do you want to encrypt?")
2271     ))
2272   (if arg
2273       (progn
2274         (setq mime-editor/pgp-processing 'encrypt)
2275         (message "This message will be encrypt.")
2276         )
2277     (if (eq mime-editor/pgp-processing 'encrypt)
2278         (setq mime-editor/pgp-processing nil)
2279       )
2280     (message "This message will not be encrypt.")
2281     ))
2282
2283 (defvar mime-editor/pgp-processing nil)
2284 (make-variable-buffer-local 'mime-editor/pgp-processing)
2285
2286 (defun mime-editor/call-mc (command)
2287   (let* ((header (rfc822/get-header-string-except
2288                   "^Content-Type:" mail-header-separator)))
2289     (goto-char (point-min))
2290     (if (search-forward mail-header-separator)
2291         (replace-match "")
2292       )
2293     (goto-char (point-min))
2294     (insert header)
2295     (insert "Content-Type: application/pgp; format=mime\n")
2296     (insert mail-header-separator)
2297     (insert "\n")
2298     (if (null (call-interactively command))
2299         (throw 'mime-editor/error 'pgp-error)
2300       )
2301     ))
2302
2303 (defun mime-editor/pgp-processing ()
2304   (let ((command
2305          (cdr (assq mime-editor/pgp-processing
2306                     '((sign    . mc-sign)
2307                       (encrypt . mc-encrypt)
2308                       )))))
2309     (and command
2310          (mime-editor/call-mc command)
2311          )))
2312
2313
2314 ;;; @ split
2315 ;;;
2316
2317 (defun mime-editor/insert-partial-header
2318   (fields subject id number total separator)
2319   (insert fields)
2320   (insert (format "Subject: %s (%d/%d)\n" subject number total))
2321   (insert (format "Mime-Version: 1.0 (split by tm-edit %s)\n"
2322                   mime-editor/version))
2323   (insert (format "\
2324 Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n"
2325                   id number total separator))
2326   )
2327
2328 (defun mime-editor/split-and-send
2329   (&optional cmd lines mime-editor/message-max-length)
2330   (interactive)
2331   (or lines
2332       (setq lines
2333             (count-lines (point-min) (point-max)))
2334       )
2335   (or mime-editor/message-max-length
2336       (setq mime-editor/message-max-length
2337             (or (cdr (assq major-mode mime-editor/message-max-length-alist))
2338                 mime-editor/message-default-max-length))
2339       )
2340   (let* ((mime-editor/draft-file-name 
2341           (or (buffer-file-name)
2342               (make-temp-name
2343                (expand-file-name "tm-draft" mime/tmp-dir))))
2344          (separator mail-header-separator)
2345          (config
2346           (eval (cdr (assq major-mode mime-editor/window-config-alist))))
2347          (id (concat "\""
2348                      (replace-space-with-underline (current-time-string))
2349                      "@" (system-name) "\"")))
2350     (run-hooks 'mime-editor/before-split-hook)
2351     (let* ((header (rfc822/get-header-string-except
2352                     mime-editor/split-ignored-field-regexp separator))
2353            (subject (mail-fetch-field "subject"))
2354            (total (+ (/ lines mime-editor/message-max-length)
2355                      (if (> (mod lines mime-editor/message-max-length) 0)
2356                          1)))
2357            (the-buf (current-buffer))
2358            (buf (get-buffer "*tmp-send*"))
2359            (command
2360             (or cmd
2361                 (cdr
2362                  (assq major-mode
2363                        mime-editor/split-message-sender-alist))
2364                 (cdr
2365                  (assq major-mode
2366                        mime-editor/message-default-sender-alist))
2367                 ))
2368            data)
2369       (goto-char (point-min))
2370       (if (re-search-forward (concat "^" (regexp-quote separator) "$")
2371                              nil t)
2372           (replace-match "")
2373         )
2374       (if buf
2375           (progn
2376             (switch-to-buffer buf)
2377             (erase-buffer)
2378             (switch-to-buffer the-buf)
2379             )
2380         (setq buf (get-buffer-create "*tmp-send*"))
2381         )
2382       (switch-to-buffer buf)
2383       (make-local-variable 'mail-header-separator)
2384       (setq mail-header-separator separator)
2385       (switch-to-buffer the-buf)
2386       (goto-char (point-min))
2387       (re-search-forward "^$" nil t)
2388       (let ((mime-editor/partial-number 1))
2389         (setq data (buffer-substring
2390                     (point-min)
2391                     (progn
2392                       (goto-line mime-editor/message-max-length)
2393                       (point))
2394                     ))
2395         (delete-region (point-min)(point))
2396         (switch-to-buffer buf)
2397         (mime-editor/insert-partial-header
2398          header subject id mime-editor/partial-number total separator)
2399         (insert data)
2400         (save-excursion
2401           (save-restriction
2402             (goto-char (point-min))
2403             (search-forward (concat "\n" mail-header-separator "\n"))
2404             (narrow-to-region
2405              (match-end 0)
2406              (if (re-search-forward "^$" nil t)
2407                  (match-beginning 0)
2408                (point-max)
2409                ))
2410             (goto-char (point-min))
2411             (while (re-search-forward
2412                     mime-editor/split-blind-field-regexp nil t)
2413               (delete-region (match-beginning 0)
2414                              (let ((e (rfc822/field-end)))
2415                                (if (< e (point-max))
2416                                    (1+ e)
2417                                  e)))
2418               )
2419             ))
2420         (save-excursion
2421           (message (format "Sending %d/%d..."
2422                            mime-editor/partial-number total))
2423           (call-interactively command)
2424           (message (format "Sending %d/%d... done"
2425                            mime-editor/partial-number total))
2426           )
2427         (erase-buffer)
2428         (switch-to-buffer the-buf)
2429         (setq mime-editor/partial-number 2)
2430         (while (< mime-editor/partial-number total)
2431           (setq data (buffer-substring
2432                       (point-min)
2433                       (progn
2434                         (goto-line mime-editor/message-max-length)
2435                         (point))
2436                       ))
2437           (delete-region (point-min)(point))
2438           (switch-to-buffer buf)
2439           (mime-editor/insert-partial-header
2440            header subject id mime-editor/partial-number total separator)
2441           (insert data)
2442           (save-excursion
2443             (message (format "Sending %d/%d..."
2444                              mime-editor/partial-number total))
2445             (call-interactively command)
2446             (message (format "Sending %d/%d... done"
2447                              mime-editor/partial-number total))
2448             )
2449           (erase-buffer)
2450           (switch-to-buffer the-buf)
2451           (setq mime-editor/partial-number
2452                 (1+ mime-editor/partial-number))
2453           )
2454         (goto-char (point-min))
2455         (mime-editor/insert-partial-header
2456          header subject id mime-editor/partial-number total separator)
2457         (message (format "Sending %d/%d..."
2458                          mime-editor/partial-number total))
2459         ))))
2460
2461 (defun mime-editor/maybe-split-and-send (&optional cmd)
2462   (interactive)
2463   (run-hooks 'mime-editor/before-send-hook)
2464   (let ((mime-editor/message-max-length
2465          (or (cdr (assq major-mode mime-editor/message-max-length-alist))
2466              mime-editor/message-default-max-length))
2467         (lines (count-lines (point-min) (point-max)))
2468         )
2469     (if (and (> lines mime-editor/message-max-length)
2470              mime-editor/split-message)
2471         (mime-editor/split-and-send cmd lines mime-editor/message-max-length)
2472       )))
2473
2474
2475 ;;; @ preview message
2476 ;;;
2477
2478 (defun mime-editor/preview-message ()
2479   "preview editing MIME message. [tm-edit.el]"
2480   (interactive)
2481   (let* ((str (buffer-string))
2482          (separator mail-header-separator)
2483          (the-buf (current-buffer))
2484          (buf-name (buffer-name))
2485          (temp-buf-name (concat "*temp-article:" buf-name "*"))
2486          (buf (get-buffer temp-buf-name))
2487          )
2488     (if buf
2489         (progn
2490           (switch-to-buffer buf)
2491           (erase-buffer)
2492           )
2493       (setq buf (get-buffer-create temp-buf-name))
2494       (switch-to-buffer buf)
2495       )
2496     (insert str)
2497     (setq major-mode 'mime/temporary-message-mode)
2498     (make-local-variable 'mail-header-separator)
2499     (setq mail-header-separator separator)
2500     (make-local-variable 'mime/editing-buffer)
2501     (setq mime/editing-buffer the-buf)
2502     
2503     (run-hooks 'mime-editor/translate-hook)
2504     (mime-editor/translate-buffer)
2505     (goto-char (point-min))
2506     (if (re-search-forward
2507          (concat "^" (regexp-quote separator) "$"))
2508         (replace-match "")
2509       )
2510     (mime/viewer-mode)
2511     ))
2512
2513 (defun mime-editor/quitting-method ()
2514   (let ((temp mime::preview/article-buffer)
2515         buf)
2516     (mime-viewer/kill-buffer)
2517     (set-buffer temp)
2518     (setq buf mime/editing-buffer)
2519     (kill-buffer temp)
2520     (switch-to-buffer buf)
2521     ))
2522
2523 (set-alist 'mime-viewer/quitting-method-alist
2524            'mime/temporary-message-mode
2525            (function mime-editor/quitting-method)
2526            )
2527
2528
2529 ;;; @ draft preview
2530 ;;; 
2531 ;; by "OKABE Yasuo <okabe@kudpc.kyoto-u.ac.jp>
2532 ;;       Mon, 10 Apr 1995 20:03:07 +0900
2533
2534 (defvar mime-editor/draft-header-separator-alist
2535   '((news-reply-mode . mail-header-separator)
2536     (mh-letter-mode . mail-header-separator)
2537     ))
2538
2539 (defvar mime::article/draft-header-separator nil)
2540
2541 (defun mime-editor/draft-preview ()
2542   (interactive)
2543   (let ((sep (cdr (assq major-mode mime-editor/draft-header-separator-alist))))
2544     (or (stringp sep) (setq sep (eval sep)))
2545     (make-variable-buffer-local 'mime::article/draft-header-separator)
2546     (goto-char (point-min))
2547     (re-search-forward
2548      (concat "^\\(" (regexp-quote sep) "\\)?$"))
2549     (setq mime::article/draft-header-separator
2550           (buffer-substring (match-beginning 0) (match-end 0)))
2551     (replace-match "")
2552     (mime/viewer-mode (current-buffer))
2553     (pop-to-buffer (current-buffer))
2554     ))
2555
2556 (defun mime-viewer::quitting-method/draft-preview ()
2557   (let ((mother mime::preview/mother-buffer))
2558     (save-excursion
2559       (switch-to-buffer mother)
2560       (goto-char (point-min))
2561       (if (and
2562            (re-search-forward
2563             (concat "^\\("
2564                     (regexp-quote mime::article/draft-header-separator)
2565                     "\\)?$") nil t)
2566            (bolp))
2567           (progn
2568             (insert mime::article/draft-header-separator)
2569             (set-buffer-modified-p (buffer-modified-p))
2570             )))
2571     (mime-viewer/kill-buffer)
2572     (pop-to-buffer mother)
2573     ))
2574
2575 (set-alist 'mime-viewer/quitting-method-alist
2576            'mh-letter-mode
2577            (function mime-viewer::quitting-method/draft-preview)
2578            )
2579
2580 (set-alist 'mime-viewer/quitting-method-alist
2581            'news-reply-mode
2582            (function mime-viewer::quitting-method/draft-preview)
2583            )
2584
2585
2586 ;;; @ etc
2587 ;;;
2588
2589 (defun replace-space-with-underline (str)
2590   (mapconcat (function
2591               (lambda (arg)
2592                 (char-to-string
2593                  (if (= arg 32)
2594                      ?_
2595                    arg)))) str "")
2596   )
2597
2598
2599 ;;; @ end
2600 ;;;
2601
2602 (provide 'tm-edit)
2603
2604 (run-hooks 'tm-edit-load-hook)
2605
2606 ;;; tm-edit.el ends here