* message.el (message-setup-1): Don't bind the constant -forbidden-properties.
[gnus] / lisp / message.el
index 2198702..1111d2c 100644 (file)
@@ -1,7 +1,6 @@
 ;;; message.el --- composing mail and news messages
 
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1996-2011 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: mail, news
@@ -29,6 +28,7 @@
 
 ;;; Code:
 
+;; For Emacs <22.2 and XEmacs.
 (eval-and-compile
   (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
 (eval-when-compile
   :group 'message-buffers
   :type '(choice function (const nil)))
 
+(defcustom message-cite-style nil
+  "The overall style to be used when yanking cited text.
+Values are either `traditional' (cited text first),
+`top-post' (cited text at the bottom), or nil (don't override the
+individual message variables)."
+  :version "24.1"
+  :group 'message-various
+  :type '(choice (const :tag "None" :value nil)
+                (const :tag "Traditional" :value traditional)
+                (const :tag "Top-post" :value top-post)))
+
 (defcustom message-fcc-handler-function 'message-output
   "*A function called to save outgoing articles.
 This function will be called with the name of the file to store the
@@ -160,7 +171,11 @@ If this variable is nil, no such courtesy message will be added."
   :type 'regexp)
 
 (defcustom message-from-style 'default
-  "*Specifies how \"From\" headers look.
+  ;; In Emacs 24.1 this defaults to the value of `mail-from-style'
+  ;; that defaults to:
+  ;; `angles' in Emacs 22.1~23.1, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `system-default' in Emacs 23.2, and 24.1
+  "Specifies how \"From\" headers look.
 
 If nil, they contain just the return address like:
        king@grassland.com
@@ -276,14 +291,14 @@ This is a list of regexps and regexp matches."
                 regexp))
 
 (defcustom message-ignored-mail-headers
-  "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
+  "^\\([GF]cc\\|Resent-Fcc\\|Xref\\|X-Draft-From\\|X-Gnus-Agent-Meta-Information\\):"
   "*Regexp of headers to be removed unconditionally before mailing."
   :group 'message-mail
   :group 'message-headers
   :link '(custom-manual "(message)Mail Headers")
   :type 'regexp)
 
-(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-ID:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:\\|^Approved:"
+(defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-ID:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:\\|^Approved:\\|^Injection-Date:\\|^Injection-Info:"
   "*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."
@@ -305,7 +320,7 @@ any confusion."
 
 ;;; Start of variables adopted from `message-utils.el'.
 
-(defcustom message-subject-trailing-was-query 'ask
+(defcustom message-subject-trailing-was-query t
   "*What to do with trailing \"(was: <old subject>)\" in subject lines.
 If nil, leave the subject unchanged.  If it is the symbol `ask', query
 the user what do do.  In this case, the subject is matched against
@@ -313,7 +328,7 @@ the user what do do.  In this case, the subject is matched against
 `message-subject-trailing-was-query' is t, always strip the trailing
 old subject.  In this case, `message-subject-trailing-was-regexp' is
 used."
-  :version "22.1"
+  :version "24.1"
   :type '(choice (const :tag "never" nil)
                 (const :tag "always strip" t)
                 (const ask))
@@ -321,7 +336,7 @@ used."
   :group 'message-various)
 
 (defcustom message-subject-trailing-was-ask-regexp
-  "[ \t]*\\([[(]+[Ww][Aa][Ss][ \t]*.*[\])]+\\)"
+  "[ \t]*\\([[(]+[Ww][Aa][Ss]:?[ \t]*.*[])]+\\)"
   "*Regexp matching \"(was: <old subject>)\" in the subject line.
 
 The function `message-strip-subject-trailing-was' uses this regexp if
@@ -444,6 +459,10 @@ whitespace)."
   :group 'message-various)
 
 (defcustom message-interactive t
+  ;; In Emacs 24.1 this defaults to the value of `mail-interactive'
+  ;; that defaults to:
+  ;; `nil' in Emacs 22.1~22.3, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `t' in Emacs 23.1~24.1
   "Non-nil means when sending a message wait for and display errors.
 A value of nil means let mailer mail back a message to report errors."
   :version "23.2"
@@ -506,14 +525,9 @@ This is used by `message-kill-buffer'."
   :group 'message-buffers
   :type 'boolean)
 
-(defvar gnus-local-organization)
 (defcustom message-user-organization
-  (or (and (boundp 'gnus-local-organization)
-          (stringp gnus-local-organization)
-          gnus-local-organization)
-      (getenv "ORGANIZATION")
-      t)
-  "*String to be used as an Organization header.
+  (or (getenv "ORGANIZATION") t)
+  "String to be used as an Organization header.
 If t, use `message-user-organization-file'."
   :group 'message-headers
   :type '(choice string
@@ -622,9 +636,13 @@ Done before generating the new subject of a forward."
   :type 'regexp)
 
 (defcustom message-cite-prefix-regexp
+  ;; In Emacs 24.1 this defaults to the value of
+  ;; `mail-citation-prefix-regexp'; the default value varies according
+  ;; to the Emacs version.  In XEmacs 21.4 and 21.5, sendmail.el
+  ;; provides it.
   (if (string-match "[[:digit:]]" "1")
       ;; Support POSIX?  XEmacs 21.5.27 doesn't.
-      "\\([ \t]*[_.[:word:]]+>+\\|[ \t]*[]>|}]\\)+"
+      "\\([ \t]*[_.[:word:]]+>+\\|[ \t]*[]>|]\\)+"
     ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
     (let (non-word-constituents)
       (with-syntax-table text-mode-syntax-table
@@ -633,12 +651,12 @@ Done before generating the new subject of a forward."
               (if (string-match "\\w" "_")  "" "_")
               (if (string-match "\\w" ".")  "" "."))))
       (if (equal non-word-constituents "")
-         "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|}]\\)+"
+         "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|]\\)+"
        (concat "\\([ \t]*\\(\\w\\|["
                non-word-constituents
-               "]\\)+>+\\|[ \t]*[]>|}]\\)+"))))
+               "]\\)+>+\\|[ \t]*[]>|]\\)+"))))
   "*Regexp matching the longest possible citation prefix on a line."
-  :version "23.2"
+  :version "24.1"
   :group 'message-insertion
   :link '(custom-manual "(message)Insertion Variables")
   :type 'regexp
@@ -830,6 +848,9 @@ Doing so would be even more evil than leaving it out."
   :type 'boolean)
 
 (defcustom message-sendmail-envelope-from nil
+  ;; In Emacs 24.1 this defaults to the value of `mail-envelope-from'
+  ;; if it is available, or defaults to nil.  sendmail.el provides it;
+  ;; the default value is nil in all (X)Emacsen that Gnus supports.
   "*Envelope-from when sending mail with sendmail.
 If this is nil, use `user-mail-address'.  If it is the symbol
 `header', use the From: header of the message."
@@ -887,11 +908,7 @@ variable isn't used."
   ;; create a dependence to `gnus.el'.
   :type 'sexp)
 
-;; FIXME: This should be a temporary workaround until someone implements a
-;; proper solution.  If a crash happens while replying, the auto-save file
-;; will *not* have a `References:' header if `message-generate-headers-first'
-;; is nil.  See: http://article.gmane.org/gmane.emacs.gnus.general/51138
-(defcustom message-generate-headers-first '(references)
+(defcustom message-generate-headers-first nil
   "Which headers should be generated before starting to compose a message.
 If t, generate all required headers.  This can also be a list of headers to
 generate.  The variables `message-required-news-headers' and
@@ -903,7 +920,6 @@ will not have a visible effect for those headers."
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
   :type '(choice (const :tag "None" nil)
-                (const :tag "References" '(references))
                 (const :tag "All" t)
                 (repeat (sexp :tag "Header"))))
 
@@ -1007,6 +1023,10 @@ Please also read the note in the documentation of
   :group 'message-insertion)
 
 (defcustom message-yank-prefix "> "
+  ;; In Emacs 24.1 this defaults to the value of `mail-yank-prefix'
+  ;; that defaults to:
+  ;; `nil' in Emacs 22.1~23.1;
+  ;; "> " in Emacs 23.2, 24.1, XEmacs 21.4, 21.5, and SXEmacs 22.1
   "*Prefix inserted on the lines of yanked messages.
 Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
 See also `message-yank-cited-prefix' and `message-yank-empty-prefix'."
@@ -1033,6 +1053,10 @@ See also `message-yank-prefix' and `message-yank-cited-prefix'."
   :group 'message-insertion)
 
 (defcustom message-indentation-spaces 3
+  ;; In Emacs 24.1 this defaults to the value of
+  ;; `mail-indentation-spaces' that defaults to `3' in Emacs 22.1~24.1,
+  ;; and SXEmacs 22.1.  In XEmacs 21.4 and 21.5, sendmail.el provides
+  ;; it; the defalut value is `3'.
   "*Number of spaces to insert at the beginning of each cited line.
 Used by `message-yank-original' via `message-yank-cite'."
   :version "23.2"
@@ -1063,6 +1087,10 @@ point and mark around the citation text as modified."
   :group 'message-insertion)
 
 (defcustom message-signature t
+  ;; In Emacs 24.1 this defaults to the value of `mail-signature' that
+  ;; defaults to:
+  ;; `nil' in Emacs 22.1~23.1, XEmacs 21.4, 21.5, and SXEmacs 22.1;
+  ;; `t' in Emacs 23.2, and 24.1
   "*String to be inserted at the end of the message buffer.
 If t, the `message-signature-file' file will be inserted instead.
 If a function, the result from the function will be used instead.
@@ -1073,6 +1101,10 @@ If a form, the result from the form will be used instead."
   :group 'message-insertion)
 
 (defcustom message-signature-file "~/.signature"
+  ;; In Emacs 24.1 this defaults to the value of `mail-signature-file'
+  ;; that defaults to "~/.signature" in Emacs 22.1~24.1, and SXEmacs
+  ;; 22.1.  In XEmacs 21.4 and 21.5, sendmail.el provides it;
+  ;; the defalut value is "~/.signature".
   "*Name of file containing the text inserted at end of message buffer.
 Ignored if the named file doesn't exist.
 If nil, don't insert a signature.
@@ -1137,6 +1169,8 @@ It is a vector of the following headers:
 (defvar message-checksum nil)
 (defvar message-send-actions nil
   "A list of actions to be performed upon successful sending of a message.")
+(defvar message-return-action nil
+  "Action to return to the caller after sending or postphoning a message.")
 (defvar message-exit-actions nil
   "A list of actions to be performed upon exiting after sending a message.")
 (defvar message-kill-actions nil
@@ -1151,13 +1185,17 @@ It is a vector of the following headers:
   :error "All header lines must be newline terminated")
 
 (defcustom message-default-headers ""
-  "*A string containing header lines to be inserted in outgoing messages.
-It is inserted before you edit the message, so you can edit or delete
-these lines."
+  "Header lines to be inserted in outgoing messages.
+This can be set to a string containing or a function returning
+header lines to be inserted before you edit the message, so you
+can edit or delete these lines.  If set to a function, it is
+called and its result is inserted."
   :version "23.2"
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
-  :type 'message-header-lines)
+  :type '(choice
+          (message-header-lines :tag "String")
+          (function :tag "Function")))
 
 (defcustom message-default-mail-headers
   ;; Ease the transition from mail-mode to message-mode.  See bugs#4431, 5555.
@@ -1171,8 +1209,8 @@ these lines."
                   (stringp mail-archive-file-name))
              (format "FCC: %s\n" mail-archive-file-name))
          ;; Use the value of `mail-default-headers' if available.
-         ;; Note: as for Emacs 21, XEmacs 21.4 and 21.5, it is
-         ;; unavailable unless sendmail.el is loaded.
+         ;; Note: as for XEmacs 21.4 and 21.5, it is unavailable
+         ;; unless sendmail.el is loaded.
          (if (boundp 'mail-default-headers)
              mail-default-headers))
   "*A string of header lines to be inserted in outgoing mails."
@@ -1195,14 +1233,11 @@ these lines."
   (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
                         system-configuration)
           (file-readable-p "/etc/sendmail.cf")
-          (let ((buffer (get-buffer-create " *temp*")))
-            (unwind-protect
-                (with-current-buffer buffer
-                  (insert-file-contents "/etc/sendmail.cf")
-                  (goto-char (point-min))
-                  (let ((case-fold-search nil))
-                    (re-search-forward "^OR\\>" nil t)))
-              (kill-buffer buffer))))
+          (with-temp-buffer
+             (insert-file-contents "/etc/sendmail.cf")
+             (goto-char (point-min))
+             (let ((case-fold-search nil))
+               (re-search-forward "^OR\\>" nil t))))
       ;; According to RFC822, "The field-name must be composed of printable
       ;; ASCII characters (i. e., characters that have decimal values between
       ;; 33 and 126, except colon)", i. e., any chars except ctl chars,
@@ -1699,13 +1734,14 @@ functionality to work."
                 (const :tag "Never" nil)
                 (const :tag "Always" t)))
 
-(defcustom message-generate-hashcash (if (executable-find "hashcash") t)
+(defcustom message-generate-hashcash (if (executable-find "hashcash") 'opportunistic)
   "*Whether to generate X-Hashcash: headers.
 If t, always generate hashcash headers.  If `opportunistic',
 only generate hashcash headers if it can be done without the user
 waiting (i.e., only asynchronously).
 
 You must have the \"hashcash\" binary installed, see `hashcash-path'."
+  :version "24.1"
   :group 'message-headers
   :link '(custom-manual "(message)Mail Headers")
   :type '(choice (const :tag "Always" t)
@@ -2163,7 +2199,6 @@ Leading \"Re: \" is not stripped by this function.  Use the function
 
 (defun message-change-subject (new-subject)
   "Ask for NEW-SUBJECT header, append (was: <Old Subject>)."
-  ;; <URL:http://www.landfield.com/usefor/drafts/draft-ietf-usefor-useage--1.02.unpaged>
   (interactive
    (list
     (read-from-minibuffer "New subject: ")))
@@ -2651,7 +2686,6 @@ PGG manual, depending on the value of `mml2015-use'."
 
   (define-key message-mode-map "\C-a" 'message-beginning-of-line)
   (define-key message-mode-map "\t" 'message-tab)
-  (define-key message-mode-map "\M-;" 'comment-region)
 
   (define-key message-mode-map "\M-n" 'message-display-abbrev))
 
@@ -2877,6 +2911,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
   (set (make-local-variable 'message-reply-buffer) nil)
   (set (make-local-variable 'message-inserted-headers) nil)
   (set (make-local-variable 'message-send-actions) nil)
+  (set (make-local-variable 'message-return-action) nil)
   (set (make-local-variable 'message-exit-actions) nil)
   (set (make-local-variable 'message-kill-actions) nil)
   (set (make-local-variable 'message-postpone-actions) nil)
@@ -2928,6 +2963,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
          (mail-aliases-setup))))
    ((message-mail-alias-type-p 'ecomplete)
     (ecomplete-setup)))
+  (add-hook 'completion-at-point-functions 'message-completion-function nil t)
   (unless buffer-file-name
     (message-set-auto-save-file-name))
   (unless (buffer-base-buffer)
@@ -3056,10 +3092,22 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
   (interactive)
   (message-position-on-field "Summary" "Subject"))
 
-(defun message-goto-body (&optional interactivep)
+(eval-when-compile
+  (defmacro message-called-interactively-p (kind)
+    (condition-case nil
+       (progn
+         (eval '(called-interactively-p 'any))
+         ;; Emacs >=23.2
+         `(called-interactively-p ,kind))
+      ;; Emacs <23.2
+      (wrong-number-of-arguments '(called-interactively-p))
+      ;; XEmacs
+      (void-function '(interactive-p)))))
+
+(defun message-goto-body ()
   "Move point to the beginning of the message body."
-  (interactive (list t))
-  (when (and interactivep
+  (interactive)
+  (when (and (message-called-interactively-p 'any)
             (looking-at "[ \t]*\n"))
     (expand-abbrev))
   (goto-char (point-min))
@@ -3068,7 +3116,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
 
 (defun message-in-body-p ()
   "Return t if point is in the message body."
-  (let ((body (save-excursion (message-goto-body) (point))))
+  (let ((body (save-excursion (message-goto-body))))
     (>= (point) body)))
 
 (defun message-goto-eoh ()
@@ -3956,11 +4004,9 @@ The text will also be indented the normal way."
        (actions message-exit-actions))
     (when (and (message-send arg)
               (buffer-name buf))
+      (message-bury buf)
       (if message-kill-buffer-on-exit
-         (kill-buffer buf)
-       (bury-buffer buf)
-       (when (eq buf (current-buffer))
-         (message-bury buf)))
+         (kill-buffer buf))
       (message-do-actions actions)
       t)))
 
@@ -4010,9 +4056,8 @@ Instead, just auto-save the buffer and then bury it."
   "Bury this mail BUFFER."
   (let ((newbuf (other-buffer buffer)))
     (bury-buffer buffer)
-    (if (and (window-dedicated-p (selected-window))
-            (not (null (delq (selected-frame) (visible-frame-list)))))
-       (delete-frame (selected-frame))
+    (if message-return-action
+       (apply (car message-return-action) (cdr message-return-action))
       (switch-to-buffer newbuf))))
 
 (defun message-send (&optional arg)
@@ -4132,7 +4177,6 @@ not have PROP."
     (nreverse regions)))
 
 (defcustom message-bogus-addresses
-  ;; '("noreply" "nospam" "invalid")
   '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
   "List of regexps of potentially bogus mail addresses.
 See `message-check-recipients' how to setup checking.
@@ -4218,7 +4262,7 @@ conformance."
                 (?r ,(format
                       "Replace non-printable characters with \"%s\" and send"
                       message-replacement-char))
-                (?i "Ignore non-printable characters and send")
+                (?s "Send as is without removing anything")
                 (?e "Continue editing"))))
        (if (eq choice ?e)
          (error "Non-printable characters"))
@@ -4262,9 +4306,10 @@ matching entry in `message-bogus-addresses'."
   ;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
   (let (found)
     (mapc (lambda (address)
-           (setq address (cadr address))
+           (setq address (or (cadr address) ""))
            (when
-               (or (not
+               (or (string= "" address)
+                    (not
                     (or
                      (not (string-match "@" address))
                      (string-match
@@ -4278,7 +4323,7 @@ matching entry in `message-bogus-addresses'."
                                               "\\|")
                                  message-bogus-addresses)))
                           (string-match re address))))
-                        (push address found)))
+              (push address found)))
          ;;
          (mail-extract-address-components recipients t))
     found))
@@ -4297,7 +4342,17 @@ This function could be useful in `message-setup-hook'."
            (and bog
                 (not (y-or-n-p
                       (format
-                       "Address `%s' might be bogus.  Continue? " bog)))
+                       "Address `%s'%s might be bogus.  Continue? "
+                       bog
+                       ;; If the encoded version of the email address
+                       ;; is different from the unencoded version,
+                       ;; then we likely have invisible characters or
+                       ;; the like.  Display the encoded version,
+                       ;; too.
+                       (let ((encoded (rfc2047-encode-string bog)))
+                         (if (string= encoded bog)
+                             ""
+                           (format " (%s)" encoded))))))
                 (error "Bogus address"))))))))
 
 (custom-add-option 'message-setup-hook 'message-check-recipients)
@@ -4340,7 +4395,7 @@ This function could be useful in `message-setup-hook'."
        (tembuf (message-generate-new-buffer-clone-locals " message temp"))
        (curbuf (current-buffer))
        (id (message-make-message-id)) (n 1)
-       plist total  header required-mail-headers)
+        plist total header)
     (while (not (eobp))
       (if (< (point-max) (+ p message-send-mail-partially-limit))
          (goto-char (point-max))
@@ -4491,6 +4546,8 @@ This function could be useful in `message-setup-hook'."
              (save-restriction
                (message-narrow-to-headers)
                (and news
+                    (not (message-fetch-field "List-Post"))
+                    (not (message-fetch-field "List-ID"))
                     (or (message-fetch-field "cc")
                         (message-fetch-field "bcc")
                         (message-fetch-field "to"))
@@ -4507,7 +4564,9 @@ This function could be useful in `message-setup-hook'."
                         (string= "base64"
                                  (message-fetch-field
                                   "content-transfer-encoding")))))))
-           (message-insert-courtesy-copy))
+           (message-insert-courtesy-copy
+            (with-current-buffer mailbuf
+              message-courtesy-message)))
           ;; Let's make sure we encoded all the body.
           (assert (save-excursion
                     (goto-char (point-min))
@@ -4668,6 +4727,8 @@ to find out how to use this."
     ;; should never happen
     (t   (error "qmail-inject reported unknown failure"))))
 
+(defvar mh-previous-window-config)
+
 (defun message-send-mail-with-mh ()
   "Send the prepared message buffer with mh."
   (let ((mh-previous-window-config nil)
@@ -4888,8 +4949,7 @@ Otherwise, generate and save a value for `canlock-password' first."
        t))
    ;; Check long header lines.
    (message-check 'long-header-lines
-     (let ((start (point))
-          (header nil)
+     (let ((header nil)
           (length 0)
           found)
        (while (and (not found)
@@ -4898,7 +4958,6 @@ Otherwise, generate and save a value for `canlock-password' first."
             (setq found t
                   length (- (point) (match-beginning 0)))
           (setq header (match-string-no-properties 1)))
-        (setq start (match-beginning 0))
         (forward-line 1))
        (if found
           (y-or-n-p (format "Your %s header is too long (%d).  Really post? "
@@ -5321,8 +5380,14 @@ Otherwise, generate and save a value for `canlock-password' first."
 
 (defun message-output (filename)
   "Append this article to Unix/babyl mail file FILENAME."
-  (if (and (file-readable-p filename)
-          (mail-file-babyl-p filename))
+  (if (or (and (file-readable-p filename)
+              (mail-file-babyl-p filename))
+         ;; gnus-output-to-mail does the wrong thing with live, mbox
+         ;; Rmail buffers in Emacs 23.
+         ;; http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597255
+         (let ((buff (find-buffer-visiting filename)))
+           (and buff (with-current-buffer buff
+                       (eq major-mode 'rmail-mode)))))
       (gnus-output-to-rmail filename t)
     (gnus-output-to-mail filename t)))
 
@@ -5735,14 +5800,16 @@ subscribed address (and not the additional To and Cc header contents)."
 (defun message-idna-to-ascii-rhs-1 (header)
   "Interactively potentially IDNA encode domain names in HEADER."
   (let ((field (message-fetch-field header))
-       rhs ace  address)
+        ace)
     (when field
       (dolist (rhs
               (mm-delete-duplicates
                (mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
                        (mapcar 'downcase
                                (mapcar
-                                'cadr
+                                (lambda (elem)
+                                  (or (cadr elem)
+                                      ""))
                                 (mail-extract-address-components field t))))))
        ;; Note that `rhs' will be "" if the address does not have
        ;; the domain part, i.e., if it is a local user's address.
@@ -5782,6 +5849,21 @@ See `message-idna-encode'."
        (message-idna-to-ascii-rhs-1 "Mail-Followup-To")
        (message-idna-to-ascii-rhs-1 "Cc")))))
 
+(defvar Date)
+(defvar Message-ID)
+(defvar Organization)
+(defvar From)
+(defvar Path)
+(defvar Subject)
+(defvar Newsgroups)
+(defvar In-Reply-To)
+(defvar References)
+(defvar To)
+(defvar Distribution)
+(defvar Lines)
+(defvar User-Agent)
+(defvar Expires)
+
 (defun message-generate-headers (headers)
   "Prepare article HEADERS.
 Headers already prepared in the buffer are not modified."
@@ -5940,7 +6022,7 @@ Headers already prepared in the buffer are not modified."
       ;; Check for IDNA
       (message-idna-to-ascii-rhs))))
 
-(defun message-insert-courtesy-copy ()
+(defun message-insert-courtesy-copy (message)
   "Insert a courtesy message in mail copies of combined messages."
   (let (newsgroups)
     (save-excursion
@@ -5950,12 +6032,12 @@ Headers already prepared in the buffer are not modified."
          (goto-char (point-max))
          (insert "Posted-To: " newsgroups "\n")))
       (forward-line 1)
-      (when message-courtesy-message
+      (when message
        (cond
-        ((string-match "%s" message-courtesy-message)
-         (insert (format message-courtesy-message newsgroups)))
+        ((string-match "%s" message)
+         (insert (format message newsgroups)))
         (t
-         (insert message-courtesy-message)))))))
+         (insert message)))))))
 
 ;;;
 ;;; Setting up a message buffer
@@ -6055,6 +6137,7 @@ If the current line has `message-yank-prefix', insert it on the new line."
 When sending via news, also check that the REFERENCES are less
 than 988 characters long, and if they are not, trim them until
 they are."
+  ;; 21 is the number suggested by USEAGE.
   (let ((maxcount 21)
        (count 0)
        (cut 2)
@@ -6291,11 +6374,11 @@ between beginning of field and beginning of line."
 ;; YANK-ACTION, if non-nil, can be a buffer or a yank action of the
 ;; form (FUNCTION . ARGS).
 (defun message-setup (headers &optional yank-action actions
-                             continue switch-function)
+                             continue switch-function return-action)
   (let ((mua (message-mail-user-agent))
        subject to field)
     (if (not (and message-this-is-mail mua))
-       (message-setup-1 headers yank-action actions)
+       (message-setup-1 headers yank-action actions return-action)
       (setq headers (copy-sequence headers))
       (setq field (assq 'Subject headers))
       (when field
@@ -6343,11 +6426,12 @@ are not included."
        (push header result)))
     (nreverse result)))
 
-(defun message-setup-1 (headers &optional yank-action actions)
+(defun message-setup-1 (headers &optional yank-action actions return-action)
   (dolist (action actions)
     (condition-case nil
        (add-to-list 'message-send-actions
                     `(apply ',(car action) ',(cdr action)))))
+  (setq message-return-action return-action)
   (setq message-reply-buffer
        (if (and (consp yank-action)
                 (eq (car yank-action) 'insert-buffer))
@@ -6366,32 +6450,39 @@ are not included."
    headers)
   (delete-region (point) (progn (forward-line -1) (point)))
   (when message-default-headers
-    (insert message-default-headers)
+    (insert
+     (if (functionp message-default-headers)
+         (funcall message-default-headers)
+       message-default-headers))
     (or (bolp) (insert ?\n)))
-  (insert mail-header-separator "\n")
+  (insert (propertize (concat mail-header-separator "\n")
+                     'read-only t 'rear-nonsticky t 'intangible t))
   (forward-line -1)
-  (when (message-news-p)
-    (when message-default-news-headers
-      (insert message-default-news-headers)
-      (or (bolp) (insert ?\n)))
-    (when message-generate-headers-first
+  ;; If a crash happens while replying, the auto-save file would *not* have a
+  ;; `References:' header if `message-generate-headers-first' was nil.
+  ;; Therefore, always generate it first.
+  (let ((message-generate-headers-first
+         (append message-generate-headers-first '(References))))
+    (when (message-news-p)
+      (when message-default-news-headers
+        (insert message-default-news-headers)
+        (or (bolp) (insert ?\n)))
       (message-generate-headers
        (message-headers-to-generate
-       (append message-required-news-headers
-               message-required-headers)
-       message-generate-headers-first
-       '(Lines Subject)))))
-  (when (message-mail-p)
-    (when message-default-mail-headers
-      (insert message-default-mail-headers)
-      (or (bolp) (insert ?\n)))
-    (when message-generate-headers-first
+        (append message-required-news-headers
+                message-required-headers)
+        message-generate-headers-first
+        '(Lines Subject))))
+    (when (message-mail-p)
+      (when message-default-mail-headers
+        (insert message-default-mail-headers)
+        (or (bolp) (insert ?\n)))
       (message-generate-headers
        (message-headers-to-generate
-       (append message-required-mail-headers
-               message-required-headers)
-       message-generate-headers-first
-       '(Lines Subject)))))
+        (append message-required-mail-headers
+                message-required-headers)
+        message-generate-headers-first
+        '(Lines Subject)))))
   (run-hooks 'message-signature-setup-hook)
   (message-insert-signature)
   (save-restriction
@@ -6473,9 +6564,9 @@ are not included."
 ;;;
 
 ;;;###autoload
-(defun message-mail (&optional to subject
-                              other-headers continue switch-function
-                              yank-action send-actions)
+(defun message-mail (&optional to subject other-headers continue
+                              switch-function yank-action send-actions
+                              return-action &rest ignored)
   "Start editing a mail message to be sent.
 OTHER-HEADERS is an alist of header/value pairs.  CONTINUE says whether
 to continue editing a message already being composed.  SWITCH-FUNCTION
@@ -6495,10 +6586,15 @@ is a function used to switch to and display the mail buffer."
     (message-setup
      (nconc
       `((To . ,(or to "")) (Subject . ,(or subject "")))
-      (when other-headers other-headers))
-     yank-action send-actions continue switch-function)
-    ;; FIXME: Should return nil if failure.
-    t))
+      ;; C-h f compose-mail says that headers should be specified as
+      ;; (string . value); however all the rest of message expects
+      ;; headers to be symbols, not strings (eg message-header-format-alist).
+      ;; http://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html
+      ;; We need to convert any string input, eg from rmail-start-mail.
+      (dolist (h other-headers other-headers)
+       (if (stringp (car h)) (setcar h (intern (capitalize (car h)))))))
+     yank-action send-actions continue switch-function
+     return-action)))
 
 ;;;###autoload
 (defun message-news (&optional newsgroups subject)
@@ -6571,6 +6667,10 @@ The function is called with one parameter, a cons cell ..."
     (save-match-data
       ;; Build (textual) list of new recipient addresses.
       (cond
+       (to-address
+       (setq recipients (concat ", " to-address))
+       ;; If the author explicitly asked for a copy, we don't deny it to them.
+       (if mct (setq recipients (concat recipients ", " mct))))
        ((not wide)
        (setq recipients (concat ", " author)))
        (address-headers
@@ -6606,10 +6706,6 @@ responses here are directed to other addresses.
 You may customize the variable `message-use-mail-followup-to', if you
 want to get rid of this query permanently.")))
        (setq recipients (concat ", " mft)))
-       (to-address
-       (setq recipients (concat ", " to-address))
-       ;; If the author explicitly asked for a copy, we don't deny it to them.
-       (if mct (setq recipients (concat recipients ", " mct))))
        (t
        (setq recipients (if never-mct "" (concat ", " author)))
        (if to (setq recipients (concat recipients ", " to)))
@@ -6730,7 +6826,7 @@ Useful functions to put in this list include:
   (interactive)
   (require 'gnus-sum)                  ; for gnus-list-identifiers
   (let ((cur (current-buffer))
-       from subject date reply-to to cc
+       from subject date
        references message-id follow-to
        (inhibit-point-motion-hooks t)
        (message-this-is-mail t)
@@ -7251,11 +7347,9 @@ Optional DIGEST will use digest to forward."
 (defun message-forward-make-body-digest-plain (forward-buffer)
   (insert
    "\n-------------------- Start of forwarded message --------------------\n")
-  (let ((b (point)) e)
-    (mml-insert-buffer forward-buffer)
-    (setq e (point))
-    (insert
-     "\n-------------------- End of forwarded message --------------------\n")))
+  (mml-insert-buffer forward-buffer)
+  (insert
+   "\n-------------------- End of forwarded message --------------------\n"))
 
 (defun message-forward-make-body-digest-mime (forward-buffer)
   (insert "\n<#multipart type=digest>\n")
@@ -7375,6 +7469,8 @@ is for the internal use."
   (setq rmail-insert-mime-forwarded-message-function
        'message-forward-rmail-make-body))
 
+(defvar message-inhibit-body-encoding nil)
+
 ;;;###autoload
 (defun message-resend (address)
   "Resend the current article to ADDRESS."
@@ -7425,7 +7521,11 @@ is for the internal use."
       (when (looking-at "From ")
        (replace-match "X-From-Line: "))
       ;; Send it.
-      (let ((message-inhibit-body-encoding t)
+      (let ((message-inhibit-body-encoding
+            ;; Don't do any further encoding if it looks like the
+            ;; message has already been encoded.
+            (let ((case-fold-search t))
+              (re-search-forward "^mime-version:" nil t)))
            (message-inhibit-ecomplete t)
            message-required-mail-headers
            message-generate-hashcash
@@ -7622,24 +7722,22 @@ Pre-defined symbols include `message-tool-bar-gnome' and
 
 (defcustom message-tool-bar-gnome
   '((ispell-message "spell" nil
+                   :vert-only t
                    :visible (or (not (boundp 'flyspell-mode))
                                 (not flyspell-mode)))
     (flyspell-buffer "spell" t
+                    :vert-only t
                     :visible (and (boundp 'flyspell-mode)
                                   flyspell-mode)
                     :help "Flyspell whole buffer")
-    (gmm-ignore "separator")
-    (message-send-and-exit "mail/send")
+    (message-send-and-exit "mail/send" t :label "Send")
     (message-dont-send "mail/save-draft")
-    (message-kill-buffer "close") ;; stock_cancel
-    (mml-attach-file "attach" mml-mode-map)
+    (mml-attach-file "attach" mml-mode-map :vert-only t)
     (mml-preview "mail/preview" mml-mode-map)
     (mml-secure-message-sign-encrypt "lock" mml-mode-map :visible nil)
     (message-insert-importance-high "important" nil :visible nil)
     (message-insert-importance-low "unimportant" nil :visible nil)
-    (message-insert-disposition-notification-to "receipt" nil :visible nil)
-    (gmm-customize-mode "preferences" t :help "Edit mode preferences")
-    (message-info "help" t :help "Message manual"))
+    (message-insert-disposition-notification-to "receipt" nil :visible nil))
   "List of items for the message tool bar (GNOME style).
 
 See `gmm-tool-bar-from-list' for details on the format of the list."
@@ -7725,7 +7823,7 @@ When FORCE, rebuild the tool bar."
   :type '(alist :key-type regexp :value-type function))
 
 (defcustom message-expand-name-databases
-  (list 'bbdb 'eudc)
+  '(bbdb eudc)
   "List of databases to try for name completion (`message-expand-name').
 Each element is a symbol and can be `bbdb' or `eudc'."
   :group 'message
@@ -7747,15 +7845,27 @@ If nil, the function bound in `text-mode-map' or `global-map' is executed."
 Execute function specified by `message-tab-body-function' when not in
 those headers."
   (interactive)
+  (cond
+   ((if (and (boundp 'completion-fail-discreetly)
+             (fboundp 'completion-at-point))
+        (let ((completion-fail-discreetly t)) (completion-at-point))
+      (funcall (or (message-completion-function) #'ignore)))
+    ;; Completion was performed; nothing else to do.
+    nil)
+   (message-tab-body-function (funcall message-tab-body-function))
+   (t (funcall (or (lookup-key text-mode-map "\t")
+                   (lookup-key global-map "\t")
+                   'indent-relative)))))
+
+(defvar mail-abbrev-mode-regexp)
+
+(defun message-completion-function ()
   (let ((alist message-completion-alist))
     (while (and alist
                (let ((mail-abbrev-mode-regexp (caar alist)))
                  (not (mail-abbrev-in-expansion-header-p))))
       (setq alist (cdr alist)))
-    (funcall (or (cdar alist) message-tab-body-function
-                (lookup-key text-mode-map "\t")
-                (lookup-key global-map "\t")
-                'indent-relative))))
+    (cdar alist)))
 
 (eval-and-compile
   (condition-case nil
@@ -7826,7 +7936,12 @@ those headers."
         (eudc-expand-inline))
        ((and (memq 'bbdb message-expand-name-databases)
              (fboundp 'bbdb-complete-name))
-        (bbdb-complete-name))
+         (let ((starttick (buffer-modified-tick)))
+           (or (bbdb-complete-name)
+               ;; Apparently, bbdb-complete-name can return nil even when
+               ;; completion took place.  So let's double check the buffer was
+               ;; not modified.
+               (/= starttick (buffer-modified-tick)))))
        (t
         (expand-abbrev))))
 
@@ -7887,8 +8002,6 @@ regexp VARSTR."
 ;;; MIME functions
 ;;;
 
-(defvar message-inhibit-body-encoding nil)
-
 (defun message-encode-message-body ()
   (unless message-inhibit-body-encoding
     (let ((mail-parse-charset (or mail-parse-charset