;;; mml.el --- A package for parsing and validating MML documents
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; This file is part of GNU Emacs.
(autoload 'message-make-message-id "message")
(autoload 'gnus-setup-posting-charset "gnus-msg")
(autoload 'gnus-add-minor-mode "gnus-ems")
+ (autoload 'gnus-make-local-hook "gnus-util")
(autoload 'message-fetch-field "message")
(autoload 'fill-flowed-encode "flow-fill")
(autoload 'message-posting-charset "message"))
: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."
+ :type 'boolean
+ :group 'message)
+
(defvar mml-tweak-type-alist nil
"A list of (TYPE . FUNCTION) for tweaking MML parts.
TYPE is a string containing a regexp to match the MIME type. FUNCTION
(defvar mml-tweak-sexp-alist
'((mml-externalize-attachments . mml-tweak-externalize-attachments))
"A list of (SEXP . FUNCTION) for tweaking MML parts.
-SEXP is a s-expression. If the evaluation of SEXP is non-nil, FUNCTION
+SEXP is an s-expression. If the evaluation of SEXP is non-nil, FUNCTION
is called. FUNCTION is a Lisp function which is called with the MML
handle to tweak the part.")
(if (or (memq 'unknown-encoding mml-confirmation-set)
(message-options-get 'unknown-encoding)
(and (y-or-n-p "\
-Message contains characters with unknown encoding. Really send?")
+Message contains characters with unknown encoding. Really send? ")
(message-options-set 'unknown-encoding t)))
(if (setq use-ascii
(or (memq 'use-ascii mml-confirmation-set)
(message-options-get 'use-ascii)
- (and (y-or-n-p "Use ASCII as charset?")
+ (and (y-or-n-p "Use ASCII as charset? ")
(message-options-set 'use-ascii t))))
(setq charsets (delq nil charsets))
(setq warn nil))
;; ignore 0x1b, it is part of iso-2022-jp
(setq encoding (mm-body-7-or-8))))
(t
+ ;; Only perform format=flowed filling on text/plain
+ ;; parts where there either isn't a format parameter
+ ;; in the mml tag or it says "flowed" and there
+ ;; actually are hard newlines in the text.
+ (let (use-hard-newlines)
+ (when (and (string= type "text/plain")
+ (or (null (assq 'format cont))
+ (string= (cdr (assq 'format cont))
+ "flowed"))
+ (setq use-hard-newlines
+ (text-property-any
+ (point-min) (point-max) 'hard 't)))
+ (fill-flowed-encode)
+ ;; Indicate that `mml-insert-mime-headers' should
+ ;; insert a "; format=flowed" string unless the
+ ;; user has already specified it.
+ (setq flowed (null (assq 'format cont)))))
(setq charset (mm-encode-body charset))
(setq encoding (mm-body-encoding
charset (cdr (assq 'encoding cont))))))
- ;; Only perform format=flowed filling on text/plain
- ;; parts where there either isn't a format parameter
- ;; in the mml tag or it says "flowed" and there
- ;; actually are hard newlines in the text.
- (let (use-hard-newlines)
- (when (and (string= type "text/plain")
- (or (null (assq 'format cont))
- (string= (cdr (assq 'format cont))
- "flowed"))
- (setq use-hard-newlines
- (text-property-any
- (point-min) (point-max) 'hard 't)))
- (fill-flowed-encode)
- ;; Indicate that `mml-insert-mime-headers' should
- ;; insert a "; format=flowed" string unless the
- ;; user has already specified it.
- (setq flowed (null (assq 'format cont)))))
(setq coded (buffer-string)))
(mml-insert-mime-headers cont type charset encoding flowed)
(insert "\n")
mml-encrypt-alist))
sender recipients)
(when (or sign-item encrypt-item)
- (if (setq sender (cdr (assq 'sender cont)))
- (message-options-set 'message-sender sender))
+ (when (setq sender (cdr (assq 'sender cont)))
+ (message-options-set 'mml-sender sender)
+ (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)))))
(when (or charset
parameters
flowed
- (not (equal type mml-generate-default-type)))
+ (not (equal type mml-generate-default-type))
+ mml-insert-mime-headers-always)
(when (consp charset)
(error
- "Can't encode a part with several charsets."))
+ "Can't encode a part with several charsets"))
(insert "Content-Type: " type)
(when charset
(insert "; " (mail-header-encode-parameter
(mml-insert-mml-markup handle buffer textp)))
(cond
(mmlp
- (insert-buffer buffer)
+ (insert-buffer-substring buffer)
(goto-char (point-max))
(insert "<#/mml>\n"))
((stringp (car handle))
(insert "<#/multipart>\n"))
(textp
(let ((charset (mail-content-type-get
- (mm-handle-type handle) 'charset)))
+ (mm-handle-type handle) 'charset))
+ (start (point)))
(if (eq charset 'gnus-decoded)
(mm-insert-part handle)
- (insert (mm-decode-string (mm-get-part handle) charset))))
+ (insert (mm-decode-string (mm-get-part handle) charset)))
+ (mml-quote-region start (point)))
(goto-char (point-max)))
(t
(insert "<#/part>\n")))))
;;;
(defun mml-minibuffer-read-file (prompt)
- (let ((file (read-file-name prompt nil nil t)))
+ (let* ((completion-ignored-extensions nil)
+ (file (read-file-name prompt nil nil t)))
;; Prevent some common errors. This is inspired by similar code in
;; VM.
(when (file-directory-p file)
(when value
;; Quote VALUE if it contains suspicious characters.
(when (string-match "[\"'\\~/*;() \t\n]" value)
- (setq value (prin1-to-string value)))
+ (setq value (with-output-to-string
+ (let (print-escape-nonascii)
+ (prin1 value)))))
(insert (format " %s=%s" key value)))))
(insert ">\n"))
(mml-insert-tag 'part 'type type 'disposition "inline")
(forward-line -1))
+(defun mml-preview-insert-mail-followup-to ()
+ "Insert a Mail-Followup-To header before previewing an article.
+Should be adopted if code in `message-send-mail' is changed."
+ (when (and (message-mail-p)
+ (message-subscribed-p)
+ (not (mail-fetch-field "mail-followup-to"))
+ (message-make-mail-followup-to))
+ (message-position-on-field "Mail-Followup-To" "X-Draft-From")
+ (insert (message-make-mail-followup-to))))
+
(defun mml-preview (&optional raw)
"Display current buffer with Gnus, in a new buffer.
If RAW, don't highlight the article."
(concat (if raw "*Raw MIME preview of "
"*MIME preview of ") (buffer-name))))
(erase-buffer)
- (insert-buffer buf)
+ (insert-buffer-substring buf)
+ (mml-preview-insert-mail-followup-to)
(let ((message-deletable-headers (if (message-news-p)
nil
message-deletable-headers)))
(gnus-article-prepare-display))))
;; Disable article-mode-map.
(use-local-map nil)
+ (gnus-make-local-hook 'kill-buffer-hook)
+ (add-hook 'kill-buffer-hook
+ (lambda ()
+ (mm-destroy-parts gnus-article-mime-handles)) nil t)
(setq buffer-read-only t)
(local-set-key "q" (lambda () (interactive) (kill-buffer nil)))
+ (local-set-key "=" (lambda () (interactive) (delete-other-windows)))
+ (local-set-key "\r"
+ (lambda ()
+ (interactive)
+ (widget-button-press (point))))
+ (local-set-key gnus-mouse-2
+ (lambda (event)
+ (interactive "@e")
+ (widget-button-press (widget-event-point event) event)))
(goto-char (point-min)))))
(defun mml-validate ()