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