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