Merge remote branch 'origin/no-gnus'
[gnus] / lisp / message.el
index 40c4577..0a8feb6 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-2012 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
@@ -49,6 +49,7 @@
 (require 'mail-parse)
 (require 'mml)
 (require 'rfc822)
+(require 'format-spec)
 
 (autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
 
@@ -160,7 +161,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 +281,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 +310,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 +318,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 +326,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
@@ -438,12 +443,19 @@ whitespace)."
   :group 'message-various)
 
 (defcustom message-elide-ellipsis "\n[...]\n\n"
-  "*The string which is inserted for elided text."
+  "*The string which is inserted for elided text.
+This is a format-spec string, and you can use %l to say how many
+lines were removed, and %c to say how many characters were
+removed."
   :type 'string
   :link '(custom-manual "(message)Various Commands")
   :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 +518,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,27 +629,25 @@ Done before generating the new subject of a forward."
   :type 'regexp)
 
 (defcustom message-cite-prefix-regexp
-  ;; Default to the value of `mail-citation-prefix-regexp' if available.
-  ;; Note: as for XEmacs 21.4 and 21.5, it is unavailable unless sendmail.el
-  ;; is loaded.
-  (cond ((boundp 'mail-citation-prefix-regexp)
-        mail-citation-prefix-regexp)
-       ((string-match "[[:digit:]]" "1")
-        ;; Support POSIX?  XEmacs 21.5.27 doesn't.
-        "\\([ \t]*[_.[:word:]]+>+\\|[ \t]*[]>|}]\\)+")
-       (t
-        ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
-        (let (non-word-constituents)
-          (with-syntax-table text-mode-syntax-table
-            (setq non-word-constituents
-                  (concat
-                   (if (string-match "\\w" "_")  "" "_")
-                   (if (string-match "\\w" ".")  "" "."))))
-          (if (equal non-word-constituents "")
-              "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|}]\\)+"
-            (concat "\\([ \t]*\\(\\w\\|["
-                    non-word-constituents
-                    "]\\)+>+\\|[ \t]*[]>|}]\\)+")))))
+  ;; 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]*[]>|]\\)+"
+    ;; ?-, ?_ or ?. MUST NOT be in syntax entry w.
+    (let (non-word-constituents)
+      (with-syntax-table text-mode-syntax-table
+       (setq non-word-constituents
+             (concat
+              (if (string-match "\\w" "_")  "" "_")
+              (if (string-match "\\w" ".")  "" "."))))
+      (if (equal non-word-constituents "")
+         "\\([ \t]*\\(\\w\\)+>+\\|[ \t]*[]>|]\\)+"
+       (concat "\\([ \t]*\\(\\w\\|["
+               non-word-constituents
+               "]\\)+>+\\|[ \t]*[]>|]\\)+"))))
   "*Regexp matching the longest possible citation prefix on a line."
   :version "24.1"
   :group 'message-insertion
@@ -677,13 +682,16 @@ Done before generating the new subject of a forward."
        (t
         (error "Don't know how to send mail.  Please customize `message-send-mail-function'"))))
 
-;; Useful to set in site-init.el
-(defcustom message-send-mail-function
+(defun message-default-send-mail-function ()
   (cond ((eq send-mail-function 'smtpmail-send-it) 'message-smtpmail-send-it)
        ((eq send-mail-function 'feedmail-send-it) 'feedmail-send-it)
+       ((eq send-mail-function 'sendmail-query-once) 'sendmail-query-once)
        ((eq send-mail-function 'mailclient-send-it)
         'message-send-mail-with-mailclient)
-       (t (message-send-mail-function)))
+       (t (message-send-mail-function))))
+
+;; Useful to set in site-init.el
+(defcustom message-send-mail-function (message-default-send-mail-function)
   "Function to call to send the current buffer as mail.
 The headers should be delimited by a line whose contents match the
 variable `mail-header-separator'.
@@ -836,6 +844,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."
@@ -893,11 +904,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
@@ -909,7 +916,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"))))
 
@@ -930,7 +936,7 @@ The function `message-setup' runs this hook."
   :type 'hook)
 
 (defcustom message-cancel-hook nil
-  "Hook run when cancelling articles."
+  "Hook run when canceling articles."
   :group 'message-various
   :link '(custom-manual "(message)Various Message Variables")
   :type 'hook)
@@ -1013,6 +1019,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'."
@@ -1039,6 +1049,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"
@@ -1069,6 +1083,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.
@@ -1079,6 +1097,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.
@@ -1106,6 +1128,72 @@ needed."
   :link '(custom-manual "(message)Insertion Variables")
   :group 'message-insertion)
 
+(defcustom message-cite-reply-position 'traditional
+  "*Where the reply should be positioned.
+If `traditional', reply inline.
+If `above', reply above quoted text.
+If `below', reply below quoted text.
+
+Note: Many newsgroups frown upon nontraditional reply styles. You
+probably want to set this variable only for specific groups,
+e.g. using `gnus-posting-styles':
+
+  (eval (set (make-local-variable 'message-cite-reply-position) 'above))"
+  :version "24.1"
+  :type '(choice (const :tag "Reply inline" 'traditional)
+                (const :tag "Reply above" 'above)
+                (const :tag "Reply below" 'below))
+  :group 'message-insertion)
+
+(defcustom message-cite-style nil
+  "*The overall style to be used when yanking cited text.
+Value is either `nil' (no variable overrides) or a let-style list
+of pairs (VARIABLE VALUE) that will be bound in
+`message-yank-original' to do the quoting.
+
+Presets to impersonate popular mail agents are found in the
+message-cite-style-* variables.  This variable is intended for
+use in `gnus-posting-styles', such as:
+
+  ((posting-from-work-p) (eval (set (make-local-variable 'message-cite-style) message-cite-style-outlook)))"
+  :version "24.1"
+  :group 'message-insertion
+  :type '(choice (const :tag "Do not override variables" :value nil)
+                (const :tag "MS Outlook" :value message-cite-style-outlook)
+                (const :tag "Mozilla Thunderbird" :value message-cite-style-thunderbird)
+                (const :tag "Gmail" :value message-cite-style-gmail)
+                (variable :tag "User-specified")))
+
+(defconst message-cite-style-outlook
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "")
+    (message-yank-cited-prefix  "")
+    (message-yank-empty-prefix  "")
+    (message-citation-line-format  "\n\n-----------------------\nOn %a, %b %d %Y, %N wrote:\n"))
+  "Message citation style used by MS Outlook. Use with message-cite-style.")
+
+(defconst message-cite-style-thunderbird
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "> ")
+    (message-yank-cited-prefix  ">")
+    (message-yank-empty-prefix  ">")
+    (message-citation-line-format "On %D %R %p, %N wrote:"))
+  "Message citation style used by Mozilla Thunderbird. Use with message-cite-style.")
+
+(defconst message-cite-style-gmail
+  '((message-cite-function  'message-cite-original)
+    (message-citation-line-function  'message-insert-formatted-citation-line)
+    (message-cite-reply-position 'above)
+    (message-yank-prefix  "    ")
+    (message-yank-cited-prefix  "    ")
+    (message-yank-empty-prefix  "    ")
+    (message-citation-line-format "On %e %B %Y %R, %f wrote:\n"))
+  "Message citation style used by Gmail. Use with message-cite-style.")
+
 (defcustom message-distribution-function nil
   "*Function called to return a Distribution header."
   :group 'message-news
@@ -1143,6 +1231,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 postponing 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
@@ -1157,13 +1247,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.
@@ -1177,8 +1271,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."
@@ -1201,14 +1295,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,
@@ -1266,7 +1357,9 @@ text and it replaces `self-insert-command' with the other command, e.g.
   :type '(repeat function))
 
 (defcustom message-auto-save-directory
-  (file-name-as-directory (expand-file-name "drafts" message-directory))
+  (if (file-writable-p message-directory)
+      (file-name-as-directory (expand-file-name "drafts" message-directory))
+    "~/")
   "*Directory where Message auto-saves buffers if Gnus isn't running.
 If nil, Message won't auto-save."
   :group 'message-buffers
@@ -1307,7 +1400,8 @@ candidates:
 `quoted-text-only'  Allow you to post quoted text only;
 `multiple-copies'   Allow you to post multiple copies;
 `cancel-messages'   Allow you to cancel or supersede messages from
-                   your other email addresses.")
+                   your other email addresses;
+`canlock-verify'    Allow you to cancel messages without verifying canlock.")
 
 (defsubst message-gnksa-enable-p (feature)
   (or (not (listp message-shoot-gnksa-feet))
@@ -1829,25 +1923,31 @@ You must have the \"hashcash\" binary installed, see `hashcash-path'."
 
 (defvar        message-options nil
   "Some saved answers when sending message.")
+;; FIXME: On XEmacs this causes problems since let-binding like:
+;; (let ((message-options message-options)) ...)
+;; as in `message-send' and `mml-preview' loses to buffer-local
+;; variable initialization.
+(unless (featurep 'xemacs)
+  (make-variable-buffer-local 'message-options))
 
 (defvar message-send-mail-real-function nil
   "Internal send mail function.")
 
-(defvar message-bogus-system-names "^localhost\\.\\|\\.local$"
+(defvar message-bogus-system-names "\\`localhost\\.\\|\\.local\\'"
   "The regexp of bogus system names.")
 
 (defcustom message-valid-fqdn-regexp
   (concat "[a-z0-9][-.a-z0-9]+\\." ;; [hostname.subdomain.]domain.
          ;; valid TLDs:
          "\\([a-z][a-z]\\|" ;; two letter country TDLs
-         "aero\\|arpa\\|bitnet\\|biz\\|bofh\\|"
+         "aero\\|arpa\\|asia\\|bitnet\\|biz\\|bofh\\|"
          "cat\\|com\\|coop\\|edu\\|gov\\|"
          "info\\|int\\|jobs\\|"
          "mil\\|mobi\\|museum\\|name\\|net\\|"
-         "org\\|pro\\|travel\\|uucp\\)")
+         "org\\|pro\\|tel\\|travel\\|uucp\\)")
   ;; http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
   ;; http://en.wikipedia.org/wiki/GTLD
-  ;; `in the process of being approved': .asia .post .tel .sex
+  ;; `approved, but not yet in operation': .xxx
   ;; "dead" nato bitnet uucp
   "Regular expression that matches a valid FQDN."
   ;; see also: gnus-button-valid-fqdn-regexp
@@ -2170,7 +2270,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: ")))
@@ -2451,7 +2550,7 @@ Return the number of headers removed."
      (point-max)))
   (goto-char (point-min)))
 
-;; FIXME: clarify diffference: message-narrow-to-head,
+;; FIXME: clarify difference: message-narrow-to-head,
 ;; message-narrow-to-headers-or-head, message-narrow-to-headers
 (defun message-narrow-to-head ()
   "Narrow the buffer to the head of the message.
@@ -2658,7 +2757,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))
 
@@ -2792,7 +2890,7 @@ message composition doesn't break too bad."
   :link '(custom-manual "(message)Various Message Variables")
   :type 'boolean)
 
-(defconst message-forbidden-properties
+(defvar message-forbidden-properties
   ;; No reason this should be clutter up customize.  We make it a
   ;; property list (rather than a list of property symbols), to be
   ;; directly useful for `remove-text-properties'.
@@ -2884,6 +2982,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)
@@ -2935,6 +3034,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)
@@ -3001,81 +3101,107 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
 (defun message-goto-to ()
   "Move point to the To header."
   (interactive)
+  (push-mark)
   (message-position-on-field "To"))
 
 (defun message-goto-from ()
   "Move point to the From header."
   (interactive)
+  (push-mark)
   (message-position-on-field "From"))
 
 (defun message-goto-subject ()
   "Move point to the Subject header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Subject"))
 
 (defun message-goto-cc ()
   "Move point to the Cc header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Cc" "To"))
 
 (defun message-goto-bcc ()
   "Move point to the Bcc  header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Bcc" "Cc" "To"))
 
 (defun message-goto-fcc ()
   "Move point to the Fcc header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Fcc" "To" "Newsgroups"))
 
 (defun message-goto-reply-to ()
   "Move point to the Reply-To header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Reply-To" "Subject"))
 
 (defun message-goto-newsgroups ()
   "Move point to the Newsgroups header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Newsgroups"))
 
 (defun message-goto-distribution ()
   "Move point to the Distribution header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Distribution"))
 
 (defun message-goto-followup-to ()
   "Move point to the Followup-To header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Followup-To" "Newsgroups"))
 
 (defun message-goto-mail-followup-to ()
   "Move point to the Mail-Followup-To header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Mail-Followup-To" "To"))
 
 (defun message-goto-keywords ()
   "Move point to the Keywords header."
   (interactive)
+  (push-mark)
   (message-position-on-field "Keywords" "Subject"))
 
 (defun message-goto-summary ()
   "Move point to the Summary header."
   (interactive)
+  (push-mark)
   (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))
+  (push-mark)
   (goto-char (point-min))
   (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
       (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
 
 (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 ()
@@ -3089,6 +3215,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
 If there is no signature in the article, go to the end and
 return nil."
   (interactive)
+  (push-mark)
   (goto-char (point-min))
   (if (re-search-forward message-signature-separator nil t)
       (forward-line 1)
@@ -3363,8 +3490,12 @@ Message buffers and is not meant to be called directly."
 (defun message-point-in-header-p ()
   "Return t if point is in the header."
   (save-excursion
-    (not (re-search-backward
-         (concat "^" (regexp-quote mail-header-separator) "\n") nil t))))
+    (and
+     (not
+      (re-search-backward
+       (concat "^" (regexp-quote mail-header-separator) "\n") nil t))
+     (re-search-forward
+      (concat "^" (regexp-quote mail-header-separator) "\n") nil t))))
 
 (defun message-do-auto-fill ()
   "Like `do-auto-fill', but don't fill in message header."
@@ -3478,8 +3609,12 @@ Note that this should not be used in newsgroups."
 An ellipsis (from `message-elide-ellipsis') will be inserted where the
 text was killed."
   (interactive "r")
-  (kill-region b e)
-  (insert message-elide-ellipsis))
+  (let ((lines (count-lines b e))
+        (chars (- e b)))
+    (kill-region b e)
+    (insert (format-spec message-elide-ellipsis
+                         `((?l . ,lines)
+                           (?c . ,chars))))))
 
 (defvar message-caesar-translation-table nil)
 
@@ -3606,7 +3741,7 @@ However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
       (message-delete-line))
     ;; Delete blank lines at the end of the buffer.
     (goto-char (point-max))
-    (unless (eolp)
+    (unless (eq (preceding-char) ?\n)
       (insert "\n"))
     (while (and (zerop (forward-line -1))
                (looking-at "$"))
@@ -3647,16 +3782,49 @@ To use this automatically, you may add this function to
       (while (re-search-forward citexp nil t)
        (replace-match (if remove "" "\n"))))))
 
-(defvar message-cite-reply-above nil
-  "If non-nil, start own text above the quote.
-
-Note: Top posting is bad netiquette.  Don't use it unless you
-really must.  You probably want to set variable only for specific
-groups, e.g. using `gnus-posting-styles':
-
-  (eval (set (make-local-variable 'message-cite-reply-above) t))
-
-This variable has no effect in news postings.")
+(defun message--yank-original-internal (arg)
+  (let ((modified (buffer-modified-p))
+       body-text)
+       (when (and message-reply-buffer
+                  message-cite-function)
+         (when (equal message-cite-reply-position 'above)
+           (save-excursion
+             (setq body-text
+                   (buffer-substring (message-goto-body)
+                                     (point-max)))
+             (delete-region (message-goto-body) (point-max))))
+         (if (bufferp message-reply-buffer)
+             (delete-windows-on message-reply-buffer t))
+         (push-mark (save-excursion
+                      (cond
+                       ((bufferp message-reply-buffer)
+                        (insert-buffer-substring message-reply-buffer))
+                       ((and (consp message-reply-buffer)
+                             (functionp (car message-reply-buffer)))
+                        (apply (car message-reply-buffer)
+                               (cdr message-reply-buffer))))
+                      (unless (bolp)
+                        (insert ?\n))
+                      (point)))
+         (unless arg
+           (funcall message-cite-function)
+           (unless (eq (char-before (mark t)) ?\n)
+    &n