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