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