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