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