2002-01-02 ShengHuo ZHU <zsh@cs.rochester.edu>
[gnus] / lisp / mml.el
index db1c57b..af9b23c 100644 (file)
@@ -1,5 +1,5 @@
 ;;; mml.el --- A package for parsing and validating MML documents
-;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; This file is part of GNU Emacs.
@@ -64,6 +64,16 @@ NAME is a string containing the name of the TWEAK parameter in the MML
 handle.  FUNCTION is a Lisp function which is called with the MML
 handle to tweak the part.")
 
+(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
+is called.  FUNCTION is a Lisp function which is called with the MML
+handle to tweak the part.")
+
+(defvar mml-externalize-attachments nil
+  "*If non-nil, local-file attachments are generated as external parts.")
+
 (defvar mml-generate-multipart-alist nil
   "*Alist of multipart generation functions.
 Each entry has the form (NAME . FUNCTION), where
@@ -334,49 +344,53 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
          (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))))
-               (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))
-                   (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)))
+             (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))
+                     (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)))
+               (mml-insert-mime-headers cont type charset encoding)
+               (insert "\n")
+               (insert coded))
            (mm-with-unibyte-buffer
              (cond
               ((cdr (assq 'buffer cont))
@@ -388,10 +402,11 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
               (t
                (insert (cdr (assq 'contents cont)))))
              (setq encoding (mm-encode-buffer type)
-                   coded (mm-string-as-multibyte (buffer-string)))))
-         (mml-insert-mime-headers cont type charset encoding)
-         (insert "\n")
-         (insert coded)))
+                   coded (mm-string-as-multibyte (buffer-string))))
+           (mml-insert-mime-headers cont type charset encoding)
+           (insert "\n")
+           (mm-with-unibyte-current-buffer
+             (insert coded)))))
        ((eq (car cont) 'external)
        (insert "Content-Type: message/external-body")
        (let ((parameters (mml-parameter-string
@@ -613,6 +628,7 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
     ;; Remove them, they are confusing.
     (message-remove-header "Content-Type")
     (message-remove-header "MIME-Version")
+    (message-remove-header "Content-Disposition")
     (message-remove-header "Content-Transfer-Encoding")))
 
 (defun mml-to-mime ()
@@ -700,8 +716,10 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
        (map (make-sparse-keymap))
        (main (make-sparse-keymap)))
     (define-key sign "p" 'mml-secure-sign-pgpmime)
+    (define-key sign "o" 'mml-secure-sign-pgp)
     (define-key sign "s" 'mml-secure-sign-smime)
     (define-key encrypt "p" 'mml-secure-encrypt-pgpmime)
+    (define-key encrypt "o" 'mml-secure-encrypt-pgp)
     (define-key encrypt "s" 'mml-secure-encrypt-smime)
     (define-key map "f" 'mml-attach-file)
     (define-key map "b" 'mml-attach-buffer)
@@ -721,14 +739,18 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
 
 (easy-menu-define
   mml-menu mml-mode-map ""
-  '("Attachments"
-    ["Attach File" mml-attach-file t]
+  `("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-sign-pgpmime t]
     ["PGP/MIME Encrypt" mml-secure-encrypt-pgpmime t]
+    ["PGP Sign" mml-secure-sign-pgp t]
+    ["PGP Encrypt" mml-secure-encrypt-pgp t]
     ["S/MIME Sign" mml-secure-sign-smime t]
     ["S/MIME Encrypt" mml-secure-encrypt-smime t]
     ;;["Narrow" mml-narrow-to-part t]
@@ -741,6 +763,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
 
 (defun mml-mode (&optional arg)
   "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")
@@ -905,7 +929,8 @@ If RAW, don't highlight the article."
     (if (re-search-forward
         (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
        (replace-match "\n"))
-    (mml-to-mime)
+    (let ((mail-header-separator "")) ;; mail-header-separator is removed.
+      (mml-to-mime))
     (if raw
        (when (fboundp 'set-buffer-multibyte)
          (let ((s (buffer-string)))
@@ -947,7 +972,23 @@ If RAW, don't highlight the article."
            (setq alist (cdr alist)))))))
     (if func
        (funcall func cont)
-      cont)))
+      cont)
+    (let ((alist mml-tweak-sexp-alist))
+      (while alist
+       (if (eval (caar alist))
+           (funcall (cdar alist) cont))
+       (setq alist (cdr alist)))))
+  cont)
+
+(defun mml-tweak-externalize-attachments (cont)
+  "Tweak attached files as external parts."
+  (let (filename-cons)
+    (when (and (eq (car cont) 'part) 
+              (not (cdr (assq 'buffer cont)))
+              (and (setq filename-cons (assq 'filename cont))
+                   (not (equal (cdr (assq 'nofile cont)) "yes"))))
+      (setcar cont 'external)
+      (setcar filename-cons 'name))))
 
 (provide 'mml)