* lisp/gnus.el (gnus-version-number): Update to 6.12.20
[elisp/gnus.git-] / lisp / message.el
index e83afde..f7f6b3a 100644 (file)
@@ -4,7 +4,10 @@
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;         MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;;         Shuhei KOBAYASHI <shuhei-k@jaist.ac.jp>
-;;         Keiichi Suzuki <kei-suzu@mail.wbs.ne.jp>
+;;         Keiichi Suzuki   <keiichi@nanap.org>
+;;         Tatsuya Ichikawa <t-ichi@po.shiojiri.ne.jp>
+;;         Katsumi Yamaoka  <yamaoka@jpl.org>
+;;         Kiyokazu SUTO    <suto@merry.xmath.ous.ac.jp>
 ;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
@@ -133,15 +136,18 @@ mailbox format."
                (function :tag "Other"))
   :group 'message-sending)
 
-(defcustom message-encode-function 'message-maybe-encode
+(autoload 'message-locale-maybe-encode "mess-lcl")
+(defcustom message-encode-function 'message-locale-maybe-encode
   "*A function called to encode messages."
-  :group 'message-sending
-  :type 'function)
+  :type '(radio (function-item message-locale-maybe-encode)
+               (function-item message-maybe-encode)
+               (function :tag "Other"))
+  :group 'message-sending)
 
-(defcustom message-default-encoding "7bit"
-  "*Default content transfer encoding type."
+(defcustom message-8bit-encoding-list '(8bit binary)
+  "*8bit encoding type in Content-Transfer-Encoding field."
   :group 'message-sending
-  :type 'string)
+  :type '(repeat (symbol :tag "Type")))
 
 (defcustom message-courtesy-message
   "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
@@ -157,6 +163,11 @@ If this variable is nil, no such courtesy message will be added."
   :group 'message-interface
   :type 'regexp)
 
+(defcustom message-bounce-setup-function 'message-bounce-setup-for-mime-edit
+  "Function to setup a re-sending bounced message."
+  :group 'message-sending
+  :type 'function)
+
 ;;;###autoload
 (defcustom message-from-style 'default
   "*Specifies how \"From\" headers look.
@@ -238,6 +249,12 @@ any confusion."
   :group 'message-interface
   :type 'regexp)
 
+(defcustom message-supersede-setup-function
+  'message-supersede-setup-for-mime-edit
+  "Function to setup a supersede message."
+  :group 'message-sending
+  :type 'function)
+
 (defcustom message-subject-re-regexp "^[ \t]*\\([Rr][Ee]:[ \t]*\\)*[ \t]*"
   "*Regexp matching \"Re: \" in the subject line."
   :group 'message-various
@@ -348,7 +365,7 @@ The provided functions are:
   :group 'message-forwarding
   :type 'boolean)
 
-(defcustom message-ignored-resent-headers "^Return-receipt"
+(defcustom message-ignored-resent-headers "^Return-Receipt"
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :type 'regexp)
@@ -469,7 +486,7 @@ variable isn't used."
   :group 'message-headers
   :type 'boolean)
 
-(defcustom message-setup-hook '(turn-on-mime-edit)
+(defcustom message-setup-hook '(message-mime-setup)
   "Normal hook, run each time a new outgoing message is initialized.
 The function `message-setup' runs this hook."
   :group 'message-various
@@ -482,6 +499,18 @@ the signature is inserted."
   :group 'message-various
   :type 'hook)
 
+(defcustom message-bounce-setup-hook nil
+  "Normal hook, run each time a a re-sending bounced message is initialized.
+The function `message-bounce' runs this hook."
+  :group 'message-various
+  :type 'hook)
+
+(defcustom message-supersede-setup-hook nil
+  "Normal hook, run each time a supersede message is initialized.
+The function `message-supersede' runs this hook."
+  :group 'message-various
+  :type 'hook)
+
 (defcustom message-mode-hook nil
   "Hook run in message mode buffers."
   :group 'message-various
@@ -490,11 +519,11 @@ the signature is inserted."
 (defcustom message-header-hook nil
   "Hook run in a message mode before header encode. Buffer narrowed 
 to the headers."
-  :group 'message-various
-  :type 'hook)
+   :group 'message-various
+   :type 'hook)
 
 (defcustom message-header-encode-function
-  'eword-encode-header
+  '(lambda () (eword-encode-header t))
   "A function called to encode header."
   :group 'message-various
   :type 'function)
@@ -523,6 +552,21 @@ nil means use indentation."
   :type 'string
   :group 'message-insertion)
 
+(defcustom message-yank-add-new-references t
+  "*Non-nil means new IDs will be added to \"References\" field when an
+article is yanked by the command `message-yank-original' interactively."
+  :type '(radio (const :tag "Do not add anything" nil)
+               (const :tag "From Message-Id, References and In-Reply-To fields" t)
+               (const :tag "From only Message-Id field." message-id-only))
+  :group 'message-insertion)
+
+(defcustom message-list-references-add-position nil
+  "*Integer value means position for adding to \"References\" field when
+an article is yanked by the command `message-yank-original' interactively."
+  :type '(radio (const :tag "Add to last" nil)
+               (integer :tag "Position from last ID"))
+  :group 'message-insertion)
+
 (defcustom message-indentation-spaces 3
   "*Number of spaces to insert at the beginning of each cited line.
 Used by `message-yank-original' via `message-yank-cite'."
@@ -591,7 +635,6 @@ If stringp, use this; if non-nil, use no host name (user name only)."
 
 (defvar message-reply-buffer nil)
 (defvar message-reply-headers nil)
-(defvar message-user-agent nil) ; XXX: This symbol is overloaded!  See below.
 (defvar message-sent-message-via nil)
 (defvar message-checksum nil)
 (defvar message-send-actions nil
@@ -632,6 +675,11 @@ articles."
   :group 'message-news
   :type 'message-header-lines)
 
+(defcustom message-mail-follow-up-address-checker nil
+  "A function of check follow up mail address."
+  :group 'message-mail
+  :type 'function)
+
 ;; Note: could use /usr/ucb/mail instead of sendmail;
 ;; options -t, and -v if not interactive.
 (defcustom message-mailer-swallows-blank-line
@@ -694,10 +742,10 @@ the prefix.")
 The default is `abbrev', which uses mailabbrev.  nil switches
 mail aliases off.")
 
-(defcustom message-autosave-directory
+(defcustom message-auto-save-directory
   (nnheader-concat message-directory "drafts/")
-  "*Directory where Message autosaves buffers if Gnus isn't running.
-If nil, Message won't autosave."
+  "*Directory where Message auto-saves buffers if Gnus isn't running.
+If nil, Message won't auto-save."
   :group 'message-buffers
   :type 'directory)
 
@@ -905,9 +953,6 @@ The cdr of ech entry is a function for applying the face to a region.")
                 (const :tag "always" t)
                 (const :tag "ask" ask)))
 
-(defvar message-send-coding-system 'binary
-  "Coding system to encode outgoing mail.")
-
 ;;; Internal variables.
 
 (defvar message-buffer-list nil)
@@ -1024,6 +1069,22 @@ The cdr of ech entry is a function for applying the face to a region.")
 ;;;
 ;;; Utility functions.
 ;;;
+(defun message-eval-parameter (parameter)
+  (condition-case ()
+      (if (symbolp parameter)
+         (if (functionp parameter)
+             (funcall parameter)
+           (eval parameter))
+       parameter)
+    (error nil)))
+
+(defsubst message-get-parameter (key &optional alist)
+  (unless alist
+    (setq alist message-parameter-alist))
+  (cdr (assq key alist)))
+
+(defmacro message-get-parameter-with-eval (key &optional alist)
+  `(message-eval-parameter (message-get-parameter ,key ,alist)))
 
 (defmacro message-y-or-n-p (question show &rest text)
   "Ask QUESTION, displaying the rest of the arguments in a temp. buffer if SHOW"
@@ -1058,12 +1119,12 @@ The cdr of ech entry is a function for applying the face to a region.")
                               (not paren))))
                 (push (buffer-substring beg (point)) elems)
                 (setq beg (match-end 0)))
-               ((= (following-char) ?\")
+               ((eq (char-after) ?\")
                 (setq quoted (not quoted)))
-               ((and (= (following-char) ?\()
+               ((and (eq (char-after) ?\()
                      (not quoted))
                 (setq paren t))
-               ((and (= (following-char) ?\))
+               ((and (eq (char-after) ?\))
                      (not quoted))
                 (setq paren nil))))
        (nreverse elems)))))
@@ -1100,7 +1161,7 @@ The cdr of ech entry is a function for applying the face to a region.")
 
 (defun message-fetch-reply-field (header)
   "Fetch FIELD from the message we're replying to."
-  (let ((buffer (message-get-reply-buffer)))
+  (let ((buffer (message-eval-parameter message-reply-buffer)))
     (when (and buffer
               (buffer-name buffer))
       (save-excursion
@@ -1245,22 +1306,6 @@ Return the number of headers removed."
               (- max rank)
             (1+ max)))))
       (message-sort-headers-1))))
-
-(defun message-eval-parameter (parameter)
-  (condition-case ()
-      (if (symbolp parameter)
-         (if (functionp parameter)
-             (funcall parameter)
-           (eval parameter))
-       parameter)
-    (error nil)))
-
-(defun message-get-reply-buffer ()
-  (message-eval-parameter message-reply-buffer))
-
-(defun message-get-original-reply-buffer ()
-  (message-eval-parameter
-   (cdr (assq 'original-buffer message-parameter-alist))))
 \f
 
 ;;;
@@ -1311,7 +1356,7 @@ Return the number of headers removed."
 
   (define-key message-mode-map "\t" 'message-tab)
 
-  (define-key message-mode-map "\C-xk" 'message-kill-buffer))
+  (define-key message-mode-map "\C-xk" 'message-mimic-kill-buffer))
 
 (easy-menu-define
  message-mode-menu message-mode-map "Message Menu."
@@ -1527,7 +1572,7 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   "Move point to the end of the headers."
   (interactive)
   (message-goto-body)
-  (forward-line -2))
+  (forward-line -1))
 
 (defun message-goto-signature ()
   "Move point to the beginning of the message signature.
@@ -1812,6 +1857,39 @@ However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
          (forward-line 1))))
     (goto-char start)))
 
+(defun message-list-references (refs-list &rest refs-strs)
+  "Add `Message-ID's which appear in REFS-STRS but not in REFS-LIST,
+to REFS-LIST."
+  (let (refs ref id saved-id)
+    (when (and refs-list
+              (integerp message-list-references-add-position))
+      (let ((pos message-list-references-add-position))
+       (while (and refs-list
+                   (> pos 0))
+         (setq saved-id (cons (car refs-list) saved-id)
+               refs-list (cdr refs-list)
+               pos (1- pos)))))
+    (while refs-strs
+      (setq refs (car refs-strs)
+           refs-strs (cdr refs-strs))
+      (when refs
+       (setq refs (std11-parse-msg-ids (std11-lexical-analyze refs)))
+       (while refs
+         (setq ref (car refs)
+               refs (cdr refs))
+         (when (eq (car ref) 'msg-id)
+           (setq id (concat "<"
+                            (mapconcat
+                             (function (lambda (p) (cdr p)))
+                             (cdr ref) "")
+                            ">"))
+           (or (member id refs-list)
+               (push id refs-list))))))
+    (while saved-id
+      (setq refs-list (cons (car saved-id) refs-list)
+           saved-id (cdr saved-id)))
+    refs-list))
+
 (defvar gnus-article-copy)
 (defun message-yank-original (&optional arg)
   "Insert the message being replied to, if any.
@@ -1822,14 +1900,55 @@ if `message-yank-prefix' is non-nil, insert that prefix on each line.
 This function uses `message-cite-function' to do the actual citing.
 
 Just \\[universal-argument] as argument means don't indent, insert no
-prefix, and don't delete any headers."
+prefix, and don't delete any headers.
+
+In addition, if `message-yank-add-new-references' is non-nil and this
+command is called interactively, new IDs from the yanked article will
+be added to \"References\" field.
+\(See also `message-yank-add-new-references'.)"
   (interactive "P")
   (let ((modified (buffer-modified-p))
-       (buffer (message-get-reply-buffer)))
+       (buffer (message-eval-parameter message-reply-buffer))
+       start end refs)
     (when (and buffer
               message-cite-function)
       (delete-windows-on buffer t)
-      (insert-buffer buffer)
+      (insert-buffer buffer) ; mark will be set at the end of article.
+      (setq start (point)
+           end (mark t))
+
+      ;; Add new IDs to References field.
+      (when (and message-yank-add-new-references (interactive-p))
+       (save-excursion
+         (save-restriction
+           (message-narrow-to-headers)
+           (setq refs (message-list-references
+                       nil
+                       (message-fetch-field "References")))
+           (widen)
+           (narrow-to-region start end)
+           (std11-narrow-to-header)
+           (when (setq refs (message-list-references
+                             refs
+                             (unless (eq message-yank-add-new-references
+                                         'message-id-only)
+                               (or (message-fetch-field "References")
+                                   (message-fetch-field "In-Reply-To")))
+                             (message-fetch-field "Message-ID")))
+             (widen)
+             (message-narrow-to-headers)
+             (goto-char (point-min))
+             (let ((case-fold-search t))
+               (if (re-search-forward "^References:\\([\t ]+.+\n\\)+" nil t)
+                   (replace-match "")
+                 (goto-char (point-max))))
+             (mail-header-format
+              (list (or (assq 'References message-header-format-alist)
+                        '(References . message-fill-references)))
+              (list (cons 'References
+                          (mapconcat 'identity (nreverse refs) " "))))
+             (backward-delete-char 1)))))
+
       (funcall message-cite-function)
       (message-exchange-point-and-mark)
       (unless (bolp)
@@ -1971,9 +2090,12 @@ The text will also be indented the normal way."
   (interactive)
   (set-buffer-modified-p t)
   (save-buffer)
-  (let ((actions message-postpone-actions))
+  (let ((actions message-postpone-actions)
+       (frame (selected-frame))
+       (org-frame message-original-frame))
     (message-bury (current-buffer))
-    (message-do-actions actions)))
+    (message-do-actions actions)
+    (message-delete-frame frame org-frame)))
 
 (defun message-kill-buffer ()
   "Kill the current buffer."
@@ -1991,6 +2113,21 @@ The text will also be indented the normal way."
       (message-delete-frame frame org-frame)))
   (message ""))
 
+(defun message-mimic-kill-buffer ()
+  "Kill the current buffer with query."
+  (interactive)
+  (unless (eq 'message-mode major-mode)
+    (error "%s must be invoked from a message buffer." this-command))
+  (let ((command this-command)
+       (bufname (read-buffer (format "Kill buffer: (default %s) "
+                                     (buffer-name)))))
+    (if (or (not bufname)
+           (string-equal bufname "")
+           (string-equal bufname (buffer-name)))
+       (let ((message-delete-frame-on-exit nil))
+         (message-kill-buffer))
+      (message "%s must be invoked only for the current buffer." command))))
+
 (defun message-delete-frame (frame org-frame)
   "Delete frame for editing message."
   (when (and (or (and (featurep 'xemacs)
@@ -2027,55 +2164,62 @@ or error messages, and inform user.
 Otherwise any failure is reported in a message back to
 the user from the mailer."
   (interactive "P")
-  ;; Disabled test.
-  (when (or (buffer-modified-p)
-           (message-check-element 'unchanged)
-           (y-or-n-p "No changes in the buffer; really send? "))
-    ;; Make it possible to undo the coming changes.
-    (undo-boundary)
-    (let ((inhibit-read-only t))
-      (put-text-property (point-min) (point-max) 'read-only nil))
-    (run-hooks 'message-send-hook)
-    (message "Sending...")
-    (let ((message-encoding-buffer
-          (message-generate-new-buffer-clone-locals " message encoding"))
-         (message-edit-buffer (current-buffer))
-         (message-mime-mode mime-edit-mode-flag)
-         (alist message-send-method-alist)
-         (success t)
-         elem sent)
-      (save-excursion
-       (set-buffer message-encoding-buffer)
-       (erase-buffer)
-       (insert-buffer message-edit-buffer)
-       (funcall message-encode-function)
-       (message-fix-before-sending)
-       (while (and success
-                   (setq elem (pop alist)))
-         (when (and (or (not (funcall (cadr elem)))
-                        (and (or (not (memq (car elem)
-                                            message-sent-message-via))
-                                 (y-or-n-p
-                                  (format
-                                   "Already sent message via %s; resend? "
-                                   (car elem))))
-                             (setq success (funcall (caddr elem) arg)))))
-           (setq sent t))))
-      (when (and success sent)
-       (message-do-fcc)
-       ;;(when (fboundp 'mail-hist-put-headers-into-history)
-       ;; (mail-hist-put-headers-into-history))
-       (run-hooks 'message-sent-hook)
-       (message "Sending...done")
-       ;; Mark the buffer as unmodified and delete autosave.
-       (set-buffer-modified-p nil)
-       (delete-auto-save-file-if-necessary t)
-       (message-disassociate-draft)
-       ;; Delete other mail buffers and stuff.
-       (message-do-send-housekeeping)
-       (message-do-actions message-send-actions)
-       ;; Return success.
-       t))))
+  (if (catch 'message-sending-cancel
+       ;; Disabled test.
+       (unless (or (buffer-modified-p)
+                   (message-check-element 'unchanged)
+                   (y-or-n-p "No changes in the buffer; really send? "))
+         (throw 'message-sending-cancel t))
+       ;; Make it possible to undo the coming changes.
+       (undo-boundary)
+       (let ((inhibit-read-only t))
+         (put-text-property (point-min) (point-max) 'read-only nil))
+       (run-hooks 'message-send-hook)
+       (message "Sending...")
+       (let ((message-encoding-buffer
+              (message-generate-new-buffer-clone-locals " message encoding"))
+             (message-edit-buffer (current-buffer))
+             (message-mime-mode mime-edit-mode-flag)
+             (alist message-send-method-alist)
+             (success t)
+             elem sent)
+         (unwind-protect
+             (if (save-excursion
+                   (set-buffer message-encoding-buffer)
+                   (erase-buffer)
+                   (insert-buffer message-edit-buffer)
+                   (funcall message-encode-function)
+                   (message-fix-before-sending)
+                   (while (and success
+                               (setq elem (pop alist)))
+                     (and (funcall (cadr elem))
+                          (and (or (not (memq (car elem)
+                                              message-sent-message-via))
+                                   (y-or-n-p
+                                    (format
+                                     "Already sent message via %s; resend? "
+                                     (car elem))))
+                               (setq success (funcall (caddr elem) arg)))
+                          (setq sent t)))
+                   (not (and success sent)))
+                 (throw 'message-sending-cancel t)
+               (message-do-fcc)
+               (run-hooks 'message-sent-hook)
+               (message "Sending...done")
+               ;; Mark the buffer as unmodified and delete auto-save.
+               (set-buffer-modified-p nil)
+               (delete-auto-save-file-if-necessary t)
+               (message-disassociate-draft)
+               ;; Delete other mail buffers and stuff.
+               (message-do-send-housekeeping)
+               (message-do-actions message-send-actions)
+               nil)
+           (kill-buffer message-encoding-buffer))))
+      (progn
+       (message "Canceled")
+       nil)
+    ;; Return success.
+    t))
 
 (defun message-send-via-mail (arg)
   "Send the current message via mail."
@@ -2119,11 +2263,56 @@ the user from the mailer."
        (eval (car actions)))))
     (pop actions)))
 
+(defsubst message-maybe-split-and-send-mail ()
+  "Split a message if necessary, and send it via mail.
+Returns nil if sending succeeded, returns any string if sending failed.
+This sub function is for exclusive use of `message-send-mail'."
+  (let ((mime-edit-split-ignored-field-regexp
+        mime-edit-split-ignored-field-regexp)
+       (case-fold-search t)
+       failure)
+    (while (string-match "Message-ID" mime-edit-split-ignored-field-regexp)
+      (setq mime-edit-split-ignored-field-regexp
+           (concat (substring mime-edit-split-ignored-field-regexp
+                              0 (match-beginning 0))
+                   "Hey_MIME-Edit,_there_is_an_inviolable_Message_ID"
+                   "_so_don't_rape_it!"
+                   (substring mime-edit-split-ignored-field-regexp
+                              (match-end 0)))))
+    (setq failure
+         (or
+          (catch 'message-sending-mail-failure
+            (mime-edit-maybe-split-and-send
+             (function
+              (lambda ()
+                (interactive)
+                (save-restriction
+                  (std11-narrow-to-header mail-header-separator)
+                  (goto-char (point-min))
+                  (when (re-search-forward "^Message-ID:" nil t)
+                    (delete-region (match-end 0) (std11-field-end))
+                    (insert " " (message-make-message-id))))
+                (condition-case err
+                    (funcall message-send-mail-function)
+                  (error
+                   (throw 'message-sending-mail-failure err))))))
+            nil)
+          (condition-case err
+              (progn
+                (funcall message-send-mail-function)
+                nil)
+            (error err))))
+    (when failure
+      (if (eq 'error (car failure))
+         (cadr failure)
+       (prin1-to-string failure)))))
+
 (defun message-send-mail (&optional arg)
   (require 'mail-utils)
   (let ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
        (case-fold-search nil)
-       (news (message-news-p)))
+       (news (message-news-p))
+       failure)
     (save-restriction
       (message-narrow-to-headers)
       ;; Insert some headers.
@@ -2138,7 +2327,6 @@ the user from the mailer."
     (if (not (message-check-mail-syntax))
        (progn
          (message "")
-         ;;(message "Posting not performed")
          nil)
       (unwind-protect
          (save-excursion
@@ -2148,25 +2336,24 @@ the user from the mailer."
            ;; Remove some headers.
            (save-restriction
              (message-narrow-to-headers)
+             ;; Remove some headers.
              (message-remove-header message-ignored-mail-headers t))
            (goto-char (point-max))
            ;; require one newline at the end.
-           (or (= (preceding-char) ?\n)
+           (or (eq (char-before) ?\n)
                (insert ?\n))
            (when (and news
                       (or (message-fetch-field "cc")
                           (message-fetch-field "to")))
              (message-insert-courtesy-copy))
-           (mime-edit-maybe-split-and-send
-            (function
-             (lambda ()
-               (interactive)
-               (funcall message-send-mail-function)
-               )))
-           (funcall message-send-mail-function))
+           (setq failure (message-maybe-split-and-send-mail)))
        (kill-buffer tembuf))
       (set-buffer message-edit-buffer)
-      (push 'mail message-sent-message-via))))
+      (if failure
+         (progn
+           (message "Couldn't send message via mail: %s" failure)
+           nil)
+       (push 'mail message-sent-message-via)))))
 
 (defun message-send-mail-with-sendmail ()
   "Send off the prepared buffer with sendmail."
@@ -2195,31 +2382,31 @@ the user from the mailer."
        (save-excursion
          (set-buffer errbuf)
          (erase-buffer))))
-    (let ((default-directory "/")
-         (coding-system-for-write message-send-coding-system))
-      (apply 'call-process-region
-            (append (list (point-min) (point-max)
-                          (if (boundp 'sendmail-program)
-                              sendmail-program
-                            "/usr/lib/sendmail")
-                          nil errbuf nil "-oi")
-                    ;; Always specify who from,
-                    ;; since some systems have broken sendmails.
-                    ;; But some systems are more broken with -f, so
-                    ;; we'll let users override this.
-                    (if (null message-sendmail-f-is-evil)
-                        (list "-f" (user-login-name)))
-                    ;; These mean "report errors by mail"
-                    ;; and "deliver in background".
-                    (if (null message-interactive) '("-oem" "-odb"))
-                    ;; Get the addresses from the message
-                    ;; unless this is a resend.
-                    ;; We must not do that for a resend
-                    ;; because we would find the original addresses.
-                    ;; For a resend, include the specific addresses.
-                    (if resend-to-addresses
-                        (list resend-to-addresses)
-                      '("-t")))))
+    (let ((default-directory "/"))
+      (as-binary-process
+       (apply 'call-process-region
+             (append (list (point-min) (point-max)
+                           (if (boundp 'sendmail-program)
+                               sendmail-program
+                             "/usr/lib/sendmail")
+                           nil errbuf nil "-oi")
+                     ;; Always specify who from,
+                     ;; since some systems have broken sendmails.
+                     ;; But some systems are more broken with -f, so
+                     ;; we'll let users override this.
+                     (if (null message-sendmail-f-is-evil)
+                         (list "-f" (user-login-name)))
+                     ;; These mean "report errors by mail"
+                     ;; and "deliver in background".
+                     (if (null message-interactive) '("-oem" "-odb"))
+                     ;; Get the addresses from the message
+                     ;; unless this is a resend.
+                     ;; We must not do that for a resend
+                     ;; because we would find the original addresses.
+                     ;; For a resend, include the specific addresses.
+                     (if resend-to-addresses
+                         (list resend-to-addresses)
+                       '("-t"))))))
     (when message-interactive
       (save-excursion
        (set-buffer errbuf)
@@ -2244,28 +2431,28 @@ to find out how to use this."
   (run-hooks 'message-send-mail-hook)
   ;; send the message
   (case
-      (let ((coding-system-for-write message-send-coding-system))
-       (apply
-        'call-process-region 1 (point-max) message-qmail-inject-program
-        nil nil nil
-        ;; qmail-inject's default behaviour is to look for addresses on the
-        ;; command line; if there're none, it scans the headers.
-        ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
-        ;;
-        ;; in general, ALL of qmail-inject's defaults are perfect for simply
-        ;; reading a formatted (i. e., at least a To: or Resent-To header)
-        ;; message from stdin.
-        ;;
-        ;; qmail also has the advantage of not having been raped by
-        ;; various vendors, so we don't have to allow for that, either --
-        ;; compare this with message-send-mail-with-sendmail and weep
-        ;; for sendmail's lost innocence.
-        ;;
-        ;; all this is way cool coz it lets us keep the arguments entirely
-        ;; free for -inject-arguments -- a big win for the user and for us
-        ;; since we don't have to play that double-guessing game and the user
-        ;; gets full control (no gestapo'ish -f's, for instance).  --sj
-        message-qmail-inject-args))
+      (as-binary-process
+       (apply
+       'call-process-region 1 (point-max) message-qmail-inject-program
+       nil nil nil
+       ;; qmail-inject's default behaviour is to look for addresses on the
+       ;; command line; if there're none, it scans the headers.
+       ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
+       ;;
+       ;; in general, ALL of qmail-inject's defaults are perfect for simply
+       ;; reading a formatted (i. e., at least a To: or Resent-To header)
+       ;; message from stdin.
+       ;;
+       ;; qmail also has the advantage of not having been raped by
+       ;; various vendors, so we don't have to allow for that, either --
+       ;; compare this with message-send-mail-with-sendmail and weep
+       ;; for sendmail's lost innocence.
+       ;;
+       ;; all this is way cool coz it lets us keep the arguments entirely
+       ;; free for -inject-arguments -- a big win for the user and for us
+       ;; since we don't have to play that double-guessing game and the user
+       ;; gets full control (no gestapo'ish -f's, for instance).  --sj
+       message-qmail-inject-args))
     ;; qmail-inject doesn't say anything on it's stdout/stderr,
     ;; we have to look at the retval instead
     (0 nil)
@@ -2293,143 +2480,64 @@ to find out how to use this."
     (mh-send-letter)))
 
 (defun message-send-mail-with-smtp ()
-  "Send the prepared message buffer with SMTP."
-  (require 'smtp)
-  (let ((errbuf (if mail-interactive
-                   (generate-new-buffer " smtp errors")
-                 0))
-       (case-fold-search nil)
-       resend-to-addresses
-       delimline)
-    (unwind-protect
-       (save-excursion
-         (goto-char (point-max))
-         ;; require one newline at the end.
-         (or (= (preceding-char) ?\n)
-             (insert ?\n))
-         ;; Change header-delimiter to be what sendmail expects.
-         (goto-char (point-min))
-         (re-search-forward
-          (concat "^" (regexp-quote mail-header-separator) "\n"))
-         (replace-match "\n")
-         (backward-char 1)
-         (setq delimline (point-marker))
-         (run-hooks 'message-send-mail-hook)
-         ;; (sendmail-synch-aliases)
-          ;; (if mail-aliases
-          ;;     (expand-mail-aliases (point-min) delimline))
-         (goto-char (point-min))
-         ;; ignore any blank lines in the header
-         (while (and (re-search-forward "\n\n\n*" delimline t)
-                     (< (point) delimline))
-           (replace-match "\n"))
-         (let ((case-fold-search t))
-           (goto-char (point-min))
-           (goto-char (point-min))
-           (while (re-search-forward "^Resent-to:" delimline t)
-             (setq resend-to-addresses
-                   (save-restriction
-                     (narrow-to-region (point)
-                                       (save-excursion
-                                         (end-of-line)
-                                         (point)))
-                     (append (mail-parse-comma-list)
-                             resend-to-addresses))))
-;;; Apparently this causes a duplicate Sender.
-;;;        ;; If the From is different than current user, insert Sender.
-;;;        (goto-char (point-min))
-;;;        (and (re-search-forward "^From:"  delimline t)
-;;;             (progn
-;;;               (require 'mail-utils)
-;;;               (not (string-equal
-;;;                     (mail-strip-quoted-names
-;;;                      (save-restriction
-;;;                        (narrow-to-region (point-min) delimline)
-;;;                        (mail-fetch-field "From")))
-;;;                     (user-login-name))))
-;;;             (progn
-;;;               (forward-line 1)
-;;;               (insert "Sender: " (user-login-name) "\n")))
-           ;; Don't send out a blank subject line
-           (goto-char (point-min))
-           (if (re-search-forward "^Subject:[ \t]*\n" delimline t)
-               (replace-match ""))
-           ;; Put the "From:" field in unless for some odd reason
-           ;; they put one in themselves.
-           (goto-char (point-min))
-           (if (not (re-search-forward "^From:" delimline t))
-               (let* ((login user-mail-address)
-                      (fullname (user-full-name)))
-                 (cond ((eq mail-from-style 'angles)
-                        (insert "From: " fullname)
-                        (let ((fullname-start (+ (point-min) 6))
-                              (fullname-end (point-marker)))
-                          (goto-char fullname-start)
-                          ;; Look for a character that cannot appear unquoted
-                          ;; according to RFC 822.
-                          (if (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]"
-                                                 fullname-end 1)
-                              (progn
-                                ;; Quote fullname, escaping specials.
-                                (goto-char fullname-start)
-                                (insert "\"")
-                                (while (re-search-forward "[\"\\]"
-                                                          fullname-end 1)
-                                  (replace-match "\\\\\\&" t))
-                                (insert "\""))))
-                        (insert " <" login ">\n"))
-                       ((eq mail-from-style 'parens)
-                        (insert "From: " login " (")
-                        (let ((fullname-start (point)))
-                          (insert fullname)
-                          (let ((fullname-end (point-marker)))
-                            (goto-char fullname-start)
-                            ;; RFC 822 says \ and nonmatching parentheses
-                            ;; must be escaped in comments.
-                            ;; Escape every instance of ()\ ...
-                            (while (re-search-forward "[()\\]" fullname-end 1)
-                              (replace-match "\\\\\\&" t))
-                            ;; ... then undo escaping of matching parentheses,
-                            ;; including matching nested parentheses.
-                            (goto-char fullname-start)
-                            (while (re-search-forward 
-                                    "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
-                                    fullname-end 1)
-                              (replace-match "\\1(\\3)" t)
-                              (goto-char fullname-start))))
-                        (insert ")\n"))
-                       ((null mail-from-style)
-                        (insert "From: " login "\n")))))
-           ;; Insert an extra newline if we need it to work around
-           ;; Sun's bug that swallows newlines.
-           (goto-char (1+ delimline))
-           (if (eval mail-mailer-swallows-blank-line)
-               (newline))
-           ;; Find and handle any FCC fields.
-           (goto-char (point-min))
-           (if (re-search-forward "^FCC:" delimline t)
-               (mail-do-fcc delimline))
-           (if mail-interactive
-               (save-excursion
-                 (set-buffer errbuf)
-                 (erase-buffer))))
-         ;;
-         ;;
-         ;;
-         (let ((recipient-address-list
-                (or resend-to-addresses
-                    (smtp-deduce-address-list (current-buffer)
-                                              (point-min) delimline))))
-           (smtp-do-bcc delimline)
-           
-           (if recipient-address-list
-               (if (not (smtp-via-smtp recipient-address-list
-                                       (current-buffer)))
-                   (error "Sending failed; SMTP protocol error"))
-             (error "Sending failed; no recipients"))
-           ))
-      (if (bufferp errbuf)
-         (kill-buffer errbuf)))))
+  "Send off the prepared buffer with SMTP."
+  (require 'smtp) ; XXX
+  (let ((case-fold-search t)
+       recipients)
+    (save-restriction
+      (message-narrow-to-headers)
+      (setq recipients
+           ;; XXX: Should be replaced by better one.
+           (smtp-deduce-address-list (current-buffer)
+                                     (point-min) (point-max)))
+      ;; Remove BCC lines.
+      (message-remove-header "bcc"))
+    ;; replace the header delimiter with a blank line.
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "\n"))
+    (replace-match "\n")
+    (backward-char 1)
+    (run-hooks 'message-send-mail-hook)
+    (if recipients
+       (let ((result (smtp-via-smtp user-mail-address
+                                    recipients
+                                    (current-buffer))))
+         (unless (eq result t)
+           (error "Sending failed; " result)))
+      (error "Sending failed; no recipients"))))
+
+(defsubst message-maybe-split-and-send-news (method)
+  "Split a message if necessary, and send it via news.
+Returns nil if sending succeeded, returns t if sending failed.
+This sub function is for exclusive use of `message-send-news'."
+  (let ((mime-edit-split-ignored-field-regexp
+        mime-edit-split-ignored-field-regexp)
+       (case-fold-search t))
+    (while (string-match "Message-ID" mime-edit-split-ignored-field-regexp)
+      (setq mime-edit-split-ignored-field-regexp
+           (concat (substring mime-edit-split-ignored-field-regexp
+                              0 (match-beginning 0))
+                   "Hey_MIME-Edit,_there_is_an_inviolable_Message_ID"
+                   "_so_don't_rape_it!"
+                   (substring mime-edit-split-ignored-field-regexp
+                              (match-end 0)))))
+    (or
+     (catch 'message-sending-news-failure
+       (mime-edit-maybe-split-and-send
+       (function
+        (lambda ()
+          (interactive)
+          (save-restriction
+            (std11-narrow-to-header mail-header-separator)
+            (goto-char (point-min))
+            (when (re-search-forward "^Message-ID:" nil t)
+              (delete-region (match-end 0) (std11-field-end))
+              (insert " " (message-make-message-id))))
+          (unless (funcall message-send-news-function method)
+            (throw 'message-sending-news-failure t)))))
+       nil)
+     (not (funcall message-send-news-function method)))))
 
 (defun message-send-news (&optional arg)
   (let ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
@@ -2454,10 +2562,7 @@ to find out how to use this."
       (run-hooks 'message-header-encoded-hook))
     (message-cleanup-headers)
     (if (not (message-check-news-syntax))
-       (progn
-         (message "")
-         ;;(message "Posting not performed")
-         nil)
+       nil
       (unwind-protect
          (save-excursion
            (set-buffer tembuf)
@@ -2471,29 +2576,17 @@ to find out how to use this."
              (message-remove-header message-ignored-news-headers t))
            (goto-char (point-max))
            ;; require one newline at the end.
-           (or (= (preceding-char) ?\n)
+           (or (eq (char-before) ?\n)
                (insert ?\n))
-           (mime-edit-maybe-split-and-send
-            (function
-             (lambda ()
-               (interactive)
-               (save-restriction
-                 (std11-narrow-to-header mail-header-separator)
-                 (goto-char (point-min))
-                 (when (re-search-forward "^Message-Id:" nil t)
-                   (delete-region (match-end 0)(std11-field-end))
-                   (insert (concat " " (message-make-message-id)))
-                   ))
-               (funcall message-send-news-function method)
-               )))
-           (setq result (funcall message-send-news-function method)))
+           (setq result (message-maybe-split-and-send-news method)))
        (kill-buffer tembuf))
       (set-buffer message-edit-buffer)
       (if result
-         (push 'news message-sent-message-via)
-       (message "Couldn't send message via news: %s"
-                (nnheader-get-report (car method)))
-       nil))))
+         (progn
+           (message "Couldn't send message via news: %s"
+                    (nnheader-get-report (car method)))
+           nil)
+       (push 'news message-sent-message-via)))))
 
 ;; 1997-09-29 by MORIOKA Tomohiko
 (defun message-send-news-with-gnus (method)
@@ -2766,9 +2859,9 @@ to find out how to use this."
         (y-or-n-p
          "The article contains control characters.  Really post? ")
        t))
-   ;; Check content transfer encoding.
-   (message-check 'encoding
-     (message-check-encoding))
+   ;; Check 8bit characters.
+   (message-check '8bit
+     (message-check-8bit))
    ;; Check excessive size.
    (message-check 'size
      (if (> (buffer-size) 60000)
@@ -2817,31 +2910,29 @@ to find out how to use this."
 
 (defun message-check-mail-body-syntax ()
   (and
-   ;; Check content transfer encoding.
-   (message-check 'encoding
-     (message-check-encoding)
+   ;; Check 8bit characters.
+   (message-check '8bit
+     (message-check-8bit)
      )))
 
-(defun message-check-encoding ()
-  "Check content encoding type."
+(defun message-check-8bit ()
+  "Check the article contains 8bit characters."
   (save-excursion
     (set-buffer message-encoding-buffer)
     (message-narrow-to-headers)
     (let* ((case-fold-search t)
-          (encoding-string
-           (message-fetch-field "content-transfer-encoding"))
-          (encoding (or encoding-string
-                        message-default-encoding)))
-      (message "%s %s" encoding-string encoding)
-      (if (string-match "^8bit" encoding)
+          (field-value (message-fetch-field "content-transfer-encoding")))
+      (if (and field-value
+              (member (downcase field-value) message-8bit-encoding-list))
          t
        (widen)
        (set-buffer (get-buffer-create " message syntax"))
        (erase-buffer)
+       (goto-char (point-min))
        (set-buffer-multibyte nil)
        (insert-buffer message-encoding-buffer)
        (goto-char (point-min))
-       (if (re-search-forward "[\200-\377]" nil t)
+       (if (re-search-forward "[^\x00-\x7f]" nil t)
            (y-or-n-p
             "The article contains 8bit characters.  Really post? ")
          t)))))
@@ -2855,15 +2946,15 @@ to find out how to use this."
        (concat "^" (regexp-quote mail-header-separator) "$"))
       (while (not (eobp))
        (when (not (looking-at "[ \t\n]"))
-         (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
-                           (following-char))))
+         (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
+                           (char-after))))
        (forward-char 1)))
     sum))
 
 (defun message-do-fcc ()
   "Process Fcc headers in the current buffer."
   (let ((case-fold-search t)
-       (coding-system-for-write 'raw-text)
+       (coding-system-for-write nnheader-message-coding-system-for-write)
        list file)
     (save-excursion
       (set-buffer (get-buffer-create " *message temp*"))
@@ -2874,12 +2965,7 @@ to find out how to use this."
        (message-narrow-to-headers)
        (while (setq file (message-fetch-field "fcc"))
          (push file list)
-         (message-remove-header "fcc" nil t))
-       (run-hooks 'message-header-hook)
-       (when (functionp message-header-encode-function)
-         (funcall message-header-encode-function))
-       (run-hooks 'message-header-encoded-hook))
-      (run-hooks 'message-before-do-fcc-hook)
+         (message-remove-header "fcc" nil t)))
       (goto-char (point-min))
       (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
       (replace-match "" t t)
@@ -3274,7 +3360,9 @@ Headers already prepared in the buffer are not modified."
                  (progn
                    ;; The header was found.  We insert a space after the
                    ;; colon, if there is none.
-                   (if (/= (following-char) ? ) (insert " ") (forward-char 1))
+                   (if (eq (char-after) ? )
+                       (forward-char 1)
+                     (insert " "))
                    ;; Find out whether the header is empty...
                    (looking-at "[ \t]*$")))
          ;; So we find out what value we should insert.
@@ -3383,7 +3471,7 @@ Headers already prepared in the buffer are not modified."
       (goto-char (point-min))
       (while (not (eobp))
        (skip-chars-forward "^,\"" (point-max))
-       (if (or (= (following-char) ?,)
+       (if (or (eq (char-after) ?,)
                (eobp))
            (when (not quoted)
              (if (and (> (current-column) 78)
@@ -3455,7 +3543,7 @@ Headers already prepared in the buffer are not modified."
     (search-backward ":" )
     (widen)
     (forward-char 1)
-    (if (= (following-char) ? )
+    (if (eq (char-after) ? )
        (forward-char 1)
       (insert " ")))
    (t
@@ -3557,7 +3645,7 @@ Headers already prepared in the buffer are not modified."
   (when actions
     (setq message-send-actions actions))
   (setq message-reply-buffer
-       (or (cdr (assq 'reply-buffer message-parameter-alist))
+       (or (message-get-parameter 'reply-buffer)
            replybuffer))
   (goto-char (point-min))
   ;; Insert all the headers.
@@ -3606,18 +3694,20 @@ Headers already prepared in the buffer are not modified."
     (run-hooks 'message-header-setup-hook))
   (set-buffer-modified-p nil)
   (setq buffer-undo-list nil)
+  (add-to-list 'buffer-file-format 'message)
+  (set-buffer-file-coding-system nnheader-message-coding-system-for-write)
   (run-hooks 'message-setup-hook)
   (message-position-point)
   (undo-boundary))
 
 (defun message-set-auto-save-file-name ()
   "Associate the message buffer with a file in the drafts directory."
-  (when message-autosave-directory
+  (when message-auto-save-directory
     (if (gnus-alive-p)
        (setq message-draft-article
              (nndraft-request-associate-buffer "drafts"))
       (setq buffer-file-name (expand-file-name "*message*"
-                                              message-autosave-directory))
+                                              message-auto-save-directory))
       (setq buffer-auto-save-file-name (make-auto-save-file-name)))
     (clear-visited-file-modtime)))
 
@@ -3664,7 +3754,7 @@ OTHER-HEADERS is an alist of header/value pairs."
        from subject date reply-to to cc
        references message-id follow-to
        (inhibit-point-motion-hooks t)
-       mct never-mct gnus-warning)
+       mct never-mct gnus-warning in-reply-to)
     (save-restriction
       (message-narrow-to-head)
       ;; Allow customizations to have their say.
@@ -3687,6 +3777,12 @@ OTHER-HEADERS is an alist of header/value pairs."
            reply-to (message-fetch-field "reply-to")
            references (message-fetch-field "references")
            message-id (message-fetch-field "message-id" t))
+      ;; Get the references from "In-Reply-To" field if there were
+      ;; no references and "In-Reply-To" field looks promising.
+      (unless references
+       (when (and (setq in-reply-to (message-fetch-field "in-reply-to"))
+                  (string-match "<[^>]+>" in-reply-to))
+         (setq references (match-string 0 in-reply-to))))
       ;; Remove any (buggy) Re:'s that are present and make a
       ;; proper one.
       (when (string-match message-subject-re-regexp subject)
@@ -3737,7 +3833,10 @@ OTHER-HEADERS is an alist of header/value pairs."
                     (message-tokenize-header (buffer-string))))
              (let ((s ccalist))
                (while s
-                 (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
+                 (setq ccalist (delq (assoc (car (pop s)) s) ccalist))))
+             (when (functionp message-mail-follow-up-address-checker)
+               (setq ccalist (funcall message-mail-follow-up-address-checker
+                                      ccalist))))
            (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
            (when ccalist
              (let ((ccs (cons 'Cc (mapconcat
@@ -3931,6 +4030,10 @@ responses here are directed to other newsgroups."))
            (message "Canceling your article...done"))
        (kill-buffer buf)))))
 
+(defun message-supersede-setup-for-mime-edit ()
+  (set (make-local-variable 'message-setup-hook) nil)
+  (mime-edit-again))
+
 ;;;###autoload
 (defun message-supersede ()
   "Start composing a message to supersede the current message.
@@ -3964,7 +4067,11 @@ header line with the old Message-ID."
     (goto-char (point-max))
     (insert mail-header-separator)
     (widen)
-    (forward-line 1)))
+    (when message-supersede-setup-function
+      (funcall message-supersede-setup-function))
+    (run-hooks 'message-supersede-setup-hook)
+    (goto-char (point-min))
+    (search-forward (concat "\n" mail-header-separator "\n") nil t)))
 
 ;;;###autoload
 (defun message-recover ()
@@ -4042,14 +4149,14 @@ the message."
       (current-buffer)
       (message-narrow-to-head)
       (let ((funcs message-make-forward-subject-function)
-           (subject (if message-wash-forwarded-subjects
-                        (message-wash-subject
-                         (or (nnheader-decode-subject
-                              (message-fetch-field "Subject"))
-                             ""))
-                      (or (nnheader-decode-subject
-                           (message-fetch-field "Subject"))
-                          ""))))
+           (subject (message-fetch-field "Subject")))
+       (setq subject
+             (if subject
+                 (if message-wash-forwarded-subjects
+                     (message-wash-subject
+                      (nnheader-decode-subject subject))
+                   (nnheader-decode-subject subject))
+               "(none)"))
        ;; Make sure funcs is a list.
        (and funcs
             (not (listp funcs))
@@ -4150,6 +4257,10 @@ Optional NEWS will use news to forward instead of mail."
       (kill-buffer (current-buffer)))
     (message "Resending message to %s...done" address)))
 
+(defun message-bounce-setup-for-mime-edit ()
+  (set (make-local-variable 'message-setup-hook) nil)
+  (mime-edit-again))
+
 ;;;###autoload
 (defun message-bounce ()
   "Re-mail the current message.
@@ -4189,6 +4300,9 @@ you."
       (message-remove-header message-ignored-bounced-headers t)
       (goto-char (point-max))
       (insert mail-header-separator))
+    (when message-bounce-setup-function
+      (funcall message-bounce-setup-function))
+    (run-hooks 'message-bounce-setup-hook)
     (message-position-point)))
 
 ;;;
@@ -4266,7 +4380,7 @@ which specify the range to operate on."
       (goto-char (min start end))
       (while (< (point) end1)
        (or (looking-at "[_\^@- ]")
-           (insert (following-char) "\b"))
+           (insert (char-after) "\b"))
        (forward-char 1)))))
 
 ;;;###autoload
@@ -4280,7 +4394,7 @@ which specify the range to operate on."
       (move-marker end1 (max start end))
       (goto-char (min start end))
       (while (re-search-forward "\b" end1 t)
-       (if (eq (following-char) (char-after (- (point) 2)))
+       (if (eq (char-after) (char-after (- (point) 2)))
            (delete-char -2))))))
 
 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
@@ -4401,26 +4515,119 @@ regexp varstr."
                (cdr local)))))
      locals)))
 
-;;; @ for MIME Edit mode
+;; @ For `message-mail-follow-up-address-checker'.
+
+(defcustom message-mailing-list-address-list nil
+  "*Regexp matching addresses that are mailing lists.
+It must be a simple regexp string or a list of regexp strings.
+This variable is used by \`message-check-mailing-list-with-address-list\'."
+  :group 'message-mail
+  :type '(repeat regexp))
+
+(defun message-check-mailing-list-with-address-list (alist)
+  (let ((s alist)
+       (regexp (if (stringp message-mailing-list-address-list)
+                   message-mailing-list-address-list
+                 (mapconcat
+                  (lambda (x)
+                    x)
+                  message-mailing-list-address-list
+                  "\\|")))
+       address non-mailing-list mailing-list)
+    (while (setq address (car (pop s)))
+      (if (string-match regexp address)
+         (setq mailing-list t)
+       (setq non-mailing-list
+             (append non-mailing-list (list address)))))
+    (if (or (not non-mailing-list)
+           (not mailing-list)
+           (not (y-or-n-p "Do you want to remove private address? ")))
+       alist
+      (setq s non-mailing-list)
+      (while s
+       (setq alist (delq (assoc (pop s) alist) alist)))
+      alist)
+    ))
+
+(defcustom message-mailing-list-address-p nil
+  "*The function return t if address is a mailing list.
+It must be function, and interface is (ADDRESS).
+ADDRESS is a string of mail address.
+This variable is used by \`message-check-mailing-list-with-function\'."
+  :group 'message-mail
+  :type 'function)
+
+(defun message-check-mailing-list-with-function (alist)
+  (let ((s alist)
+       address non-mailing-list mailing-list)
+    (while (setq address (car (pop s)))
+      (if (funcall message-mailing-list-address-p address)
+         (setq mailing-list t)
+       (setq non-mailing-list
+             (append non-mailing-list (list address)))))
+    (if (or (not non-mailing-list)
+           (not mailing-list)
+           (not (y-or-n-p "Do you want to remove private address? ")))
+       alist
+      (setq s non-mailing-list)
+      (while s
+       (setq alist (delq (assoc (pop s) alist) alist)))
+      alist)
+    ))
+
+;;; @ Encode buffer.
 ;;;
 
 (defun message-maybe-encode ()
   (when message-mime-mode
+    ;; Inherit the buffer local variable `mime-edit-pgp-processing'.
+    (let ((pgp-processing (with-current-buffer message-edit-buffer
+                           mime-edit-pgp-processing)))
+      (setq mime-edit-pgp-processing pgp-processing))
     (run-hooks 'mime-edit-translate-hook)
     (if (catch 'mime-edit-error
          (save-excursion
+           (mime-edit-pgp-enclose-buffer)
            (mime-edit-translate-body)
            ))
        (error "Translation error!")
-      )
-    (end-of-invisible)
-    (run-hooks 'mime-edit-exit-hook)
+      ))
+  (end-of-invisible)
+  (run-hooks 'mime-edit-exit-hook)
+  )
+
+;;; @ for saving buffer
+;;;
+
+(defvar message-save-encoder 'message-mime-save-encoder)
+
+(defun message-save-formatter (start end &optional orig-buf)
+  "Format message, when save message buffer. [message.el]"
+  (save-restriction
+    (narrow-to-region start end)
+    (and message-save-encoder
+        (funcall message-save-encoder orig-buf))
+    (goto-char start)
+    (and (search-forward (concat "\n" mail-header-separator "\n") nil t)
+        (replace-match "\n\n"))
     ))
 
+(set-alist 'format-alist
+          'message
+          '("Message."
+            "1\\(^\\)"
+            nil
+            message-save-formatter
+            t nil))
+
+;;; @ for MIME Edit mode
+;;;
+
 (defun message-mime-insert-article (&optional message)
   (interactive)
   (let ((message-cite-function 'mime-edit-inserted-message-filter)
-       (message-reply-buffer (message-get-original-reply-buffer))
+       (message-reply-buffer
+        (message-get-parameter-with-eval 'original-buffer))
        (start (point)))
     (message-yank-original nil)
     (save-excursion
@@ -4435,35 +4642,22 @@ regexp varstr."
 (set-alist 'mime-edit-message-inserter-alist
           'message-mode (function message-mime-insert-article))
 
-;;; Miscellaneous functions
-
-;; stolen (and renamed) from nnheader.el
-(defun message-replace-chars-in-string (string from to)
-  "Replace characters in STRING from FROM to TO."
-  (let ((string (substring string 0))  ;Copy string.
-       (len (length string))
-       (idx 0))
-    ;; Replace all occurrences of FROM with TO.
-    (while (< idx len)
-      (when (= (aref string idx) from)
-       (aset string idx to))
-      (setq idx (1+ idx)))
-    string))
-
-(defvar message-save-buffer " *encoding")
-(defun message-save-drafts ()
-  (interactive)
-  (if (not (get-buffer message-save-buffer))
-      (get-buffer-create message-save-buffer))
-  (let ((filename buffer-file-name)
-       (buffer (current-buffer)))
-    (set-buffer message-save-buffer)
-    (erase-buffer)
-    (insert-buffer buffer)
-    (mime-edit-translate-buffer)
-    (write-region (point-min) (point-max) filename)
-    (set-buffer buffer)
-    (set-buffer-modified-p nil)))
+(defun message-mime-save-encoder (orig-buf)
+  (when (with-current-buffer orig-buf mime-edit-mode-flag)
+    (mime-edit-translate-body)
+    (mime-edit-translate-header)
+    ))
+
+(defun message-mime-after-save-hook ()
+  (set-buffer-file-coding-system nnheader-message-coding-system-for-write)
+  (set-buffer-modified-p nil)
+  )
+
+(defun message-mime-setup ()
+  (turn-on-mime-edit)
+  (make-local-hook 'after-save-hook)
+  (add-hook 'after-save-hook 'message-mime-after-save-hook nil t)
+  )
 
 (run-hooks 'message-load-hook)