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