Modify for SEMI 1.11, FLIM 1.12.
[elisp/gnus.git-] / lisp / message.el
index 953941a..60e6ed9 100644 (file)
@@ -2,9 +2,11 @@
 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
 
 ;; 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>
+;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;;     Shuhei KOBAYASHI <shuhei-k@jaist.ac.jp>
+;;     Keiichi Suzuki <kei-suzu@mail.wbs.ne.jp>
+;;     Tatsuya Ichikawa <t-ichi@po.shiojiri.ne.jp>
+;;     Katsumi Yamaoka <yamaoka@jpl.org>
 ;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
@@ -39,7 +41,6 @@
 
 (require 'mailheader)
 (require 'nnheader)
-(require 'timezone)
 (require 'easymenu)
 (require 'custom)
 (if (string-match "XEmacs\\|Lucid" emacs-version)
   (require 'mailabbrev))
 (require 'mime-edit)
 
+;; Avoid byte-compile warnings.
+(eval-when-compile
+  (require 'mail-parse)
+  (require 'mm-bodies)
+  (require 'mm-encode)
+  (require 'mml)
+  )
+
 (defgroup message '((user-mail-address custom-variable)
                    (user-full-name custom-variable))
   "Mail and news message composing."
@@ -138,6 +147,11 @@ mailbox format."
   :group 'message-sending
   :type 'function)
 
+(defcustom message-8bit-encoding-list '(8bit binary)
+  "*8bit encoding type in Content-Transfer-Encoding field."
+  :group 'message-sending
+  :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"
   "*This is inserted at the start of a mailed copy of a posted message.
@@ -152,6 +166,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.
@@ -297,14 +316,15 @@ nil means let mailer mail back a message to report errors."
   :group 'message-mail
   :type 'boolean)
 
-(defcustom message-generate-new-buffers t
+(defcustom message-generate-new-buffers 'unique
   "*Non-nil means that a new message buffer will be created whenever `message-setup' is called.
 If this is a function, call that function with three parameters:  The type,
 the to address and the group name.  (Any of these may be nil.)  The function
 should return the new buffer name."
   :group 'message-buffers
   :type '(choice (const :tag "off" nil)
-                (const :tag "on" t)
+                (const :tag "unique" unique)
+                (const :tag "unsuniqueent" unsent)
                 (function fun)))
 
 (defcustom message-kill-buffer-on-exit nil
@@ -312,6 +332,15 @@ should return the new buffer name."
   :group 'message-buffers
   :type 'boolean)
 
+(defcustom message-kill-buffer-query-function 'yes-or-no-p
+  "*A function called to query the user whether to kill buffer anyway or not.
+If it is t, the buffer will be killed peremptorily."
+  :type '(radio (function-item yes-or-no-p)
+               (function-item y-or-n-p)
+               (function-item nnheader-Y-or-n-p)
+               (function :tag "Other" t))
+  :group 'message-buffers)
+
 (defvar gnus-local-organization)
 (defcustom message-user-organization
   (or (and (boundp 'gnus-local-organization)
@@ -338,7 +367,7 @@ If t, use `message-user-organization-file'."
   :type 'string)
 
 (defcustom message-forward-end-separator
-  ""
+  (concat (mime-make-tag "text" "plain") "\n")
   "*Delimiter inserted after forwarded messages."
   :group 'message-forwarding
   :type 'string)
@@ -375,7 +404,7 @@ The provided functions are:
   :group 'message-forwarding
   :type 'boolean)
 
-(defcustom message-ignored-resent-headers "^Return-receipt"
+(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus"
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :type 'regexp)
@@ -478,7 +507,7 @@ query the user whether to use the value.  If it is t or the symbol
   "*Specifies what to do with Mail-Reply-To/Reply-To header.
 If nil, always ignore the header.  If it is t or the symbol `use', use
 its value.  If it is the symbol `ask', always query the user whether to
-use the value.  Not that if \"Reply-To\" is marked as \"broken\", its value
+use the value.  Note that if \"Reply-To\" is marked as \"broken\", its value
 is never used."
   :group 'message-interface
   :type '(choice (const :tag "ignore" nil)
@@ -533,8 +562,7 @@ variable isn't used."
   :group 'message-headers
   :type 'boolean)
 
-(defcustom message-setup-hook
-  '(message-maybe-setup-default-charset turn-on-mime-edit)
+(defcustom message-setup-hook '(turn-on-mime-edit)
   "Normal hook, run each time a new outgoing message is initialized.
 The function `message-setup' runs this hook."
   :group 'message-various
@@ -547,6 +575,12 @@ 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-mode-hook nil
   "Hook run in message mode buffers."
   :group 'message-various
@@ -654,6 +688,8 @@ If stringp, use this; if non-nil, use no host name (user name only)."
 (defvar message-postpone-actions nil
   "A list of actions to be performed after postponing a message.")
 (defvar message-original-frame nil)
+(defvar message-parameter-alist nil)
+(defvar message-startup-parameter-alist nil)
 
 (define-widget 'message-header-lines 'text
   "All header lines must be LFD terminated."
@@ -743,19 +779,28 @@ 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)
 
+(defcustom message-buffer-naming-style 'unique
+  "*The way new message buffers are named.
+Valid valued are `unique' and `unsent'."
+  :group 'message-buffers
+  :type '(choice (const :tag "unique" unique)
+                (const :tag "unsent" unsent)))
+
 ;;; Internal variables.
 ;;; Well, not really internal.
 
 (defvar message-mode-syntax-table
   (let ((table (copy-syntax-table text-mode-syntax-table)))
     (modify-syntax-entry ?% ". " table)
+    (modify-syntax-entry ?> ". " table)
+    (modify-syntax-entry ?< ". " table)
     table)
   "Syntax table used while in Message mode.")
 
@@ -957,12 +1002,17 @@ 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-default-charset nil)
 (defvar message-buffer-list nil)
 (defvar message-this-is-news nil)
 (defvar message-this-is-mail nil)
 (defvar message-draft-article nil)
+(defvar message-mime-part nil)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
@@ -1047,7 +1097,6 @@ The cdr of ech entry is a function for applying the face to a region.")
     (Lines)
     (Expires)
     (Message-ID)
-    ;; (References . message-shorten-references)
     (References . message-fill-header)
     (User-Agent))
   "Alist used for formatting headers.")
@@ -1059,12 +1108,12 @@ The cdr of ech entry is a function for applying the face to a region.")
   (autoload 'gnus-point-at-eol "gnus-util")
   (autoload 'gnus-point-at-bol "gnus-util")
   (autoload 'gnus-output-to-mail "gnus-util")
-  (autoload 'gnus-output-to-rmail "gnus-util")
   (autoload 'mail-abbrev-in-expansion-header-p "mailabbrev")
   (autoload 'nndraft-request-associate-buffer "nndraft")
   (autoload 'nndraft-request-expire-articles "nndraft")
   (autoload 'gnus-open-server "gnus-int")
   (autoload 'gnus-request-post "gnus-int")
+  (autoload 'gnus-copy-article-buffer "gnus-msg")
   (autoload 'gnus-alive-p "gnus-util")
   (autoload 'rmail-output "rmail"))
 
@@ -1107,12 +1156,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)))))
@@ -1122,7 +1171,7 @@ The cdr of ech entry is a function for applying the face to a region.")
   (when (and (file-exists-p file)
             (file-readable-p file)
             (file-regular-p file))
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (looking-at message-unix-mail-delimiter))))
@@ -1132,7 +1181,23 @@ The cdr of ech entry is a function for applying the face to a region.")
   (let* ((inhibit-point-motion-hooks t)
         (value (mail-fetch-field header nil (not not-all))))
     (when value
-      (nnheader-replace-chars-in-string value ?\n ? ))))
+      (while (string-match "\n[\t ]+" value)
+       (setq value (replace-match " " t t value)))
+      value)))
+
+(defun message-narrow-to-field ()
+  "Narrow the buffer to the header on the current line."
+  (beginning-of-line)
+  (narrow-to-region
+   (point)
+   (progn
+     (forward-line 1)
+     (if (re-search-forward "^[^ \n\t]" nil t)
+        (progn
+          (beginning-of-line)
+          (point))
+       (point-max))))
+  (goto-char (point-min)))
 
 (defun message-add-header (&rest headers)
   "Add the HEADERS to the message header, skipping those already present."
@@ -1149,11 +1214,12 @@ 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."
-  (when (and message-reply-buffer
-            (buffer-name message-reply-buffer))
-    (save-excursion
-      (set-buffer message-reply-buffer)
-      (message-fetch-field header))))
+  (let ((buffer (message-get-reply-buffer)))
+    (when (and buffer
+              (buffer-name buffer))
+      (save-excursion
+       (set-buffer buffer)
+       (message-fetch-field header)))))
 
 (defun message-set-work-buffer ()
   (if (get-buffer " *message work*")
@@ -1161,8 +1227,7 @@ The cdr of ech entry is a function for applying the face to a region.")
        (set-buffer " *message work*")
        (erase-buffer))
     (set-buffer (get-buffer-create " *message work*"))
-    (kill-all-local-variables)
-    (buffer-disable-undo (current-buffer))))
+    (kill-all-local-variables)))
 
 (defun message-functionp (form)
   "Return non-nil if FORM is funcallable."
@@ -1222,7 +1287,8 @@ Return the number of headers removed."
   (goto-char (point-min)))
 
 (defun message-narrow-to-head ()
-  "Narrow the buffer to the head of the message."
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
   (widen)
   (narrow-to-region
    (goto-char (point-min))
@@ -1231,6 +1297,21 @@ Return the number of headers removed."
      (point-max)))
   (goto-char (point-min)))
 
+(defun message-narrow-to-headers-or-head ()
+  "Narrow the buffer to the head of the message."
+  (widen)
+  (narrow-to-region
+   (goto-char (point-min))
+   (cond
+    ((re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
+     (match-beginning 0))
+    ((search-forward "\n\n" nil t)
+     (1- (point)))
+    (t
+     (point-max))))
+  (goto-char (point-min)))
+
 (defun message-news-p ()
   "Say whether the current buffer contains a news message."
   (and (not message-this-is-mail)
@@ -1294,6 +1375,22 @@ Return the number of headers removed."
             (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
 
 ;;;
@@ -1305,7 +1402,8 @@ Return the number of headers removed."
 (defvar message-mode-map nil)
 
 (unless message-mode-map
-  (setq message-mode-map (copy-keymap text-mode-map))
+  (setq message-mode-map (make-keymap))
+  (set-keymap-parent message-mode-map text-mode-map)
   (define-key message-mode-map "\C-c?" 'describe-mode)
 
   (define-key message-mode-map "\C-c\C-f\C-t" 'message-goto-to)
@@ -1344,7 +1442,10 @@ Return the number of headers removed."
   (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
   (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
 
-  (define-key message-mode-map "\t" 'message-tab))
+  (define-key message-mode-map "\t" 'message-tab)
+
+  (define-key message-mode-map "\C-x\C-s" 'message-save-drafts)
+  (define-key message-mode-map "\C-xk" 'message-kill-buffer))
 
 (easy-menu-define
  message-mode-menu message-mode-map "Message Menu."
@@ -1411,12 +1512,12 @@ C-c C-w  message-insert-signature (insert `message-signature-file' file).
 C-c C-y  message-yank-original (insert current message, if any).
 C-c C-q  message-fill-yanked-message (fill what was yanked).
 C-c C-e  message-elide-region (elide the text between point and mark).
+C-c C-v  message-delete-not-region (remove the text outside the region).
 C-c C-z  message-kill-to-signature (kill the text up to the signature).
 C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (interactive)
   (kill-all-local-variables)
-  (make-local-variable 'message-reply-buffer)
-  (setq message-reply-buffer nil)
+  (set (make-local-variable 'message-reply-buffer) nil)
   (make-local-variable 'message-send-actions) 
   (make-local-variable 'message-exit-actions) 
   (make-local-variable 'message-kill-actions)
@@ -1457,10 +1558,11 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (setq message-reply-headers nil)
   (make-local-variable 'message-user-agent)
   (make-local-variable 'message-post-method)
-  (make-local-variable 'message-sent-message-via)
-  (setq message-sent-message-via nil)
-  (make-local-variable 'message-checksum)
-  (setq message-checksum nil)
+  (set (make-local-variable 'message-sent-message-via) nil)
+  (set (make-local-variable 'message-checksum) nil)
+  (make-local-variable 'message-parameter-alist)
+  (setq message-parameter-alist
+       (copy-sequence message-startup-parameter-alist))
   ;;(when (fboundp 'mail-hist-define-keys)
   ;;  (mail-hist-define-keys))
   (when (string-match "XEmacs\\|Lucid" emacs-version)
@@ -1600,7 +1702,8 @@ With the prefix argument FORCE, insert the header anyway."
   (let ((co (message-fetch-reply-field "mail-copies-to")))
     (when (and (null force)
               co
-              (equal (downcase co) "never"))
+              (or (equal (downcase co) "never")
+                  (equal (downcase co) "nobody")))
       (error "The user has requested not to have copies sent via mail")))
   (when (and (message-position-on-field "To")
             (mail-fetch-field "to")
@@ -1735,9 +1838,10 @@ text was killed."
     ;; Then we translate the region.  Do it this way to retain
     ;; text properties.
     (while (< b e)
-      (subst-char-in-region
-       b (1+ b) (char-after b)
-       (aref message-caesar-translation-table (char-after b)))
+      (when (< (char-after b) 255)
+       (subst-char-in-region
+        b (1+ b) (char-after b)
+        (aref message-caesar-translation-table (char-after b))))
       (incf b))))
 
 (defun message-make-caesar-translation-table (n)
@@ -1861,6 +1965,7 @@ However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
          (forward-line 1))))
     (goto-char start)))
 
+(defvar gnus-article-copy)
 (defun message-yank-original (&optional arg)
   "Insert the message being replied to, if any.
 Puts point before the text and mark after.
@@ -1872,13 +1977,12 @@ 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."
   (interactive "P")
-  (let ((modified (buffer-modified-p)))
-    (when (and message-reply-buffer
+  (let ((modified (buffer-modified-p))
+       (buffer (message-get-reply-buffer)))
+    (when (and buffer
               message-cite-function)
-      (gnus-copy-article-buffer)
-      (setq message-reply-buffer gnus-article-copy)
-      (delete-windows-on message-reply-buffer t)
-      (insert-buffer message-reply-buffer)
+      (delete-windows-on buffer t)
+      (insert-buffer buffer)
       (funcall message-cite-function)
       (message-exchange-point-and-mark)
       (unless (bolp)
@@ -1895,12 +1999,17 @@ prefix, and don't delete any headers."
           (if (listp message-indent-citation-function)
               message-indent-citation-function
             (list message-indent-citation-function)))))
+    (goto-char start)
+    ;; Quote parts.
+    (while (re-search-forward "<#/?!*\\(multi\\|part\\)>" end t)
+      (goto-char (match-beginning 1))
+      (insert "!"))
     (goto-char end)
     (when (re-search-backward "^-- $" start t)
       ;; Also peel off any blank lines before the signature.
       (forward-line -1)
       (while (looking-at "^[ \t]*$")
-       (forward-line -1))
+       (forward-line -1))
       (forward-line 1)
       (delete-region (point) end))
     (goto-char start)
@@ -1911,18 +2020,25 @@ prefix, and don't delete any headers."
        (insert "\n"))
       (funcall message-citation-line-function))))
 
+(defvar mail-citation-hook) ;Compiler directive
 (defun message-cite-original ()
   "Cite function in the standard Message manner."
   (if (and (boundp 'mail-citation-hook)
           mail-citation-hook)
       (run-hooks 'mail-citation-hook)
     (let ((start (point))
+         (end (mark t))
          (functions
           (when message-indent-citation-function
             (if (listp message-indent-citation-function)
                 message-indent-citation-function
               (list message-indent-citation-function)))))
       (goto-char start)
+      ;; Quote parts.
+      (while (re-search-forward "<#/?!*\\(multi\\|part\\)>" end t)
+       (goto-char (match-beginning 1))
+       (insert "!"))
+      (goto-char start)
       (while functions
        (funcall (pop functions)))
       (when message-citation-line-function
@@ -1991,6 +2107,11 @@ The text will also be indented the normal way."
 ;;; Sending messages
 ;;;
 
+;; Avoid byte-compile warning.
+(defvar message-encoding-buffer nil)
+(defvar message-edit-buffer nil)
+(defvar message-mime-mode nil)
+
 (defun message-send-and-exit (&optional arg)
   "Send message like `message-send', then, if no errors, exit from mail buffer."
   (interactive "P")
@@ -2006,25 +2127,8 @@ The text will also be indented the normal way."
        (when (eq buf (current-buffer))
          (message-bury buf)))
       (message-do-actions actions)
-      (message-delete-frame frame org-frame))))
-
-(defun message-delete-frame (frame org-frame)
-  "Delete frame for editing message."
-  (when (and (or (and (featurep 'xemacs)
-                     (not (eq 'tty (device-type))))
-                window-system)
-            (or (and (eq message-delete-frame-on-exit t)
-                     (select-frame frame)
-                     (or (eq frame org-frame)
-                         (prog1
-                             (y-or-n-p "Delete this frame?")
-                           (message ""))))
-                (and (eq message-delete-frame-on-exit 'ask)
-                     (select-frame frame)
-                     (prog1
-                         (y-or-n-p "Delete this frame?")
-                       (message "")))))
-    (delete-frame frame)))
+      (message-delete-frame frame org-frame)
+      t)))
 
 (defun message-dont-send ()
   "Don't send the message you have been editing."
@@ -2039,14 +2143,36 @@ The text will also be indented the normal way."
   "Kill the current buffer."
   (interactive)
   (when (or (not (buffer-modified-p))
-           (yes-or-no-p "Message modified; kill anyway? "))
+           (eq t message-kill-buffer-query-function)
+           (funcall message-kill-buffer-query-function
+                    "The buffer modified; kill anyway? "))
     (let ((actions message-kill-actions)
          (frame (selected-frame))
          (org-frame message-original-frame))
       (setq buffer-file-name nil)
       (kill-buffer (current-buffer))
       (message-do-actions actions)
-      (message-delete-frame frame org-frame))))
+      (message-delete-frame frame org-frame)))
+  (message ""))
+
+(defun message-delete-frame (frame org-frame)
+  "Delete frame for editing message."
+  (when (and (or (and (featurep 'xemacs)
+                     (not (eq 'tty (device-type))))
+                window-system
+                (>= emacs-major-version 20))
+            (or (and (eq message-delete-frame-on-exit t)
+                     (select-frame frame)
+                     (or (eq frame org-frame)
+                         (prog1
+                             (y-or-n-p "Delete this frame?")
+                           (message ""))))
+                (and (eq message-delete-frame-on-exit 'ask)
+                     (select-frame frame)
+                     (prog1
+                         (y-or-n-p "Delete this frame?")
+                       (message "")))))
+    (delete-frame frame)))
 
 (defun message-bury (buffer)
   "Bury this mail buffer."
@@ -2073,7 +2199,6 @@ the user from the mailer."
     (undo-boundary)
     (let ((inhibit-read-only t))
       (put-text-property (point-min) (point-max) 'read-only nil))
-    (message-fix-before-sending)
     (run-hooks 'message-send-hook)
     (message "Sending...")
     (let ((message-encoding-buffer
@@ -2088,6 +2213,7 @@ the user from the mailer."
        (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)))
@@ -2123,6 +2249,15 @@ the user from the mailer."
   "Send the current message via news."
   (message-send-news arg))
 
+(defmacro message-check (type &rest forms)
+  "Eval FORMS if TYPE is to be checked."
+  `(or (message-check-element ,type)
+       (save-excursion
+        ,@forms)))
+
+(put 'message-check 'lisp-indent-function 1)
+(put 'message-check 'edebug-form-spec '(form body))
+
 (defun message-fix-before-sending ()
   "Do various things to make the message nice before sending it."
   ;; Make sure there's a newline at the end of the message.
@@ -2130,10 +2265,11 @@ the user from the mailer."
   (unless (bolp)
     (insert "\n"))
   ;; Delete all invisible text.
-  (when (text-property-any (point-min) (point-max) 'invisible t)
-    (put-text-property (point-min) (point-max) 'invisible nil)
-    (unless (yes-or-no-p "Invisible text found and made visible; continue posting?")
-      (error "Invisible text found and made visible"))))
+  (message-check 'invisible-text
+    (when (text-property-any (point-min) (point-max) 'invisible t)
+      (put-text-property (point-min) (point-max) 'invisible nil)
+      (unless (yes-or-no-p "Invisible text found and made visible; continue posting? ")
+       (error "Invisible text found and made visible")))))
 
 (defun message-add-action (action &rest types)
   "Add ACTION to be performed when doing an exit of type TYPES."
@@ -2156,11 +2292,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.
@@ -2169,46 +2350,47 @@ the user from the mailer."
        (message-generate-headers message-required-mail-headers))
       ;; Let the user do all of the above.
       (run-hooks 'message-header-hook))
-    (unwind-protect
-       (save-excursion
-         (set-buffer tembuf)
-         (erase-buffer)
-         (insert-buffer message-encoding-buffer)
-         ;; Remove some headers.
-         (save-restriction
-           (message-narrow-to-headers)
+    (if (not (message-check-mail-syntax))
+       (progn
+         (message "")
+         nil)
+      (unwind-protect
+         (save-excursion
+           (set-buffer tembuf)
+           (erase-buffer)
+           (insert-buffer message-encoding-buffer)
            ;; 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)
-             (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))
-      (kill-buffer tembuf))
-    (set-buffer message-edit-buffer)
-    (push 'mail message-sent-message-via)))
+           (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)
+               (insert ?\n))
+           (when (and news
+                      (or (message-fetch-field "cc")
+                          (message-fetch-field "to")))
+             (message-insert-courtesy-copy))
+           (setq failure (message-maybe-split-and-send-mail)))
+       (kill-buffer tembuf))
+      (set-buffer message-edit-buffer)
+      (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."
   (let ((errbuf (if message-interactive
                    (generate-new-buffer " sendmail errors")
                  0))
-       resend-addresses delimline)
+       resend-to-addresses delimline)
     (let ((case-fold-search t))
       (save-restriction
        (message-narrow-to-headers)
-       ;; XXX: We need to handle Resent-CC/Resent-BCC, too.
-       (setq resend-addresses (message-fetch-field "resent-to")))
+       (setq resend-to-addresses (message-fetch-field "resent-to")))
       ;; Change header-delimiter to be what sendmail expects.
       (goto-char (point-min))
       (re-search-forward
@@ -2227,7 +2409,7 @@ the user from the mailer."
          (set-buffer errbuf)
          (erase-buffer))))
     (let ((default-directory "/")
-         (coding-system-for-write 'binary))
+         (coding-system-for-write message-send-coding-system))
       (apply 'call-process-region
             (append (list (point-min) (point-max)
                           (if (boundp 'sendmail-program)
@@ -2248,8 +2430,8 @@ the user from the mailer."
                     ;; We must not do that for a resend
                     ;; because we would find the original addresses.
                     ;; For a resend, include the specific addresses.
-                    (if resend-addresses
-                        (list resend-addresses)
+                    (if resend-to-addresses
+                        (list resend-to-addresses)
                       '("-t")))))
     (when message-interactive
       (save-excursion
@@ -2267,7 +2449,7 @@ the user from the mailer."
   "Pass the prepared message buffer to qmail-inject.
 Refer to the documentation for the variable `message-send-mail-function'
 to find out how to use this."
-  ;; replace the header delimiter with a blank line.
+  ;; replace the header delimiter with a blank line
   (goto-char (point-min))
   (re-search-forward
    (concat "^" (regexp-quote mail-header-separator) "\n"))
@@ -2276,7 +2458,7 @@ to find out how to use this."
   (run-hooks 'message-send-mail-hook)
   ;; send the message
   (case
-      (let ((coding-system-for-write 'binary))
+      (let ((coding-system-for-write message-send-coding-system))
        (apply
         'call-process-region 1 (point-max) message-qmail-inject-program
         nil nil nil
@@ -2352,6 +2534,38 @@ to find out how to use this."
            (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*"))
        (case-fold-search nil)
@@ -2372,13 +2586,11 @@ to find out how to use this."
       (run-hooks 'message-header-hook))
     (message-cleanup-headers)
     (if (not (message-check-news-syntax))
-       (progn
-         ;;(message "Posting not performed")
-         nil)
+       nil
       (unwind-protect
          (save-excursion
            (set-buffer tembuf)
-           (buffer-disable-undo (current-buffer))
+           (buffer-disable-undo)
            (erase-buffer)
            (insert-buffer message-encoding-buffer)
            ;; Remove some headers.
@@ -2390,27 +2602,15 @@ to find out how to use this."
            ;; require one newline at the end.
            (or (= (preceding-char) ?\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)
@@ -2436,15 +2636,6 @@ to find out how to use this."
 ;;; Header generation & syntax checking.
 ;;;
 
-(defmacro message-check (type &rest forms)
-  "Eval FORMS if TYPE is to be checked."
-  `(or (message-check-element ,type)
-       (save-excursion
-        ,@forms)))
-
-(put 'message-check 'lisp-indent-function 1)
-(put 'message-check 'edebug-form-spec '(form body))
-
 (defun message-check-element (type)
   "Returns non-nil if this type is not to be checked."
   (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
@@ -2633,7 +2824,7 @@ to find out how to use this."
    (message-check 'from
      (let* ((case-fold-search t)
            (from (message-fetch-field "from"))
-           (ad (nth 1 (funcall gnus-extract-address-components from))))
+           (ad (nth 1 (std11-extract-address-components from))))
        (cond
        ((not from)
         (message "There is no From line.  Posting is denied.")
@@ -2679,10 +2870,13 @@ to find out how to use this."
           (y-or-n-p "Empty article.  Really post? "))))
    ;; Check for control characters.
    (message-check 'control-chars
-     (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
+     (if (re-search-forward "[\000-\007\013\015-\032\034-\037\200-\237]" nil t)
         (y-or-n-p
          "The article contains control characters.  Really post? ")
        t))
+   ;; Check 8bit characters.
+   (message-check '8bit
+     (message-check-8bit))
    ;; Check excessive size.
    (message-check 'size
      (if (> (buffer-size) 60000)
@@ -2710,6 +2904,54 @@ to find out how to use this."
             (1- (count-lines (point) (point-max)))))
         t)))))
 
+(defun message-check-mail-syntax ()
+  "Check the syntax of the message."
+  (save-excursion
+    (save-restriction
+      (widen)
+      (and
+       ;; We narrow to the headers and check them first.
+       (save-excursion
+        (save-restriction
+          (message-narrow-to-headers)
+          (message-check-mail-header-syntax)))
+       ;; Check the body.
+       (save-excursion
+        (set-buffer message-edit-buffer)
+        (message-check-mail-body-syntax))))))
+
+(defun message-check-mail-header-syntax ()
+  t)
+
+(defun message-check-mail-body-syntax ()
+  (and
+   ;; Check 8bit characters.
+   (message-check '8bit
+     (message-check-8bit)
+     )))
+
+(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)
+          (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 "[^\x00-\x7f]" nil t)
+           (y-or-n-p
+            "The article contains 8bit characters.  Really post? ")
+         t)))))
+
 (defun message-checksum ()
   "Return a \"checksum\" for the current buffer."
   (let ((sum 0))
@@ -2720,7 +2962,7 @@ to find out how to use this."
       (while (not (eobp))
        (when (not (looking-at "[ \t\n]"))
          (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
-                           (following-char))))
+                           (char-after))))
        (forward-char 1)))
     sum))
 
@@ -2731,7 +2973,6 @@ to find out how to use this."
        list file)
     (save-excursion
       (set-buffer (get-buffer-create " *message temp*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
       (insert-buffer-substring message-encoding-buffer)
       (save-restriction
@@ -2739,7 +2980,6 @@ to find out how to use this."
        (while (setq file (message-fetch-field "fcc"))
          (push file list)
          (message-remove-header "fcc" nil t)))
-      (run-hooks 'message-header-hook 'message-before-do-fcc-hook)
       (goto-char (point-min))
       (re-search-forward (concat "^" (regexp-quote mail-header-separator) "$"))
       (replace-match "" t t)
@@ -2762,14 +3002,13 @@ to find out how to use this."
                (rmail-output file 1 nil t)
              (let ((mail-use-rfc822 t))
                (rmail-output file 1 t t))))))
-
       (kill-buffer (current-buffer)))))
 
 (defun message-output (filename)
   "Append this article to Unix/babyl mail file.."
   (if (and (file-readable-p filename)
           (mail-file-babyl-p filename))
-      (gnus-output-to-rmail filename t)
+      (rmail-output-to-rmail-file filename t)
     (gnus-output-to-mail filename t)))
 
 (defun message-cleanup-headers ()
@@ -2804,11 +3043,24 @@ to find out how to use this."
        (when (re-search-forward ",+$" nil t)
          (replace-match "" t t))))))
 
-(defun message-make-date ()
-  "Make a valid data header."
-  (let ((now (current-time)))
-    (timezone-make-date-arpa-standard
-     (current-time-string now) (current-time-zone now))))
+(defun message-make-date (&optional now)
+  "Make a valid data header.
+If NOW, use that time instead."
+  (let* ((now (or now (current-time)))
+        (zone (nth 8 (decode-time now)))
+        (sign "+"))
+    (when (< zone 0)
+      (setq sign "-")
+      (setq zone (- zone)))
+    (concat
+     (format-time-string "%d" now)
+     ;; The month name of the %b spec is locale-specific.  Pfff.
+     (format " %s "
+            (capitalize (car (rassoc (nth 4 (decode-time now))
+                                     parse-time-months))))
+     (format-time-string "%Y %H:%M:%S " now)
+     ;; We do all of this because XEmacs doesn't have the %z spec.
+     (format "%s%02d%02d" sign (/ zone 3600) (% zone 3600)))))
 
 (defun message-make-followup-subject (subject)
   "Make a followup Subject."
@@ -2922,14 +3174,13 @@ to find out how to use this."
       (when mid
        (concat mid
                (when from
-                 (let ((stop-pos 
-                        (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+                 (let ((pair (std11-extract-address-components from)))
                    (concat "\n ("
-                           (if stop-pos (substring from 0 stop-pos) from)
-                           "'s message of " 
+                           (or (car pair) (cadr pair))
+                           "'s message of \""
                            (if (or (not date) (string= date ""))
                                "(unknown date)" date)
-                           ")"))))))))
+                           "\")"))))))))
 
 (defun message-make-distribution ()
   "Make a Distribution header."
@@ -2945,9 +3196,7 @@ to find out how to use this."
     ;; Add the future to current.
     (setcar current (+ (car current) (round (/ future (expt 2 16)))))
     (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
-    ;; Return the date in the future in UT.
-    (timezone-make-date-arpa-standard
-     (current-time-string current) (current-time-zone current) '(0 "UT"))))
+    (message-make-date current)))
 
 (defun message-make-path ()
   "Return uucp path."
@@ -3033,7 +3282,7 @@ give as trustworthy answer as possible."
   "Return the pertinent part of `user-mail-address'."
   (when user-mail-address
     (if (string-match " " user-mail-address)
-       (nth 1 (funcall gnus-extract-address-components user-mail-address))
+       (nth 1 (std11-extract-address-components user-mail-address))
       user-mail-address)))
 
 (defun message-make-fqdn ()
@@ -3069,6 +3318,31 @@ give as trustworthy answer as possible."
   (or mail-host-address
       (message-make-fqdn)))
 
+;; Dummy to avoid byte-compile warning.
+(defvar mule-version)
+(defvar emacs-beta-version)
+(defvar xemacs-codename)
+(defvar gnus-inviolable-extended-version)
+
+(defun message-make-user-agent ()
+  "Return user-agent info if the value `message-user-agent' is non-nil. If the
+\"User-Agent\" field has already exist, it's value will be added in the return
+string."
+  (when message-user-agent
+    (save-excursion
+      (goto-char (point-min))
+      (let ((case-fold-search t)
+           user-agent start p end)
+       (if (re-search-forward "^User-Agent:[\t ]*" nil t)
+           (progn
+             (setq start (match-beginning 0)
+                   p (match-end 0)
+                   end (std11-field-end)
+                   user-agent (buffer-substring-no-properties p end))
+             (delete-region start (1+ end))
+             (concat message-user-agent " " user-agent))
+         message-user-agent)))))
+
 (defun message-generate-headers (headers)
   "Prepare article HEADERS.
 Headers already prepared in the buffer are not modified."
@@ -3085,7 +3359,7 @@ Headers already prepared in the buffer are not modified."
           (To nil)
           (Distribution (message-make-distribution))
           (Lines (message-make-lines))
-          (User-Agent message-user-agent)
+          (User-Agent (message-make-user-agent))
           (Expires (message-make-expires))
           (case-fold-search t)
           header value elem)
@@ -3113,12 +3387,18 @@ Headers already prepared in the buffer are not modified."
              (setq header (car elem)))
          (setq header elem))
        (when (or (not (re-search-forward
-                       (concat "^" (downcase (symbol-name header)) ":")
+                       (concat "^"
+                               (regexp-quote
+                                (downcase
+                                 (if (stringp header)
+                                     header
+                                   (symbol-name header))))
+                               ":")
                        nil t))
                  (progn
                    ;; The header was found.  We insert a space after the
                    ;; colon, if there is none.
-                   (if (/= (following-char) ? ) (insert " ") (forward-char 1))
+                   (if (/= (char-after) ? ) (insert " ") (forward-char 1))
                    ;; Find out whether the header is empty...
                    (looking-at "[ \t]*$")))
          ;; So we find out what value we should insert.
@@ -3155,7 +3435,8 @@ Headers already prepared in the buffer are not modified."
                  (progn
                    ;; This header didn't exist, so we insert it.
                    (goto-char (point-max))
-                   (insert (symbol-name header) ": " value "\n")
+                   (insert (if (stringp header) header (symbol-name header))
+                           ": " value "\n")
                    (forward-line -1))
                ;; The value of this header was empty, so we clear
                ;; totally and insert the new value.
@@ -3175,15 +3456,13 @@ Headers already prepared in the buffer are not modified."
                   (not (message-check-element 'sender))
                   (not (string=
                         (downcase
-                         (cadr (funcall gnus-extract-address-components
-                                        from)))
+                         (cadr (std11-extract-address-components from)))
                         (downcase secure-sender)))
                   (or (null sender)
                       (not
                        (string=
                         (downcase
-                         (cadr (funcall gnus-extract-address-components
-                                        sender)))
+                         (cadr (std11-extract-address-components sender)))
                         (downcase secure-sender)))))
          (goto-char (point-min))
          ;; Rename any old Sender headers to Original-Sender.
@@ -3228,10 +3507,11 @@ 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 last
+             (if (and (> (current-column) 78)
+                      last)
                   (save-excursion
                     (goto-char last)
                    (looking-at "[ \t]*")
@@ -3244,6 +3524,13 @@ Headers already prepared in the buffer are not modified."
     (widen)
     (forward-line 1)))
 
+(defun message-fill-references (header value)
+  (insert (capitalize (symbol-name header))
+         ": "
+         (std11-fill-msg-id-list-string
+         (if (consp value) (car value) value))
+         "\n"))
+
 (defun message-fill-header (header value)
   (let ((begin (point))
        (fill-column 78)
@@ -3270,7 +3557,7 @@ Headers already prepared in the buffer are not modified."
   (let ((max 988)
        (cut 4)
        refs)
-    (nnheader-temp-write nil
+    (with-temp-buffer
       (insert references)
       (goto-char (point-min))
       (while (re-search-forward "<[^>]+>" nil t)
@@ -3291,7 +3578,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
@@ -3310,12 +3597,22 @@ Headers already prepared in the buffer are not modified."
    ((message-functionp message-generate-new-buffers)
     (funcall message-generate-new-buffers type to group))
    ;; Generate a new buffer name The Message Way.
-   (message-generate-new-buffers
+   ((eq message-generate-new-buffers 'unique)
     (generate-new-buffer-name
      (concat "*" type
             (if to
                 (concat " to "
-                        (or (car (funcall gnus-extract-address-components to))
+                        (or (car (std11-extract-address-components to))
+                            to) "")
+              "")
+            (if (and group (not (string= group ""))) (concat " on " group) "")
+            "*")))
+   ((eq message-generate-new-buffers 'unsent)
+    (generate-new-buffer-name
+     (concat "*unsent " type
+            (if to
+                (concat " to "
+                        (or (car (mail-extract-address-components to))
                             to) "")
               "")
             (if (and group (not (string= group ""))) (concat " on " group) "")
@@ -3335,7 +3632,8 @@ Headers already prepared in the buffer are not modified."
        (cur (current-buffer)))
     (if (or (and (featurep 'xemacs)
                 (not (eq 'tty (device-type))))
-           window-system)
+           window-system
+           (>= emacs-major-version 20))
        (when message-use-multi-frames
          (setq pop-up-frames t
                special-display-buffer-names nil
@@ -3374,7 +3672,7 @@ Headers already prepared in the buffer are not modified."
   ;; Rename the buffer.
   (if message-send-rename-function
       (funcall message-send-rename-function)
-    (when (string-match "\\`\\*" (buffer-name))
+    (when (string-match "\\`\\*\\(unsent \\)?" (buffer-name))
       (rename-buffer
        (concat "*sent " (substring (buffer-name) (match-end 0))) t)))
   ;; Push the current buffer onto the list.
@@ -3391,7 +3689,9 @@ Headers already prepared in the buffer are not modified."
          mc-modes-alist))
   (when actions
     (setq message-send-actions actions))
-  (setq message-reply-buffer replybuffer)
+  (setq message-reply-buffer
+       (or (cdr (assq 'reply-buffer message-parameter-alist))
+           replybuffer))
   (goto-char (point-min))
   ;; Insert all the headers.
   (mail-header-format
@@ -3445,12 +3745,12 @@ Headers already prepared in the buffer are not modified."
 
 (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)))
 
@@ -3470,7 +3770,8 @@ Headers already prepared in the buffer are not modified."
 (defun message-mail (&optional to subject
                               other-headers continue switch-function
                               yank-action send-actions)
-  "Start editing a mail message to be sent."
+  "Start editing a mail message to be sent.
+OTHER-HEADERS is an alist of header/value pairs."
   (interactive)
   (let ((message-this-is-mail t))
     (message-pop-to-buffer (message-buffer-name "mail" to))
@@ -3493,10 +3794,10 @@ Headers already prepared in the buffer are not modified."
   "Start editing a reply to the article in the current buffer."
   (interactive)
   (let ((cur (current-buffer))
+       from subject date to cc
+       references message-id follow-to
        (inhibit-point-motion-hooks t)
-       from date subject mct mft mrt
-        never-mct to cc
-       references message-id follow-to gnus-warning)
+       mct never-mct mft mrt gnus-warning)
     (save-restriction
       (message-narrow-to-head)
       ;; Allow customizations to have their say.
@@ -3535,7 +3836,8 @@ Headers already prepared in the buffer are not modified."
     ;; Handle special values of Mail-Copies-To.
     (when mct
       (cond
-       ((and (equal (downcase mct) "never")
+       ((and (or (equal (downcase mct) "never")
+                (equal (downcase mct) "nobody"))
             (or (not (eq message-use-mail-copies-to 'ask))
                 (message-y-or-n-p
                  (concat "Obey Mail-Copies-To: never? ") t "\
@@ -3545,7 +3847,8 @@ You should normally obey the Mail-Copies-To: header.
 directs you not to send your response to the author.")))
        (setq never-mct t)
        (setq mct nil))
-       ((and (equal (downcase mct) "always")
+       ((and (or (equal (downcase mct) "always")
+                (equal (downcase mct) "poster"))
             (or (not (eq message-use-mail-copies-to 'ask))
                 (message-y-or-n-p
                  (concat "Obey Mail-Copies-To: always? ") t "\
@@ -3631,7 +3934,8 @@ that further discussion should take place only in "
                            (if wide to-address nil)))
 
     (setq message-reply-headers
-         (vector 0 subject from date message-id references 0 0 ""))
+         (make-full-mail-header-from-decoded-header
+          0 subject from date message-id references 0 0 ""))
 
     (message-setup
      `((Subject . ,subject)
@@ -3649,22 +3953,20 @@ that further discussion should take place only in "
 
 ;;;###autoload
 (defun message-followup (&optional to-newsgroups)
-  "Follow up to the message in the current buffer."
+  "Follow up to the message in the current buffer.
+If TO-NEWSGROUPS, use that as the new Newsgroups line."
   (interactive)
   (let ((cur (current-buffer))
+       from subject date mct
+       references message-id follow-to
        (inhibit-point-motion-hooks t)
-       from date subject mct mft mrt
        (message-this-is-news t)
-       followup-to distribution newsgroups posted-to
-       references message-id follow-to gnus-warning)
+       followup-to distribution newsgroups gnus-warning posted-to mft mrt)
     (save-restriction
       (message-narrow-to-head)
-      ;; Allow customizations to have their say.
-      ;; This is a followup.
       (when (message-functionp message-followup-to-function)
        (setq follow-to
              (funcall message-followup-to-function)))
-      ;; Find all relevant headers we need.
       (setq from (message-fetch-field "from")
            date (message-fetch-field "date" t)
            subject (or (message-fetch-field "subject") "none")
@@ -3698,7 +4000,8 @@ that further discussion should take place only in "
     ;; Handle special values of Mail-Copies-To.
     (when mct
       (cond
-       ((and (equal (downcase mct) "never")
+       ((and (or (equal (downcase mct) "never")
+                (equal (downcase mct) "nobody"))
             (or (not (eq message-use-mail-copies-to 'ask))
                 (message-y-or-n-p
                  (concat "Obey Mail-Copies-To: never? ") t "\
@@ -3707,7 +4010,8 @@ You should normally obey the Mail-Copies-To: header.
        `Mail-Copies-To: never'
 directs you not to send your response to the author.")))
        (setq mct nil))
-       ((and (equal (downcase mct) "always")
+       ((and (or (equal (downcase mct) "always")
+                (equal (downcase mct) "poster"))
             (or (not (eq message-use-mail-copies-to 'ask))
                 (message-y-or-n-p
                  (concat "Obey Mail-Copies-To: always? ") t "\
@@ -3797,7 +4101,8 @@ that further discussion should take place only in "
     (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
 
     (setq message-reply-headers
-         (vector 0 subject from date message-id references 0 0 ""))
+         (make-full-mail-header-from-decoded-header
+          0 subject from date message-id references 0 0 ""))
 
     (message-setup
      `((Subject . ,subject)
@@ -3832,14 +4137,13 @@ that further discussion should take place only in "
                          (downcase sender)
                          (downcase (message-make-sender))))
                    (string-equal
-                    (downcase (cadr (funcall gnus-extract-address-components
-                                             from)))
-                    (downcase (cadr (funcall gnus-extract-address-components
-                                             (message-make-from))))))
+                    (downcase (cadr (std11-extract-address-components
+                                     from)))
+                    (downcase (cadr (std11-extract-address-components
+                                     (message-make-from))))))
          (error "This article is not yours"))
        ;; Make control message.
        (setq buf (set-buffer (get-buffer-create " *message cancel*")))
-       (buffer-disable-undo (current-buffer))
        (erase-buffer)
        (insert "Newsgroups: " newsgroups "\n"
                "From: " (message-make-from) "\n"
@@ -3865,13 +4169,18 @@ that further discussion should take place only in "
 This is done simply by taking the old article and adding a Supersedes
 header line with the old Message-ID."
   (interactive)
-  (let ((cur (current-buffer)))
+  (let ((cur (current-buffer))
+       (sender (message-fetch-field "sender"))
+       (from (message-fetch-field "from")))
     ;; Check whether the user owns the article that is to be superseded.
-    (unless (string-equal
-            (downcase (or (message-fetch-field "sender")
-                          (cadr (funcall gnus-extract-address-components
-                                         (message-fetch-field "from")))))
-            (downcase (message-make-sender)))
+    (unless (or (and sender
+                    (string-equal
+                     (downcase sender)
+                     (downcase (message-make-sender))))
+               (string-equal
+                (downcase (cadr (std11-extract-address-components from)))
+                (downcase (cadr (std11-extract-address-components
+                                 (message-make-from))))))
       (error "This article is not yours"))
     ;; Get a normal message buffer.
     (message-pop-to-buffer (message-buffer-name "supersede"))
@@ -3911,12 +4220,12 @@ header line with the old Message-ID."
 
 (defun message-wash-subject (subject)
   "Remove junk like \"Re:\", \"(fwd)\", etc. that was added to the subject by previous forwarders, replyers, etc."
-  (nnheader-temp-write nil
+  (with-temp-buffer
     (insert-string subject)
     (goto-char (point-min))
     ;; strip Re/Fwd stuff off the beginning
     (while (re-search-forward
-           "\\([Rr][Ee]:\\|[Ff][Ww][Dd]:\\|[Ff][Ww]:\\)" nil t)
+           "\\([Rr][Ee]:\\|[Ff][Ww][Dd]\\(\\[[0-9]*\\]\\)?:\\|[Ff][Ww]:\\)" nil t)
       (replace-match ""))
 
     ;; and gnus-style forwards [foo@bar.com] subject
@@ -3964,11 +4273,26 @@ the message."
     (save-restriction
       (current-buffer)
       (message-narrow-to-head)
-      (concat "[" (or (message-fetch-field
-                      (if (message-news-p) "newsgroups" "from"))
-                     "(nowhere)")
-             "] " (or (eword-decode-unstructured-field-body
-                       (message-fetch-field "Subject") ""))))))
+      (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"))
+                          ""))))
+       ;; Make sure funcs is a list.
+       (and funcs
+            (not (listp funcs))
+            (setq funcs (list funcs)))
+       ;; Apply funcs in order, passing subject generated by previous
+       ;; func to the next one.
+       (while funcs
+         (when (message-functionp (car funcs))
+           (setq subject (funcall (car funcs) subject)))
+         (setq funcs (cdr funcs)))
+       subject))))
 
 ;;;###autoload
 (defun message-forward (&optional news)
@@ -4016,7 +4340,6 @@ Optional NEWS will use news to forward instead of mail."
          beg)
       ;; We first set up a normal mail buffer.
       (set-buffer (get-buffer-create " *message resend*"))
-      (buffer-disable-undo (current-buffer))
       (erase-buffer)
       ;; avoid to turn-on-mime-edit
       (let (message-setup-hook)
@@ -4054,10 +4377,18 @@ Optional NEWS will use news to forward instead of mail."
       ;; Send it.
       (let ((message-encoding-buffer (current-buffer))
            (message-edit-buffer (current-buffer)))
-       (message-send-mail))
+       (let (message-required-mail-headers)
+         (message-send-mail)))
       (kill-buffer (current-buffer)))
     (message "Resending message to %s...done" address)))
 
+(defun message-bounce-setup-for-mime-edit ()
+  (goto-char (point-min))
+  (when (search-forward (concat "\n" mail-header-separator "\n") nil t)
+    (replace-match "\n\n"))
+  (set (make-local-variable 'message-setup-hook) nil)
+  (mime-edit-again))
+
 ;;;###autoload
 (defun message-bounce ()
   "Re-mail the current message.
@@ -4097,6 +4428,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)))
 
 ;;;
@@ -4174,7 +4508,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
@@ -4188,7 +4522,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)
@@ -4229,7 +4563,6 @@ Do a `tab-to-tab-stop' if not in those headers."
                                            (point))))
         (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb))
         (completions (all-completions string hashtb))
-        (cur (current-buffer))
         comp)
     (delete-region b (point))
     (cond
@@ -4248,7 +4581,7 @@ Do a `tab-to-tab-stop' if not in those headers."
          (message "No matching groups")
        (save-selected-window
          (pop-to-buffer "*Completions*")
-         (buffer-disable-undo (current-buffer))
+         (buffer-disable-undo)
          (let ((buffer-read-only nil))
            (erase-buffer)
            (let ((standard-output (current-buffer)))
@@ -4314,19 +4647,6 @@ regexp varstr."
 ;;; @ for MIME Edit mode
 ;;;
 
-(defun message-maybe-setup-default-charset ()
-  (let ((charset
-        (and (boundp 'gnus-summary-buffer)
-              (buffer-live-p gnus-summary-buffer)
-             (save-excursion
-               (set-buffer gnus-summary-buffer)
-               default-mime-charset))))
-    (if charset
-       (progn
-         (make-local-variable 'default-mime-charset)
-         (setq default-mime-charset charset)
-         ))))
-
 (defun message-maybe-encode ()
   (when message-mime-mode
     (run-hooks 'mime-edit-translate-hook)
@@ -4340,13 +4660,22 @@ regexp varstr."
     (run-hooks 'mime-edit-exit-hook)
     ))
 
-(defun message-mime-insert-article (&optional message)
-  (interactive)
+(defun message-mime-insert-article (&optional full-headers)
+  (interactive "P")
   (let ((message-cite-function 'mime-edit-inserted-message-filter)
-        (message-reply-buffer gnus-original-article-buffer)
-       )
+       (message-reply-buffer (message-get-original-reply-buffer))
+       (start (point)))
     (message-yank-original nil)
-    ))
+    (save-excursion
+      (narrow-to-region (goto-char start)
+                       (if (search-forward "\n\n" nil t)
+                           (1- (point))
+                         (point-max)))
+      (goto-char (point-min))
+      (let ((message-included-forward-headers
+            (if full-headers "" message-included-forward-headers)))
+       (message-remove-header message-included-forward-headers t nil t))
+      (widen))))
 
 (set-alist 'mime-edit-message-inserter-alist
           'message-mode (function message-mime-insert-article))
@@ -4366,6 +4695,59 @@ regexp varstr."
       (setq idx (1+ idx)))
     string))
 
+;;;
+;;; MIME functions
+;;;
+
+(defun message-insert-mime-part (file type)
+  "Insert a multipart/alternative part into the buffer."
+  (interactive
+   (let* ((file (read-file-name "Insert file: " nil nil t))
+         (type (mm-default-file-encoding file)))
+     (list file
+          (completing-read
+           (format "MIME type for %s: " file)
+           (mapcar (lambda (m) (list (cdr m))) mailcap-mime-extensions)
+           nil nil type))))
+  (insert (format "<#part type=%s filename=\"%s\"><#/part>\n"
+                 type file)))
+
+(defun message-encode-message-body ()
+  (message-goto-body)
+  (save-restriction
+    (narrow-to-region (point) (point-max))
+    (let ((new (mml-generate-mime)))
+      (delete-region (point-min) (point-max))
+      (insert new)
+      (goto-char (point-min))
+      (widen)
+      (forward-line -1)
+      (let ((beg (point))
+           (line (buffer-substring (point) (progn (forward-line 1) (point)))))
+       (delete-region beg (point))
+       (insert "Mime-Version: 1.0\n")
+       (search-forward "\n\n")
+       (insert line)
+       (when (save-excursion
+               (re-search-backward "^Content-Type: multipart/" nil t))
+         (insert "This is a MIME multipart message.  If you are reading\n")
+         (insert "this, you shouldn't.\n\n"))))))
+
+(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)))
+
 (run-hooks 'message-load-hook)
 
 (provide 'message)