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