(message-locale-detect): Fix, when no locale detected.
[elisp/gnus.git-] / lisp / message.el
index 3696495..788824c 100644 (file)
@@ -2,7 +2,13 @@
 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: mail, news
+;;         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>
+;;         Kiyokazu SUTO    <suto@merry.xmath.ous.ac.jp>
+;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
 
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'cl)
+  (require 'smtp)
+  )
 
 (require 'mailheader)
 (require 'nnheader)
+(require 'timezone)
 (require 'easymenu)
 (require 'custom)
 (if (string-match "XEmacs\\|Lucid" emacs-version)
     (require 'mail-abbrevs)
   (require 'mailabbrev))
-(require 'mail-parse)
-(require 'mm-bodies)
-(require 'mm-encode)
+(require 'mime-edit)
 
 (defgroup message '((user-mail-address custom-variable)
                    (user-full-name custom-variable))
   :group 'message
   :group 'faces)
 
+(defgroup message-frames nil
+  "Message frames"
+  :group 'message)
+
 (defcustom message-directory "~/Mail/"
   "*Directory from which all other mail file variables are derived."
   :group 'message-various
@@ -124,6 +136,16 @@ mailbox format."
                (function :tag "Other"))
   :group 'message-sending)
 
+(defcustom message-encode-function 'message-maybe-encode
+  "*A function called to encode messages."
+  :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.
@@ -138,6 +160,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.
@@ -212,13 +239,19 @@ included.  Organization, Lines and User-Agent are optional."
   :group 'message-headers
   :type 'regexp)
 
-(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:"
+(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^X-Trace:\\|^X-Complaints-To:"
   "*Header lines matching this regexp will be deleted before posting.
 It's best to delete old Path and Date headers before posting to avoid
 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
@@ -242,15 +275,14 @@ nil means let mailer mail back a message to report errors."
   :group 'message-mail
   :type 'boolean)
 
-(defcustom message-generate-new-buffers 'unique
+(defcustom message-generate-new-buffers t
   "*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 "unique" unique)
-                (const :tag "unsuniqueent" unsent)
+                (const :tag "on" t)
                 (function fun)))
 
 (defcustom message-kill-buffer-on-exit nil
@@ -258,6 +290,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)
@@ -278,13 +319,13 @@ If t, use `message-user-organization-file'."
   :group 'message-headers)
 
 (defcustom message-forward-start-separator
-  "------- Start of forwarded message -------\n"
+  (concat (mime-make-tag "message" "rfc822") "\n")
   "*Delimiter inserted before forwarded messages."
   :group 'message-forwarding
   :type 'string)
 
 (defcustom message-forward-end-separator
-  "------- End of forwarded message -------\n"
+  (concat (mime-make-tag "text" "plain") "\n")
   "*Delimiter inserted after forwarded messages."
   :group 'message-forwarding
   :type 'string)
@@ -295,7 +336,7 @@ If t, use `message-user-organization-file'."
   :type 'boolean)
 
 (defcustom message-included-forward-headers
-  "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-\\|^Message-ID:\\|^References:\\|^Content-Transfer-Encoding:\\|^Content-Type:\\|^Mime-Version:"
+  "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-\\|^Message-ID:\\|^References:\\|^Content-Transfer-Encoding:\\|^Content-Type:\\|^MIME-Version:"
   "*Regexp matching headers to be included in forwarded messages."
   :group 'message-forwarding
   :type 'regexp)
@@ -321,7 +362,7 @@ The provided functions are:
   :group 'message-forwarding
   :type 'boolean)
 
-(defcustom message-ignored-resent-headers "^Return-receipt\\|^X-Gnus"
+(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)
@@ -345,16 +386,17 @@ variable `mail-header-separator'.
 
 Legal values include `message-send-mail-with-sendmail' (the default),
 `message-send-mail-with-mh', `message-send-mail-with-qmail' and
-`smtpmail-send-it'."
+`message-send-mail-with-smtp'."
   :type '(radio (function-item message-send-mail-with-sendmail)
                (function-item message-send-mail-with-mh)
                (function-item message-send-mail-with-qmail)
-               (function-item smtpmail-send-it)
+               (function-item message-send-mail-with-smtp)
                (function :tag "Other"))
   :group 'message-sending
   :group 'message-mail)
 
-(defcustom message-send-news-function 'message-send-news
+;; 1997-09-29 by MORIOKA Tomohiko
+(defcustom message-send-news-function 'message-send-news-with-gnus
   "Function to call to send the current buffer as news.
 The headers should be delimited by a line whose contents match the
 variable `mail-header-separator'."
@@ -441,7 +483,7 @@ variable isn't used."
   :group 'message-headers
   :type 'boolean)
 
-(defcustom message-setup-hook nil
+(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
@@ -454,13 +496,38 @@ 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
   :type 'hook)
 
 (defcustom message-header-hook nil
-  "Hook run in a message mode buffer narrowed to the headers."
+  "Hook run in a message mode before header encode. Buffer narrowed 
+to the headers."
+   :group 'message-various
+   :type 'hook)
+
+(defcustom message-header-encode-function
+  'eword-encode-header
+  "A function called to encode header."
+  :group 'message-various
+  :type 'function)
+
+(defcustom message-header-encoded-hook nil
+  "Hook run in a message mode after header encoded. Buffer narrowed 
+to the headers."
   :group 'message-various
   :type 'hook)
 
@@ -482,6 +549,12 @@ 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 'boolean
+  :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'."
@@ -550,8 +623,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-newsreader nil)
-(defvar message-mailer nil)
 (defvar message-sent-message-via nil)
 (defvar message-checksum nil)
 (defvar message-send-actions nil
@@ -562,6 +633,9 @@ If stringp, use this; if non-nil, use no host name (user name only)."
   "A list of actions to be performed before killing a message buffer.")
 (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."
@@ -589,6 +663,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
@@ -616,6 +695,10 @@ actually occur."
   :group 'message-sending
   :type 'sexp)
 
+;;; XXX: This symbol is overloaded!  See below.
+(defvar message-user-agent nil
+  "String of the form of PRODUCT/VERSION.  Used for User-Agent header field.")
+
 ;; Ignore errors in case this is used in Emacs 19.
 ;; Don't use ignore-errors because this is copied into loaddefs.el.
 ;;;###autoload
@@ -654,13 +737,6 @@ 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.
 
@@ -853,17 +929,24 @@ The cdr of ech entry is a function for applying the face to a region.")
   :group 'message-various
   :type 'hook)
 
-(defvar message-send-coding-system 'binary
-  "Coding system to encode outgoing mail.")
+(defcustom message-use-multi-frames nil
+  "Make new frame when sending messages."
+  :group 'message-frames
+  :type 'boolean)
+
+(defcustom message-delete-frame-on-exit nil
+  "Delete frame after sending messages."
+  :group 'message-frames
+  :type '(choice (const :tag "off" nil)
+                (const :tag "always" t)
+                (const :tag "ask" ask)))
 
 ;;; 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)
@@ -948,7 +1031,7 @@ 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-references)
     (User-Agent))
   "Alist used for formatting headers.")
 
@@ -959,11 +1042,13 @@ 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"))
 
@@ -972,6 +1057,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"
@@ -1021,7 +1122,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))
-    (with-temp-buffer
+    (nnheader-temp-write nil
       (nnheader-insert-file-contents file)
       (goto-char (point-min))
       (looking-at message-unix-mail-delimiter))))
@@ -1031,23 +1132,7 @@ 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
-      (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)))
+      (nnheader-replace-chars-in-string value ?\n ? ))))
 
 (defun message-add-header (&rest headers)
   "Add the HEADERS to the message header, skipping those already present."
@@ -1064,11 +1149,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-eval-parameter message-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*")
@@ -1077,7 +1163,7 @@ The cdr of ech entry is a function for applying the face to a region.")
        (erase-buffer))
     (set-buffer (get-buffer-create " *message work*"))
     (kill-all-local-variables)
-    (mm-enable-multibyte)))
+    (buffer-disable-undo (current-buffer))))
 
 (defun message-functionp (form)
   "Return non-nil if FORM is funcallable."
@@ -1137,8 +1223,7 @@ Return the number of headers removed."
   (goto-char (point-min)))
 
 (defun message-narrow-to-head ()
-  "Narrow the buffer to the head of the message.
-Point is left at the beginning of the narrowed-to region."
+  "Narrow the buffer to the head of the message."
   (widen)
   (narrow-to-region
    (goto-char (point-min))
@@ -1147,21 +1232,6 @@ Point is left at the beginning of the narrowed-to region."
      (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)
@@ -1224,7 +1294,6 @@ Point is left at the beginning of the narrowed-to region."
               (- max rank)
             (1+ max)))))
       (message-sort-headers-1))))
-
 \f
 
 ;;;
@@ -1236,8 +1305,7 @@ Point is left at the beginning of the narrowed-to region."
 (defvar message-mode-map nil)
 
 (unless message-mode-map
-  (setq message-mode-map (make-keymap))
-  (set-keymap-parent message-mode-map text-mode-map)
+  (setq message-mode-map (copy-keymap 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)
@@ -1274,9 +1342,9 @@ Point is left at the beginning of the narrowed-to region."
   (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 "\C-c\C-a" 'message-insert-mime-part)
+  (define-key message-mode-map "\t" 'message-tab)
 
-  (define-key message-mode-map "\t" 'message-tab))
+  (define-key message-mode-map "\C-xk" 'message-mimic-kill-buffer))
 
 (easy-menu-define
  message-mode-menu message-mode-map "Message Menu."
@@ -1339,12 +1407,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)
-  (set (make-local-variable 'message-reply-buffer) nil)
+  (make-local-variable 'message-reply-buffer)
+  (setq message-reply-buffer nil)
   (make-local-variable 'message-send-actions) 
   (make-local-variable 'message-exit-actions) 
   (make-local-variable 'message-kill-actions)
@@ -1383,12 +1451,15 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (setq paragraph-separate paragraph-start)
   (make-local-variable 'message-reply-headers)
   (setq message-reply-headers nil)
-  (make-local-variable 'message-newsreader)
-  (make-local-variable 'message-mailer)
+  (make-local-variable 'message-user-agent)
   (make-local-variable 'message-post-method)
-  (set (make-local-variable 'message-sent-message-via) nil)
-  (set (make-local-variable 'message-checksum) nil)
-  (set (make-local-variable 'message-mime-part) 0)
+  (make-local-variable 'message-sent-message-via)
+  (setq message-sent-message-via nil)
+  (make-local-variable 'message-checksum)
+  (setq 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)
@@ -1413,7 +1484,6 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (setq adaptive-fill-first-line-regexp
        (concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|"
                adaptive-fill-first-line-regexp))
-  (mm-enable-multibyte)
   (run-hooks 'text-mode-hook 'message-mode-hook))
 
 \f
@@ -1514,8 +1584,7 @@ With the prefix argument FORCE, insert the header anyway."
   (let ((co (message-fetch-reply-field "mail-copies-to")))
     (when (and (null force)
               co
-              (or (equal (downcase co) "never")
-                  (equal (downcase co) "nobody")))
+              (equal (downcase co) "never"))
       (error "The user has requested not to have copies sent via mail")))
   (when (and (message-position-on-field "To")
             (mail-fetch-field "to")
@@ -1650,10 +1719,9 @@ text was killed."
     ;; Then we translate the region.  Do it this way to retain
     ;; text properties.
     (while (< b e)
-      (when (< (char-after b) 255)
-       (subst-char-in-region
-        b (1+ b) (char-after b)
-        (aref message-caesar-translation-table (char-after b))))
+      (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)
@@ -1777,6 +1845,29 @@ 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)
+    (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))))))
+    refs-list))
+
+(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.
@@ -1786,13 +1877,45 @@ 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."
   (interactive "P")
-  (let ((modified (buffer-modified-p)))
-    (when (and message-reply-buffer
+  (let ((modified (buffer-modified-p))
+       (buffer (message-eval-parameter message-reply-buffer))
+       refs)
+    (when (and buffer
               message-cite-function)
-      (delete-windows-on message-reply-buffer t)
-      (insert-buffer message-reply-buffer)
+      (delete-windows-on buffer t)
+      (insert-buffer buffer) ; mark will be set at the end of article.
+
+      ;; Add new IDs to References field.
+      (when (and message-yank-add-new-references (interactive-p))
+       (save-excursion
+         (save-restriction
+           (narrow-to-region (point) (mark t))
+           (std11-narrow-to-header)
+           (when (setq refs (message-list-references
+                             '()
+                             (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)
@@ -1906,11 +2029,18 @@ 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")
   (let ((buf (current-buffer))
-       (actions message-exit-actions))
+       (actions message-exit-actions)
+       (frame (selected-frame))
+       (org-frame message-original-frame))
     (when (and (message-send arg)
               (buffer-name buf))
       (if message-kill-buffer-on-exit
@@ -1919,6 +2049,7 @@ 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)
       t)))
 
 (defun message-dont-send ()
@@ -1926,19 +2057,62 @@ 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."
   (interactive)
   (when (or (not (buffer-modified-p))
-           (yes-or-no-p "Message modified; kill anyway? "))
-    (let ((actions message-kill-actions))
+           (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-do-actions actions)
+      (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)
+                     (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."
@@ -1957,42 +2131,55 @@ or error messages, and inform user.
 Otherwise any failure is reported in a message back to
 the user from the mailer."
   (interactive "P")
-  ;; 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))
-  (message-fix-before-sending)
-  (run-hooks 'message-send-hook)
-  (message "Sending...")
-  (let ((alist message-send-method-alist)
-       (success t)
-       elem sent)
-    (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 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)
-      ;; Return success.
-      t)))
+  ;; 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 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)
+       ;; Return success.
+       t))))
 
 (defun message-send-via-mail (arg)
   "Send the current message via mail."
@@ -2000,16 +2187,7 @@ the user from the mailer."
 
 (defun message-send-via-news (arg)
   "Send the current message via news."
-  (funcall message-send-news-function 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))
+  (message-send-news arg))
 
 (defun message-fix-before-sending ()
   "Do various things to make the message nice before sending it."
@@ -2017,12 +2195,12 @@ the user from the mailer."
   (goto-char (point-max))
   (unless (bolp)
     (insert "\n"))
-  ;; Delete all invisible text.
-  (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")))))
+  ;; Make all invisible text visible.
+  ;;(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."
@@ -2045,48 +2223,97 @@ 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))
-       (mailbuf (current-buffer)))
+       failure)
     (save-restriction
       (message-narrow-to-headers)
       ;; Insert some headers.
       (let ((message-deletable-headers
             (if news nil message-deletable-headers)))
        (message-generate-headers message-required-mail-headers))
-      (mail-encode-encoded-word-buffer)
       ;; Let the user do all of the above.
-      (run-hooks 'message-header-hook))
-    (message-encode-message-body)
-    (unwind-protect
-       (save-excursion
-         (set-buffer tembuf)
-         (erase-buffer)
-         ;; Avoid copying text props.
-         (insert (format
-                  "%s" (save-excursion
-                         (set-buffer mailbuf)
-                         (buffer-string))))
-         ;; Remove some headers.
-         (save-restriction
-           (message-narrow-to-headers)
+      (run-hooks 'message-header-hook)
+      (when (functionp message-header-encode-function)
+       (funcall message-header-encode-function))
+      (run-hooks 'message-header-encoded-hook))
+    (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))
-         (funcall message-send-mail-function))
-      (kill-buffer tembuf))
-    (set-buffer mailbuf)
-    (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 (eq (char-before) ?\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."
@@ -2115,31 +2342,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)
@@ -2164,28 +2391,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)
@@ -2212,13 +2439,72 @@ to find out how to use this."
     ;; Pass it on to mh.
     (mh-send-letter)))
 
+(defun message-send-mail-with-smtp ()
+  "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*"))
        (case-fold-search nil)
        (method (if (message-functionp message-post-method)
                    (funcall message-post-method arg)
                  message-post-method))
-       (messbuf (current-buffer))
        (message-syntax-checks
         (if arg
             (cons '(existing-newsgroups . disabled)
@@ -2229,23 +2515,20 @@ to find out how to use this."
       (message-narrow-to-headers)
       ;; Insert some headers.
       (message-generate-headers message-required-news-headers)
-      (mail-encode-encoded-word-buffer)
       ;; Let the user do all of the above.
-      (run-hooks 'message-header-hook))
+      (run-hooks 'message-header-hook)
+      (when (functionp message-header-encode-function)
+       (funcall message-header-encode-function))
+      (run-hooks 'message-header-encoded-hook))
     (message-cleanup-headers)
     (if (not (message-check-news-syntax))
        nil
-      (message-encode-message-body)
       (unwind-protect
          (save-excursion
            (set-buffer tembuf)
-           (buffer-disable-undo)
+           (buffer-disable-undo (current-buffer))
            (erase-buffer)
-           ;; Avoid copying text props.
-           (insert (format
-                    "%s" (save-excursion
-                           (set-buffer messbuf)
-                           (buffer-string))))
+           (insert-buffer message-encoding-buffer)
            ;; Remove some headers.
            (save-restriction
              (message-narrow-to-headers)
@@ -2253,36 +2536,51 @@ 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))
-           (let ((case-fold-search t))
-             ;; Remove the delimiter.
-             (goto-char (point-min))
-             (re-search-forward
-              (concat "^" (regexp-quote mail-header-separator) "\n"))
-             (replace-match "\n")
-             (backward-char 1))
-           (run-hooks 'message-send-news-hook)
-           ;;(require (car method))
-           ;;(funcall (intern (format "%s-open-server" (car method)))
-           ;;(cadr method) (cddr method))
-           ;;(setq result
-           ;;    (funcall (intern (format "%s-request-post" (car method)))
-           ;;             (cadr method)))
-           (gnus-open-server method)
-           (setq result (gnus-request-post method)))
+           (setq result (message-maybe-split-and-send-news method)))
        (kill-buffer tembuf))
-      (set-buffer messbuf)
+      (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)
+  (let ((case-fold-search t))
+    ;; Remove the delimiter.
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "\n"))
+    (replace-match "\n")
+    (backward-char 1)
+    (run-hooks 'message-send-news-hook)
+    ;;(require (car method))
+    ;;(funcall (intern (format "%s-open-server" (car method)))
+    ;;(cadr method) (cddr method))
+    ;;(setq result
+    ;;   (funcall (intern (format "%s-request-post" (car method)))
+    ;;            (cadr method)))
+    (gnus-open-server method)
+    (gnus-request-post method)
+    ))
 
 ;;;
 ;;; 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)
@@ -2303,7 +2601,9 @@ to find out how to use this."
           (message-narrow-to-headers)
           (message-check-news-header-syntax)))
        ;; Check the body.
-       (message-check-news-body-syntax)))))
+       (save-excursion
+        (set-buffer message-edit-buffer)
+        (message-check-news-body-syntax))))))
 
 (defun message-check-news-header-syntax ()
   (and
@@ -2515,10 +2815,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-\032\034-\037\200-\237]" nil t)
+     (if (re-search-forward "[\000-\007\013\015-\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)
@@ -2546,6 +2849,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))
@@ -2555,20 +2906,21 @@ 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)
-                           (char-after))))
+         (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)
-       (buf (current-buffer))
+       (coding-system-for-write 'raw-text)
        list file)
     (save-excursion
       (set-buffer (get-buffer-create " *message temp*"))
+      (buffer-disable-undo (current-buffer))
       (erase-buffer)
-      (insert-buffer-substring buf)
+      (insert-buffer-substring message-encoding-buffer)
       (save-restriction
        (message-narrow-to-headers)
        (while (setq file (message-fetch-field "fcc"))
@@ -2603,7 +2955,7 @@ to find out how to use this."
   "Append this article to Unix/babyl mail file.."
   (if (and (file-readable-p filename)
           (mail-file-babyl-p filename))
-      (rmail-output-to-rmail-file filename t)
+      (gnus-output-to-rmail filename t)
     (gnus-output-to-mail filename t)))
 
 (defun message-cleanup-headers ()
@@ -2638,24 +2990,11 @@ to find out how to use this."
        (when (re-search-forward ",+$" nil t)
          (replace-match "" t t))))))
 
-(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-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-message-id ()
   "Make a unique Message-ID."
@@ -2754,17 +3093,21 @@ If NOW, use that time instead."
   "Return the In-Reply-To header for this message."
   (when message-reply-headers
     (let ((from (mail-header-from message-reply-headers))
-         (date (mail-header-date message-reply-headers)))
-      (when from
-       (let ((stop-pos
-              (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
-         (concat (if (and stop-pos
-                          (not (zerop stop-pos)))
-                     (substring from 0 stop-pos) from)
-                 "'s message of \""
-                 (if (or (not date) (string= date ""))
-                     "(unknown date)" date)
-                 "\""))))))
+         (date (mail-header-date message-reply-headers))
+         (msg-id (mail-header-message-id message-reply-headers)))
+      (when msg-id
+       (concat msg-id
+               (when from
+                 (let ((stop-pos
+                        (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+                   (concat " ("
+                           (if (and stop-pos
+                                    (not (zerop stop-pos)))
+                               (substring from 0 stop-pos) from)
+                           "'s message of \""
+                           (if (or (not date) (string= date ""))
+                               "(unknown date)" date)
+                           "\")"))))))))
 
 (defun message-make-distribution ()
   "Make a Distribution header."
@@ -2780,7 +3123,9 @@ If NOW, use that time instead."
     ;; 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))))
-    (message-make-date current)))
+    ;; Return the date in the future in UT.
+    (timezone-make-date-arpa-standard
+     (current-time-string current) (current-time-zone current) '(0 "UT"))))
 
 (defun message-make-path ()
   "Return uucp path."
@@ -2902,6 +3247,24 @@ give as trustworthy answer as possible."
   (or mail-host-address
       (message-make-fqdn)))
 
+(defun message-make-user-agent ()
+  "Return user-agent info."
+  (if message-user-agent
+      (save-excursion
+       (goto-char (point-min))
+       (let ((case-fold-search t)
+             user-agent beg p end)
+         (if (re-search-forward "^User-Agent:[ \t]*" nil t)
+             (progn
+               (setq beg (match-beginning 0)
+                     p (match-end 0)
+                     end (std11-field-end)
+                     user-agent (buffer-substring p end))
+               (delete-region beg (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."
@@ -2918,7 +3281,7 @@ Headers already prepared in the buffer are not modified."
           (To nil)
           (Distribution (message-make-distribution))
           (Lines (message-make-lines))
-          (User-Agent message-newsreader)
+          (User-Agent (message-make-user-agent))
           (Expires (message-make-expires))
           (case-fold-search t)
           header value elem)
@@ -2957,7 +3320,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 (/= (char-after) ? ) (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.
@@ -3084,6 +3449,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 990)
@@ -3110,7 +3482,7 @@ Headers already prepared in the buffer are not modified."
   (let ((max 988)
        (cut 4)
        refs)
-    (with-temp-buffer
+    (nnheader-temp-write nil
       (insert references)
       (goto-char (point-min))
       (while (re-search-forward "<[^>]+>" nil t)
@@ -3150,7 +3522,7 @@ 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.
-   ((eq message-generate-new-buffers 'unique)
+   (message-generate-new-buffers
     (generate-new-buffer-name
      (concat "*" type
             (if to
@@ -3160,23 +3532,30 @@ Headers already prepared in the buffer are not modified."
               "")
             (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) "")
-            "*")))
    ;; Use standard name.
    (t
     (format "*%s message*" type))))
 
 (defun message-pop-to-buffer (name)
   "Pop to buffer NAME, and warn if it already exists and is modified."
-  (let ((buffer (get-buffer name)))
+  (let ((pop-up-frames pop-up-frames)
+       (special-display-buffer-names special-display-buffer-names)
+       (special-display-regexps special-display-regexps)
+       (same-window-buffer-names same-window-buffer-names)
+       (same-window-regexps same-window-regexps)
+       (buffer (get-buffer name))
+       (cur (current-buffer)))
+    (if (or (and (featurep 'xemacs)
+                (not (eq 'tty (device-type))))
+           window-system
+           (>= emacs-major-version 20))
+       (when message-use-multi-frames
+         (setq pop-up-frames t
+               special-display-buffer-names nil
+               special-display-regexps nil
+               same-window-buffer-names nil
+               same-window-regexps nil))
+      (setq pop-up-frames nil))
     (if (and buffer
             (buffer-name buffer))
        (progn
@@ -3187,7 +3566,10 @@ Headers already prepared in the buffer are not modified."
            (error "Message being composed")))
       (set-buffer (pop-to-buffer name)))
     (erase-buffer)
-    (message-mode)))
+    (message-mode)
+    (when pop-up-frames
+      (make-local-variable 'message-original-frame)
+      (setq message-original-frame (selected-frame)))))
 
 (defun message-do-send-housekeeping ()
   "Kill old message buffers."
@@ -3205,7 +3587,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 "\\`\\*\\(unsent \\)?" (buffer-name))
+    (when (string-match "\\`\\*" (buffer-name))
       (rename-buffer
        (concat "*sent " (substring (buffer-name) (match-end 0))) t)))
   ;; Push the current buffer onto the list.
@@ -3222,7 +3604,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 (message-get-parameter 'reply-buffer)
+           replybuffer))
   (goto-char (point-min))
   ;; Insert all the headers.
   (mail-header-format
@@ -3328,7 +3712,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.
@@ -3351,6 +3735,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)
@@ -3363,12 +3753,10 @@ OTHER-HEADERS is an alist of header/value pairs."
 
       ;; Handle special values of Mail-Copies-To.
       (when mct
-       (cond ((or (equal (downcase mct) "never")
-                  (equal (downcase mct) "nobody"))
+       (cond ((equal (downcase mct) "never")
               (setq never-mct t)
               (setq mct nil))
-             ((or (equal (downcase mct) "always")
-                  (equal (downcase mct) "poster"))
+             ((equal (downcase mct) "always")
               (setq mct (or reply-to from)))))
 
       (unless follow-to
@@ -3403,7 +3791,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
@@ -3418,7 +3809,8 @@ OTHER-HEADERS is an alist of header/value pairs."
                            (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)
@@ -3535,17 +3927,16 @@ responses here are directed to other newsgroups."))
             `((References . ,(concat (or references "") (and references " ")
                                      (or message-id "")))))
        ,@(when (and mct
-                   (not (or (equal (downcase mct) "never")
-                            (equal (downcase mct) "nobody"))))
-          (list (cons 'Cc (if (or (equal (downcase mct) "always")
-                                  (equal (downcase mct) "poster"))
+                   (not (equal (downcase mct) "never")))
+          (list (cons 'Cc (if (equal (downcase mct) "always")
                               (or reply-to from "")
                             mct)))))
 
      cur)
 
     (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 ""))))
 
 
 ;;;###autoload
@@ -3566,17 +3957,18 @@ responses here are directed to other newsgroups."))
                message-id (message-fetch-field "message-id" t)
                distribution (message-fetch-field "distribution")))
        ;; Make sure that this article was written by the user.
-       (unless (or (and sender
-                        (string-equal
-                         (downcase sender)
-                         (downcase (message-make-sender))))
-                   (string-equal
-                    (downcase (cadr (mail-extract-address-components from)))
-                    (downcase (cadr (mail-extract-address-components
-                                     (message-make-from))))))
+       (unless (or (and sender
+                        (string-equal
+                         (downcase sender)
+                         (downcase (message-make-sender))))
+                   (string-equal
+                    (downcase (cadr (mail-extract-address-components from)))
+                    (downcase (cadr (mail-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"
@@ -3589,11 +3981,17 @@ responses here are directed to other newsgroups."))
                message-cancel-message)
        (message "Canceling your article...")
        (if (let ((message-syntax-checks
-                  'dont-check-for-anything-just-trust-me))
-             (funcall message-send-news-function))
+                  'dont-check-for-anything-just-trust-me)
+                 (message-encoding-buffer (current-buffer))
+                 (message-edit-buffer (current-buffer)))
+             (message-send-news))
            (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.
@@ -3627,7 +4025,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 ()
@@ -3651,7 +4053,7 @@ 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."
-  (with-temp-buffer
+  (nnheader-temp-write nil
     (insert-string subject)
     (goto-char (point-min))
     ;; strip Re/Fwd stuff off the beginning
@@ -3705,10 +4107,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 (message-fetch-field "Subject") ""))
-                      (or (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))
@@ -3767,8 +4173,12 @@ 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)
-      (message-setup `((To . ,address)))
+      ;; avoid to turn-on-mime-edit
+      (let (message-setup-hook)
+       (message-setup `((To . ,address)))
+       )
       ;; Insert our usual headers.
       (message-generate-headers '(From Date To))
       (message-narrow-to-headers)
@@ -3799,11 +4209,16 @@ Optional NEWS will use news to forward instead of mail."
       (when (looking-at "From ")
        (replace-match "X-From-Line: "))
       ;; Send it.
-      (let (message-required-mail-headers)
+      (let ((message-encoding-buffer (current-buffer))
+           (message-edit-buffer (current-buffer)))
        (message-send-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.
@@ -3817,7 +4232,7 @@ you."
     (insert-buffer-substring cur)
     (undo-boundary)
     (message-narrow-to-head)
-    (if (and (message-fetch-field "Mime-Version")
+    (if (and (message-fetch-field "MIME-Version")
             (setq boundary (message-fetch-field "Content-Type")))
        (if (string-match "boundary=\"\\([^\"]+\\)\"" boundary)
            (setq boundary (concat (match-string 1 boundary) " *\n"
@@ -3843,6 +4258,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)))
 
 ;;;
@@ -3993,7 +4411,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)
+         (buffer-disable-undo (current-buffer))
          (let ((buffer-read-only nil))
            (erase-buffer)
            (let ((standard-output (current-buffer)))
@@ -4044,7 +4462,7 @@ regexp varstr."
   (let ((locals (save-excursion
                  (set-buffer buffer)
                  (buffer-local-variables)))
-       (regexp "^gnus\\|^nn\\|^message"))
+       (regexp "^\\(gnus\\|nn\\|message\\|user-\\(mail-address\\|full-name\\)\\)"))
     (mapcar
      (lambda (local)
        (when (and (consp local)
@@ -4055,100 +4473,301 @@ regexp varstr."
                (cdr local)))))
      locals)))
 
-;;; 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))
+;; @ For `message-mail-follow-up-address-checker'.
 
-;;;
-;;; MIME functions
+(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)
+    ))
+
+;;; @ for locale specification.
 ;;;
 
-(defun message-encode-message-body ()
-  "Examine the message body, encode it, and add the requisite headers."
-  (message-format-mime)
-  (when (featurep 'mule)
-    (let (old-headers)
-      (save-excursion
-       (save-restriction
-         (message-narrow-to-headers-or-head)
-         (unless (setq old-headers (message-fetch-field "mime-version"))
-           (message-remove-header
-            "^Content-Transfer-Encoding:\\|^Content-Type:\\|^Mime-Version:"
-            t))
-         (goto-char (point-max))
-         (widen)
-         (narrow-to-region (point) (point-max))
-         (let* ((charset (mm-encode-body))
-                (encoding (mm-body-encoding)))
-           (when (consp charset)
-             (error "Can't encode messages with multiple charsets (yet)"))
-           (widen)
-           (message-narrow-to-headers-or-head)
-           (goto-char (point-max))
-           (setq charset (or charset
-                             (mm-mule-charset-to-mime-charset 'ascii)))
-           ;; We don't insert MIME headers if they only say the default.
-           (when (and (not old-headers)
-                      (not (and (eq charset 'us-ascii)
-                                (eq encoding '7bit))))
-             (mm-insert-rfc822-headers charset encoding))
-           (mm-encode-body)))))))
-
-(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)))
-     (setq mime-type
-          (read-string (format "MIME type for %s: " file) (car type)))
-     (unless (equal mime-type (car type))
-       (setq type (list mime-type)))
-     (list file type)))
-
-  (insert (format "-*[%s %d]*-\n" (car type) (incf message-mime-part)))
-  (let ((current buffer-file-name)
-       (part message-mime-part))
-    (mm-with-unibyte-buffer
-      (insert-file file)
-      (mm-insert-headers type (mm-encode-buffer type) file)
-      (nndraft-save-mime-part current part))))
-
-(defun message-format-mime ()
-  "Insert all the MIME parts."
-  (when (not (zerop message-mime-part))
-    (message-narrow-to-headers)
-    (goto-char (point-max))
-    (let ((boundary (mm-insert-multipart-headers))
-         (current buffer-file-name))
-      (widen)
-      (forward-line 1)
-      (insert "This is a MIME message.  If you are reading this -- *phphthth*.\n\n")
-      (insert "--" boundary "\n\n")
-      (while (re-search-forward
-             "-\\*\\[\\([-a-z/A-Z0-9]+\\) \\([0-9]+\\)\\]\\*-" nil t)
-       (let ((part (string-to-number (match-string 2))))
-         (delete-region (match-beginning 0) (match-end 0))
-         (insert "\n--" boundary "\n")
-         (narrow-to-region (point) (point))
-         (nndraft-get-mime-part current part)
-         (goto-char (point-max))
-         (widen)
-         (insert "\n--" boundary "\n\n")
+(defcustom message-mime-charset-recover-function
+  'message-mime-charset-recover-by-ask
+  "A function called to recover \
+when could not found legal MIME charset for sending message."
+  :type '(radio (function-item message-mime-charset-recover-by-ask)
+               (function :tag "Other"))
+  :group 'message-sending)
+
+(defvar message-mime-charset-recover-args nil)
+(defvar message-charsets-mime-charset-alist nil)
+
+(defun message-maybe-encode ()
+  (when message-mime-mode
+    (run-hooks 'mime-edit-translate-hook))
+  (let ((locale-list (message-locale-detect)))
+    (when message-mime-mode
+      (let* ((default-mime-charset-detect-method-for-write
+              (or message-mime-charset-recover-function
+                  default-mime-charset-detect-method-for-write))
+            message-mime-charset-recover-args
+            (charsets-mime-charset-alist charsets-mime-charset-alist)
+            (message-charsets-mime-charset-alist charsets-mime-charset-alist))
+       (message-mime-charset-setup locale-list)
+       (if (catch 'mime-edit-error
+             (save-excursion
+               (mime-edit-translate-body)
+               ))
+           (error "Translation error!")
          ))
-      (goto-char (point-max))
-      (insert "\n--" boundary "--\n"))))
-    
+      (end-of-invisible)
+      (run-hooks 'mime-edit-exit-hook)
+      )))
+
+(defcustom message-locale-default nil
+  "Default locale for sending message."
+  :group 'message-sending
+  :type 'symbol)
+
+(defcustom message-locale-detect-for-mail nil
+  "*A function called to detect locale from recipient mail address."
+  :group 'message-sending
+  :type 'function)
+
+(defcustom message-locale-detect-for-news
+  'message-locale-detect-with-newsgroup-alist
+  "*A function called to detect locale from newsgroup."
+  :group 'message-sending
+  :type 'function)
+
+(defun message-locale-detect ()
+  (when (or message-locale-detect-for-news
+           message-locale-detect-for-mail)
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-head)
+       (let (lc dest)
+         (when message-locale-detect-for-news
+           (setq lc (mapcar
+                     (lambda (newsgroup)
+                       (funcall message-locale-detect-for-news
+                                (and (string-match "[^ \t]+" newsgroup)
+                                     (match-string 0 newsgroup))))
+                     (message-tokenize-header
+                      (message-fetch-field "newsgroups")))))
+         (when message-locale-detect-for-mail
+           (let ((field-list '("to" "cc" "bcc")))
+             (while (car field-list)
+               (setq lc (append
+                         lc
+                         (mapcar
+                          (lambda (address)
+                            (funcall message-locale-detect-for-mail
+                                     (car
+                                      (cdr (std11-extract-address-components
+                                            address)))))
+                          (message-tokenize-header
+                           (message-fetch-field (pop field-list)))))))))
+         (setq lc (delq nil lc))
+         (while lc
+           (setq dest (cons (car lc) dest)
+                 lc (delq (car lc) lc)))
+         (or dest
+             (and message-locale-default (list message-locale-default)))
+         )))))
+
+(defvar message-locale-newsgroup-alist
+  '(("^fj\\." . fj)
+    ))
+
+(defun message-locale-detect-with-newsgroup-alist (newsgroup)
+  (let ((rest message-locale-newsgroup-alist)
+       done)
+    (while (and (not done)
+               rest)
+      (when (string-match (car (car rest)) newsgroup)
+       (setq done (car rest)))
+      (setq rest (cdr rest)))
+    (cdr done)
+    ))
+
+(defvar message-locale-mail-address-alist nil)
+
+(defun message-locale-detect-with-mail-address-alist (address)
+  (let ((rest message-locale-mail-address-alist)
+       done)
+    (while (and (not done)
+               rest)
+      (when (string-match (car (car rest)) address)
+       (setq done (car rest)))
+      (setq rest (cdr rest)))
+    (cdr done)
+    ))
+
+(defcustom message-mime-charset-recover-ask-function
+  'message-mime-charset-recover-ask-y-or-n
+  "A function called to ask MIME charset.
+This funtion will by called from \`message-mime-charset-recover-by-ask\'."
+  :type '(radio (function-item message-mime-charset-recover-ask-y-or-n)
+               (function-item message-mime-charset-recover-ask-charset)
+               (function :tag "Other"))
+  :group 'message-sending)
+
+(defun message-mime-charset-recover-by-ask (type charsets &rest args)
+  (let* ((charsets-mime-charset-alist message-charsets-mime-charset-alist)
+        (default-charset 
+          (upcase (symbol-name
+                   (or (charsets-to-mime-charset charsets)
+                       default-mime-charset-for-write))))
+        charset)
+    (save-excursion
+      (save-restriction
+       (save-window-excursion
+         (when (eq type 'region)
+           (narrow-to-region (car args) (car (cdr args)))
+           (pop-to-buffer (current-buffer) nil t))
+         (if (setq charset (funcall message-mime-charset-recover-ask-function
+                                    default-charset charsets))
+                  (intern (downcase charset))
+           (error "Canceled.")))))))
+
+(defun message-mime-charset-recover-ask-y-or-n (default-charset charsets)
+  (or (y-or-n-p (format "MIME charset %s is selected. OK? "
+                       default-charset))
+      (error "Canceled."))
+  default-charset)
+
+(defun message-mime-charset-recover-ask-charset (default-charset charsets)
+  (let ((alist (mapcar
+               (lambda (cs)
+                 (list (upcase (symbol-name cs))))
+               (mime-charset-list)))
+       charset)
+    (while (not charset)
+      (setq charset
+           (completing-read "What MIME charset: "
+                            alist nil t default-charset))
+      (when (string= charset "")
+       (setq charset nil)))
+    charset))
+
+(defvar message-locale-mime-charsets-alist
+  '((fj . (us-ascii iso-2022-jp iso-2022-jp-2))
+    (none . nil)
+    ))
+
+(defun message-mime-charset-setup (locale-list)
+  (let (locale-cs)
+    (while (and charsets-mime-charset-alist
+               locale-list)
+      (unless (setq locale-cs
+                   (assq (car locale-list)
+                         message-locale-mime-charsets-alist))
+       (error "Unknown locale \`%s\'. Add locale to \`%s\'."
+              (car locale-list)
+              'message-locale-mime-charsets-alist))
+      (setq locale-cs (cdr locale-cs)
+           charsets-mime-charset-alist (delq nil
+                                          (mapcar
+                                           (lambda (cs)
+                                             (and (memq (cdr cs) locale-cs)
+                                                  cs))
+                                           charsets-mime-charset-alist))
+           locale-list (cdr locale-list))
+      )))
+
+;;; @ 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-parameter-with-eval 'original-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))
+      (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))
+
+(defun message-mime-encode (start end &optional orig-buf)
+  (save-restriction
+    (narrow-to-region start end)
+    (when (with-current-buffer orig-buf
+           mime-edit-mode-flag)
+      (run-hooks 'mime-edit-translate-hook)
+      (mime-edit-translate-buffer)
+      )
+    (goto-char start)
+    (and (search-forward (concat "\n" mail-header-separator "\n") nil t)
+        (replace-match "\n\n"))
+    ))
+
+(set-alist 'format-alist
+          'mime-message
+          '("MIME message."
+            "1\\(^\\)"
+            nil
+            message-mime-encode
+            t nil))
+
+(defun message-mime-setup ()
+  (turn-on-mime-edit)
+  (add-to-list 'buffer-file-format 'mime-message))
+
 (run-hooks 'message-load-hook)
 
 (provide 'message)