X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=mime-edit.el;h=87d0e30f3949cf4f7af903ca9b686c84560861d3;hb=cd538ee87cf86f47356ec51db1b95068058c9673;hp=e23f1a649a89d74f326cf1f8ef912101d92db4f8;hpb=78464291fdc4040a6b54758bc395337f02ea95d2;p=elisp%2Fsemi.git diff --git a/mime-edit.el b/mime-edit.el index e23f1a6..87d0e30 100644 --- a/mime-edit.el +++ b/mime-edit.el @@ -1,16 +1,15 @@ ;;; mime-edit.el --- Simple MIME Composer for GNU Emacs -;; Copyright (C) 1993,1994,1995,1996,1997 Free Software Foundation, Inc. +;; Copyright (C) 1993,94,95,96,97,98,99,2000 Free Software Foundation, Inc. ;; Author: UMEDA Masanobu -;; MORIOKA Tomohiko -;; Maintainer: MORIOKA Tomohiko +;; MORIOKA Tomohiko +;; Daiki Ueno ;; Created: 1994/08/21 renamed from mime.el ;; Renamed: 1997/2/21 from tm-edit.el -;; Version: $Revision: 0.98 $ ;; Keywords: MIME, multimedia, multilingual, mail, news -;; This file is part of SEMI (SEMI is Emacs MIME Interfaces). +;; This file is part of SEMI (Sophisticated Emacs MIME Interfaces). ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as @@ -24,8 +23,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -108,27 +107,25 @@ ;;; Code: -(require 'emu) (require 'sendmail) (require 'mail-utils) (require 'mel) (require 'mime-view) -(require 'eword-encode) (require 'signature) (require 'alist) +(require 'epa) ;;; @ version ;;; -(defconst mime-edit-RCS-ID - "$Id: mime-edit.el,v 0.98 1997-11-15 14:38:09 morioka Exp $") - -(defconst mime-edit-version `,(get-version-string mime-edit-RCS-ID)) - -(defconst mime-edit-version-name - `,(concat "SEMI MIME-Edit " mime-edit-version - " - \"" semi-version-name "\"")) +(eval-and-compile + (defconst mime-edit-version + (concat + (mime-product-name mime-user-interface-product) " " + (mapconcat #'number-to-string + (mime-product-version mime-user-interface-product) ".") + " - \"" (mime-product-code-name mime-user-interface-product) "\""))) ;;; @ variables @@ -189,19 +186,12 @@ To insert a signature file automatically, call the function ("plain" ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8") ) - ("richtext" - ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8") - ) - ("enriched" - ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8") - ) - ("x-latex" - ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8") - ) - ("html" - ;;("charset" "" "ISO-2022-JP" "US-ASCII" "ISO-8859-1" "ISO-8859-8") - ) - ("x-rot13-47-48") + ("enriched") + ("html") + ("css") ; rfc2318 + ("xml") ; rfc2376 + ("x-latex") + ;; ("x-rot13-47-48") ) ("message" ("external-body" @@ -219,13 +209,19 @@ To insert a signature file automatically, call the function ("tftp" ("site") ("name")) ("afs" ("site") ("name")) ("local-file" ("site") ("name")) - ("mail-server" ("server" "ftpmail@nic.karrn.ad.jp")) - )) + ("mail-server" + ("server" "ftpmail@nic.karrn.ad.jp") + ("subject")) + ("url" ("url")))) ("rfc822") - ) + ("news")) ("application" ("octet-stream" ("type" "" "tar" "shar")) ("postscript") + ("pdf") + ("msword") + ("vnd.ms-excel") + ("vnd.ms-powerpoint") ("x-kiss" ("x-cnf"))) ("image" ("gif") @@ -235,147 +231,214 @@ To insert a signature file automatically, call the function ("x-pic") ("x-mag") ("x-xwd") - ("x-xbm") - ) + ("x-xbm")) ("audio" ("basic")) - ("video" ("mpeg")) - ) + ("video" ("mpeg"))) "*Alist of content-type, subtype, parameters and its values.") -(defvar mime-file-types - '(("\\.rtf$" - "text" "richtext" nil +(defcustom mime-file-types + '( + + ;; Programming languages + + ("\\.cc$" + "application" "octet-stream" (("type" . "C++")) + "7bit" + "attachment" (("filename" . file))) + + ("\\.el$" + "application" "octet-stream" (("type" . "emacs-lisp")) + "7bit" + "attachment" (("filename" . file))) + + ("\\.lsp$" + "application" "octet-stream" (("type" . "common-lisp")) + "7bit" + "attachment" (("filename" . file))) + + ("\\.pl$" + "application" "octet-stream" (("type" . "perl")) + "7bit" + "attachment" (("filename" . file))) + + ;; Text or translated text + + ("\\.txt$" + "text" "plain" nil nil - nil nil) + "inline" (("filename" . file))) + + ;; .rc : procmail modules pm-xxxx.rc + ;; *rc : other resource files + + ("\\.\\(rc\\|lst\\|log\\|sql\\|mak\\)$\\|\\..*rc$" + "text" "plain" nil + nil + "attachment" (("filename" . file))) + ("\\.html$" "text" "html" nil nil nil nil) + + ("\\.diff$\\|\\.patch$" + "application" "octet-stream" (("type" . "patch")) + nil + "attachment" (("filename" . file))) + + ("\\.signature" + "text" "plain" nil nil nil nil) + + + ;; Octect binary text + + ("\\.doc$" ;MS Word + "application" "msword" nil + "base64" + "attachment" (("filename" . file))) + ("\\.xls$" ; MS Excel + "application" "vnd.ms-excel" nil + "base64" + "attachment" (("filename" . file))) + ("\\.ppt$" ; MS Power Point + "application" "vnd.ms-powerpoint" nil + "base64" + "attachment" (("filename" . file))) + + ("\\.pln$" + "text" "plain" nil + nil + "inline" (("filename" . file))) ("\\.ps$" "application" "postscript" nil - "quoted-printable" - "attachment" (("filename" . file)) - ) - ("\\.jpg$" + "base64" + "attachment" (("filename" . file))) + ("\\.pdf$" + "application" "pdf" nil + "base64" + "attachment" (("filename" . file))) + + ;; Pure binary + + ("\\.jpg$\\|\\.jpeg$" "image" "jpeg" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.gif$" "image" "gif" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.png$" "image" "png" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.tiff$" "image" "tiff" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.pic$" "image" "x-pic" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.mag$" "image" "x-mag" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.xbm$" "image" "x-xbm" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.xwd$" "image" "x-xwd" nil "base64" - "inline" (("filename" . file)) - ) + "inline" (("filename" . file))) ("\\.au$" "audio" "basic" nil "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.mpg$" "video" "mpeg" nil "base64" - "attachment" (("filename" . file)) - ) - ("\\.el$" - "application" "octet-stream" (("type" . "emacs-lisp")) - "7bit" - "attachment" (("filename" . file)) - ) - ("\\.lsp$" - "application" "octet-stream" (("type" . "common-lisp")) - "7bit" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.tar\\.gz$" "application" "octet-stream" (("type" . "tar+gzip")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.tgz$" "application" "octet-stream" (("type" . "tar+gzip")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.tar\\.Z$" "application" "octet-stream" (("type" . "tar+compress")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.taz$" "application" "octet-stream" (("type" . "tar+compress")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.gz$" "application" "octet-stream" (("type" . "gzip")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.Z$" "application" "octet-stream" (("type" . "compress")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.lzh$" "application" "octet-stream" (("type" . "lha")) "base64" - "attachment" (("filename" . file)) - ) + "attachment" (("filename" . file))) ("\\.zip$" "application" "zip" nil "base64" - "attachment" (("filename" . file)) - ) - ("\\.diff$" - "application" "octet-stream" (("type" . "patch")) - nil - "attachment" (("filename" . file)) - ) - ("\\.patch$" - "application" "octet-stream" (("type" . "patch")) - nil - "attachment" (("filename" . file)) - ) - ("\\.signature" - "text" "plain" nil nil) + "attachment" (("filename" . file))) + + ;; Rest + (".*" "application" "octet-stream" nil nil - "attachment" (("filename" . file)) - ) - ) + "attachment" (("filename" . file)))) "*Alist of file name, types, parameters, and default encoding. -If encoding is nil, it is determined from its contents.") +If encoding is nil, it is determined from its contents." + :type `(repeat + (list regexp + ;; primary-type + (choice :tag "Primary-Type" + ,@(nconc (mapcar (lambda (cell) + (list 'item (car cell))) + mime-content-types) + '(string))) + ;; subtype + (choice :tag "Sub-Type" + ,@(nconc + (apply #'nconc + (mapcar (lambda (cell) + (mapcar (lambda (cell) + (list 'item (car cell))) + (cdr cell))) + mime-content-types)) + '(string))) + ;; parameters + (repeat :tag "Parameters of Content-Type field" + (cons string (choice string symbol))) + ;; content-transfer-encoding + (choice :tag "Encoding" + ,@(cons + '(const nil) + (mapcar (lambda (cell) + (list 'item cell)) + (mime-encoding-list)))) + ;; disposition-type + (choice :tag "Disposition-Type" + (item nil) + (item "inline") + (item "attachment") + string) + ;; parameters + (repeat :tag "Parameters of Content-Disposition field" + (cons string (choice string symbol))))) + :group 'mime-edit) ;;; @@ about charset, encoding and transfer-level @@ -392,16 +455,20 @@ If encoding is nil, it is determined from its contents.") (iso-8859-7 8 "quoted-printable") (iso-8859-8 8 "quoted-printable") (iso-8859-9 8 "quoted-printable") + (iso-8859-14 8 "quoted-printable") + (iso-8859-15 8 "quoted-printable") (iso-2022-jp 7 "base64") + (iso-2022-jp-3 7 "base64") (iso-2022-kr 7 "base64") (euc-kr 8 "base64") - (cn-gb2312 8 "quoted-printable") + (cn-gb 8 "base64") + (gb2312 8 "base64") (cn-big5 8 "base64") - (gb2312 8 "quoted-printable") (big5 8 "base64") + (shift_jis 8 "base64") + (tis-620 8 "base64") (iso-2022-jp-2 7 "base64") - (iso-2022-int-1 7 "base64") - )) + (iso-2022-int-1 7 "base64"))) (defvar mime-transfer-level 7 "*A number of network transfer level. It should be bigger than 7.") @@ -410,31 +477,17 @@ If encoding is nil, it is determined from its contents.") (defsubst mime-encoding-name (transfer-level &optional not-omit) (cond ((> transfer-level 8) "binary") ((= transfer-level 8) "8bit") - (not-omit "7bit") - )) + (not-omit "7bit"))) (defvar mime-transfer-level-string (mime-encoding-name mime-transfer-level 'not-omit) "A string formatted version of mime-transfer-level") (make-variable-buffer-local 'mime-transfer-level-string) -(defun mime-make-charset-default-encoding-alist (transfer-level) - (mapcar (function - (lambda (charset-type) - (let ((charset (car charset-type)) - (type (nth 1 charset-type)) - (encoding (nth 2 charset-type)) - ) - (if (<= type transfer-level) - (cons charset (mime-encoding-name type)) - (cons charset encoding) - )))) - mime-charset-type-list)) - -(defvar mime-edit-charset-default-encoding-alist - (mime-make-charset-default-encoding-alist mime-transfer-level)) -(make-variable-buffer-local 'mime-edit-charset-default-encoding-alist) +;;; @@ about content transfer encoding +(defvar mime-content-transfer-encoding-priority-list + '(nil "8bit" "binary")) ;;; @@ about message inserting ;;; @@ -477,25 +530,40 @@ If it is not specified for a major-mode, :type 'list) (defconst mime-edit-split-ignored-field-regexp - "\\(^Content-\\|^Subject:\\|^Mime-Version:\\)") + "\\(^Content-\\|^Subject:\\|^Mime-Version:\\|^Message-Id:\\)") -(defvar mime-edit-split-blind-field-regexp - "\\(^[BDFbdf]cc:\\|^cc:[ \t]*$\\)") +(defcustom mime-edit-split-blind-field-regexp + "\\(^[BDFbdf]cc:\\|^cc:[ \t]*$\\)" + "*Regular expression to match field-name to be ignored when split sending." + :group 'mime-edit + :type 'regexp) (defvar mime-edit-split-message-sender-alist nil) (defvar mime-edit-news-reply-mode-server-running nil) -;;; @@ about PGP +;;; @@ about PGP/MIME ;;; -(defvar mime-edit-signing-type 'pgp-elkins - "*PGP signing type (pgp-elkins, pgp-kazu or nil).") +(defgroup mime-edit-pgp nil + "MIME edit mode (PGP/MIME)" + :group 'mime-edit) -(defvar mime-edit-encrypting-type 'pgp-elkins - "*PGP encrypting type (pgp-elkins, pgp-kazu or nil).") +(defcustom mime-edit-pgp-verbose nil + "If non-nil, ask the user about the current operation more verbosely." + :group 'mime-edit-pgp + :type 'boolean) + +(defcustom mime-edit-pgp-signers nil + "A list of your own key ID which will be used to sign a message." + :group 'mime-edit-pgp + :type '(repeat (string :tag "Key ID"))) +(defcustom mime-edit-pgp-encrypt-to-self nil + "If t, add your own key ID to recipient list when encryption." + :group 'mime-edit-pgp + :type 'boolean) ;;; @@ about tag ;;; @@ -541,28 +609,81 @@ If it is not specified for a major-mode, ;;; @@ optional header fields ;;; -(defvar mime-edit-insert-x-emacs-field t - "*If non-nil, insert X-Emacs header field.") - -(defvar mime-edit-x-emacs-value - (if (featurep 'xemacs) - (concat emacs-version (if (featurep 'mule) - " with mule" - " without mule")) - (let ((ver (if (string-match "\\.[0-9]+$" emacs-version) - (substring emacs-version 0 (match-beginning 0)) - emacs-version))) - (if (featurep 'mule) - (concat "Emacs " ver - (if enable-multibyte-characters - (concat ", MULE " mule-version) - " (with raw setting)") - (if (featurep 'meadow) - (concat ", " (Meadow-version)) - )) - ver))) - "Body of X-Emacs field. -If variable `mime-edit-insert-x-emacs-field' is not nil, it is +(defvar mime-edit-insert-user-agent-field t + "*If non-nil, insert User-Agent header field.") + +(defvar mime-edit-user-agent-value + (concat (mime-product-name mime-user-interface-product) + "/" + (mapconcat #'number-to-string + (mime-product-version mime-user-interface-product) ".") + " (" + (mime-product-code-name mime-user-interface-product) + ") " + (mime-product-name mime-library-product) + "/" + (mapconcat #'number-to-string + (mime-product-version mime-library-product) ".") + " (" + (mime-product-code-name mime-library-product) + ") " + (if (fboundp 'apel-version) + (concat (apel-version) " ")) + "EasyPG/" epg-version-number " " + (if (featurep 'xemacs) + (concat (cond ((and (featurep 'chise) + (boundp 'xemacs-chise-version)) + (concat "CHISE-MULE/" xemacs-chise-version)) + ((featurep 'utf-2000) + (concat "UTF-2000-MULE/" utf-2000-version)) + ((featurep 'mule) "MULE")) + " XEmacs" + (if (string-match "^[0-9]+\\(\\.[0-9]+\\)" emacs-version) + (concat + "/" + (substring emacs-version 0 (match-end 0)) + (cond ((and (boundp 'xemacs-betaname) + xemacs-betaname) + ;; It does not exist in XEmacs + ;; versions prior to 20.3. + (concat " " xemacs-betaname)) + ((and (boundp 'emacs-patch-level) + emacs-patch-level) + ;; It does not exist in FSF Emacs or in + ;; XEmacs versions earlier than 21.1.1. + (format " (patch %d)" emacs-patch-level)) + (t "")) + " (" xemacs-codename ")" + ;; `xemacs-extra-name' has appeared in the + ;; development version of XEmacs 21.5-b8. + (if (and (boundp 'xemacs-extra-name) + (symbol-value 'xemacs-extra-name)) + (concat " " (symbol-value 'xemacs-extra-name)) + "") + " (" + system-configuration ")") + " (" emacs-version ")")) + (let ((ver (if (string-match "\\.[0-9]+$" emacs-version) + (substring emacs-version 0 (match-beginning 0)) + emacs-version))) + (if (featurep 'mule) + (if (boundp 'enable-multibyte-characters) + (concat "Emacs/" ver + " (" system-configuration ")" + (if enable-multibyte-characters + (concat " MULE/" mule-version) + " (with unibyte mode)") + (if (featurep 'meadow) + (let ((mver (Meadow-version))) + (if (string-match "^Meadow-" mver) + (concat " Meadow/" + (substring mver + (match-end 0))))))) + (concat "MULE/" mule-version + " (based on Emacs " ver ")")) + (concat "Emacs/" ver " (" system-configuration ")"))))) + "Body of User-Agent field. +If variable `mime-edit-insert-user-agent-field' is not nil, it is inserted into message header.") @@ -574,11 +695,14 @@ inserted into message header.") Tspecials means any character that matches with it in header must be quoted.") (defconst mime-edit-mime-version-value - (concat "1.0 (generated by " mime-edit-version-name ")") + (concat "1.0 (generated by " mime-edit-version ")") "MIME version number.") (defconst mime-edit-mime-version-field-for-message/partial - (concat "MIME-Version: 1.0 (split by " mime-edit-version-name ")\n") + (concat "MIME-Version:" + (mime-encode-field-body + (concat " 1.0 (split by " mime-edit-version ")\n") + "MIME-Version")) "MIME version field for message/partial.") @@ -588,65 +712,63 @@ Tspecials means any character that matches with it in header must be quoted.") (defvar mime-edit-mode-flag nil) (make-variable-buffer-local 'mime-edit-mode-flag) +(defvar mime-edit-mode-entity-prefix "\C-c\C-x" + "Keymap prefix for MIME-Edit mode commands to insert entity or set status.") +(defvar mime-edit-mode-entity-map (make-sparse-keymap) + "Keymap for MIME-Edit mode commands to insert entity or set status.") + +(define-key mime-edit-mode-entity-map "\C-t" 'mime-edit-insert-text) +(define-key mime-edit-mode-entity-map "\C-i" 'mime-edit-insert-file) +(define-key mime-edit-mode-entity-map "\C-e" 'mime-edit-insert-external) +(define-key mime-edit-mode-entity-map "\C-v" 'mime-edit-insert-voice) +(define-key mime-edit-mode-entity-map "\C-y" 'mime-edit-insert-message) +(define-key mime-edit-mode-entity-map "\C-m" 'mime-edit-insert-mail) +(define-key mime-edit-mode-entity-map "\C-w" 'mime-edit-insert-signature) +(define-key mime-edit-mode-entity-map "\C-s" 'mime-edit-insert-signature) +(define-key mime-edit-mode-entity-map "\C-k" 'mime-edit-insert-key) +(define-key mime-edit-mode-entity-map "t" 'mime-edit-insert-tag) + +(define-key mime-edit-mode-entity-map "7" 'mime-edit-set-transfer-level-7bit) +(define-key mime-edit-mode-entity-map "8" 'mime-edit-set-transfer-level-8bit) +(define-key mime-edit-mode-entity-map "/" 'mime-edit-set-split) +(define-key mime-edit-mode-entity-map "s" 'mime-edit-set-sign) +(define-key mime-edit-mode-entity-map "v" 'mime-edit-set-sign) +(define-key mime-edit-mode-entity-map "e" 'mime-edit-set-encrypt) +(define-key mime-edit-mode-entity-map "h" 'mime-edit-set-encrypt) +(define-key mime-edit-mode-entity-map "p" 'mime-edit-preview-message) +(define-key mime-edit-mode-entity-map "\C-z" 'mime-edit-exit) +(define-key mime-edit-mode-entity-map "?" 'mime-edit-help) + +(defvar mime-edit-mode-enclosure-prefix "\C-c\C-m" + "Keymap prefix for MIME-Edit mode commands about enclosure.") +(defvar mime-edit-mode-enclosure-map (make-sparse-keymap) + "Keymap for MIME-Edit mode commands about enclosure.") + +(define-key mime-edit-mode-enclosure-map + "\C-a" 'mime-edit-enclose-alternative-region) +(define-key mime-edit-mode-enclosure-map + "\C-p" 'mime-edit-enclose-parallel-region) +(define-key mime-edit-mode-enclosure-map + "\C-m" 'mime-edit-enclose-mixed-region) +(define-key mime-edit-mode-enclosure-map + "\C-d" 'mime-edit-enclose-digest-region) +(define-key mime-edit-mode-enclosure-map + "\C-s" 'mime-edit-enclose-pgp-signed-region) +(define-key mime-edit-mode-enclosure-map + "\C-e" 'mime-edit-enclose-pgp-encrypted-region) +(define-key mime-edit-mode-enclosure-map + "s" 'mime-edit-enclose-smime-signed-region) +(define-key mime-edit-mode-enclosure-map + "e" 'mime-edit-enclose-smime-encrypted-region) +(define-key mime-edit-mode-enclosure-map + "\C-q" 'mime-edit-enclose-quote-region) + (defvar mime-edit-mode-map (make-sparse-keymap) "Keymap for MIME-Edit mode commands.") - -(define-key mime-edit-mode-map - "\C-c\C-x\C-t" 'mime-edit-insert-text) -(define-key mime-edit-mode-map - "\C-c\C-x\C-i" 'mime-edit-insert-file) -(define-key mime-edit-mode-map - "\C-c\C-x\C-e" 'mime-edit-insert-external) -(define-key mime-edit-mode-map - "\C-c\C-x\C-v" 'mime-edit-insert-voice) -(define-key mime-edit-mode-map - "\C-c\C-x\C-y" 'mime-edit-insert-message) -(define-key mime-edit-mode-map - "\C-c\C-x\C-m" 'mime-edit-insert-mail) -(define-key mime-edit-mode-map - "\C-c\C-x\C-w" 'mime-edit-insert-signature) -(define-key mime-edit-mode-map - "\C-c\C-x\C-s" 'mime-edit-insert-signature) -(define-key mime-edit-mode-map - "\C-c\C-x\C-k" 'mime-edit-insert-key) -(define-key mime-edit-mode-map - "\C-c\C-xt" 'mime-edit-insert-tag) - -(define-key mime-edit-mode-map - "\C-c\C-m\C-a" 'mime-edit-enclose-alternative-region) -(define-key mime-edit-mode-map - "\C-c\C-m\C-p" 'mime-edit-enclose-parallel-region) -(define-key mime-edit-mode-map - "\C-c\C-m\C-m" 'mime-edit-enclose-mixed-region) -(define-key mime-edit-mode-map - "\C-c\C-m\C-d" 'mime-edit-enclose-digest-region) -(define-key mime-edit-mode-map - "\C-c\C-m\C-s" 'mime-edit-enclose-signed-region) -(define-key mime-edit-mode-map - "\C-c\C-m\C-e" 'mime-edit-enclose-encrypted-region) (define-key mime-edit-mode-map - "\C-c\C-m\C-q" 'mime-edit-enclose-quote-region) - -(define-key mime-edit-mode-map - "\C-c\C-x7" 'mime-edit-set-transfer-level-7bit) -(define-key mime-edit-mode-map - "\C-c\C-x8" 'mime-edit-set-transfer-level-8bit) -(define-key mime-edit-mode-map - "\C-c\C-x/" 'mime-edit-set-split) -(define-key mime-edit-mode-map - "\C-c\C-xs" 'mime-edit-set-sign) -(define-key mime-edit-mode-map - "\C-c\C-xv" 'mime-edit-set-sign) -(define-key mime-edit-mode-map - "\C-c\C-xe" 'mime-edit-set-encrypt) -(define-key mime-edit-mode-map - "\C-c\C-xh" 'mime-edit-set-encrypt) -(define-key mime-edit-mode-map - "\C-c\C-x\C-p" 'mime-edit-preview-message) -(define-key mime-edit-mode-map - "\C-c\C-x\C-z" 'mime-edit-exit) + mime-edit-mode-entity-prefix mime-edit-mode-entity-map) (define-key mime-edit-mode-map - "\C-c\C-x?" 'mime-edit-help) + mime-edit-mode-enclosure-prefix mime-edit-mode-enclosure-map) (defconst mime-edit-menu-title "MIME-Edit") @@ -665,23 +787,22 @@ Tspecials means any character that matches with it in header must be quoted.") (parallel "Enclose as parallel" mime-edit-enclose-parallel-region) (mixed "Enclose as serial" mime-edit-enclose-mixed-region) (digest "Enclose as digest" mime-edit-enclose-digest-region) - (signed "Enclose as signed" mime-edit-enclose-signed-region) - (encrypted "Enclose as encrypted" mime-edit-enclose-encrypted-region) + (signed "Enclose as signed" mime-edit-enclose-pgp-signed-region) + (encrypted "Enclose as encrypted" mime-edit-enclose-pgp-encrypted-region) (quote "Verbatim region" mime-edit-enclose-quote-region) (key "Insert Public Key" mime-edit-insert-key) - (split "About split" mime-edit-set-split) - (sign "About sign" mime-edit-set-sign) - (encrypt "About encryption" mime-edit-set-encrypt) + (split "Set splitting" mime-edit-set-split) + (sign "PGP sign" mime-edit-set-sign) + (encrypt "PGP encrypt" mime-edit-set-encrypt) (preview "Preview Message" mime-edit-preview-message) - (level "Toggle transfer-level" mime-edit-toggle-transfer-level) - ) + (level "Toggle transfer-level" mime-edit-toggle-transfer-level)) "MIME-edit menubar entry.") -(cond (running-xemacs +(cond ((featurep 'xemacs) ;; modified by Pekka Marjola ;; 1995/9/5 (c.f. [tm-en:69]) (defun mime-edit-define-menu-for-xemacs () - "Define menu for Emacs 19." + "Define menu for XEmacs." (cond ((featurep 'menubar) (make-local-variable 'current-menubar) (set-buffer-menubar current-menubar) @@ -691,10 +812,8 @@ Tspecials means any character that matches with it in header must be quoted.") (mapcar (function (lambda (item) (vector (nth 1 item)(nth 2 item) - mime-edit-mode-flag) - )) - mime-edit-menu-list))) - ))) + mime-edit-mode-flag))) + mime-edit-menu-list)))))) ;; modified by Steven L. Baur ;; 1995/12/6 (c.f. [tm-en:209]) @@ -705,9 +824,7 @@ Tspecials means any character that matches with it in header must be quoted.") (vector (nth 1 item) (nth 2 item) t))) - mime-edit-menu-list))) - ) - ) + mime-edit-menu-list))))) ((>= emacs-major-version 19) (define-key mime-edit-mode-map [menu-bar mime-edit] (cons mime-edit-menu-title @@ -716,17 +833,15 @@ Tspecials means any character that matches with it in header must be quoted.") (lambda (item) (define-key mime-edit-mode-map (vector 'menu-bar 'mime-edit (car item)) - (cons (nth 1 item)(nth 2 item)) - ) - )) - (reverse mime-edit-menu-list) - ) - )) + (cons (nth 1 item)(nth 2 item))))) + (reverse mime-edit-menu-list)))) ;;; @ functions ;;; +(defvar mime-edit-touched-flag nil) + ;;;###autoload (defun mime-edit-mode () "MIME minor mode for editing the tagged MIME message. @@ -782,24 +897,27 @@ Following commands are available in addition to major mode commands: \\[mime-edit-insert-tag] insert a new MIME tag. \[make enclosure (maybe multipart)\] -\\[mime-edit-enclose-alternative-region] enclose as multipart/alternative. -\\[mime-edit-enclose-parallel-region] enclose as multipart/parallel. -\\[mime-edit-enclose-mixed-region] enclose as multipart/mixed. -\\[mime-edit-enclose-digest-region] enclose as multipart/digest. -\\[mime-edit-enclose-signed-region] enclose as PGP signed. -\\[mime-edit-enclose-encrypted-region] enclose as PGP encrypted. -\\[mime-edit-enclose-quote-region] enclose as verbose mode (to avoid to expand tags) +\\[mime-edit-enclose-alternative-region] enclose as multipart/alternative. +\\[mime-edit-enclose-parallel-region] enclose as multipart/parallel. +\\[mime-edit-enclose-mixed-region] enclose as multipart/mixed. +\\[mime-edit-enclose-digest-region] enclose as multipart/digest. +\\[mime-edit-enclose-pgp-signed-region] enclose as PGP signed. +\\[mime-edit-enclose-pgp-encrypted-region] enclose as PGP encrypted. +\\[mime-edit-enclose-quote-region] enclose as verbose mode + (to avoid to expand tags) \[other commands\] \\[mime-edit-set-transfer-level-7bit] set transfer-level as 7. \\[mime-edit-set-transfer-level-8bit] set transfer-level as 8. -\\[mime-edit-set-split] set message splitting mode. -\\[mime-edit-set-sign] set PGP-sign mode. -\\[mime-edit-set-encrypt] set PGP-encryption mode. -\\[mime-edit-preview-message] preview editing MIME message. -\\[mime-edit-exit] exit and translate into a MIME compliant message. -\\[mime-edit-help] show this help. -\\[mime-edit-maybe-translate] exit and translate if in MIME mode, then split. +\\[mime-edit-set-split] set message splitting mode. +\\[mime-edit-set-sign] set PGP-sign mode. +\\[mime-edit-set-encrypt] set PGP-encryption mode. +\\[mime-edit-preview-message] preview editing MIME message. +\\[mime-edit-exit] exit and translate into a MIME + compliant message. +\\[mime-edit-help] show this help. +\\[mime-edit-maybe-translate] exit and translate if in MIME mode, + then split. Additional commands are available in some major modes: C-c C-c exit, translate and run the original command. @@ -862,30 +980,26 @@ User customizable variables (not documented all of them): (interactive) (if mime-edit-mode-flag (mime-edit-exit) - (if (and (boundp 'mime-edit-touched-flag) - mime-edit-touched-flag) + (if mime-edit-touched-flag (mime-edit-again) (make-local-variable 'mime-edit-touched-flag) (setq mime-edit-touched-flag t) - (turn-on-mime-edit) - ))) + (turn-on-mime-edit)))) -(cond (running-xemacs +(cond ((featurep 'xemacs) (add-minor-mode 'mime-edit-mode-flag '((" MIME-Edit " mime-transfer-level-string)) mime-edit-mode-map nil - 'mime-edit-mode) - ) + 'mime-edit-mode)) (t (set-alist 'minor-mode-alist 'mime-edit-mode-flag '((" MIME-Edit " mime-transfer-level-string))) (set-alist 'minor-mode-map-alist 'mime-edit-mode-flag - mime-edit-mode-map) - )) + mime-edit-mode-map))) ;;;###autoload @@ -903,11 +1017,8 @@ User customizable variables (not documented all of them): (force-mode-line-update) ;; Define menu for XEmacs. - (if running-xemacs - (mime-edit-define-menu-for-xemacs) - ) - - (enable-invisible) + (if (featurep 'xemacs) + (mime-edit-define-menu-for-xemacs)) ;; I don't care about saving these. (setq paragraph-start @@ -918,9 +1029,9 @@ User customizable variables (not documented all of them): paragraph-separate)) (run-hooks 'mime-edit-mode-hook) (message + "%s" (substitute-command-keys - "Type \\[mime-edit-exit] to exit MIME mode, and type \\[mime-edit-help] to get help.")) - )) + "Type \\[mime-edit-exit] to exit MIME mode, and type \\[mime-edit-help] to get help.")))) ;;;###autoload (defalias 'edit-mime 'turn-on-mime-edit) ; for convenience @@ -933,29 +1044,24 @@ just return to previous mode." (interactive "P") (if (not mime-edit-mode-flag) (if (null no-error) - (error "You aren't editing a MIME message.") - ) + (error "You aren't editing a MIME message.")) (if (not nomime) (progn (run-hooks 'mime-edit-translate-hook) (mime-edit-translate-buffer))) ;; Restore previous state. (setq mime-edit-mode-flag nil) - (if (and running-xemacs + (if (and (featurep 'xemacs) (featurep 'menubar)) - (delete-menu-item (list mime-edit-menu-title)) - ) - (end-of-invisible) + (delete-menu-item (list mime-edit-menu-title))) (set-buffer-modified-p (buffer-modified-p)) (run-hooks 'mime-edit-exit-hook) - (message "Exit MIME editor mode.") - )) + (message "Exit MIME editor mode."))) (defun mime-edit-maybe-translate () (interactive) (mime-edit-exit nil t) - (call-interactively 'mime-edit-maybe-split-and-send) - ) + (call-interactively 'mime-edit-maybe-split-and-send)) (defun mime-edit-help () "Show help message about MIME mode." @@ -965,26 +1071,23 @@ just return to previous mode." (princ (documentation 'mime-edit-mode)) (print-help-return-message))) -(defun mime-edit-insert-text () +(defun mime-edit-insert-text (&optional subtype) "Insert a text message. -Charset is automatically obtained from the `charsets-mime-charset-alist'." +Charset is automatically obtained from the `charsets-mime-charset-alist'. +If optional argument SUBTYPE is not nil, text/SUBTYPE tag is inserted." (interactive) - (let ((ret (mime-edit-insert-tag "text" nil nil))) - (if ret - (progn - (if (looking-at mime-edit-single-part-tag-regexp) - (progn - ;; Make a space between the following message. - (insert "\n") - (forward-char -1) - )) - (if (and (member (cadr ret) '("enriched" "richtext")) - (fboundp 'enriched-mode) - ) - (enriched-mode t) - (if (boundp 'enriched-mode) - (enriched-mode nil) - )))))) + (let ((ret (mime-edit-insert-tag "text" subtype nil))) + (when ret + (if (looking-at mime-edit-single-part-tag-regexp) + (progn + ;; Make a space between the following message. + (insert "\n") + (forward-char -1))) + (if (and (member (cadr ret) '("enriched")) + (fboundp 'enriched-mode)) + (enriched-mode t) + (if (boundp 'enriched-mode) + (enriched-mode -1)))))) (defun mime-edit-insert-file (file &optional verbose) "Insert a message from a file." @@ -995,15 +1098,12 @@ Charset is automatically obtained from the `charsets-mime-charset-alist'." (parameters (nth 2 guess)) (encoding (nth 3 guess)) (disposition-type (nth 4 guess)) - (disposition-params (nth 5 guess)) - ) + (disposition-params (nth 5 guess))) (if verbose (setq type (mime-prompt-for-type type) - subtype (mime-prompt-for-subtype type subtype) - )) + subtype (mime-prompt-for-subtype type subtype))) (if (or (interactive-p) verbose) - (setq encoding (mime-prompt-for-encoding encoding)) - ) + (setq encoding (mime-prompt-for-encoding encoding))) (if (or (consp parameters) (stringp disposition-type)) (let ((rest parameters) cell attribute value) (setq parameters "") @@ -1013,11 +1113,9 @@ Charset is automatically obtained from the `charsets-mime-charset-alist'." (setq value (cdr cell)) (if (eq value 'file) (setq value (std11-wrap-as-quoted-string - (file-name-nondirectory file))) - ) + (file-name-nondirectory file)))) (setq parameters (concat parameters "; " attribute "=" value)) - (setq rest (cdr rest)) - ) + (setq rest (cdr rest))) (if disposition-type (progn (setq parameters @@ -1030,17 +1128,12 @@ Charset is automatically obtained from the `charsets-mime-charset-alist'." (setq value (cdr cell)) (if (eq value 'file) (setq value (std11-wrap-as-quoted-string - (file-name-nondirectory file))) - ) + (file-name-nondirectory file)))) (setq parameters (concat parameters "; " attribute "=" value)) - (setq rest (cdr rest)) - ) - )) - )) + (setq rest (cdr rest))))))) (mime-edit-insert-tag type subtype parameters) - (mime-edit-insert-binary-file file encoding) - )) + (mime-edit-insert-binary-file file encoding))) (defun mime-edit-insert-external () "Insert a reference to external body." @@ -1066,18 +1159,18 @@ Charset is automatically obtained from the `charsets-mime-charset-alist'." (let ((encoding (completing-read "What transfer encoding: " - mime-file-encoding-method-alist nil t nil))) + (mime-encoding-alist) nil t nil))) (mime-edit-insert-tag "audio" "basic" nil) (mime-edit-define-encoding encoding) (save-restriction - (narrow-to-region (1- (point))(point)) + (narrow-to-region (point)(point)) (unwind-protect (funcall mime-edit-voice-recorder encoding) (progn (insert "\n") - (invisible-region (point-min)(point-max)) - (goto-char (point-max)) - ))))) + (add-text-properties + (point-min)(point-max) '(invisible t mime-edit-invisible t)) + (goto-char (point-max))))))) (defun mime-edit-insert-signature (&optional arg) "Insert a signature file." @@ -1085,12 +1178,10 @@ Charset is automatically obtained from the `charsets-mime-charset-alist'." (let ((signature-insert-hook (function (lambda () - (apply (function mime-edit-insert-tag) - (mime-find-file-type signature-file-name)) - ))) - ) - (insert-signature arg) - )) + (let ((items (mime-find-file-type signature-file-name))) + (apply (function mime-edit-insert-tag) + (car items) (cadr items) (list (caddr items)))))))) + (insert-signature arg))) ;; Insert a new tag around a point. @@ -1103,15 +1194,12 @@ If nothing is inserted, return nil." (mime-edit-goto-tag) (if (and (re-search-forward mime-edit-tag-regexp nil t) (< (match-beginning 0) p) - (< p (match-end 0)) - ) + (< p (match-end 0))) (goto-char (match-beginning 0)) - (goto-char p) - )) + (goto-char p))) (let ((oldtag nil) (newtag nil) - (current (point)) - ) + (current (point))) (setq pritype (or pritype (mime-prompt-for-type))) @@ -1129,8 +1217,7 @@ If nothing is inserted, return nil." (if (mime-edit-goto-tag) (buffer-substring (match-beginning 0) (match-end 0)) ;; Assume content type is 'text/plan'. - (mime-make-tag "text" "plain") - ))) + (mime-make-tag "text" "plain")))) ;; We are only interested in TEXT. (if (and oldtag (not (mime-test-content-type @@ -1149,8 +1236,7 @@ If nothing is inserted, return nil." ;; Restore previous point. (goto-char current) nil ;Nothing is created. - ) - )) + ))) (defun mime-edit-insert-binary-file (file &optional encoding) "Insert binary FILE at point. @@ -1162,31 +1248,23 @@ Optional argument ENCODING specifies an encoding method such as base64." (let ((en (downcase encoding))) (or (string-equal en "7bit") (string-equal en "8bit") - (string-equal en "binary") - ))))) - ) + (string-equal en "binary"))))))) (save-restriction - (narrow-to-region tagend (point)) + (narrow-to-region (point)(point)) (mime-insert-encoded-file file encoding) (if hide-p - (progn - (invisible-region (point-min) (point-max)) - (goto-char (point-max)) - ) - (goto-char (point-max)) - )) + (add-text-properties + (point-min)(point-max) '(invisible t mime-edit-invisible t))) + (goto-char (point-max))) (or hide-p (looking-at mime-edit-tag-regexp) (= (point)(point-max)) - (mime-edit-insert-tag "text" "plain") - ) + (mime-edit-insert-tag "text" "plain")) ;; Define encoding even if it is 7bit. (if (stringp encoding) (save-excursion (goto-char tagend) ; Make sure which line the tag is on. - (mime-edit-define-encoding encoding) - )) - )) + (mime-edit-define-encoding encoding))))) ;; Commands work on a current message flagment. @@ -1201,17 +1279,14 @@ Optional argument ENCODING specifies an encoding method such as base64." (goto-char (1- (match-beginning 0))) ;For multiline tag ) (t - (goto-char (point-max)) - )) + (goto-char (point-max)))) ;; Then search for the beginning. (re-search-backward mime-edit-end-tag-regexp nil t) (or (looking-at mime-edit-beginning-tag-regexp) ;; Restore previous point. (progn (goto-char current) - nil - )) - ))) + nil))))) (defun mime-edit-content-beginning () "Return the point of the beginning of content." @@ -1232,31 +1307,28 @@ Optional argument ENCODING specifies an encoding method such as base64." (concat "\n" (regexp-quote mail-header-separator) (if mime-ignore-preceding-spaces "[ \t\n]*\n" "\n")) nil 'move) - (point)) - ))) + (point))))) (defun mime-edit-content-end () "Return the point of the end of content." (save-excursion (if (mime-edit-goto-tag) (progn - (goto-char (match-end 0)) - (if (invisible-p (point)) - (next-visible-point (point)) + (goto-char (1+ (match-end 0))) + (if (get-text-property (point) 'mime-edit-invisible) + (or (next-single-property-change (point) 'mime-edit-invisible) + (point-max)) ;; Move to the end of this text. (if (re-search-forward mime-edit-tag-regexp nil 'move) ;; Don't forget a multiline tag. - (goto-char (match-beginning 0)) - ) - (point) - )) + (goto-char (match-beginning 0))) + (point))) ;; Assume the message begins with text/plain. (goto-char (mime-edit-content-beginning)) (if (re-search-forward mime-edit-tag-regexp nil 'move) ;; Don't forget a multiline tag. (goto-char (match-beginning 0))) - (point)) - )) + (point)))) (defun mime-edit-define-charset (charset) "Set charset of current tag to CHARSET." @@ -1268,9 +1340,12 @@ Optional argument ENCODING specifies an encoding method such as base64." (mime-create-tag (mime-edit-set-parameter (mime-edit-get-contype tag) - "charset" (upcase (symbol-name charset))) - (mime-edit-get-encoding tag))) - )))) + "charset" + (let ((comment (get charset 'mime-charset-comment))) + (if comment + (concat (upcase (symbol-name charset)) " (" comment ")") + (upcase (symbol-name charset))))) + (mime-edit-get-encoding tag))))))) (defun mime-edit-define-encoding (encoding) "Set encoding of current tag to ENCODING." @@ -1278,13 +1353,11 @@ Optional argument ENCODING specifies an encoding method such as base64." (if (mime-edit-goto-tag) (let ((tag (buffer-substring (match-beginning 0) (match-end 0)))) (delete-region (match-beginning 0) (match-end 0)) - (insert (mime-create-tag (mime-edit-get-contype tag) encoding))) - ))) + (insert (mime-create-tag (mime-edit-get-contype tag) encoding)))))) (defun mime-edit-choose-charset () "Choose charset of a text following current point." - (detect-mime-charset-region (point) (mime-edit-content-end)) - ) + (detect-mime-charset-region (point) (mime-edit-content-end))) (defun mime-make-text-tag (&optional subtype) "Make a tag for a text after current point. @@ -1315,10 +1388,8 @@ Otherwise, it is obtained from mime-content-types." (and (stringp tag) (or (string-match mime-edit-single-part-tag-regexp tag) (string-match mime-edit-multipart-beginning-regexp tag) - (string-match mime-edit-multipart-end-regexp tag) - ) - (substring tag (match-beginning 1) (match-end 1)) - )) + (string-match mime-edit-multipart-end-regexp tag)) + (substring tag (match-beginning 1) (match-end 1)))) (defun mime-edit-get-encoding (tag) "Return encoding of TAG." @@ -1347,8 +1418,7 @@ Nil if no such parameter." (if (string-match "\n[^ \t\n\r]+:" contype) (setq ctype (substring contype 0 (match-beginning 0)) opt-fields (substring contype (match-beginning 0))) - (setq ctype contype) - ) + (setq ctype contype)) (if (string-match (concat ";[ \t\n]*\\(" @@ -1358,7 +1428,7 @@ Nil if no such parameter." ;; Change value (concat (substring ctype 0 (match-beginning 1)) parameter "=" value - (substring contype (match-end 1)) + (substring ctype (match-end 1)) opt-fields) (concat ctype "; " parameter "=" value opt-fields) ))) @@ -1387,8 +1457,7 @@ Nil if no such parameter." (if (string-match (car (car guesses)) file) (setq guess (cdr (car guesses)))) (setq guesses (cdr guesses))) - guess - )) + guess)) (defun mime-prompt-for-type (&optional default) "Ask for Content-type." @@ -1400,15 +1469,12 @@ Nil if no such parameter." mime-content-types nil 'require-match ;Type must be specified. - default - )) + default)) (if (string-equal type "") (progn (message "Content type is required.") (beep) - (sit-for 1) - )) - ) + (sit-for 1)))) type)) (defun mime-prompt-for-subtype (type &optional default) @@ -1416,8 +1482,7 @@ Nil if no such parameter." (let ((subtypes (cdr (assoc type mime-content-types)))) (or (and default (assoc default subtypes)) - (setq default (car (car subtypes))) - )) + (setq default (car (car subtypes))))) (let* ((answer (completing-read (if default @@ -1427,8 +1492,7 @@ Nil if no such parameter." (cdr (assoc type mime-content-types)) nil 'require-match ;Subtype must be specified. - nil - ))) + nil))) (if (string-equal answer "") default answer))) (defun mime-prompt-for-parameters (pritype subtype &optional delimiter) @@ -1442,8 +1506,7 @@ Optional DELIMITER specifies parameter delimiter (';' by default)." (mime-prompt-for-parameters-1 (cdr (assoc subtype (cdr (assoc pritype mime-content-types)))))) - delimiter - ))) + delimiter))) (if (and (stringp parameters) (not (string-equal parameters ""))) (concat delimiter parameters) @@ -1456,7 +1519,7 @@ Optional DELIMITER specifies parameter delimiter (';' by default)." (defun mime-prompt-for-parameter (parameter) "Ask for PARAMETER. -Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." +Parameter must be '(PROMPT CHOICE1 (CHOICE2...))." (let* ((prompt (car parameter)) (choices (mapcar (function (lambda (e) @@ -1484,8 +1547,7 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." ;; Note: control characters ignored! (if (string-match mime-tspecials-regexp answer) (concat "\"" answer "\"") answer))) - (mime-prompt-for-parameters-1 (cdr (assoc answer (cdr parameter))))) - )) + (mime-prompt-for-parameters-1 (cdr (assoc answer (cdr parameter))))))) (defun mime-prompt-for-encoding (default) "Ask for Content-Transfer-Encoding." @@ -1494,8 +1556,7 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (setq encoding (completing-read "What transfer encoding: " - mime-file-encoding-method-alist nil t default) - ) + (mime-encoding-alist) nil t default)) "")) encoding)) @@ -1510,21 +1571,19 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (defun mime-edit-translate-header () "Encode the message header into network representation." - (eword-encode-header 'code-conversion) - (run-hooks 'mime-edit-translate-header-hook) - ) + (mime-encode-header-in-buffer 'code-conversion) + (run-hooks 'mime-edit-translate-header-hook)) (defun mime-edit-translate-buffer () "Encode the tagged MIME message in current buffer in MIME compliant message." (interactive) + (undo-boundary) (if (catch 'mime-edit-error (save-excursion - (run-hooks 'mime-edit-translate-buffer-hook) - )) + (run-hooks 'mime-edit-translate-buffer-hook))) (progn (undo) - (error "Translation error!") - ))) + (error "Translation error!")))) (defun mime-edit-find-inmost () (goto-char (point-min)) @@ -1532,35 +1591,27 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (let ((bb (match-beginning 0)) (be (match-end 0)) (type (buffer-substring (match-beginning 1)(match-end 1))) - end-exp eb ee) + end-exp eb) (setq end-exp (format "--}-<<%s>>\n" type)) (widen) (if (re-search-forward end-exp nil t) - (progn - (setq eb (match-beginning 0)) - (setq ee (match-end 0)) - ) - (setq eb (point-max)) - (setq ee (point-max)) - ) + (setq eb (match-beginning 0)) + (setq eb (point-max))) (narrow-to-region be eb) (goto-char be) (if (re-search-forward mime-edit-multipart-beginning-regexp nil t) - (let (ret) + (progn (narrow-to-region (match-beginning 0)(point-max)) - (mime-edit-find-inmost) - ) + (mime-edit-find-inmost)) (widen) - (list type bb be eb) - )))) + (list type bb be eb))))) (defun mime-edit-process-multipart-1 (boundary) (let ((ret (mime-edit-find-inmost))) (if ret (let ((type (car ret)) (bb (nth 1 ret))(be (nth 2 ret)) - (eb (nth 3 ret)) - ) + (eb (nth 3 ret))) (narrow-to-region bb eb) (delete-region bb be) (setq bb (point-min)) @@ -1569,31 +1620,22 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (goto-char eb) (if (looking-at mime-edit-multipart-end-regexp) (let ((beg (match-beginning 0)) - (end (match-end 0)) - ) + (end (match-end 0))) (delete-region beg end) (or (looking-at mime-edit-beginning-tag-regexp) + (looking-at mime-edit-multipart-end-regexp) (eobp) - (insert (concat (mime-make-text-tag) "\n")) - ))) + (insert (concat (mime-make-text-tag) "\n"))))) (cond ((string-equal type "quote") - (mime-edit-enquote-region bb eb) - ) - ((string-equal type "signed") - (cond ((eq mime-edit-signing-type 'pgp-elkins) - (mime-edit-sign-pgp-elkins bb eb boundary) - ) - ((eq mime-edit-signing-type 'pgp-kazu) - (mime-edit-sign-pgp-kazu bb eb boundary) - )) - ) - ((string-equal type "encrypted") - (cond ((eq mime-edit-encrypting-type 'pgp-elkins) - (mime-edit-encrypt-pgp-elkins bb eb boundary) - ) - ((eq mime-edit-encrypting-type 'pgp-kazu) - (mime-edit-encrypt-pgp-kazu bb eb boundary) - ))) + (mime-edit-enquote-region bb eb)) + ((string-equal type "pgp-signed") + (mime-edit-sign-pgp-mime bb eb boundary)) + ((string-equal type "pgp-encrypted") + (mime-edit-encrypt-pgp-mime bb eb boundary)) + ((string-equal type "smime-signed") + (mime-edit-sign-smime bb eb boundary)) + ((string-equal type "smime-encrypted") + (mime-edit-encrypt-smime bb eb boundary)) (t (setq boundary (nth 2 (mime-edit-translate-region bb eb @@ -1602,8 +1644,7 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (insert (format "--[[multipart/%s; boundary=\"%s\"][7bit]]\n" - type boundary)) - )) + type boundary)))) boundary)))) (defun mime-edit-enquote-region (beg end) @@ -1613,8 +1654,7 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (goto-char beg) (while (re-search-forward mime-edit-single-part-tag-regexp nil t) (let ((tag (buffer-substring (match-beginning 0)(match-end 0)))) - (replace-match (concat "- " (substring tag 1))) - ))))) + (replace-match (concat "- " (substring tag 1)))))))) (defun mime-edit-dequote-region (beg end) (save-excursion @@ -1624,32 +1664,92 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (while (re-search-forward mime-edit-quoted-single-part-tag-regexp nil t) (let ((tag (buffer-substring (match-beginning 0)(match-end 0)))) - (replace-match (concat "-" (substring tag 2))) - ))))) + (replace-match (concat "-" (substring tag 2)))))))) + +(defvar mime-edit-pgp-user-id nil) -(defun mime-edit-sign-pgp-elkins (beg end boundary) +(defun mime-edit-delete-trailing-whitespace () + (save-match-data + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "[ \t]+$" nil t) + (delete-region (match-beginning 0) (match-end 0)))))) + +(defun mime-edit-sign-pgp-mime (beg end boundary) (save-excursion (save-restriction - (narrow-to-region beg end) - (let* ((ret - (mime-edit-translate-region beg end boundary)) + (let* ((from (std11-field-body "From" mail-header-separator)) + (ret (progn + (narrow-to-region beg end) + (mime-edit-translate-region beg end boundary))) (ctype (car ret)) (encoding (nth 1 ret)) - (parts (nth 3 ret)) (pgp-boundary (concat "pgp-sign-" boundary)) - ) + (context (epg-make-context)) + (index 0) + plain signature micalg) + (mime-edit-delete-trailing-whitespace) ; RFC3156 (goto-char beg) (insert (format "Content-Type: %s\n" ctype)) (if encoding - (insert (format "Content-Transfer-Encoding: %s\n" encoding)) - ) + (insert (format "Content-Transfer-Encoding: %s\n" encoding))) (insert "\n") - (or (as-binary-process - (funcall (pgp-function 'mime-sign) - (point-min)(point-max) nil nil pgp-boundary)) - (throw 'mime-edit-error 'pgp-error) - ) - )))) + (epg-context-set-armor context t) + (epg-context-set-textmode context nil) + (if mime-edit-pgp-verbose + (epg-context-set-signers + context + (epa-select-keys + context + "\ +Select keys for signing. +If no one is selected, default secret key is used. " + (if from + (cons (nth 1 (std11-extract-address-components from)) + mime-edit-pgp-signers)) + t)) + (if mime-edit-pgp-signers + (epg-context-set-signers + context + (mapcar (lambda (name) + (car (epg-list-keys context name t))) + mime-edit-pgp-signers)))) + (setq plain (buffer-substring (point-min) (point-max))) + (while (string-match "\r?\n" plain index) + (if (eq (aref plain (match-beginning 0)) ?\r) + (setq index (match-end 0)) + (setq plain (replace-match "\r\n" t t plain) + index (1+ (match-end 0))))) + (condition-case error + (setq signature + (epg-sign-string context plain 'detached)) + (error (signal 'mime-edit-error (cdr error)))) + (setq micalg (epg-new-signature-digest-algorithm + (car (epg-context-result-for context 'sign)))) + (goto-char beg) + (insert (format "--[[multipart/signed; + boundary=\"%s\"%s; + protocol=\"application/pgp-signature\"][7bit]] +--%s +" + pgp-boundary + (if micalg + (concat "; micalg=pgp-" + (downcase + (cdr (assq micalg + epg-digest-algorithm-alist)))) + "") + pgp-boundary)) + (goto-char (point-max)) + (insert (format "\n--%s +Content-Type: application/pgp-signature +Content-Transfer-Encoding: 7bit +Content-Description: OpenPGP Digital Signature + +" pgp-boundary)) + (insert signature) + (goto-char (point-max)) + (insert (format "\n--%s--\n" pgp-boundary)))))) (defvar mime-edit-encrypt-recipient-fields-list '("To" "cc")) @@ -1664,55 +1764,73 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))." (header (and (stringp from) (if (string-equal from "") "" - (format "From: %s\n" from) - ))) + (format "From: %s\n" from)))) recipients) (while (and names values) (let ((name (car names)) - (value (car values)) - ) + (value (car values))) (and (stringp value) (or (string-equal value "") (progn (setq header (concat header name ": " value "\n") recipients (if recipients (concat recipients " ," value) - value)) - )))) + value)))))) (setq names (cdr names) - values (cdr values)) - ) - (vector from recipients header) - )) + values (cdr values))) + (vector from recipients header))) -(defun mime-edit-encrypt-pgp-elkins (beg end boundary) +(defun mime-edit-encrypt-pgp-mime (beg end boundary) (save-excursion (save-restriction - (let (from recipients header) - (let ((ret (mime-edit-make-encrypt-recipient-header))) - (setq from (aref ret 0) - recipients (aref ret 1) - header (aref ret 2)) - ) - (narrow-to-region beg end) - (let* ((ret - (mime-edit-translate-region beg end boundary)) - (ctype (car ret)) - (encoding (nth 1 ret)) - (parts (nth 3 ret)) - (pgp-boundary (concat "pgp-" boundary)) - ) - (goto-char beg) - (insert header) - (insert (format "Content-Type: %s\n" ctype)) - (if encoding - (insert (format "Content-Transfer-Encoding: %s\n" encoding)) - ) - (insert "\n") - (or (funcall (pgp-function 'encrypt) - recipients (point-min) (point-max) from) - (throw 'mime-edit-error 'pgp-error) - ) + (let* ((config (epg-configuration)) + (ret (mime-edit-make-encrypt-recipient-header)) + (recipients (aref ret 1)) + (header (aref ret 2))) + (setq recipients + (apply #'nconc + (mapcar (lambda (recipient) + (setq recipient + (nth 1 (std11-extract-address-components + recipient))) + (or (epg-expand-group config recipient) + (list recipient))) + (delete "" (split-string recipients + "[ \f\t\n\r\v,]+"))))) + (narrow-to-region beg end) + (let* ((ret + (mime-edit-translate-region beg end boundary)) + (ctype (car ret)) + (encoding (nth 1 ret)) + (pgp-boundary (concat "pgp-" boundary)) + (context (epg-make-context)) + cipher) + (goto-char beg) + (insert header) + (insert (format "Content-Type: %s\n" ctype)) + (if encoding + (insert (format "Content-Transfer-Encoding: %s\n" encoding))) + (insert "\n") + (mime-encode-header-in-buffer) + (epg-context-set-armor context t) + (if mime-edit-pgp-verbose + (setq recipients + (epa-select-keys context "\ +Select recipients for encryption. +If no one is selected, symmetric encryption will be performed. " + recipients)) + (setq recipients + (delq nil (mapcar (lambda (name) + (car (epg-list-keys context name))) + recipients)))) + (condition-case error + (setq cipher + (epg-encrypt-string + context + (buffer-substring (point-min) (point-max)) + recipients)) + (error (signal 'mime-edit-error (cdr error)))) + (delete-region (point-min)(point-max)) (goto-char beg) (insert (format "--[[multipart/encrypted; boundary=\"%s\"; @@ -1725,71 +1843,122 @@ Content-Type: application/octet-stream Content-Transfer-Encoding: 7bit " pgp-boundary pgp-boundary pgp-boundary)) + (insert cipher) (goto-char (point-max)) - (insert (format "\n--%s--\n" pgp-boundary)) - ))))) + (insert (format "\n--%s--\n" pgp-boundary))))))) -(defun mime-edit-sign-pgp-kazu (beg end boundary) +(defun mime-edit-convert-lbt-string (string) + (let ((index 0)) + (while (setq index (string-match "\n" string index)) + (setq string (replace-match "\r\n" nil nil string) + index (+ index 2))) ;(length "\r\n") + string)) + +(defun mime-edit-sign-smime (beg end boundary) (save-excursion (save-restriction - (narrow-to-region beg end) - (let* ((ret - (mime-edit-translate-region beg end boundary)) + (let* ((from (std11-field-body "From" mail-header-separator)) + (ret (progn + (narrow-to-region beg end) + (mime-edit-translate-region beg end boundary))) (ctype (car ret)) (encoding (nth 1 ret)) - (parts (nth 3 ret)) - ) + (smime-boundary (concat "smime-sign-" boundary)) + (context (epg-make-context 'CMS)) + signature micalg) (goto-char beg) (insert (format "Content-Type: %s\n" ctype)) (if encoding - (insert (format "Content-Transfer-Encoding: %s\n" encoding)) - ) + (insert (format "Content-Transfer-Encoding: %s\n" encoding))) (insert "\n") - (or (as-binary-process - (funcall (pgp-function 'traditional-sign) - beg (point-max))) - (throw 'mime-edit-error 'pgp-error) - ) + (epg-context-set-signers + context + (epa-select-keys + context + "\ +Select keys for signing. +If no one is selected, default secret key is used. " + (if from + (list (nth 1 (std11-extract-address-components from)))) + t)) + (condition-case error + (setq signature + (epg-sign-string context + (mime-edit-convert-lbt-string + (buffer-substring (point-min) (point-max))) + 'detached)) + (error (signal 'mime-edit-error (cdr error)))) + (setq micalg (epg-new-signature-digest-algorithm + (car (epg-context-result-for context 'sign)))) (goto-char beg) - (insert - "--[[application/pgp; format=mime][7bit]]\n") - )) - )) + (insert (format "--[[multipart/signed; + boundary=\"%s\"%s; + protocol=\"application/pkcs7-signature\"][7bit]] +--%s +" + smime-boundary + (if micalg + (concat "; micalg=" + (downcase + (cdr (assq micalg + epg-digest-algorithm-alist)))) + "") + smime-boundary)) + (goto-char (point-max)) + (insert (format "\n--%s +Content-Type: application/pkcs7-signature; name=smime.p7s +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename=smime.p7s +Content-Description: S/MIME Digital Signature -(defun mime-edit-encrypt-pgp-kazu (beg end boundary) +" smime-boundary) + (base64-encode-string signature)))))) + +(defun mime-edit-encrypt-smime (beg end boundary) (save-excursion - (let (from recipients header) - (let ((ret (mime-edit-make-encrypt-recipient-header))) - (setq from (aref ret 0) - recipients (aref ret 1) - header (aref ret 2)) - ) - (save-restriction - (narrow-to-region beg end) - (let* ((ret - (mime-edit-translate-region beg end boundary)) - (ctype (car ret)) - (encoding (nth 1 ret)) - (parts (nth 3 ret)) - ) - (goto-char beg) - (insert header) - (insert (format "Content-Type: %s\n" ctype)) - (if encoding - (insert (format "Content-Transfer-Encoding: %s\n" encoding)) - ) - (insert "\n") - (or (as-binary-process - (funcall (pgp-function 'encrypt) - recipients beg (point-max) nil 'maybe) - ) - (throw 'mime-edit-error 'pgp-error) - ) + (save-restriction + (let* ((ret (mime-edit-make-encrypt-recipient-header)) + (recipients (aref ret 1)) + (header (aref ret 2))) + (narrow-to-region beg end) + (let* ((ret + (mime-edit-translate-region beg end boundary)) + (ctype (car ret)) + (encoding (nth 1 ret)) + (context (epg-make-context 'CMS)) + cipher) + (goto-char beg) + (insert header) + (insert (format "Content-Type: %s\n" ctype)) + (if encoding + (insert (format "Content-Transfer-Encoding: %s\n" encoding))) + (insert "\n") + (mime-encode-header-in-buffer) + (condition-case error + (setq cipher + (epg-encrypt-string + context + (buffer-substring (point-min) (point-max)) + (epa-select-keys + context + "\ +Select recipients for encryption. +If no one is selected, symmetric encryption will be performed. " + (mapcar (lambda (recipient) + (nth 1 (std11-extract-address-components + recipient))) + (delete "" (split-string recipients + "[ \f\t\n\r\v,]+")))))) + (error (signal 'mime-edit-error (cdr error)))) + (delete-region (point-min)(point-max)) (goto-char beg) - (insert - "--[[application/pgp; format=mime][7bit]]\n") - )) - ))) + (insert (format "--[[application/pkcs7-mime; + smime-type=enveloped-data; + name=smime.p7m +Content-Disposition: attachment; filename=smime.p7m][base64]] + +") + (base64-encode-string cipher))))))) (defsubst replace-space-with-underline (str) (mapconcat (function @@ -1797,13 +1966,11 @@ Content-Transfer-Encoding: 7bit (char-to-string (if (eq arg ?\ ) ?_ - arg)))) str "") - ) + arg)))) str "")) (defun mime-edit-make-boundary () (concat mime-multipart-boundary "_" - (replace-space-with-underline (current-time-string)) - )) + (replace-space-with-underline (current-time-string)))) (defun mime-edit-translate-body () "Encode the tagged MIME body in current buffer in MIME compliant message." @@ -1814,8 +1981,7 @@ Content-Transfer-Encoding: 7bit ret) (while (mime-edit-process-multipart-1 (format "%s-%d" boundary i)) - (setq i (1+ i)) - ) + (setq i (1+ i))) (save-restriction ;; We are interested in message body. (let* ((beg @@ -1835,17 +2001,15 @@ Content-Transfer-Encoding: 7bit (point)))) (setq ret (mime-edit-translate-region beg end - (format "%s-%d" boundary i))) - )) + (format "%s-%d" boundary i))))) (mime-edit-dequote-region (point-min)(point-max)) (let ((contype (car ret)) ;Content-Type (encoding (nth 1 ret)) ;Content-Transfer-Encoding ) - ;; Insert X-Emacs field - (and mime-edit-insert-x-emacs-field - (or (mail-position-on-field "X-Emacs") - (insert mime-edit-x-emacs-value) - )) + ;; Insert User-Agent field + (and mime-edit-insert-user-agent-field + (or (mail-position-on-field "User-Agent") + (insert mime-edit-user-agent-value))) ;; Make primary MIME headers. (or (mail-position-on-field "MIME-Version") (insert mime-edit-mime-version-value)) @@ -1863,34 +2027,32 @@ Content-Transfer-Encoding: 7bit (if encoding (progn (mail-position-on-field "Content-Transfer-Encoding") - (insert encoding))) - )))) + (insert encoding))))))) -(defun mime-edit-translate-single-part-tag (&optional prefix) +(defun mime-edit-translate-single-part-tag (boundary &optional prefix) "Translate single-part-tag to MIME header." (if (re-search-forward mime-edit-single-part-tag-regexp nil t) (let* ((beg (match-beginning 0)) (end (match-end 0)) - (tag (buffer-substring beg end)) - ) + (tag (buffer-substring beg end))) (delete-region beg end) (let ((contype (mime-edit-get-contype tag)) - (encoding (mime-edit-get-encoding tag)) - ) + (encoding (mime-edit-get-encoding tag))) (insert (concat prefix "--" boundary "\n")) (save-restriction (narrow-to-region (point)(point)) (insert "Content-Type: " contype "\n") (if encoding (insert "Content-Transfer-Encoding: " encoding "\n")) - (eword-encode-header) - )) - t))) + (mime-encode-header-in-buffer)) + (cons (and contype + (downcase contype)) + (and encoding + (downcase encoding))))))) (defun mime-edit-translate-region (beg end &optional boundary multipart) (or boundary - (setq boundary (mime-edit-make-boundary)) - ) + (setq boundary (mime-edit-make-boundary))) (save-excursion (save-restriction (narrow-to-region beg end) @@ -1916,28 +2078,28 @@ Content-Transfer-Encoding: 7bit (buffer-substring (match-beginning 0) (match-end 0))) (delete-region (match-beginning 0) (1+ (match-end 0))) (setq contype (mime-edit-get-contype tag)) - (setq encoding (mime-edit-get-encoding tag)) - )) + (setq encoding (mime-edit-get-encoding tag)))) (t ;; It's a multipart message. (goto-char (point-min)) - (and (mime-edit-translate-single-part-tag) - (while (mime-edit-translate-single-part-tag "\n")) - ) - ;; Define Content-Type as "multipart/mixed". - (setq contype - (concat "multipart/mixed;\n boundary=\"" boundary "\"")) - ;; Content-Transfer-Encoding must be "7bit". - ;; The following encoding can be `nil', but is - ;; specified as is since there is no way that a user - ;; specifies it. - (setq encoding "7bit") - ;; Insert the trailer. - (goto-char (point-max)) - (insert "\n--" boundary "--\n") - )) - (list contype encoding boundary nparts) - )))) + (let ((prio mime-content-transfer-encoding-priority-list) + part-info nprio) + (when (setq part-info + (mime-edit-translate-single-part-tag boundary)) + (and (setq nprio (member (cdr part-info) prio)) + (setq prio nprio)) + (while (setq part-info + (mime-edit-translate-single-part-tag boundary "\n")) + (and (setq nprio (member (cdr part-info) prio)) + (setq prio nprio)))) + ;; Define Content-Type as "multipart/mixed". + (setq contype + (concat "multipart/mixed;\n boundary=\"" boundary "\"")) + (setq encoding (car prio)) + ;; Insert the trailer. + (goto-char (point-max)) + (insert "\n--" boundary "--\n")))) + (list contype encoding boundary nparts))))) (defun mime-edit-normalize-body () "Normalize the body part by inserting appropriate message tags." @@ -1956,23 +2118,19 @@ Content-Transfer-Encoding: 7bit (if (looking-at "[ \t]+$") (delete-region (match-beginning 0) (match-end 0))) (let ((beg (point)) - (end (mime-edit-content-end)) - ) + (end (mime-edit-content-end))) (if (= end (point-max)) nil (goto-char end) (or (looking-at mime-edit-beginning-tag-regexp) (eobp) - (insert (mime-make-text-tag) "\n") - )) - (visible-region beg end) - (goto-char beg) - ) + (insert (mime-make-text-tag) "\n"))) + (remove-text-properties beg end '(invisible mime-edit-invisible)) + (goto-char beg)) (cond ((mime-test-content-type contype "message") ;; Content-type "message" should be sent as is. - (forward-line 1) - ) + (forward-line 1)) ((mime-test-content-type contype "text") ;; Define charset for text if necessary. (setq charset (if charset @@ -1982,15 +2140,13 @@ Content-Transfer-Encoding: 7bit (cond ((string-equal contype "text/x-rot13-47-48") (save-excursion (forward-line) - (mule-caesar-region (point) (mime-edit-content-end)) - )) + (mule-caesar-region (point) (mime-edit-content-end)))) ((string-equal contype "text/enriched") (save-excursion (let ((beg (progn (forward-line) (point))) - (end (mime-edit-content-end)) - ) + (end (mime-edit-content-end))) ;; Patch for hard newlines ;; (save-excursion ;; (goto-char beg) @@ -1999,70 +2155,70 @@ Content-Transfer-Encoding: 7bit ;; (point) ;; 'hard t))) ;; End patch for hard newlines - (enriched-encode beg end) + (enriched-encode beg end nil) (goto-char beg) (if (search-forward "\n\n") - (delete-region beg (match-end 0)) - ) - )))) + (delete-region beg (match-end 0))))))) ;; Point is now on current tag. ;; Define encoding and encode text if necessary. (or encoding ;Encoding is not specified. (let* ((encoding - (cdr - (assq charset - mime-edit-charset-default-encoding-alist) - )) - (beg (mime-edit-content-beginning)) - ) + (let (bits conv) + (let ((ret (cdr (assq charset mime-charset-type-list)))) + (if ret + (setq bits (car ret) + conv (nth 1 ret)) + (setq bits 8 + conv "quoted-printable"))) + (if (<= bits mime-transfer-level) + (mime-encoding-name bits) + conv))) + (beg (mime-edit-content-beginning))) (encode-mime-charset-region beg (mime-edit-content-end) charset) ;; Protect "From " in beginning of line (save-restriction (narrow-to-region beg (mime-edit-content-end)) (goto-char beg) - (if (re-search-forward "^From " nil t) - (unless encoding - (if (memq charset '(iso-2022-jp - iso-2022-jp-2 - iso-2022-int-1 - x-ctext)) - (while (progn - (replace-match "\e(BFrom ") - (re-search-forward "^From " nil t) - )) - (setq encoding "quoted-printable") - )))) + (let (case-fold-search) + (if (re-search-forward "^From " nil t) + (unless encoding + (if (memq charset '(iso-2022-jp + iso-2022-jp-2 + iso-2022-int-1 + x-ctext)) + (while (progn + (replace-match "\e(BFrom ") + (re-search-forward "^From " nil t))) + (setq encoding "quoted-printable")))))) ;; canonicalize line break code (or (member encoding '(nil "7bit" "8bit" "quoted-printable")) (save-restriction (narrow-to-region beg (mime-edit-content-end)) (goto-char beg) - (while (re-search-forward "\\([^\r]\\)\n" nil t) - (replace-match - (concat (buffer-substring (match-beginning 0) - (match-end 1)) "\r\n")) - ))) + (while (re-search-forward "\\(\\=\\|[^\r]\\)\n" nil t) + ;; In a certain period, `replace-match' with "\\N" + ;; converted 8-bit characters into multibyte string, + ;; but it has been fixed at 2004-01-15. + ;;(replace-match "\\1\r\n")))) + (backward-char 1) + (insert "\r") + (forward-char 1)))) (goto-char beg) - (mime-encode-region beg (mime-edit-content-end) encoding) - (mime-edit-define-encoding encoding) - )) - (goto-char (mime-edit-content-end)) - ) + (mime-encode-region beg (mime-edit-content-end) + (or encoding "7bit")) + (mime-edit-define-encoding encoding))) + (goto-char (mime-edit-content-end))) ((null encoding) ;Encoding is not specified. ;; Application, image, audio, video, and any other ;; unknown content-type without encoding should be ;; encoded. (let* ((encoding "base64") ;Encode in BASE64 by default. (beg (mime-edit-content-beginning)) - (end (mime-edit-content-end)) - (body (buffer-substring beg end)) - ) + (end (mime-edit-content-end))) (mime-encode-region beg end encoding) (mime-edit-define-encoding encoding)) - (forward-line 1) - )) - ))) + (forward-line 1)))))) (defun mime-delete-field (field) "Delete header FIELD." @@ -2070,8 +2226,7 @@ Content-Transfer-Encoding: 7bit (goto-char (point-min)) (while (re-search-forward regexp nil t) (delete-region (match-beginning 0) - (progn (forward-line 1) (point))) - ))) + (1+ (std11-field-end)))))) ;;; @@ -2085,8 +2240,7 @@ Content-Transfer-Encoding: 7bit and insert data encoded as ENCODING." (message "Start the recording on %s. Type C-g to finish the recording..." (system-name)) - (mime-insert-encoded-file "/dev/audio" encoding) - ) + (mime-insert-encoded-file "/dev/audio" encoding)) ;;; @ Other useful commands. @@ -2100,10 +2254,8 @@ and insert data encoded as ENCODING." (if (and inserter (fboundp inserter)) (progn (mime-edit-insert-tag "message" "rfc822") - (funcall inserter message) - ) - (message "Sorry, I don't have message inserter for your MUA.") - ))) + (funcall inserter message)) + (message "Sorry, I don't have message inserter for your MUA.")))) (defun mime-edit-insert-mail (&optional message) (interactive) @@ -2111,10 +2263,8 @@ and insert data encoded as ENCODING." (if (and inserter (fboundp inserter)) (progn (mime-edit-insert-tag "message" "rfc822") - (funcall inserter message) - ) - (message "Sorry, I don't have mail inserter for your MUA.") - ))) + (funcall inserter message)) + (message "Sorry, I don't have mail inserter for your MUA.")))) (defun mime-edit-inserted-message-filter () (save-excursion @@ -2125,17 +2275,13 @@ and insert data encoded as ENCODING." ;; for Emacs 18 ;; (if (re-search-forward "^$" (marker-position (mark-marker))) (if (re-search-forward "^$" (mark t)) - (narrow-to-region header-start (match-beginning 0)) - ) + (narrow-to-region header-start (match-beginning 0))) (goto-char header-start) (while (and (re-search-forward mime-edit-yank-ignored-field-regexp nil t) (setq beg (match-beginning 0)) - (setq end (1+ (std11-field-end))) - ) - (delete-region beg end) - ) - )))) + (setq end (1+ (std11-field-end)))) + (delete-region beg end)))))) ;;; @ multipart enclosure @@ -2144,66 +2290,65 @@ and insert data encoded as ENCODING." (defun mime-edit-enclose-region-internal (type beg end) (save-excursion (goto-char beg) - (let ((current (point))) - (save-restriction - (narrow-to-region beg end) - (insert (format "--<<%s>>-{\n" type)) - (goto-char (point-max)) - (insert (format "--}-<<%s>>\n" type)) - (goto-char (point-max)) - ) - (or (looking-at mime-edit-beginning-tag-regexp) - (eobp) - (insert (mime-make-text-tag) "\n") - ) - ))) + (save-restriction + (narrow-to-region beg end) + (insert (format "--<<%s>>-{\n" type)) + (goto-char (point-max)) + (insert (format "--}-<<%s>>\n" type)) + (goto-char (point-max))) + (or (looking-at mime-edit-beginning-tag-regexp) + (eobp) + (insert (mime-make-text-tag) "\n")))) (defun mime-edit-enclose-quote-region (beg end) (interactive "*r") - (mime-edit-enclose-region-internal 'quote beg end) - ) + (mime-edit-enclose-region-internal 'quote beg end)) (defun mime-edit-enclose-mixed-region (beg end) (interactive "*r") - (mime-edit-enclose-region-internal 'mixed beg end) - ) + (mime-edit-enclose-region-internal 'mixed beg end)) (defun mime-edit-enclose-parallel-region (beg end) (interactive "*r") - (mime-edit-enclose-region-internal 'parallel beg end) - ) + (mime-edit-enclose-region-internal 'parallel beg end)) (defun mime-edit-enclose-digest-region (beg end) (interactive "*r") - (mime-edit-enclose-region-internal 'digest beg end) - ) + (mime-edit-enclose-region-internal 'digest beg end)) (defun mime-edit-enclose-alternative-region (beg end) (interactive "*r") - (mime-edit-enclose-region-internal 'alternative beg end) - ) + (mime-edit-enclose-region-internal 'alternative beg end)) -(defun mime-edit-enclose-signed-region (beg end) +(defun mime-edit-enclose-pgp-signed-region (beg end) (interactive "*r") - (if mime-edit-signing-type - (mime-edit-enclose-region-internal 'signed beg end) - (message "Please specify signing type.") - )) + (mime-edit-enclose-region-internal 'pgp-signed beg end)) -(defun mime-edit-enclose-encrypted-region (beg end) +(defun mime-edit-enclose-pgp-encrypted-region (beg end) (interactive "*r") - (if mime-edit-signing-type - (mime-edit-enclose-region-internal 'encrypted beg end) - (message "Please specify encrypting type.") - )) + (mime-edit-enclose-region-internal 'pgp-encrypted beg end)) + +(defun mime-edit-enclose-smime-signed-region (beg end) + (interactive "*r") + (mime-edit-enclose-region-internal 'smime-signed beg end)) + +(defun mime-edit-enclose-smime-encrypted-region (beg end) + (interactive "*r") + (mime-edit-enclose-region-internal 'smime-encrypted beg end)) (defun mime-edit-insert-key (&optional arg) "Insert a pgp public key." (interactive "P") (mime-edit-insert-tag "application" "pgp-keys") (mime-edit-define-encoding "7bit") - (funcall (pgp-function 'insert-key)) - ) + (let ((context (epg-make-context))) + (epg-context-set-armor context t) + (epg-export-keys-to-string context + (epa-select-keys context + "Select keys for export. "))) + (if (and (not (eobp)) + (not (looking-at mime-edit-single-part-tag-regexp))) + (insert (mime-make-text-tag) "\n"))) ;;; @ flag setting @@ -2212,13 +2357,11 @@ and insert data encoded as ENCODING." (defun mime-edit-set-split (arg) (interactive (list - (y-or-n-p "Do you want to enable split? ") - )) + (y-or-n-p "Do you want to enable split? "))) (setq mime-edit-split-message arg) (if arg (message "This message is enabled to split.") - (message "This message is not enabled to split.") - )) + (message "This message is not enabled to split."))) (defun mime-edit-toggle-transfer-level (&optional transfer-level) "Toggle transfer-level is 7bit or 8bit through. @@ -2229,88 +2372,72 @@ Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8." (setq mime-transfer-level transfer-level) (if (< mime-transfer-level 8) (setq mime-transfer-level 8) - (setq mime-transfer-level 7) - )) - (setq mime-edit-charset-default-encoding-alist - (mime-make-charset-default-encoding-alist mime-transfer-level)) + (setq mime-transfer-level 7))) (message (format "Current transfer-level is %d bit" mime-transfer-level)) (setq mime-transfer-level-string (mime-encoding-name mime-transfer-level 'not-omit)) - (force-mode-line-update) - ) + (force-mode-line-update)) (defun mime-edit-set-transfer-level-7bit () (interactive) - (mime-edit-toggle-transfer-level 7) - ) + (mime-edit-toggle-transfer-level 7)) (defun mime-edit-set-transfer-level-8bit () (interactive) - (mime-edit-toggle-transfer-level 8) - ) + (mime-edit-toggle-transfer-level 8)) ;;; @ pgp ;;; +(defvar mime-edit-pgp-processing nil) +(make-variable-buffer-local 'mime-edit-pgp-processing) + (defun mime-edit-set-sign (arg) (interactive (list - (y-or-n-p "Do you want to sign? ") - )) + (y-or-n-p "Do you want to sign? "))) (if arg - (if mime-edit-signing-type - (progn - (setq mime-edit-pgp-processing 'sign) - (message "This message will be signed.") - ) - (message "Please specify signing type.") - ) - (if (eq mime-edit-pgp-processing 'sign) - (setq mime-edit-pgp-processing nil) - ) - (message "This message will not be signed.") - )) + (progn + (or (memq 'sign mime-edit-pgp-processing) + (setq mime-edit-pgp-processing + (nconc mime-edit-pgp-processing + (copy-sequence '(sign))))) + (message "This message will be signed.")) + (setq mime-edit-pgp-processing + (delq 'sign mime-edit-pgp-processing)) + (message "This message will not be signed."))) (defun mime-edit-set-encrypt (arg) (interactive (list - (y-or-n-p "Do you want to encrypt? ") - )) + (y-or-n-p "Do you want to encrypt? "))) (if arg - (if mime-edit-encrypting-type - (progn - (setq mime-edit-pgp-processing 'encrypt) - (message "This message will be encrypt.") - ) - (message "Please specify encrypting type.") - ) - (if (eq mime-edit-pgp-processing 'encrypt) - (setq mime-edit-pgp-processing nil) - ) - (message "This message will not be encrypt.") - )) - -(defvar mime-edit-pgp-processing nil) -(make-variable-buffer-local 'mime-edit-pgp-processing) + (progn + (or (memq 'encrypt mime-edit-pgp-processing) + (setq mime-edit-pgp-processing + (nconc mime-edit-pgp-processing + (copy-sequence '(encrypt))))) + (message "This message will be encrypt.")) + (setq mime-edit-pgp-processing + (delq 'encrypt mime-edit-pgp-processing)) + (message "This message will not be encrypt."))) (defun mime-edit-pgp-enclose-buffer () (let ((beg (save-excursion (goto-char (point-min)) (if (search-forward (concat "\n" mail-header-separator "\n")) - (match-end 0) - ))) - (end (point-max)) - ) + (match-end 0))))) (if beg - (cond ((eq mime-edit-pgp-processing 'sign) - (mime-edit-enclose-signed-region beg end) - ) - ((eq mime-edit-pgp-processing 'encrypt) - (mime-edit-enclose-encrypted-region beg end) - )) - ))) + (dolist (pgp-processing mime-edit-pgp-processing) + (case pgp-processing + (sign + (mime-edit-enclose-pgp-signed-region + beg (point-max))) + (encrypt + (mime-edit-enclose-pgp-encrypted-region + beg (point-max)))))))) ;;; @ split @@ -2323,29 +2450,22 @@ Optional TRANSFER-LEVEL is a number of transfer-level, 7 or 8." (insert mime-edit-mime-version-field-for-message/partial) (insert (format "\ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" - id number total separator)) - ) + id number total separator))) (defun mime-edit-split-and-send (&optional cmd lines mime-edit-message-max-length) (interactive) (or lines (setq lines - (count-lines (point-min) (point-max))) - ) + (count-lines (point-min) (point-max)))) (or mime-edit-message-max-length (setq mime-edit-message-max-length (or (cdr (assq major-mode mime-edit-message-max-lines-alist)) - mime-edit-message-default-max-lines)) - ) - (let* ((mime-edit-draft-file-name - (or (buffer-file-name) - (make-temp-name - (expand-file-name "mime-draft" mime-temp-directory)))) - (separator mail-header-separator) - (id (concat "\"" - (replace-space-with-underline (current-time-string)) - "@" (system-name) "\""))) + mime-edit-message-default-max-lines))) + (let ((separator mail-header-separator) + (id (concat "\"" + (replace-space-with-underline (current-time-string)) + "@" (system-name) "\""))) (run-hooks 'mime-edit-before-split-hook) (let ((the-buf (current-buffer)) (copy-buf (get-buffer-create " *Original Message*")) @@ -2363,9 +2483,7 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (function (lambda () (interactive) - (error "Split sender is not specified for `%s'." major-mode) - )) - )) + (error "Split sender is not specified for `%s'." major-mode))))) (mime-edit-partial-number 1) data) (save-excursion @@ -2377,13 +2495,11 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (concat "^" (regexp-quote separator) "$") nil t) (let ((he (match-beginning 0))) (replace-match "") - (narrow-to-region (point-min) he) - )) + (narrow-to-region (point-min) he))) (goto-char (point-min)) (while (re-search-forward mime-edit-split-blind-field-regexp nil t) (delete-region (match-beginning 0) - (1+ (std11-field-end))) - ))) + (1+ (std11-field-end)))))) (while (< mime-edit-partial-number total) (erase-buffer) (save-excursion @@ -2392,10 +2508,8 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (point-min) (progn (goto-line mime-edit-message-max-length) - (point)) - )) - (delete-region (point-min)(point)) - ) + (point)))) + (delete-region (point-min)(point))) (mime-edit-insert-partial-header header subject id mime-edit-partial-number total separator) (insert data) @@ -2403,28 +2517,23 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (message (format "Sending %d/%d..." mime-edit-partial-number total)) (call-interactively command) - (message (format "Sending %d/%d... done" - mime-edit-partial-number total)) - ) + (message (format "Sending %d/%d...done" + mime-edit-partial-number total))) (setq mime-edit-partial-number - (1+ mime-edit-partial-number)) - ) + (1+ mime-edit-partial-number))) (erase-buffer) (save-excursion (set-buffer copy-buf) (setq data (buffer-string)) - (erase-buffer) - ) + (erase-buffer)) (mime-edit-insert-partial-header header subject id mime-edit-partial-number total separator) (insert data) (save-excursion (message (format "Sending %d/%d..." mime-edit-partial-number total)) - (message (format "Sending %d/%d... done" - mime-edit-partial-number total)) - ) - ))) + (message (format "Sending %d/%d...done" + mime-edit-partial-number total)))))) (defun mime-edit-maybe-split-and-send (&optional cmd) (interactive) @@ -2432,18 +2541,17 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (let ((mime-edit-message-max-length (or (cdr (assq major-mode mime-edit-message-max-lines-alist)) mime-edit-message-default-max-lines)) - (lines (count-lines (point-min) (point-max))) - ) + (lines (count-lines (point-min) (point-max)))) (if (and (> lines mime-edit-message-max-length) mime-edit-split-message) - (mime-edit-split-and-send cmd lines mime-edit-message-max-length) - ))) + (mime-edit-split-and-send cmd lines mime-edit-message-max-length)))) ;;; @ preview message ;;; (defvar mime-edit-buffer nil) ; buffer local variable +(defvar mime-edit-temp-message-buffer nil) ; buffer local variable (defun mime-edit-preview-message () "preview editing MIME message." @@ -2454,47 +2562,44 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (buf-name (buffer-name)) (temp-buf-name (concat "*temp-article:" buf-name "*")) (buf (get-buffer temp-buf-name)) - ) + (pgp-processing mime-edit-pgp-processing)) (if buf (progn (switch-to-buffer buf) - (erase-buffer) - ) + (erase-buffer)) (setq buf (get-buffer-create temp-buf-name)) - (switch-to-buffer buf) - ) + (switch-to-buffer buf)) (insert str) (setq major-mode 'mime-temp-message-mode) (make-local-variable 'mail-header-separator) (setq mail-header-separator separator) (make-local-variable 'mime-edit-buffer) (setq mime-edit-buffer the-buf) + (setq mime-edit-pgp-processing pgp-processing) (run-hooks 'mime-edit-translate-hook) (mime-edit-translate-buffer) (goto-char (point-min)) (if (re-search-forward (concat "^" (regexp-quote separator) "$")) - (replace-match "") - ) - (mime-view-mode) - )) + (replace-match "")) + (mime-view-buffer) + (make-local-variable 'mime-edit-temp-message-buffer) + (setq mime-edit-temp-message-buffer buf))) (defun mime-edit-quitting-method () "Quitting method for mime-view." - (let ((temp mime-raw-buffer) - buf) - (mime-view-kill-buffer) + (let* ((temp mime-edit-temp-message-buffer) + buf) + (mime-preview-kill-buffer) (set-buffer temp) (setq buf mime-edit-buffer) (kill-buffer temp) - (switch-to-buffer buf) - )) + (switch-to-buffer buf))) -(set-alist 'mime-view-quitting-method-alist +(set-alist 'mime-preview-quitting-method-alist 'mime-temp-message-mode - (function mime-edit-quitting-method) - ) + #'mime-edit-quitting-method) ;;; @ edit again @@ -2502,145 +2607,218 @@ Content-Type: message/partial; id=%s; number=%d; total=%d\n%s\n" (defvar mime-edit-again-ignored-field-regexp (concat "^\\(" "Content-.*\\|Mime-Version" - (if mime-edit-insert-x-emacs-field "\\|X-Emacs") + (if mime-edit-insert-user-agent-field "\\|User-Agent") "\\):") "Regexp for deleted header fields when `mime-edit-again' is called.") -(defun mime-edit-decode-buffer (not-decode-text) +(defsubst eliminate-top-spaces (string) + "Eliminate top sequence of space or tab in STRING." + (if (string-match "^[ \t]+" string) + (substring string (match-end 0)) + string)) + +(defun mime-edit-decode-multipart-in-buffer (content-type not-decode-text) + (let* ((subtype + (or + (cdr (assoc (mime-content-type-parameter content-type "protocol") + '(("application/pgp-encrypted" . pgp-encrypted) + ("application/pgp-signature" . pgp-signed)))) + (mime-content-type-subtype content-type))) + (boundary (mime-content-type-parameter content-type "boundary")) + (boundary-pat (concat "\n--" (regexp-quote boundary) "[ \t]*\n"))) + (re-search-forward boundary-pat nil t) + (let ((bb (match-beginning 0)) eb tag) + (setq tag (format "\n--<<%s>>-{\n" subtype)) + (goto-char bb) + (insert tag) + (setq bb (+ bb (length tag))) + (re-search-forward + (concat "\n--" (regexp-quote boundary) "--[ \t]*\n") + nil t) + (setq eb (match-beginning 0)) + (replace-match (format "--}-<<%s>>\n" subtype)) + (save-restriction + (narrow-to-region bb eb) + (goto-char (point-min)) + (while (re-search-forward boundary-pat nil t) + (let ((beg (match-beginning 0)) + end) + (delete-region beg (match-end 0)) + (save-excursion + (if (re-search-forward boundary-pat nil t) + (setq end (match-beginning 0)) + (setq end (point-max))) + (save-restriction + (narrow-to-region beg end) + (cond + ((eq subtype 'pgp-encrypted) + (when (progn + (goto-char (point-min)) + (re-search-forward "^-+BEGIN PGP MESSAGE-+$" + nil t)) + (insert (epg-decrypt-string + (epg-make-context) + (buffer-substring (match-beginning 0) + (point-max)))) + (delete-region (point)(point-max)) + (mime-edit-decode-message-in-buffer + nil not-decode-text) + (delete-region (goto-char (point-min)) + (if (search-forward "\n\n" nil t) + (match-end 0) + (point-min))) + (goto-char (point-max)))) + (t + (mime-edit-decode-message-in-buffer + (if (eq subtype 'digest) + (eval-when-compile + (make-mime-content-type 'message 'rfc822))) + not-decode-text) + (goto-char (point-max)))))))))) + (goto-char (point-min)) + (or (= (point-min) 1) + (delete-region (point-min) + (if (search-forward "\n\n" nil t) + (match-end 0) + (point-min)))))) + +(defun mime-edit-decode-single-part-in-buffer + (content-type not-decode-text &optional content-disposition) + (let* ((type (mime-content-type-primary-type content-type)) + (subtype (mime-content-type-subtype content-type)) + (ctype (format "%s/%s" type subtype)) + charset + (pstr (let ((bytes (+ 14 (length ctype)))) + (mapconcat (function + (lambda (attr) + (if (string= (car attr) "charset") + (progn + (setq charset (cdr attr)) + "") + (let* ((str (concat (car attr) + "=" (cdr attr))) + (bs (length str))) + (setq bytes (+ bytes bs 2)) + (if (< bytes 76) + (concat "; " str) + (setq bytes (+ bs 1)) + (concat ";\n " str) + ))))) + (mime-content-type-parameters content-type) ""))) + encoding + encoded + (limit (save-excursion + (if (search-forward "\n\n" nil t) + (1- (point))))) + (disposition-type + (mime-content-disposition-type content-disposition)) + (disposition-str + (if disposition-type + (let ((bytes (+ 21 (length (format "%s" disposition-type))))) + (mapconcat (function + (lambda (attr) + (let* ((str (concat + (car attr) + "=" + (if (string-equal "filename" + (car attr)) + (std11-wrap-as-quoted-string + (cdr attr)) + (cdr attr)))) + (bs (length str))) + (setq bytes (+ bytes bs 2)) + (if (< bytes 76) + (concat "; " str) + (setq bytes (+ bs 1)) + (concat ";\n " str) + )))) + (mime-content-disposition-parameters + content-disposition) + ""))))) + (if disposition-type + (setq pstr (format "%s\nContent-Disposition: %s%s" + pstr disposition-type disposition-str))) + (save-excursion + (if (re-search-forward + "^Content-Transfer-Encoding:" limit t) + (let ((beg (match-beginning 0)) + (hbeg (match-end 0)) + (end (std11-field-end limit))) + (setq encoding + (downcase + (eliminate-top-spaces + (std11-unfold-string + (buffer-substring hbeg end))))) + (if (or charset (eq type 'text)) + (progn + (delete-region beg (1+ end)) + (goto-char (point-min)) + (if (search-forward "\n\n" nil t) + (progn + (mime-decode-region + (match-end 0)(point-max) encoding) + (setq encoded t + encoding nil)))))))) + (if (and (eq type 'text) + (or encoded (not not-decode-text))) + (progn + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "\r\n" nil t) + (replace-match "\n"))) + (decode-mime-charset-region (point-min)(point-max) + (or charset default-mime-charset)))) + (let ((he (if (re-search-forward "^$" nil t) + (match-end 0) + (point-min)))) + (if (and (eq type 'text) + (eq subtype 'x-rot13-47-48)) + (mule-caesar-region he (point-max))) + (if (= (point-min) 1) + (progn + (goto-char he) + (insert + (concat "\n" + (mime-create-tag + (format "%s/%s%s" type subtype pstr) + encoding)))) + (delete-region (point-min) he) + (insert + (mime-create-tag (format "%s/%s%s" type subtype pstr) + encoding)))))) + +;;;###autoload +(defun mime-edit-decode-message-in-buffer (&optional default-content-type + not-decode-text) (save-excursion (goto-char (point-min)) - (let ((ctl (mime-read-Content-Type))) + (let ((ctl (or (mime-read-Content-Type) + default-content-type))) (if ctl - (let ((type (car ctl)) - (stype (car (cdr ctl))) - (params (cdr (cdr ctl))) - ) + (let ((type (mime-content-type-primary-type ctl))) (cond - ((and (eq type 'application)(eq stype 'pgp-signature)) - (delete-region (point-min)(point-max)) - ) + ((and (eq type 'application) + (eq (mime-content-type-subtype ctl) 'pgp-signature)) + (delete-region (point-min)(point-max))) ((eq type 'multipart) - (let* ((boundary (cdr (assoc "boundary" params))) - (boundary-pat - (concat "\n--" (regexp-quote boundary) "[ \t]*\n")) - ) - (re-search-forward boundary-pat nil t) - (let ((bb (match-beginning 0)) eb tag) - (setq tag (format "\n--<<%s>>-{\n" stype)) - (goto-char bb) - (insert tag) - (setq bb (+ bb (length tag))) - (re-search-forward - (concat "\n--" (regexp-quote boundary) "--[ \t]*\n") - nil t) - (setq eb (match-beginning 0)) - (replace-match (format "--}-<<%s>>\n" stype)) - (save-restriction - (narrow-to-region bb eb) - (goto-char (point-min)) - (while (re-search-forward boundary-pat nil t) - (let ((beg (match-beginning 0)) - end) - (delete-region beg (match-end 0)) - (save-excursion - (if (re-search-forward boundary-pat nil t) - (setq end (match-beginning 0)) - (setq end (point-max)) - ) - (save-restriction - (narrow-to-region beg end) - (mime-edit-decode-buffer not-decode-text) - (goto-char (point-max)) - )))) - )) - (goto-char (point-min)) - (or (= (point-min) 1) - (delete-region (point-min) - (if (search-forward "\n\n" nil t) - (match-end 0) - (point-min) - ))) - )) + (mime-edit-decode-multipart-in-buffer ctl not-decode-text)) (t - (let* ((ctype (format "%s/%s" type stype)) - charset - (pstr - (let ((bytes (+ 14 (length ctype)))) - (mapconcat (function - (lambda (attr) - (if (string= (car attr) "charset") - (progn - (setq charset (cdr attr)) - "") - (let* ((str - (concat (car attr) - "=" (cdr attr)) - ) - (bs (length str)) - ) - (setq bytes (+ bytes bs 2)) - (if (< bytes 76) - (concat "; " str) - (setq bytes (+ bs 1)) - (concat ";\n " str) - ) - )))) - params ""))) - encoding - encoded) - (save-excursion - (if (re-search-forward - "Content-Transfer-Encoding:" nil t) - (let ((beg (match-beginning 0)) - (hbeg (match-end 0)) - (end (std11-field-end))) - (setq encoding - (eliminate-top-spaces - (std11-unfold-string - (buffer-substring hbeg end)))) - (if (or charset (eq type 'text)) - (progn - (delete-region beg (1+ end)) - (goto-char (point-min)) - (if (search-forward "\n\n" nil t) - (progn - (mime-decode-region - (match-end 0)(point-max) encoding) - (setq encoded t - encoding nil) - ))))))) - (if (or encoded (not not-decode-text)) - (decode-mime-charset-region - (point-min)(point-max) - (or charset default-mime-charset)) - ) - (let ((he - (if (re-search-forward "^$" nil t) - (match-end 0) - (point-min) - ))) - (if (= (point-min) 1) - (progn - (goto-char he) - (insert - (concat "\n" - (mime-create-tag - (format "%s/%s%s" type stype pstr) - encoding))) - ) - (delete-region (point-min) he) - (insert - (mime-create-tag - (format "%s/%s%s" type stype pstr) - encoding)) - )) - )))) + (mime-edit-decode-single-part-in-buffer + ctl not-decode-text (mime-read-Content-Disposition))))) (or not-decode-text (decode-mime-charset-region (point-min) (point-max) - default-mime-charset) - ) - )))) + default-mime-charset))) + (if (= (point-min) 1) + (progn + (save-restriction + (std11-narrow-to-header) + (goto-char (point-min)) + (while (re-search-forward + mime-edit-again-ignored-field-regexp nil t) + (delete-region (match-beginning 0) (1+ (std11-field-end))))) + (mime-decode-header-in-buffer (not not-decode-text))))))) +;;;###autoload (defun mime-edit-again (&optional not-decode-text no-separator not-turn-on) "Convert current buffer to MIME-Edit buffer and turn on MIME-Edit mode. Content-Type and Content-Transfer-Encoding header fields will be @@ -2650,23 +2828,14 @@ converted to MIME-Edit tags." (if (search-forward (concat "\n" (regexp-quote mail-header-separator) "\n") nil t) - (replace-match "\n\n") - ) - (mime-edit-decode-buffer not-decode-text) + (replace-match "\n\n")) + (mime-edit-decode-message-in-buffer nil not-decode-text) (goto-char (point-min)) - (save-restriction - (std11-narrow-to-header) - (goto-char (point-min)) - (while (re-search-forward mime-edit-again-ignored-field-regexp nil t) - (delete-region (match-beginning 0) (1+ (std11-field-end))) - )) (or no-separator (and (re-search-forward "^$") - (replace-match mail-header-separator) - )) + (replace-match mail-header-separator))) (or not-turn-on - (turn-on-mime-edit) - )) + (turn-on-mime-edit))) ;;; @ end