(mml-generate-mime-1): Only flow encode messages when
[gnus] / lisp / mml.el
index b2f194c..227141c 100644 (file)
@@ -1,5 +1,6 @@
 ;;; 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, 1999, 2000, 2001, 2002, 2003
+;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; This file is part of GNU Emacs.
@@ -34,6 +35,7 @@
   (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"))
@@ -52,6 +54,12 @@ These parameters are generated in Content-Disposition header if exists."
   :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
@@ -68,7 +76,7 @@ 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
+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.")
 
@@ -208,12 +216,12 @@ one charsets.")
          (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))
@@ -438,19 +446,15 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
                    ;; 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)))
+                   (when (and use-hard-newlines
+                              (string= type "text/plain")
+                              (or (null (assq 'format cont))
+                                  (string= (cdr (assq 'format cont)) "flowed")))
                        (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 flowed (null (assq 'format cont))))
                    (setq charset (mm-encode-body charset))
                    (setq encoding (mm-body-encoding
                                    charset (cdr (assq 'encoding cont))))))
@@ -522,8 +526,11 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
              (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))
+             (insert (format "Content-Type: multipart/%s; boundary=\"%s\""
+                             type mml-boundary)
+                     (if (cdr (assq 'start cont))
+                         (format "; start=\"%s\"\n" (cdr (assq 'start cont)))
+                       "\n"))
              (let ((cont cont) part)
                (while (setq part (pop cont))
                  ;; Skip `multipart' and attributes.
@@ -539,8 +546,9 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
                                 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)))))
@@ -598,17 +606,18 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
          mml-base-boundary))
 
 (defun mml-insert-mime-headers (cont type charset encoding flowed)
-  (let (parameters disposition description)
+  (let (parameters id disposition description)
     (setq parameters
          (mml-parameter-string
           cont mml-content-type-parameters))
     (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
@@ -619,6 +628,8 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
        (mml-insert-parameter-string
         cont mml-content-type-parameters))
       (insert "\n"))
+    (when (setq id (cdr (assq 'id cont)))
+      (insert "Content-ID: " id "\n"))
     (setq parameters
          (mml-parameter-string
           cont mml-content-disposition-parameters))
@@ -737,7 +748,7 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
        (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))
@@ -745,10 +756,12 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
       (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")))))
@@ -756,8 +769,12 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
 (defun mml-insert-mml-markup (handle &optional buffer nofile mmlp)
   "Take a MIME handle and insert an MML tag."
   (if (stringp (car handle))
-      (insert "<#multipart type=" (mm-handle-media-subtype handle)
-             ">\n")
+      (progn
+       (insert "<#multipart type=" (mm-handle-media-subtype handle))
+       (let ((start (mm-handle-multipart-ctl-parameter handle 'start)))
+         (when start
+           (insert " start=\"" start "\"")))
+       (insert ">\n"))
     (if mmlp
        (insert "<#mml type=" (mm-handle-media-type handle))
       (insert "<#part type=" (mm-handle-media-type handle)))
@@ -765,6 +782,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
                          (cdr (mm-handle-disposition handle))))
       (unless (symbolp (cdr elem))
        (insert " " (symbol-name (car elem)) "=\"" (cdr elem) "\"")))
+    (when (mm-handle-id handle)
+      (insert " id=\"" (mm-handle-id handle) "\""))
     (when (mm-handle-disposition handle)
       (insert " disposition=" (car (mm-handle-disposition handle))))
     (when buffer
@@ -880,7 +899,8 @@ See Info node `(emacs-mime)Composing'.
 ;;;
 
 (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)
@@ -1009,15 +1029,15 @@ TYPE is the MIME type to use."
   (mml-insert-tag 'part 'type type 'disposition "inline")
   (forward-line -1))
 
-(defun mml-preview-insert-mft ()
+(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-mft))
+            (message-make-mail-followup-to))
     (message-position-on-field "Mail-Followup-To" "X-Draft-From")
-    (insert (message-make-mft))))
+    (insert (message-make-mail-followup-to))))
 
 (defun mml-preview (&optional raw)
   "Display current buffer with Gnus, in a new buffer.
@@ -1038,8 +1058,8 @@ If RAW, don't highlight the article."
                         (concat (if raw "*Raw MIME preview of "
                                   "*MIME preview of ") (buffer-name))))
       (erase-buffer)
-      (insert-buffer buf)
-      (mml-preview-insert-mft)
+      (insert-buffer-substring buf)
+      (mml-preview-insert-mail-followup-to)
       (let ((message-deletable-headers (if (message-news-p)
                                           nil
                                         message-deletable-headers)))
@@ -1068,8 +1088,21 @@ If RAW, don't highlight the article."
            (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 ()