diff lisp/vm/vm-reply.el @ 98:0d2f883870bc r20-1b1

Import from CVS: tag r20-1b1
author cvs
date Mon, 13 Aug 2007 09:13:56 +0200
parents c0c698873ce1
children 4be1180a9e89
line wrap: on
line diff
--- a/lisp/vm/vm-reply.el	Mon Aug 13 09:12:43 2007 +0200
+++ b/lisp/vm/vm-reply.el	Mon Aug 13 09:13:56 2007 +0200
@@ -1,5 +1,5 @@
 ;;; Mailing, forwarding, and replying commands for VM
-;;; Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995 Kyle E. Jones
+;;; Copyright (C) 1989-1997 Kyle E. Jones
 ;;;
 ;;; This program is free software; you can redistribute it and/or modify
 ;;; it under the terms of the GNU General Public License as published by
@@ -29,11 +29,12 @@
 	 ((eq mlist mp)
 	  (cond ((setq to
 		       (let ((reply-to
-			      (vm-get-header-contents (car mp) "Reply-To:")))
+			      (vm-get-header-contents (car mp) "Reply-To:"
+						      ", ")))
 			 (if (vm-ignored-reply-to reply-to)
 			     nil
 			   reply-to ))))
-		((setq to (vm-get-header-contents (car mp) "From:")))
+		((setq to (vm-get-header-contents (car mp) "From:" ", ")))
 		;; bad, but better than nothing for some
 		((setq to (vm-grok-From_-author (car mp))))
 		(t (error "No From: or Reply-To: header in message")))
@@ -51,9 +52,11 @@
 				 subject)
 		   0)))
 	       (setq subject (concat vm-reply-subject-prefix subject))))
