Erase message.
[gnus] / lisp / mml.el
index ed8753d..39f9dfa 100644 (file)
@@ -73,27 +73,6 @@ unknown encoding; `use-ascii': always use ASCII for those characters
 with unknown encoding; `multipart': always send messages with more than
 one charsets.")
 
-(defvar mml-generate-mime-preprocess-function nil
-  "A function called before generating a mime part.
-The function is called with one parameter, which is the part to be 
-generated.")
-
-(defvar mml-generate-mime-postprocess-function 'mml-postprocess
-  "A function called after generating a mime part.
-The function is called with one parameter, which is the generated part.")
-
-(autoload 'mml2015-sign "mml2015")
-(autoload 'mml2015-encrypt "mml2015")
-(autoload 'mml-smime-encrypt "mml-smime")
-(autoload 'mml-smime-sign "mml-smime")
-
-(defvar mml-postprocess-alist
-  '(("pgp-sign" . mml2015-sign)
-    ("pgp-encrypt" . mml2015-encrypt)
-    ("smime-sign" . mml-smime-sign)
-    ("smime-encrypt" . mml-smime-encrypt))
-  "Alist of postprocess functions.")
-
 (defvar mml-generate-default-type "text/plain")
 
 (defvar mml-buffer-list nil)
@@ -240,7 +219,7 @@ The function is called with one parameter, which is the generated part.")
     (setq name (buffer-substring-no-properties
                (point) (progn (forward-sexp 1) (point))))
     (skip-chars-forward " \t\n")
-    (while (not (looking-at ">"))
+    (while (not (looking-at ">[ \t]*\n?"))
       (setq elem (buffer-substring-no-properties
                  (point) (progn (forward-sexp 1) (point))))
       (skip-chars-forward "= \t\n")
@@ -250,8 +229,9 @@ The function is called with one parameter, which is the generated part.")
        (setq val (match-string 1 val)))
       (push (cons (intern elem) val) contents)
       (skip-chars-forward " \t\n"))
-    (forward-char 1)
-    (skip-chars-forward " \t\n")
+    (goto-char (match-end 0))
+    ;; Don't skip the leading space.
+    ;;(skip-chars-forward " \t\n")
     (cons (intern name) (nreverse contents))))
 
 (defun mml-read-part (&optional mml)
@@ -300,130 +280,148 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
        (buffer-string)))))
 
 (defun mml-generate-mime-1 (cont)
-  (save-restriction
-    (narrow-to-region (point) (point))
-    (if mml-generate-mime-preprocess-function
-       (funcall mml-generate-mime-preprocess-function cont))
-    (cond
-     ((or (eq (car cont) 'part) (eq (car cont) 'mml))
-      (let ((raw (cdr (assq 'raw cont)))
-           coded encoding charset filename type)
-       (setq type (or (cdr (assq 'type cont)) "text/plain"))
-       (if (and (not raw)
-                (member (car (split-string type "/")) '("text" "message")))
-           (with-temp-buffer
+  (let ((mm-use-ultra-safe-encoding 
+        (or mm-use-ultra-safe-encoding (assq 'sign cont))))
+    (save-restriction
+      (narrow-to-region (point) (point))
+      (cond
+       ((or (eq (car cont) 'part) (eq (car cont) 'mml))
+       (let ((raw (cdr (assq 'raw cont)))
+             coded encoding charset filename type)
+         (setq type (or (cdr (assq 'type cont)) "text/plain"))
+         (if (and (not raw)
+                  (member (car (split-string type "/")) '("text" "message")))
+             (with-temp-buffer
+               (setq charset (mm-charset-to-coding-system 
+                              (cdr (assq 'charset cont))))
+               (if (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))
+                   (mm-insert-file-contents filename)))
+                ((eq 'mml (car cont))
+                 (insert (cdr (assq 'contents cont))))
+                (t
+                 (save-restriction
+                   (narrow-to-region (point) (point))
+                   (insert (cdr (assq 'contents cont)))
+                   ;; Remove quotes from quoted tags.
+                   (goto-char (point-min))
+                   (while (re-search-forward
+                           "<#!+/?\\(part\\|multipart\\|external\\|mml\\)" nil t)
+                     (delete-region (+ (match-beginning 0) 2)
+                                    (+ (match-beginning 0) 3))))))
+               (cond 
+                ((eq (car cont) 'mml)
+                 (let ((mml-boundary (funcall mml-boundary-function
+                                              (incf mml-multipart-number)))
+                       (mml-generate-default-type "text/plain"))
+                   (mml-to-mime))
+                 (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))))
+                ((string= (car (split-string type "/")) "message")
+                 (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))))
+                (t 
+                 (setq charset (mm-encode-body charset))
+                 (setq encoding (mm-body-encoding
+                                 charset (cdr (assq 'encoding cont))))))
+               (setq coded (buffer-string)))
+           (mm-with-unibyte-buffer
              (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")))
-               (mm-insert-file-contents filename))
-              ((eq 'mml (car cont))
-               (insert (cdr (assq 'contents cont))))
+               (let ((coding-system-for-read mm-binary-coding-system))
+                 (mm-insert-file-contents filename nil nil nil nil t)))
               (t
-               (save-restriction
-                 (narrow-to-region (point) (point))
-                 (insert (cdr (assq 'contents cont)))
-                 ;; Remove quotes from quoted tags.
-                 (goto-char (point-min))
-                 (while (re-search-forward
-                         "<#!+/?\\(part\\|multipart\\|external\\|mml\\)" nil t)
-                   (delete-region (+ (match-beginning 0) 2)
-                                  (+ (match-beginning 0) 3))))))
-             (cond 
-              ((eq (car cont) 'mml)
-               (let ((mml-boundary (funcall mml-boundary-function
-                                            (incf mml-multipart-number)))
-                     (mml-generate-default-type "text/plain"))
-                 (mml-to-mime))
-               (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))))
-              ((string= (car (split-string type "/")) "message")
-               (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))))
-              (t 
-               (setq charset (mm-encode-body))
-               (setq encoding (mm-body-encoding
-                               charset (cdr (assq 'encoding cont))))))
-             (setq coded (buffer-string)))
-         (mm-with-unibyte-buffer
-           (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 mm-binary-coding-system))
-               (mm-insert-file-contents filename nil nil nil nil t)))
-            (t
-             (insert (cdr (assq 'contents cont)))))
-           (setq encoding (mm-encode-buffer type)
-                 coded (buffer-string))))
-       (mml-insert-mime-headers cont type charset encoding)
-       (insert "\n")
-       (insert coded)))
-     ((eq (car cont) 'external)
-      (insert "Content-Type: message/external-body")
-      (let ((parameters (mml-parameter-string
-                        cont '(expiration size permission)))
-           (name (cdr (assq 'name cont))))
-       (when name
-         (setq name (mml-parse-file-name name))
-         (if (stringp name)
+               (insert (cdr (assq 'contents cont)))))
+             (setq encoding (mm-encode-buffer type)
+                   coded (buffer-string))))
+         (mml-insert-mime-headers cont type charset encoding)
+         (insert "\n")
+         (insert coded)))
+       ((eq (car cont) 'external)
+       (insert "Content-Type: message/external-body")
+       (let ((parameters (mml-parameter-string
+                          cont '(expiration size permission)))
+             (name (cdr (assq 'name cont)))
+             (url (cdr (assq 'url cont))))
+         (when name
+           (setq name (mml-parse-file-name name))
+           (if (stringp name)
+               (mml-insert-parameter
+                (mail-header-encode-parameter "name" name)
+                "access-type=local-file")
              (mml-insert-parameter
-              (mail-header-encode-parameter "name" name)
-              "access-type=local-file")
-           (mml-insert-parameter
-            (mail-header-encode-parameter
-             "name" (file-name-nondirectory (nth 2 name)))
-            (mail-header-encode-parameter "site" (nth 1 name))
-            (mail-header-encode-parameter
-             "directory" (file-name-directory (nth 2 name))))
+              (mail-header-encode-parameter
+               "name" (file-name-nondirectory (nth 2 name)))
+              (mail-header-encode-parameter "site" (nth 1 name))
+              (mail-header-encode-parameter
+               "directory" (file-name-directory (nth 2 name))))
+             (mml-insert-parameter
+              (concat "access-type="
+                      (if (member (nth 0 name) '("ftp@" "anonymous@"))
+                          "anon-ftp"
+                        "ftp")))))      
+         (when url
            (mml-insert-parameter
-            (concat "access-type="
-                    (if (member (nth 0 name) '("ftp@" "anonymous@"))
-                        "anon-ftp"
-                      "ftp")))))      
-       (when parameters
-         (mml-insert-parameter-string
-          cont '(expiration size permission))))
-      (insert "\n\n")
-      (insert "Content-Type: " (cdr (assq 'type cont)) "\n")
-      (insert "Content-ID: " (message-make-message-id) "\n")
-      (insert "Content-Transfer-Encoding: "
-             (or (cdr (assq 'encoding cont)) "binary"))
-      (insert "\n\n")
-      (insert (or (cdr (assq 'contents cont))))
-      (insert "\n"))
-     ((eq (car cont) 'multipart)
-      (let* ((type (or (cdr (assq 'type cont)) "mixed"))
-            (mml-generate-default-type (if (equal type "digest")
-                                           "message/rfc822"
-                                         "text/plain"))
-            (handler (assoc type mml-generate-multipart-alist)))
-       (if handler
-           (funcall (cdr handler) cont)
-         ;; No specific handler.  Use default one.
-         (let ((mml-boundary (mml-compute-boundary cont)))
-           (insert (format "Content-Type: multipart/%s; boundary=\"%s\"\n"
-                           type mml-boundary))
-           ;; Skip `multipart' and `type' elements.
-           (setq cont (cddr cont))
-           (while cont
-             (insert "\n--" mml-boundary "\n")
-             (mml-generate-mime-1 (pop cont)))
-           (insert "\n--" mml-boundary "--\n")))))
-     (t
-      (error "Invalid element: %S" cont)))
-    (if mml-generate-mime-postprocess-function
-       (funcall mml-generate-mime-postprocess-function cont))
-    (let ((item (assoc (cdr (assq 'sign cont)) mml-sign-alist)))
-      (when item
-       (funcall (nth 1 item) cont)))
-    (let ((item (assoc (cdr (assq 'encrypt cont)) mml-encrypt-alist)))
-      (when item
-       (funcall (nth 1 item) cont)))))
+            (mail-header-encode-parameter "url" url)
+            "access-type=url"))
+         (when parameters
+           (mml-insert-parameter-string
+            cont '(expiration size permission))))
+       (insert "\n\n")
+       (insert "Content-Type: " (cdr (assq 'type cont)) "\n")
+       (insert "Content-ID: " (message-make-message-id) "\n")
+       (insert "Content-Transfer-Encoding: "
+               (or (cdr (assq 'encoding cont)) "binary"))
+       (insert "\n\n")
+       (insert (or (cdr (assq 'contents cont))))
+       (insert "\n"))
+       ((eq (car cont) 'multipart)
+       (let* ((type (or (cdr (assq 'type cont)) "mixed"))
+              (mml-generate-default-type (if (equal type "digest")
+                                             "message/rfc822"
+                                           "text/plain"))
+              (handler (assoc type mml-generate-multipart-alist)))
+         (if handler
+             (funcall (cdr handler) cont)
+           ;; No specific handler.  Use default one.
+           (let ((mml-boundary (mml-compute-boundary cont)))
+             (insert (format "Content-Type: multipart/%s; boundary=\"%s\"\n"
+                             type mml-boundary))
+             (let ((cont cont) part)
+               (while (setq part (pop cont))
+                 ;; Skip `multipart' and attributes.
+                 (when (and (consp part) (consp (cdr part)))
+                   (insert "\n--" mml-boundary "\n")
+                   (mml-generate-mime-1 part))))
+             (insert "\n--" mml-boundary "--\n")))))
+       (t
+       (error "Invalid element: %S" cont)))
+      (let ((item (assoc (cdr (assq 'sign cont)) mml-sign-alist))
+           sender recipients)
+       (when item
+         (if (setq sender (cdr (assq 'sender cont)))
+             (message-options-set 'message-sender sender))
+         (if (setq recipients (cdr (assq 'recipients cont)))
+             (message-options-set 'message-sender recipients))
+         (funcall (nth 1 item) cont)))
+      (let ((item (assoc (cdr (assq 'encrypt cont)) mml-encrypt-alist))
+           sender recipients)
+       (when item
+         (if (setq sender (cdr (assq 'sender cont)))
+             (message-options-set 'message-sender sender))
+         (if (setq recipients (cdr (assq 'recipients cont)))
+             (message-options-set 'message-sender recipients))
+         (funcall (nth 1 item) cont))))))
 
 (defun mml-compute-boundary (cont)
   "Return a unique boundary that does not exist in CONT."
@@ -548,20 +546,22 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
 ;;; Transforming MIME to MML
 ;;;
 
-(defun mime-to-mml ()
-  "Translate the current buffer (which should be a message) into MML."
+(defun mime-to-mml (&optional handles)
+  "Translate the current buffer (which should be a message) into MML.
+If HANDLES is non-nil, use it instead reparsing the buffer."
   ;; First decode the head.
   (save-restriction
     (message-narrow-to-head)
     (mail-decode-encoded-word-region (point-min) (point-max)))
-  (let ((handles (mm-dissect-buffer t)))
-    (goto-char (point-min))
-    (search-forward "\n\n" nil t)
-    (delete-region (point) (point-max))
-    (if (stringp (car handles))
-       (mml-insert-mime handles)
-      (mml-insert-mime handles t))
-    (mm-destroy-parts handles))
+  (unless handles
+    (setq handles (mm-dissect-buffer t)))
+  (goto-char (point-min))
+  (search-forward "\n\n" nil t)
+  (delete-region (point) (point-max))
+  (if (stringp (car handles))
+      (mml-insert-mime handles)
+    (mml-insert-mime handles t))
+  (mm-destroy-parts handles)
   (save-restriction
     (message-narrow-to-head)
     ;; Remove them, they are confusing.
@@ -602,10 +602,11 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
       (mapcar 'mml-insert-mime (cdr handle))
       (insert "<#/multipart>\n"))
      (textp
-      (let ((text (mm-get-part handle))
-           (charset (mail-content-type-get
+      (let ((charset (mail-content-type-get
                      (mm-handle-type handle) 'charset)))
-       (insert (mm-decode-string text charset)))
+       (if (eq charset 'gnus-decoded)
+           (mm-insert-part handle)
+         (insert (mm-decode-string (mm-get-part handle) charset))))
       (goto-char (point-max)))
      (t
       (insert "<#/part>\n")))))
@@ -620,7 +621,8 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
       (insert "<#part type=" (mm-handle-media-type handle)))
     (dolist (elem (append (cdr (mm-handle-type handle))
                          (cdr (mm-handle-disposition handle))))
-      (insert " " (symbol-name (car elem)) "=\"" (cdr elem) "\""))
+      (unless (symbolp (cdr elem))
+       (insert " " (symbol-name (car elem)) "=\"" (cdr elem) "\"")))
     (when (mm-handle-disposition handle)
       (insert " disposition=" (car (mm-handle-disposition handle))))
     (when buffer
@@ -880,13 +882,6 @@ If RAW, don't highlight the article."
   (interactive)
   (mml-parse))
 
-(defun mml-postprocess (cont)
-  (let ((pp (cdr (or (assq 'postprocess cont)
-                    (assq 'pp cont))))
-       item)
-    (if (and pp (setq item (assoc pp mml-postprocess-alist)))
-       (funcall (cdr item) cont))))
-
 (provide 'mml)
 
 ;;; mml.el ends here