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