-	 (t (cond ((setq tmp (vm-get-header-contents (car mp) "Reply-To:"))
+	 (t (cond ((setq tmp (vm-get-header-contents (car mp) "Reply-To:"
+						     ", "))
 		   (setq to (concat to "," tmp)))
-		  ((setq tmp (vm-get-header-contents (car mp) "From:"))
+		  ((setq tmp (vm-get-header-contents (car mp) "From:"
+						     ", "))
 		   (setq to (concat to "," tmp)))
 		  ;; bad, but better than nothing for some
 		  ((setq tmp (vm-grok-From_-author (car mp)))
@@ -61,8 +64,10 @@
 		  (t (error "No From: or Reply-To: header in message")))))
 	(if to-all
 	    (progn
-	      (setq tmp (vm-get-header-contents (car mp) "To:"))
-	      (setq tmp2 (vm-get-header-contents (car mp) "Cc:"))
+	      (setq tmp (vm-get-header-contents (car mp) "To:"
+						", "))
+	      (setq tmp2 (vm-get-header-contents (car mp) "Cc:"
+						 ", "))
 	      (if tmp
 		  (if cc
 		      (setq cc (concat cc "," tmp))
@@ -72,13 +77,14 @@
 		      (setq cc (concat cc "," tmp2))
 		    (setq cc tmp2)))))
 	(setq references
-	      (cons (vm-get-header-contents (car mp) "References:")
-		    (cons (vm-get-header-contents (car mp) "In-reply-to:")
-			  (cons (vm-get-header-contents (car mp) "Message-ID:")
+	      (cons (vm-get-header-contents (car mp) "References:" " ")
+		    (cons (vm-get-header-contents (car mp) "In-reply-to:" " ")
+			  (cons (vm-get-header-contents (car mp) "Message-ID:"
+							" ")
 				references))))
 	(setq newsgroups
-	      (cons (or (and to-all (vm-get-header-contents (car mp) "Followup-To:"))
-			(vm-get-header-contents (car mp) "Newsgroups:"))
+	      (cons (or (and to-all (vm-get-header-contents (car mp) "Followup-To:" ","))
+			(vm-get-header-contents (car mp) "Newsgroups:" ","))
 		    newsgroups))
 	(setq mp (cdr mp)))
       (if vm-strip-reply-headers
@@ -192,6 +198,8 @@
     (setq newbuf (current-buffer))
     (if (not (eq major-mode 'vm-mode))
 	(vm-mode))
+    (if vm-presentation-buffer-handle
+	(vm-bury-buffer vm-presentation-buffer-handle))
     (if (null vm-message-pointer)
 	(error "No messages in folder %s" folder))
     (setq default (vm-number-of (car vm-message-pointer)))
@@ -275,12 +283,34 @@
     (save-restriction
       (widen)
       (save-excursion
-	(set-buffer (vm-buffer-of message))
-	(save-restriction
-	  (widen)
-	  (append-to-buffer b (vm-headers-of message) (vm-text-end-of message))
-	  (setq end (vm-marker (+ start (- (vm-text-end-of message)
-					   (vm-headers-of message))) b))))
+	(if (vectorp (vm-mm-layout message))
+	    (let* ((o (vm-mm-layout message))
+		   (type (car (vm-mm-layout-type o)))
+		   parts)
+	      (vm-insert-region-from-buffer (vm-buffer-of message)
+					    (vm-headers-of message)
+					    (vm-text-of message))
+	      (cond ((vm-mime-types-match "multipart" type)
+		     (setq parts (vm-mm-layout-parts o)))
+		    (t (setq parts (list o))))
+	      (while parts
+		(cond ((vm-mime-text-type-p (car parts))
+		       (if (vm-mime-display-internal-text/plain (car parts) t)
+			   nil
+			 ;; charset problems probably
+			 ;; just dump the raw bits
+			 (vm-mime-insert-mime-body (car parts))
+			 (vm-mime-transfer-decode-region (car parts)
+							 start (point)))))
+		(setq parts (cdr parts)))
+	      (setq end (point-marker)))
+	  (set-buffer (vm-buffer-of message))
+	  (save-restriction
+	    (widen)
+	    (append-to-buffer b (vm-headers-of message)
+			      (vm-text-end-of message))
+	    (setq end (vm-marker (+ start (- (vm-text-end-of message)
+					     (vm-headers-of message))) b)))))
       (push-mark end)
       (cond (mail-citation-hook (run-hooks 'mail-citation-hook))
 	    (mail-yank-hooks (run-hooks 'mail-yank-hooks))
@@ -290,11 +320,14 @@
   "Just like mail-send-and-exit except that VM flags the appropriate message(s)
 as having been replied to, if appropriate."
   (interactive "P")
+  (vm-check-for-killed-folder)
   (let ((b (current-buffer)))
     (vm-mail-send)
     (cond ((null (buffer-name b)) ;; dead buffer
 	   (vm-display nil nil '(vm-mail-send-and-exit)
-		       '(vm-mail-send-and-exit reading-message startup)))
+		       '(vm-mail-send-and-exit
+			 reading-message
+			 startup)))
 	  (t
 	   (vm-display b nil '(vm-mail-send-and-exit)
 		       '(vm-mail-send-and-exit reading-message startup))
@@ -337,27 +370,78 @@
   (interactive)
   (if vm-tale-is-an-idiot
       (vm-help-tale))
-  (if (and vm-confirm-mail-send
-	   (not (y-or-n-p "Send the message? ")))
-      (error "Message not sent."))
+  ;; protect value of this-command from minibuffer read
+  (let ((this-command this-command))
+    (if (and vm-confirm-mail-send
+	     (not (y-or-n-p "Send the message? ")))
+	(error "Message not sent.")))
+  ;; send mail using MIME if user requests it and if the buffer
+  ;; has not already been MIME encoded.
+  (if (and vm-send-using-mime
+	   (null (vm-mail-mode-get-header-contents "MIME-Version:")))
+      (vm-mime-encode-composition))
   ;; this to prevent Emacs 19 from asking whether a message that
   ;; has already been sent should be sent again.  VM renames mail
   ;; buffers after the message has been sent, so the user should
   ;; already know that the message has been sent.
   (set-buffer-modified-p t)
-  ;; don't want a buffer change to occur here
-  ;; save-excursion to be sure.
-  (save-excursion
-    (mail-send))
-  (vm-rename-current-mail-buffer)
-  (cond ((eq vm-system-state 'replying)
-	 (vm-mail-mark-replied))
-	((eq vm-system-state 'forwarding)
-	 (vm-mail-mark-forwarded))
-	((eq vm-system-state 'redistributing)
-	 (vm-mail-mark-redistributed)))
-  (vm-keep-mail-buffer (current-buffer))
-  (vm-display nil nil '(vm-mail-send) '(vm-mail-send)))
+  (let ((composition-buffer (current-buffer))
+	;; preserve these in case the composition buffer gets
+	;; killed.
+	(vm-reply-list vm-reply-list)
+	(vm-forward-list vm-forward-list)
+	(vm-redistribute-list vm-redistribute-list))
+    ;; fragment message using message/partial if it is too big.
+    (if (and vm-send-using-mime
+	     (integerp vm-mime-max-message-size)
+	     (> (buffer-size) vm-mime-max-message-size))
+	(let (list)
+	  (setq list (vm-mime-fragment-composition vm-mime-max-message-size))
+	  (while list
+	    (save-excursion
+	      (set-buffer (car list))
+	      (vm-mail-send)
+	      (kill-buffer (car list)))
+	    (setq list (cdr list)))
+	  ;; what mail-send would have done
+	  (set-buffer-modified-p nil))
+      ;; don't want a buffer change to occur here
+      ;; save-excursion to be sure.
+      ;;
+      ;; also protect value of this-command from minibuffer reads
+      (let ((this-command this-command))
+	(save-excursion
+	  (mail-send))))
+    (cond ((eq vm-system-state 'replying)
+	   (vm-mail-mark-replied))
+	  ((eq vm-system-state 'forwarding)
+	   (vm-mail-mark-forwarded))
+	  ((eq vm-system-state 'redistributing)
+	   (vm-mail-mark-redistributed)))
+    ;; be careful, something could have killed the composition
+    ;; buffer inside mail-send.
+    (if (eq (current-buffer) composition-buffer)
+	(progn
+	  (vm-rename-current-mail-buffer)
+	  (vm-keep-mail-buffer (current-buffer))))
+    (vm-display nil nil '(vm-mail-send) '(vm-mail-send))))
+
+(defun vm-mail-mode-get-header-contents (header-name-regexp)
+  (let ((contents nil)
+	regexp)
+    (setq regexp (concat "^\\(" header-name-regexp "\\)\\|\\(^"
+			 (regexp-quote mail-header-separator) "$\\)"))
+    (save-excursion
+      (save-restriction
+	(widen)
+	(goto-char (point-min))
+	(let ((case-fold-search t))
+	  (if (and (re-search-forward regexp nil t)
+		   (match-beginning 1)
+		   (progn (goto-char (match-beginning 0))
+			  (vm-match-header)))
+	      (vm-matched-header-contents)
+	    nil ))))))
 
 (defun vm-rename-current-mail-buffer ()
   (if vm-rename-current-buffer-function
@@ -503,6 +587,10 @@
 	(setq this-command 'vm-next-command-uses-marks)
 	(command-execute 'vm-send-digest))
     (let ((dir default-directory)
+	  (miming (and vm-send-using-mime
+		       (equal vm-forwarding-digest-type "mime")))
+	  mail-buffer
+	  header-end boundary
 	  (mp vm-message-pointer))
       (save-restriction
 	(widen)
@@ -518,10 +606,33 @@
 	(setq vm-system-state 'forwarding
 	      vm-forward-list (list (car mp))
 	      default-directory dir)
-	(goto-char (point-min))
-	(re-search-forward
-	 (concat "^" (regexp-quote mail-header-separator) "\n") nil 0)
-	(cond ((equal vm-forwarding-digest-type "rfc934")
+	(if miming
+	    (progn
+	      (setq mail-buffer (current-buffer))
+	      (set-buffer (generate-new-buffer "*vm-forward-buffer*"))
+	      (setq header-end (point))
+	      (insert "\n"))
+	  (goto-char (point-min))
+	  (re-search-forward (concat "^" (regexp-quote mail-header-separator)
+				     "\n"))
+	  (goto-char (match-end 0))
+	  (setq header-end (match-beginning 0)))
+	(cond ((equal vm-forwarding-digest-type "mime")
+	       (setq boundary (vm-mime-encapsulate-messages
+			       (list (car mp)) vm-forwarded-headers
+			       vm-unforwarded-header-regexp))
+	       (goto-char header-end)
+	       (insert "MIME-Version: 1.0\n")
+	       (insert (if vm-mime-avoid-folding-content-type
+			   "Content-Type: multipart/digest; boundary=\""
+			 "Content-Type: multipart/digest;\n\tboundary=\"")
+		       boundary "\"\n")
+	       (insert "Content-Transfer-Encoding: "
+		       (vm-determine-proper-content-transfer-encoding
+			(point)
+			(point-max))
+		       "\n"))
+	      ((equal vm-forwarding-digest-type "rfc934")
 	       (vm-rfc934-encapsulate-messages
 		vm-forward-list vm-forwarded-headers
 		vm-unforwarded-header-regexp))
@@ -533,6 +644,17 @@
 	       (vm-no-frills-encapsulate-message
 		(car vm-forward-list) vm-forwarded-headers
 		vm-unforwarded-header-regexp)))
+      (if miming
+	  (let ((b (current-buffer)))
+	    (set-buffer mail-buffer)
+	    (mail-text)
+	    (vm-mime-attach-object b "multipart/digest"
+				   (list (concat "boundary=\""
+						 boundary "\"")) t)
+	    (add-hook 'kill-buffer-hook
+		      (list 'lambda ()
+			    (list 'if (list 'eq mail-buffer '(current-buffer))
+				  (list 'kill-buffer b))))))
 	(mail-position-on-field "To"))
       (run-hooks 'vm-forward-message-hook)
       (run-hooks 'vm-mail-mode-hook))))
@@ -548,20 +670,25 @@
   (vm-error-if-folder-empty)
   (let ((b (current-buffer)) start
 	(dir default-directory)
+	(layout (vm-mm-layout (car vm-message-pointer)))
 	(lim (vm-text-end-of (car vm-message-pointer))))
       (save-restriction
 	(widen)
-	(save-excursion
-	  (goto-char (vm-text-of (car vm-message-pointer)))
-	  (let ((case-fold-search t))
-	    ;; What a wonderful world it would be if mailers used a single
-	    ;; message encapsulation standard instead all the weird variants
-	    ;; It is useless to try to cover them all.
-	    ;; This simple rule should cover the sanest of the formats
-	    (if (not (re-search-forward "^Received:" lim t))
-		(error "This doesn't look like a bounced message."))
-	    (beginning-of-line)
-	    (setq start (point))))
+	(if (or (not (vectorp layout))
+		(not (setq layout (vm-mime-layout-contains-type
+				   layout "message/rfc822"))))
+	    (save-excursion
+	      (goto-char (vm-text-of (car vm-message-pointer)))
+	      (let ((case-fold-search t))
+		;; What a wonderful world it would be if mailers
+		;; used a single message encapsulation standard
+		;; instead of all the weird variants. It is
+		;; useless to try to cover them all.  This simple
+		;; rule should cover the sanest of the formats
+		(if (not (re-search-forward "^Received:" lim t))
+		    (error "This doesn't look like a bounced message."))
+		(beginning-of-line)
+		(setq start (point)))))
 	;; briefly nullify vm-mail-header-from to keep vm-mail-internal
 	;; from inserting another From header.
 	(let ((vm-mail-header-from nil))
@@ -569,7 +696,12 @@
 	   (format "retry of bounce from %s"
 		   (vm-su-from (car vm-message-pointer)))))
 	(goto-char (point-min))
-	(insert-buffer-substring b start lim)
+	(if (vectorp layout)
+	    (progn
+	      (setq start (point))
+	      (vm-mime-insert-mime-body layout)
+	      (vm-mime-transfer-decode-region layout start (point)))
+	  (insert-buffer-substring b start lim))
 	(delete-region (point) (point-max))
 	(goto-char (point-min))
 	;; delete all but pertinent headers
@@ -658,13 +790,14 @@
   (vm-check-for-killed-summary)
   (vm-error-if-folder-empty)
   (let ((dir default-directory)
-	(mp vm-message-pointer)
+	(miming (and vm-send-using-mime (equal vm-digest-send-type "mime")))
+	mp mail-buffer b
 	;; prefix arg doesn't have "normal" meaning here, so only call
 	;; vm-select-marked-or-prefixed-messages if we're using marks.
 	(mlist (if (eq last-command 'vm-next-command-uses-marks)
 		   (vm-select-marked-or-prefixed-messages 0)
 		 vm-message-list))
-	start)
+	start header-end boundary)
     (save-restriction
       (widen)
       (vm-mail-internal (format "digest from %s" (buffer-name)))
@@ -672,14 +805,36 @@
       (setq vm-system-state 'forwarding
 	    vm-forward-list mlist
 	    default-directory dir)
-      (goto-char (point-min))
-      (re-search-forward (concat "^" (regexp-quote mail-header-separator)
-				 "\n"))
-      (goto-char (match-end 0))
-      (setq start (point)
-	    mp mlist)
+      (if miming
+	  (progn
+	    (setq mail-buffer (current-buffer))
+	    (set-buffer (generate-new-buffer "*vm-digest-buffer*"))
+	    (setq header-end (point))
+	    (insert "\n")
+	    (setq start (point-marker)))
+	(goto-char (point-min))
+	(re-search-forward (concat "^" (regexp-quote mail-header-separator)
+				   "\n"))
+	(goto-char (match-end 0))
+	(setq start (point-marker)
+	      header-end (match-beginning 0)))
       (vm-unsaved-message "Building %s digest..." vm-digest-send-type)
-      (cond ((equal vm-digest-send-type "rfc934")
+      (cond ((equal vm-digest-send-type "mime")
+	     (setq boundary (vm-mime-encapsulate-messages
+			     mlist vm-mime-digest-headers
+			     vm-mime-digest-discard-header-regexp))
+	     (goto-char header-end)
+	     (insert "MIME-Version: 1.0\n")
+	     (insert (if vm-mime-avoid-folding-content-type
+			 "Content-Type: multipart/digest; boundary=\""
+		       "Content-Type: multipart/digest;\n\tboundary=\"")
+		     boundary "\"\n")
+	     (insert "Content-Transfer-Encoding: "
+		     (vm-determine-proper-content-transfer-encoding
+		      (point)
+		      (point-max))
+		     "\n"))
+	    ((equal vm-digest-send-type "rfc934")
 	     (vm-rfc934-encapsulate-messages
 	      mlist vm-rfc934-digest-headers
 	      vm-rfc934-digest-discard-header-regexp))
@@ -701,6 +856,17 @@
 		    (center-line)
 		    (forward-char 1)))
 	      (setq mp (cdr mp)))))
+      (if miming
+	  (let ((b (current-buffer)))
+	    (set-buffer mail-buffer)
+	    (mail-text)
+	    (vm-mime-attach-object b "multipart/digest"
+				   (list (concat "boundary=\""
+						 boundary "\"")) t)
+	    (add-hook 'kill-buffer-hook
+		      (list 'lambda ()
+			    (list 'if (list 'eq mail-buffer '(current-buffer))
+				  (list 'kill-buffer b))))))
       (mail-position-on-field "To")
       (message "Building %s digest... done" vm-digest-send-type)))
   (run-hooks 'vm-send-digest-hook)
@@ -718,6 +884,12 @@
   (let ((vm-digest-send-type "rfc1153"))
     (vm-send-digest preamble)))
 
+(defun vm-send-mime-digest (&optional preamble)
+  "Like vm-send-digest but always sends an MIME (multipart/digest) digest."
+  (interactive "P")
+  (let ((vm-digest-send-type "mime"))
+    (vm-send-digest preamble)))
+
 (defun vm-continue-composing-message (&optional not-picky)
   "Find and select the most recently used mail composition buffer.
 If the selected buffer is already a Mail mode buffer then it is
@@ -753,6 +925,14 @@
 		      '(vm-continue-composing-message composing-message)))
       (message "No composition buffers found"))))
 
+(defun vm-mail-to-mailto-url (url)
+  (let ((address (car (vm-parse url "^mailto:\\(.+\\)"))))
+    (vm-select-folder-buffer)
+    (vm-check-for-killed-summary)
+    (vm-mail-internal nil address)
+    (run-hooks 'vm-mail-hook)
+    (run-hooks 'vm-mail-mode-hook)))
+
 ;; to quiet the v19 byte compiler
 (defvar mail-mode-map)
 (defvar mail-aliases)
@@ -780,7 +960,7 @@
 	       (nconc vm-mail-mode-map mail-mode-map)
 	       (setq vm-mail-mode-map-parented t))))
     (setq vm-mail-buffer folder-buffer
-	  mode-popup-menu (and vm-use-menus
+	  mode-popup-menu (and vm-use-menus vm-popup-menu-on-mouse-3
 			       (vm-menu-support-possible-p)
 			       (vm-menu-mode-menu)))
     ;; sets up popup menu for FSF Emacs
@@ -852,6 +1032,8 @@
 		  vm-send-rfc934-digest-other-frame
 		  vm-send-rfc1153-digest
 		  vm-send-rfc1153-digest-other-frame
+		  vm-send-mime-digest
+		  vm-send-mime-digest-other-frame
 		  vm-forward-message
 		  vm-forward-message-other-frame
 		  vm-forward-message-all-headers
@@ -985,3 +1167,14 @@
     (vm-send-rfc1153-digest prefix))
   (if (vm-multiple-frames-possible-p)
       (vm-set-hooks-for-frame-deletion)))
+
+(defun vm-send-mime-digest-other-frame (&optional prefix)
+  "Like vm-send-mime-digest, but run in a newly created frame."
+  (interactive "P")
+  (if (vm-multiple-frames-possible-p)
+      (vm-goto-new-frame 'composition))
+  (let ((vm-frame-per-composition nil)
+	(vm-search-other-frames nil))
+    (vm-send-mime-digest prefix))
+  (if (vm-multiple-frames-possible-p)
+      (vm-set-hooks-for-frame-deletion)))