Split -request-update-info into -request-marks and -update-info.
[gnus] / lisp / mml.el
index 796470b..15b1bb7 100644 (file)
@@ -1,7 +1,7 @@
 ;;; mml.el --- A package for parsing and validating MML documents
 
 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-;;   2007, 2008, 2009  Free Software Foundation, Inc.
+;;   2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; This file is part of GNU Emacs.
 (require 'mm-decode)
 (require 'mml-sec)
 (eval-when-compile (require 'cl))
+(eval-when-compile
+  (when (featurep 'xemacs)
+    (require 'easy-mmode))) ; for `define-minor-mode'
 
 (autoload 'message-make-message-id "message")
-(autoload 'gnus-setup-posting-charset "gnus-msg")
+(declare-function gnus-setup-posting-charset "gnus-msg" (group))
 (autoload 'gnus-make-local-hook "gnus-util")
 (autoload 'message-fetch-field "message")
 (autoload 'message-mark-active-p "message")
@@ -117,10 +120,10 @@ match found will be used."
                          ,dispositions))))
   :group 'message)
 
-(defcustom mml-insert-mime-headers-always nil
+(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 "22.1"
+  :version "24.1"
   :type 'boolean
   :group 'message)
 
@@ -225,7 +228,10 @@ part.  This is for the internal use, you should never modify the value.")
        (let* (secure-mode
               (taginfo (mml-read-tag))
               (keyfile (cdr (assq 'keyfile taginfo)))
-              (certfile (cdr (assq 'certfile 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)))
@@ -251,8 +257,10 @@ part.  This is for the internal use, you should never modify the value.")
                                 ,@tags
                                 ,(if keyfile "keyfile")
                                 ,keyfile
-                                ,(if certfile "certfile")
-                                ,certfile
+                                ,@(apply #'append
+                                         (mapcar (lambda (certfile)
+                                                   (list "certfile" certfile))
+                                                 certfiles))
                                 ,(if recipients "recipients")
                                 ,recipients
                                 ,(if sender "sender")
@@ -392,8 +400,8 @@ A message part needs to be split into %d charset parts.  Really send? "
       (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))
@@ -520,7 +528,10 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
                          ;; `m-g-d-t' will be bound to "message/rfc822"
                          ;; when encoding an article to be forwarded.
                          (mml-generate-default-type "text/plain"))
-                     (mml-to-mime))
+                     (mml-to-mime)
+                     ;; Update handle so mml-compute-boundary can
+                     ;; detect collisions with the nested parts.
+                     (setcdr (assoc 'contents cont) (buffer-string)))
                    (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
                      ;; ignore 0x1b, it is part of iso-2022-jp
                      (setq encoding (mm-body-7-or-8))))
@@ -585,7 +596,9 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
                        (unless raw
                          (setq charset (mm-encode-body charset))))
                    (insert contents)))))
-             (setq encoding (mm-encode-buffer type)
+             (if (setq encoding (cdr (assq 'encoding cont)))
+                 (setq encoding (intern (downcase encoding))))
+             (setq encoding (mm-encode-buffer type encoding)
                    coded (mm-string-as-multibyte (buffer-string))))
            (mml-insert-mime-headers cont type charset encoding nil)
            (insert "\n" coded))))
@@ -697,7 +710,7 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
 (defun mml-compute-boundary-1 (cont)
   (let (filename)
     (cond
-     ((eq (car cont) 'part)
+     ((member (car cont) '(part mml))
       (with-temp-buffer
        (cond
         ((cdr (assq 'buffer cont))
@@ -896,8 +909,7 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
     ;; Determine type and stuff.
     (unless (stringp (car handle))
       (unless (setq textp (equal (mm-handle-media-supertype handle) "text"))
-       (save-excursion
-         (set-buffer (setq buffer (mml-generate-new-buffer " *mml*")))
+       (with-current-buffer (setq buffer (mml-generate-new-buffer " *mml*"))
          (if (eq (mail-content-type-get (mm-handle-type handle) 'charset)
                  'gnus-decoded)
              ;; A part that mm-uu dissected from a non-MIME message
@@ -1124,25 +1136,18 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
      ,@(if (featurep 'xemacs) '(t)
         '(:help "Display the EasyPG manual"))]))
 
-(defvar mml-mode nil
-  "Minor mode for editing MML.")
-
-(defun mml-mode (&optional arg)
+(define-minor-mode mml-mode
   "Minor mode for editing MML.
 MML is the MIME Meta Language, a minor mode for composing MIME articles.
 See Info node `(emacs-mime)Composing'.
 
 \\{mml-mode-map}"
-  (interactive "P")
-  (when (set (make-local-variable 'mml-mode)
-            (if (null arg) (not mml-mode)
-              (> (prefix-numeric-value arg) 0)))
-    (add-minor-mode 'mml-mode " MML" mml-mode-map)
+  :lighter " MML" :keymap mml-mode-map
+  (when mml-mode
     (easy-menu-add mml-menu mml-mode-map)
     (when (boundp 'dnd-protocol-alist)
       (set (make-local-variable 'dnd-protocol-alist)
-          (append mml-dnd-protocol-alist dnd-protocol-alist)))
-    (run-hooks 'mml-mode-hook)))
+          (append mml-dnd-protocol-alist dnd-protocol-alist)))))
 
 ;;;
 ;;; Helper functions for reading MIME stuff from the minibuffer and
@@ -1171,7 +1176,11 @@ If not set, `default-directory' will be used."
       (error "Permission denied: %s" file))
     file))
 
+(declare-function mailcap-parse-mimetypes "mailcap" (&optional path force))
+(declare-function mailcap-mime-types "mailcap" ())
+
 (defun mml-minibuffer-read-type (name &optional default)
+  (require 'mailcap)
   (mailcap-parse-mimetypes)
   (let* ((default (or default
                      (mm-default-file-encoding name)
@@ -1292,14 +1301,24 @@ body) or \"attachment\" (separate from the body)."
          (description (mml-minibuffer-read-description))
          (disposition (mml-minibuffer-read-disposition type nil file)))
      (list file type description disposition)))
-  (unless (message-in-body-p) (goto-char (point-max)))
-  (mml-insert-empty-tag 'part
-                       'type type
-                       ;; icicles redefines read-file-name and returns a
-                       ;; string w/ text properties :-/
-                       'filename (mm-substring-no-properties file)
-                       'disposition (or disposition "attachment")
-                       'description description))
+  ;; Don't move point if this command is invoked inside the message header.
+  (let ((head (unless (message-in-body-p)
+               (prog1
+                   (point)
+                 (goto-char (point-max))))))
+    (mml-insert-empty-tag 'part
+                         'type type
+                         ;; icicles redefines read-file-name and returns a
+                         ;; string w/ text properties :-/
+                         'filename (mm-substring-no-properties file)
+                         'disposition (or disposition "attachment")
+                         'description description)
+    (when head
+      (unless (prog1
+                 (pos-visible-in-window-p)
+               (goto-char head))
+       (message "The file \"%s\" has been attached at the end of the message"
+                (file-name-nondirectory file))))))
 
 (defun mml-dnd-attach-file (uri action)
   "Attach a drag and drop file.
@@ -1335,10 +1354,21 @@ BUFFER is the name of the buffer to attach.  See
          (description (mml-minibuffer-read-description))
          (disposition (mml-minibuffer-read-disposition type nil)))
      (list buffer type description disposition)))
-  (unless (message-in-body-p) (goto-char (point-max)))
-  (mml-insert-empty-tag 'part 'type type 'buffer buffer
-                       'disposition disposition
-                       'description description))
+  ;; Don't move point if this command is invoked inside the message header.
+  (let ((head (unless (message-in-body-p)
+               (prog1
+                   (point)
+                 (goto-char (point-max))))))
+    (mml-insert-empty-tag 'part 'type type 'buffer buffer
+                         'disposition disposition
+                         'description description)
+    (when head
+      (unless (prog1
+                 (pos-visible-in-window-p)
+               (goto-char head))
+       (message
+        "The buffer \"%s\" has been attached at the end of the message"
+        buffer)))))
 
 (defun mml-attach-external (file &optional type description)
   "Attach an external file into the buffer.
@@ -1349,25 +1379,38 @@ TYPE is the MIME type to use."
          (type (mml-minibuffer-read-type file))
          (description (mml-minibuffer-read-description)))
      (list file type description)))
-  (unless (message-in-body-p) (goto-char (point-max)))
-  (mml-insert-empty-tag 'external 'type type 'name file
-                       'disposition "attachment" 'description description))
+  ;; Don't move point if this command is invoked inside the message header.
+  (let ((head (unless (message-in-body-p)
+               (prog1
+                   (point)
+                 (goto-char (point-max))))))
+    (mml-insert-empty-tag 'external 'type type 'name file
+                         'disposition "attachment" 'description description)
+    (when head
+      (unless (prog1
+                 (pos-visible-in-window-p)
+               (goto-char head))
+       (message "The file \"%s\" has been attached at the end of the message"
+                (file-name-nondirectory file))))))
 
 (defun mml-insert-multipart (&optional type)
-  (interactive (list (completing-read "Multipart type (default mixed): "
-                                     '(("mixed") ("alternative") ("digest") ("parallel")
-                                       ("signed") ("encrypted"))
-                                     nil nil "mixed")))
+  (interactive (if (message-in-body-p)
+                  (list (completing-read "Multipart type (default mixed): "
+                                         '(("mixed") ("alternative")
+                                           ("digest") ("parallel")
+                                           ("signed") ("encrypted"))
+                                         nil nil "mixed"))
+                (error "Use this command in the message body")))
   (or type
       (setq type "mixed"))
   (mml-insert-empty-tag "multipart" 'type type)
   (forward-line -1))
 
 (defun mml-insert-part (&optional type)
-  (interactive
-   (list (mml-minibuffer-read-type "")))
-  (mml-insert-tag 'part 'type type 'disposition "inline")
-  (forward-line -1))
+  (interactive (if (message-in-body-p)
+                  (list (mml-minibuffer-read-type ""))
+                (error "Use this command in the message body")))
+  (mml-insert-tag 'part 'type type 'disposition "inline"))
 
 (declare-function message-subscribed-p "message" ())
 (declare-function message-make-mail-followup-to "message"
@@ -1409,6 +1452,7 @@ or the `pop-to-buffer' function."
   (setq mml-preview-buffer (generate-new-buffer
                            (concat (if raw "*Raw MIME preview of "
                                      "*MIME preview of ") (buffer-name))))
+  (require 'gnus-msg)                ; for gnus-setup-posting-charset
   (save-excursion
     (let* ((buf (current-buffer))
           (message-options message-options)
@@ -1526,5 +1570,4 @@ or the `pop-to-buffer' function."
 
 (provide 'mml)
 
-;; arch-tag: 583c96cf-1ffe-451b-a5e5-4733ae9ddd12
 ;;; mml.el ends here