;;; mml.el --- A package for parsing and validating MML documents
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
-;; Free Software Foundation, Inc.
+
+;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; 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.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
+;; For Emacs <22.2 and XEmacs.
+(eval-and-compile
+ (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
+
(require 'mm-util)
(require 'mm-bodies)
(require 'mm-encode)
(require 'mm-decode)
(require 'mml-sec)
(eval-when-compile (require 'cl))
-
-(eval-and-compile
- (autoload 'message-make-message-id "message")
- (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 'x-dnd-get-local-file-name "x-dnd"))
+(eval-when-compile
+ (when (featurep 'xemacs)
+ (require 'easy-mmode))) ; for `define-minor-mode'
+
+(autoload 'message-make-message-id "message")
+(declare-function gnus-setup-posting-charset "gnus-msg" (group))
+(autoload 'gnus-make-local-hook "gnus-util")
+(autoload 'gnus-completing-read "gnus-util")
+(autoload 'message-fetch-field "message")
+(autoload 'message-mark-active-p "message")
+(autoload 'message-info "message")
+(autoload 'fill-flowed-encode "flow-fill")
+(autoload 'message-posting-charset "message")
+(autoload 'dnd-get-local-file-name "dnd")
+
+(autoload 'message-options-set "message")
+(autoload 'message-narrow-to-head "message")
+(autoload 'message-in-body-p "message")
+(autoload 'message-mail-p "message")
+
+(defvar gnus-article-mime-handles)
+(defvar gnus-mouse-2)
+(defvar gnus-newsrc-hashtb)
+(defvar message-default-charset)
+(defvar message-deletable-headers)
+(defvar message-options)
+(defvar message-posting-charset)
+(defvar message-required-mail-headers)
+(defvar message-required-news-headers)
+(defvar dnd-protocol-alist)
+(defvar mml-dnd-protocol-alist)
(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 "21.4"
+ :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 "21.4"
+ :version "22.1"
:type '(repeat (symbol :tag "Parameter"))
:group 'message)
-(defcustom mml-insert-mime-headers-always nil
+(defcustom mml-content-disposition-alist
+ '((text (rtf . "attachment") (t . "inline"))
+ (t . "attachment"))
+ "Alist of MIME types or regexps matching file names and default dispositions.
+Each element should be one of the following three forms:
+
+ (REGEXP . DISPOSITION)
+ (SUPERTYPE (SUBTYPE . DISPOSITION) (SUBTYPE . DISPOSITION)...)
+ (TYPE . DISPOSITION)
+
+Where REGEXP is a string which matches the file name (if any) of an
+attachment, SUPERTYPE, SUBTYPE and TYPE should be symbols which are a
+MIME supertype (e.g., text), a MIME subtype (e.g., plain) and a MIME
+type (e.g., text/plain) respectively, and DISPOSITION should be either
+the string \"attachment\" or the string \"inline\". The value t for
+SUPERTYPE, SUBTYPE or TYPE matches any of those types. The first
+match found will be used."
+ :version "23.1" ;; No Gnus
+ :type (let ((dispositions '(radio :format "DISPOSITION: %v"
+ :value "attachment"
+ (const :format "%v " "attachment")
+ (const :format "%v\n" "inline"))))
+ `(repeat
+ :offset 0
+ (choice :format "%[Value Menu%]%v"
+ (cons :tag "(REGEXP . DISPOSITION)" :extra-offset 4
+ (regexp :tag "REGEXP" :value ".*")
+ ,dispositions)
+ (cons :tag "(SUPERTYPE (SUBTYPE . DISPOSITION)...)"
+ :indent 0
+ (symbol :tag " SUPERTYPE" :value text)
+ (repeat :format "%v%i\n" :offset 0 :extra-offset 4
+ (cons :format "%v" :extra-offset 5
+ (symbol :tag "SUBTYPE" :value t)
+ ,dispositions)))
+ (cons :tag "(TYPE . DISPOSITION)" :extra-offset 4
+ (symbol :tag "TYPE" :value t)
+ ,dispositions))))
+ :group 'message)
+
+(defcustom mml-insert-mime-headers-always t
"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 "21.4"
+ :version "24.1"
+ :type 'boolean
+ :group 'message)
+
+(defcustom mml-enable-flowed t
+ "If non-nil, enable format=flowed usage when encoding a message.
+This is only performed when filling on text/plain with hard
+newlines in the text."
+ :version "24.1"
:type 'boolean
:group 'message)
with unknown encoding; `multipart': always send messages with more than
one charsets.")
-(defvar mml-generate-default-type "text/plain")
+(defvar mml-generate-default-type "text/plain"
+ "Content type by which the Content-Type header can be omitted.
+The Content-Type header will not be put in the MIME part if the type
+equals the value and there's no parameter (e.g. charset, format, etc.)
+and `mml-insert-mime-headers-always' is nil. The value will be bound
+to \"message/rfc822\" when encoding an article to be forwarded as a MIME
+part. This is for the internal use, you should never modify the value.")
(defvar mml-buffer-list nil)
;; included in the message
(let* (secure-mode
(taginfo (mml-read-tag))
+ (keyfile (cdr (assq 'keyfile taginfo)))
+ (certfiles (delq nil (mapcar (lambda (tag)
+ (if (eq (car-safe tag) 'certfile)
+ (cdr tag)))
+ 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
+ ,@(apply #'append
+ (mapcar (lambda (certfile)
+ (list "certfile" certfile))
+ certfiles))
,(if recipients "recipients")
,recipients
,(if sender "sender")
(skip-chars-forward "= \t\n")
(setq val (buffer-substring-no-properties
(point) (progn (forward-sexp 1) (point))))
- (when (string-match "^\"\\(.*\\)\"$" val)
- (setq val (match-string 1 val)))
+ (when (string-match "\\`\"" val)
+ (setq val (read val))) ;; inverse of prin1 in mml-insert-tag
(push (cons (intern elem) val) contents)
(skip-chars-forward " \t\n"))
(goto-char (match-end 0))
(defvar mml-boundary nil)
(defvar mml-base-boundary "-=-=")
(defvar mml-multipart-number 0)
+(defvar mml-inhibit-compute-boundary nil)
-(defun mml-generate-mime ()
- "Generate a MIME message based on the current MML document."
+(defun mml-generate-mime (&optional multipart-type)
+ "Generate a MIME message based on the current MML document.
+MULTIPART-TYPE defaults to \"mixed\", but can also
+be \"related\" or \"alternate\"."
(let ((cont (mml-parse))
- (mml-multipart-number mml-multipart-number))
+ (mml-multipart-number mml-multipart-number)
+ (options message-options))
(if (not cont)
nil
- (with-temp-buffer
- (if (and (consp (car cont))
- (= (length cont) 1))
- (mml-generate-mime-1 (car cont))
- (mml-generate-mime-1 (nconc (list 'multipart '(type . "mixed"))
- cont)))
- (buffer-string)))))
+ (prog1
+ (mm-with-multibyte-buffer
+ (setq message-options options)
+ (if (and (consp (car cont))
+ (= (length cont) 1))
+ (mml-generate-mime-1 (car cont))
+ (mml-generate-mime-1
+ (nconc (list 'multipart (cons 'type (or multipart-type "mixed")))
+ cont)))
+ (setq options message-options)
+ (buffer-string))
+ (setq message-options options)))))
(defun mml-generate-mime-1 (cont)
(let ((mm-use-ultra-safe-encoding
(mml-tweak-part cont)
(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"))
+ (let* ((raw (cdr (assq 'raw cont)))
+ (filename (cdr (assq 'filename cont)))
+ (type (or (cdr (assq 'type cont))
+ (if filename
+ (or (mm-default-file-encoding filename)
+ "application/octet-stream")
+ "text/plain")))
+ (charset (cdr (assq 'charset cont)))
+ (coding (mm-charset-to-coding-system charset))
+ encoding flowed coded)
+ (cond ((eq coding 'ascii)
+ (setq charset nil
+ coding nil))