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