;;; mml.el --- A package for parsing and validating MML documents
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(autoload 'gnus-setup-posting-charset "gnus-msg")
(autoload 'gnus-make-local-hook "gnus-util")
(autoload 'message-fetch-field "message")
+ (autoload 'message-mark-active-p "message")
(autoload 'fill-flowed-encode "flow-fill")
- (autoload 'message-posting-charset "message"))
+ (autoload 'message-posting-charset "message")
+ (autoload 'x-dnd-get-local-file-name "x-dnd"))
(defcustom mml-content-type-parameters
'(name access-type expiration size permission format)
"*A list of acceptable parameters in MML tag.
These parameters are generated in Content-Type header if exists."
+ :version "22.1"
:type '(repeat (symbol :tag "Parameter"))
:group 'message)
'(filename creation-date modification-date read-date)
"*A list of acceptable parameters in MML tag.
These parameters are generated in Content-Disposition header if exists."
+ :version "22.1"
:type '(repeat (symbol :tag "Parameter"))
:group 'message)
(defcustom mml-insert-mime-headers-always nil
"If non-nil, always put Content-Type: text/plain at top of empty parts.
It is necessary to work against a bug in certain clients."
+ :version "22.1"
:type 'boolean
:group 'message)
(defun mml-destroy-buffers ()
(let (kill-buffer-hook)
- (mapcar 'kill-buffer mml-buffer-list)
+ (mapc 'kill-buffer mml-buffer-list)
(setq mml-buffer-list nil)))
(defun mml-parse ()
;; included in the message
(let* (secure-mode
(taginfo (mml-read-tag))
+ (keyfile (cdr (assq 'keyfile taginfo)))
+ (certfile (cdr (assq 'certfile taginfo)))
(recipients (cdr (assq 'recipients taginfo)))
(sender (cdr (assq 'sender taginfo)))
(location (cdr (assq 'tag-location taginfo)))
(setq tags (list "sign" method "encrypt" method))))
(eval `(mml-insert-tag ,secure-mode
,@tags
+ ,(if keyfile "keyfile")
+ ,keyfile
+ ,(if certfile "certfile")
+ ,certfile
,(if recipients "recipients")
,recipients
,(if sender "sender")
(cond
((or (eq (car cont) 'part) (eq (car cont) 'mml))
(let ((raw (cdr (assq 'raw cont)))
- coded encoding charset filename type flowed)
- (setq type (or (cdr (assq 'type cont)) "text/plain"))
+ type charset coding filename encoding flowed coded)
+ (setq type (or (cdr (assq 'type cont)) "text/plain")
+ charset (cdr (assq 'charset cont))
+ coding (mm-charset-to-coding-system charset))
+ (cond ((eq coding 'ascii)
+ (setq charset nil
+ coding nil))
+ (charset
+ (setq charset (intern (downcase charset)))))
(if (and (not raw)
(member (car (split-string type "/")) '("text" "message")))
(progn
(with-temp-buffer
- (setq charset (mm-charset-to-coding-system
- (cdr (assq 'charset cont))))
- (when (eq charset 'ascii)
- (setq charset nil))
(cond
((cdr (assq 'buffer cont))
(insert-buffer-substring (cdr (assq 'buffer cont))))
((and (setq filename (cdr (assq 'filename cont)))
(not (equal (cdr (assq 'nofile cont)) "yes")))
- (let ((coding-system-for-read charset))
+ (let ((coding-system-for-read coding))
(mm-insert-file-contents filename)))
((eq 'mml (car cont))
(insert (cdr (assq 'contents cont))))
;; actually are hard newlines in the text.
(let (use-hard-newlines)
(when (and (string= type "text/plain")
+ (not (string= (cdr (assq 'sign cont)) "pgp"))
(or (null (assq 'format cont))
(string= (cdr (assq 'format cont))
"flowed"))
(mm-with-unibyte-buffer
(cond
((cdr (assq 'buffer cont))
- (insert-buffer-substring (cdr (assq 'buffer cont))))
+ (insert (with-current-buffer (cdr (assq 'buffer cont))
+ (mm-with-unibyte-current-buffer
+ (buffer-string)))))
((and (setq filename (cdr (assq 'filename cont)))
(not (equal (cdr (assq 'nofile cont)) "yes")))
(let ((coding-system-for-read mm-binary-coding-system))
- (mm-insert-file-contents filename nil nil nil nil t)))
+ (mm-insert-file-contents filename nil nil nil nil t))
+ (unless charset
+ (setq charset (mm-coding-system-to-mime-charset
+ (mm-find-buffer-file-coding-system
+ filename)))))
(t
(insert (cdr (assq 'contents cont)))))
(setq encoding (mm-encode-buffer type)
(message-options-set 'message-sender sender))
(if (setq recipients (cdr (assq 'recipients cont)))
(message-options-set 'message-recipients recipients))
- (let ((style (mml-signencrypt-style (first (or sign-item encrypt-item)))))
+ (let ((style (mml-signencrypt-style
+ (first (or sign-item encrypt-item)))))
;; check if: we're both signing & encrypting, both methods
;; are the same (why would they be different?!), and that
;; the signencrypt style allows for combined operation.
(insert-buffer-substring (cdr (assq 'buffer cont))))
((and (setq filename (cdr (assq 'filename cont)))
(not (equal (cdr (assq 'nofile cont)) "yes")))
- (mm-insert-file-contents filename))
+ (mm-insert-file-contents filename nil nil nil nil t))
(t
(insert (cdr (assq 'contents cont)))))
(goto-char (point-min))
(incf mml-multipart-number)))
(throw 'not-unique nil))))
((eq (car cont) 'multipart)
- (mapcar 'mml-compute-boundary-1 (cddr cont))))
+ (mapc 'mml-compute-boundary-1 (cddr cont))))
t))
(defun mml-make-boundary (number)
;; First decode the head.
(save-restriction
(message-narrow-to-head)
- (mail-decode-encoded-word-region (point-min) (point-max)))
+ (let ((rfc2047-quote-decoded-words-containing-tspecials t))
+ (mail-decode-encoded-word-region (point-min) (point-max))))
(unless handles
(setq handles (mm-dissect-buffer t)))
(goto-char (point-min))
(insert " " param)
(when (> (current-column) 71)
(goto-char point)
- (insert "\n ")
+ (insert "\n")
(end-of-line)))))
;;;
main))
(easy-menu-define
- mml-menu mml-mode-map ""
- `("Attachments"
- ["Attach File..." mml-attach-file
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Attach a file at point"))]
- ["Attach Buffer..." mml-attach-buffer t]
- ["Attach External..." mml-attach-external t]
- ["Insert Part..." mml-insert-part t]
- ["Insert Multipart..." mml-insert-multipart t]
- ["PGP/MIME Sign" mml-secure-message-sign-pgpmime t]
- ["PGP/MIME Encrypt" mml-secure-message-encrypt-pgpmime t]
- ["PGP Sign" mml-secure-message-sign-pgp t]
- ["PGP Encrypt" mml-secure-message-encrypt-pgp t]
- ["S/MIME Sign" mml-secure-message-sign-smime t]
- ["S/MIME Encrypt" mml-secure-message-encrypt-smime t]
- ("Secure MIME part"
- ["PGP/MIME Sign Part" mml-secure-sign-pgpmime t]
- ["PGP/MIME Encrypt Part" mml-secure-encrypt-pgpmime t]
- ["PGP Sign Part" mml-secure-sign-pgp t]
- ["PGP Encrypt Part" mml-secure-encrypt-pgp t]
- ["S/MIME Sign Part" mml-secure-sign-smime t]
- ["S/MIME Encrypt Part" mml-secure-encrypt-smime t])
- ["Encrypt/Sign off" mml-unsecure-message t]
- ;;["Narrow" mml-narrow-to-part t]
- ["Quote MML" mml-quote-region t]
- ["Validate MML" mml-validate t]
- ["Preview" mml-preview t]))
+ mml-menu mml-mode-map ""
+ `("Attachments"
+ ["Attach File..." mml-attach-file
+ ,@(if (featurep 'xemacs) '(t)
+ '(:help "Attach a file at point"))]
+ ["Attach Buffer..." mml-attach-buffer t]
+ ["Attach External..." mml-attach-external t]
+ ["Insert Part..." mml-insert-part t]
+ ["Insert Multipart..." mml-insert-multipart t]
+ ["PGP/MIME Sign" mml-secure-message-sign-pgpmime t]
+ ["PGP/MIME Encrypt" mml-secure-message-encrypt-pgpmime t]
+ ["PGP Sign" mml-secure-message-sign-pgp t]
+ ["PGP Encrypt" mml-secure-message-encrypt-pgp t]
+ ["S/MIME Sign" mml-secure-message-sign-smime t]
+ ["S/MIME Encrypt" mml-secure-message-encrypt-smime t]
+ ("Secure MIME part"
+ ["PGP/MIME Sign Part" mml-secure-sign-pgpmime t]
+ ["PGP/MIME Encrypt Part" mml-secure-encrypt-pgpmime t]
+ ["PGP Sign Part" mml-secure-sign-pgp t]
+ ["PGP Encrypt Part" mml-secure-encrypt-pgp t]
+ ["S/MIME Sign Part" mml-secure-sign-smime t]
+ ["S/MIME Encrypt Part" mml-secure-encrypt-smime t])
+ ["Encrypt/Sign off" mml-unsecure-message t]
+ ;;["Narrow" mml-narrow-to-part t]
+ ["Quote MML" mml-quote-region
+ :active (message-mark-active-p)
+ ,@(if (featurep 'xemacs) nil
+ '(:help "Quote MML tags in region"))]
+ ["Validate MML" mml-validate t]
+ ["Preview" mml-preview t]))
(defvar mml-mode nil
"Minor mode for editing MML.")
(> (prefix-numeric-value arg) 0)))
(add-minor-mode 'mml-mode " MML" mml-mode-map)
(easy-menu-add mml-menu mml-mode-map)
+ (when (boundp 'x-dnd-protocol-alist)
+ (set (make-local-variable 'x-dnd-protocol-alist)
+ '(("^file:///" . mml-x-dnd-attach-file)
+ ("^file://" . x-dnd-open-file)
+ ("^file:" . mml-x-dnd-attach-file))))
(run-hooks 'mml-mode-hook)))
;;;
(if (string-match "^text/.*" type)
"inline"
"attachment")))
- (disposition (completing-read
- (format "Disposition: (default %s): " default)
- '(("attachment") ("inline") (""))
- nil
- nil)))
+ (disposition (completing-read "Disposition: "
+ '(("attachment") ("inline") (""))
+ nil t)))
(if (not (equal disposition ""))
disposition
default)))
'disposition (or disposition "attachment")
'description description))
+(defun mml-x-dnd-attach-file (uri action)
+ "Attach a drag and drop file."
+ (let ((file (x-dnd-get-local-file-name uri t)))
+ (when (and file (file-regular-p file))
+ (let* ((type (mml-minibuffer-read-type file))
+ (description (mml-minibuffer-read-description))
+ (disposition (mml-minibuffer-read-disposition type)))
+ (mml-attach-file file type description disposition)))))
+
(defun mml-attach-buffer (buffer &optional type description)
"Attach a buffer to the outgoing MIME message.
See `mml-attach-file' for details of operation."
(message-position-on-field "Mail-Followup-To" "X-Draft-From")
(insert (message-make-mail-followup-to))))
+(defvar mml-preview-buffer nil)
+
(defun mml-preview (&optional raw)
"Display current buffer with Gnus, in a new buffer.
If RAW, don't highlight the article."
(interactive "P")
+ (setq mml-preview-buffer (generate-new-buffer
+ (concat (if raw "*Raw MIME preview of "
+ "*MIME preview of ") (buffer-name))))
(save-excursion
(let* ((buf (current-buffer))
(message-options message-options)
(message-fetch-field "Newsgroups")))
message-posting-charset)))
(message-options-set-recipient)
- (switch-to-buffer (generate-new-buffer
- (concat (if raw "*Raw MIME preview of "
- "*MIME preview of ") (buffer-name))))
(when (boundp 'gnus-buffers)
- (push (current-buffer) gnus-buffers))
- (erase-buffer)
- (insert-buffer-substring buf)
+ (push mml-preview-buffer gnus-buffers))
+ (save-restriction
+ (widen)
+ (set-buffer mml-preview-buffer)
+ (erase-buffer)
+ (insert-buffer-substring buf))
(mml-preview-insert-mail-followup-to)
(let ((message-deletable-headers (if (message-news-p)
nil
(concat "^" (regexp-quote mail-header-separator) "\n") nil t)
(replace-match "\n"))
(let ((mail-header-separator ""));; mail-header-separator is removed.
+ (message-sort-headers)
(mml-to-mime))
(if raw
(when (fboundp 'set-buffer-multibyte)
(lambda (event)
(interactive "@e")
(widget-button-press (widget-event-point event) event)))
- (goto-char (point-min)))))
+ (goto-char (point-min))))
+ (if (and (boundp 'gnus-buffer-configuration)
+ (assq 'mml-preview gnus-buffer-configuration))
+ (gnus-configure-windows 'mml-preview)
+ (pop-to-buffer mml-preview-buffer)))
(defun mml-validate ()
"Validate the current MML document."