Revision: miles@gnu.org--gnu-2005/gnus--devo--0--patch-37
[gnus] / lisp / message.el
index b9d56e5..e585501 100644 (file)
@@ -1,5 +1,5 @@
 ;;; message.el --- composing mail and news messages
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -33,7 +33,8 @@
 (eval-when-compile
   (require 'cl)
   (defvar gnus-message-group-art)
-  (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
+  (defvar gnus-list-identifiers) ; gnus-sum is required where necessary
+  (require 'hashcash))
 (require 'canlock)
 (require 'mailheader)
 (require 'nnheader)
@@ -131,6 +132,7 @@ mailbox format."
 
 (defcustom message-fcc-externalize-attachments nil
   "If non-nil, attachments are included as external parts in Fcc copies."
+  :version "22.1"
   :type 'boolean
   :group 'message-sending)
 
@@ -141,7 +143,7 @@ If the string contains the format spec \"%s\", the Newsgroups
 the article has been posted to will be inserted there.
 If this variable is nil, no such courtesy message will be added."
   :group 'message-sending
-  :type '(radio (string :format "%t: %v\n" :size 0) (const nil)))
+  :type '(radio string (const nil)))
 
 (defcustom message-ignored-bounced-headers
   "^\\(Received\\|Return-Path\\|Delivered-To\\):"
@@ -170,7 +172,7 @@ Otherwise, most addresses look like `angles', but they look like
 
 (defcustom message-insert-canlock t
   "Whether to insert a Cancel-Lock header in news postings."
-  :version "21.3"
+  :version "22.1"
   :group 'message-headers
   :type 'boolean)
 
@@ -199,6 +201,7 @@ Checks include `subject-cmsg', `multiple-headers', `sendsys',
   "*Headers to be generated or prompted for when sending a message.
 Also see `message-required-news-headers' and
 `message-required-mail-headers'."
+  :version "22.1"
   :group 'message-news
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
@@ -206,6 +209,7 @@ Also see `message-required-news-headers' and
 
 (defcustom message-draft-headers '(References From)
   "*Headers to be generated when saving a draft message."
+  :version "22.1"
   :group 'message-news
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
@@ -248,7 +252,12 @@ included.  Organization and User-Agent are optional."
   :group 'message-news
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-ignored-mail-headers
   "^[GF]cc:\\|^Resent-Fcc:\\|^Xref:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
@@ -258,13 +267,18 @@ included.  Organization and User-Agent are optional."
   :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-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:"
+(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:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:\\|^Approved:"
   "*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
   :link '(custom-manual "(message)Superseding")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-subject-re-regexp
   "^[ \t]*\\([Rr][Ee]\\(\\[[0-9]*\\]\\)*:[ \t]*\\)*[ \t]*"
@@ -283,6 +297,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"
   :type '(choice (const :tag "never" nil)
                 (const :tag "always strip" t)
                  (const ask))
@@ -299,6 +314,7 @@ the variable is t instead of `ask', use
 `message-subject-trailing-was-regexp' instead.
 
 It is okay to create some false positives here, as the user is asked."
+  :version "22.1"
   :group 'message-various
   :link '(custom-manual "(message)Message Headers")
   :type 'regexp)
@@ -311,6 +327,7 @@ If `message-subject-trailing-was-query' is set to t, the subject is
 matched against `message-subject-trailing-was-regexp' in
 `message-strip-subject-trailing-was'.  You should use a regexp creating very
 few false positives here."
+  :version "22.1"
   :group 'message-various
   :link '(custom-manual "(message)Message Headers")
   :type 'regexp)
@@ -323,6 +340,7 @@ few false positives here."
 (defcustom message-mark-insert-begin
   "--8<---------------cut here---------------start------------->8---\n"
   "How to mark the beginning of some inserted text."
+  :version "22.1"
   :type 'string
   :link '(custom-manual "(message)Insertion Variables")
   :group 'message-various)
@@ -331,6 +349,7 @@ few false positives here."
 (defcustom message-mark-insert-end
   "--8<---------------cut here---------------end--------------->8---\n"
   "How to mark the end of some inserted text."
+  :version "22.1"
   :type 'string
   :link '(custom-manual "(message)Insertion Variables")
   :group 'message-various)
@@ -340,6 +359,7 @@ few false positives here."
   "X-No-Archive: Yes\n"
   "Header to insert when you don't want your article to be archived.
 Archives \(such as groups.google.com\) respect this header."
+  :version "22.1"
   :type 'string
   :link '(custom-manual "(message)Header Commands")
   :group 'message-various)
@@ -349,8 +369,8 @@ Archives \(such as groups.google.com\) respect this header."
   "X-No-Archive: Yes - save http://groups.google.com/"
   "Note to insert why you wouldn't want this posting archived.
 If nil, don't insert any text in the body."
-  :type '(radio (string :format "%t: %v\n" :size 0)
-               (const nil))
+  :version "22.1"
+  :type '(radio string (const nil))
   :link '(custom-manual "(message)Header Commands")
   :group 'message-various)
 
@@ -368,6 +388,7 @@ If nil, don't insert any text in the body."
 If nil, `message-cross-post-followup-to' will only do a followup.  Note that
 you can explicitly override this setting by calling
 `message-cross-post-followup-to' with a prefix."
+  :version "22.1"
   :type 'boolean
   :group 'message-various)
 
@@ -375,6 +396,7 @@ you can explicitly override this setting by calling
 (defcustom message-cross-post-note
   "Crosspost & Followup-To: "
   "Note to insert before signature to notify of cross-post and follow-up."
+  :version "22.1"
   :type 'string
   :group 'message-various)
 
@@ -382,6 +404,7 @@ you can explicitly override this setting by calling
 (defcustom message-followup-to-note
   "Followup-To: "
   "Note to insert before signature to notify of follow-up only."
+  :version "22.1"
   :type 'string
   :group 'message-various)
 
@@ -392,6 +415,7 @@ you can explicitly override this setting by calling
 The function will be called with four arguments.  The function should not only
 insert a note, but also ensure old notes are deleted.  See the documentation
 for `message-cross-post-insert-note'."
+  :version "22.1"
   :type 'function
   :group 'message-various)
 
@@ -516,13 +540,22 @@ Done before generating the new subject of a forward."
   "*All headers that match this regexp will be deleted when resending a message."
   :group 'message-interface
   :link '(custom-manual "(message)Resending")
-  :type 'regexp)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
+                regexp))
 
 (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
   "*All headers that match this regexp will be deleted when forwarding a message."
   :version "21.1"
   :group 'message-forwarding
-  :type '(choice (const :tag "None" nil)
+  :type '(repeat :value-to-internal (lambda (widget value)
+                                     (custom-split-regexp-maybe value))
+                :match (lambda (widget value)
+                         (or (stringp value)
+                             (widget-editable-list-match widget value)))
                 regexp))
 
 (defcustom message-ignored-cited-headers "."
@@ -548,6 +581,7 @@ Done before generating the new subject of a forward."
                non-word-constituents
                "]\\)+>+\\|[ \t]*[]>|}+]\\)+"))))
   "*Regexp matching the longest possible citation prefix on a line."
+  :version "22.1"
   :group 'message-insertion
   :link '(custom-manual "(message)Insertion Variables")
   :type 'regexp)
@@ -560,7 +594,20 @@ Done before generating the new subject of a forward."
 
 ;; Useful to set in site-init.el
 ;;;###autoload
-(defcustom message-send-mail-function 'message-send-mail-with-sendmail
+(defcustom message-send-mail-function
+  (let ((program (if (boundp 'sendmail-program)
+                    ;; see paths.el
+                    sendmail-program)))
+    (cond
+     ((and program
+          (string-match "/" program) ;; Skip path
+          (file-executable-p program))
+      'message-send-mail-with-sendmail)
+     ((and program
+          (executable-find program))
+      'message-send-mail-with-sendmail)
+     (t
+      'smtpmail-send-it)))
   "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'.
@@ -614,6 +661,12 @@ and respond with new To and Cc headers."
   :link '(custom-manual "(message)Followup")
   :type '(choice function (const nil)))
 
+(defcustom message-extra-wide-headers nil
+  "If non-nil, a list of additional address headers.
+These are used when composing a wide reply."
+  :group 'message-sending
+  :type '(repeat string))
+
 (defcustom message-use-followup-to 'ask
   "*Specifies what to do with Followup-To header.
 If nil, always ignore the header.  If it is t, use its value, but
@@ -632,6 +685,7 @@ always query the user whether to use the value.  If it is the symbol
 If nil, always ignore the header.  If it is the symbol `ask', always
 query the user whether to use the value.  If it is the symbol `use',
 always use the value."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
   :type '(choice (const :tag "ignore" nil)
@@ -645,6 +699,7 @@ If non-nil, this variable contains a list of functions which return
 regular expressions to match lists.  These functions can be used in
 conjunction with `message-subscribed-regexps' and
 `message-subscribed-addresses'."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
   :type '(repeat sexp))
@@ -653,16 +708,17 @@ conjunction with `message-subscribed-regexps' and
   "*A file containing addresses the user is subscribed to.
 If nil, do not look at any files to determine list subscriptions.  If
 non-nil, each line of this file should be a mailing list address."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
-  :type '(radio (file :format "%t: %v\n" :size 0)
-               (const nil)))
+  :type '(radio file (const nil)))
 
 (defcustom message-subscribed-addresses nil
   "*Specifies a list of addresses the user is subscribed to.
 If nil, do not use any predefined list subscriptions.  This list of
 addresses can be used in conjunction with
 `message-subscribed-address-functions' and `message-subscribed-regexps'."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
   :type '(repeat string))
@@ -672,6 +728,7 @@ addresses can be used in conjunction with
 If nil, do not use any predefined list subscriptions.  This list of
 regular expressions can be used in conjunction with
 `message-subscribed-address-functions' and `message-subscribed-addresses'."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Mailing Lists")
   :type '(repeat regexp))
@@ -681,6 +738,7 @@ regular expressions can be used in conjunction with
 If it is the symbol `always', the posting is allowed.  If it is the
 symbol `never', the posting is not allowed.  If it is the symbol
 `ask', you are prompted."
+  :version "22.1"
   :group 'message-interface
   :link '(custom-manual "(message)Message Headers")
   :type '(choice (const always)
@@ -698,6 +756,7 @@ Doing so would be even more evil than leaving it out."
   "*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."
+  :version "22.1"
   :type '(choice (string :tag "From name")
                 (const :tag "Use From: header from message" header)
                 (const :tag "Use `user-mail-address'" nil))
@@ -805,7 +864,8 @@ the signature is inserted."
   (let ((map (make-sparse-keymap 'message-minibuffer-local-map)))
     (set-keymap-parent map minibuffer-local-map)
     map)
-  "Keymap for `message-read-from-minibuffer'.")
+  "Keymap for `message-read-from-minibuffer'."
+  :version "22.1")
 
 ;;;###autoload
 (defcustom message-citation-line-function 'message-insert-citation-line
@@ -832,6 +892,7 @@ See also `message-yank-cited-prefix'."
   "*Prefix inserted on cited or empty lines of yanked messages.
 Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
 See also `message-yank-prefix'."
+  :version "22.1"
   :type 'string
   :link '(custom-manual "(message)Insertion Variables")
   :group 'message-insertion)
@@ -888,6 +949,7 @@ If nil, don't insert a signature."
 ;;;###autoload
 (defcustom message-signature-insert-empty-line t
   "*If non-nil, insert an empty line before the signature separator."
+  :version "22.1"
   :type 'boolean
   :link '(custom-manual "(message)Insertion Variables")
   :group 'message-insertion)
@@ -1064,13 +1126,22 @@ candidates:
   (or (not (listp message-shoot-gnksa-feet))
       (memq feature message-shoot-gnksa-feet)))
 
-(defcustom message-hidden-headers nil
+(defcustom message-hidden-headers "^References:"
   "Regexp of headers to be hidden when composing new messages.
 This can also be a list of regexps to match headers.  Or a list
 starting with `not' and followed by regexps."
+  :version "22.1"
   :group 'message
   :link '(custom-manual "(message)Message Headers")
-  :type '(repeat regexp))
+  :type '(choice
+         :format "%{%t%}: %[Value Type%] %v"
+         (regexp :menu-tag "regexp" :format "regexp\n%t: %v")
+         (repeat :menu-tag "(regexp ...)" :format "(regexp ...)\n%v%i"
+                 (regexp :format "%t: %v"))
+         (cons :menu-tag "(not regexp ...)" :format "(not regexp ...)\n%v"
+               (const not)
+               (repeat :format "%v%i"
+                       (regexp :format "%t: %v")))))
 
 (defcustom message-cite-articles-with-x-no-archive t
   "If non-nil, cite text from articles that has X-No-Archive set."
@@ -1348,6 +1419,7 @@ subaddresses.  So if the first address appears in the recipient list
 for a message, the subaddresses will be removed (if present) before
 the mail is sent.  All addresses in this structure should be
 downcased."
+  :version "22.1"
   :group 'message-headers
   :type '(repeat (repeat string)))
 
@@ -1355,6 +1427,7 @@ downcased."
   "Like `mail-user-agent'.
 Except if it is nil, use Gnus native MUA; if it is t, use
 `mail-user-agent'."
+  :version "22.1"
   :type '(radio (const :tag "Gnus native"
                       :format "%t\n"
                       nil)
@@ -1378,17 +1451,18 @@ If this variable is non-nil, pose the question \"Reply to all
 recipients?\" before a wide reply to multiple recipients.  If the user
 answers yes, reply to all recipients as usual.  If the user answers
 no, only reply back to the author."
-  :version "21.3"
+  :version "22.1"
   :group 'message-headers
   :link '(custom-manual "(message)Wide Reply")
   :type 'boolean)
 
 (defcustom message-user-fqdn nil
   "*Domain part of Messsage-Ids."
+  :version "22.1"
   :group 'message-headers
   :link '(custom-manual "(message)News Headers")
   :type '(radio (const :format "%v  " nil)
-               (string :format "FQDN: %v\n" :size 0)))
+               (string :format "FQDN: %v")))
 
 (defcustom message-use-idna (and (condition-case nil (require 'idna)
                                   (file-error))
@@ -1396,12 +1470,20 @@ no, only reply back to the author."
                                 (executable-find idna-program)
                                 'ask)
   "Whether to encode non-ASCII in domain names into ASCII according to IDNA."
+  :version "22.1"
   :group 'message-headers
   :link '(custom-manual "(message)IDNA")
   :type '(choice (const :tag "Ask" ask)
                 (const :tag "Never" nil)
                 (const :tag "Always" t)))
 
+(defcustom message-generate-hashcash nil
+  "*Whether to generate X-Hashcash: headers.
+You must have the \"hashcash\" binary installed, see `hashcash-path'."
+  :group 'message-headers
+  :link '(custom-manual "(message)Mail Headers")
+  :type 'boolean)
+
 ;;; Internal variables.
 
 (defvar message-sending-message "Sending...")
@@ -1491,7 +1573,8 @@ no, only reply back to the author."
   "Alist of header names/filler functions.")
 
 (defvar message-header-format-alist
-  `((Newsgroups)
+  `((From)
+    (Newsgroups)
     (To)
     (Cc)
     (Subject)
@@ -1527,6 +1610,7 @@ no, only reply back to the author."
          "\\)")
   "Regular expression that matches a valid FQDN."
   ;; see also: gnus-button-valid-fqdn-regexp
+  :version "22.1"
   :group 'message-headers
   :type 'regexp)
 
@@ -1557,9 +1641,6 @@ no, only reply back to the author."
   (autoload 'rmail-msg-restore-non-pruned-header "rmail")
   (autoload 'rmail-output "rmailout"))
 
-(eval-when-compile
-  (autoload 'sha1 "sha1-el"))
-
 \f
 
 ;;;
@@ -1595,11 +1676,11 @@ is used by default."
   (if (not header)
       nil
     (let ((regexp (format "[%s]+" (or separator ",")))
-         (beg 1)
          (first t)
-         quoted elems paren)
+         beg quoted elems paren)
       (with-temp-buffer
        (mm-enable-multibyte)
+       (setq beg (point-min))
        (insert header)
        (goto-char (point-min))
        (while (not (eobp))
@@ -1642,7 +1723,6 @@ see `message-narrow-to-headers-or-head'."
     (when value
       (while (string-match "\n[\t ]+" value)
        (setq value (replace-match " " t t value)))
-      (set-text-properties 0 (length value) nil value)
       value)))
 
 (defun message-field-value (header &optional not-all)
@@ -2348,6 +2428,7 @@ these properties from the message composition buffer.  However, some
 packages requires these properties to be present in order to work.
 If you use one of these packages, turn this option off, and hope the
 message composition doesn't break too bad."
+  :version "22.1"
   :group 'message-various
   :link '(custom-manual "(message)Various Message Variables")
   :type 'boolean)
@@ -2364,7 +2445,7 @@ message composition doesn't break too bad."
   ;; fontified: is used by font-lock.
   ;; syntax-table, local-map: I dunno.
   ;; We need to add XEmacs names to the list.
-  "Property list of with properties.forbidden in message buffers.
+  "Property list of with properties forbidden in message buffers.
 The values of the properties are ignored, only the property names are used.")
 
 (defun message-tamago-not-in-use-p (pos)
@@ -2387,11 +2468,9 @@ This function is intended to be called from `after-change-functions'.
 See also `message-forbidden-properties'."
   (when (and message-strip-special-text-properties
             (message-tamago-not-in-use-p begin))
-    (while (not (= begin end))
-      (when (not (get-text-property begin 'message-hidden))
-       (remove-text-properties begin (1+ begin)
-                               message-forbidden-properties))
-      (incf begin))))
+    (let ((buffer-read-only nil)
+         (inhibit-read-only t))
+      (remove-text-properties begin end message-forbidden-properties))))
 
 ;;;###autoload
 (define-derived-mode message-mode text-mode "Message"
@@ -2457,7 +2536,11 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
   (set (make-local-variable 'message-mime-part) 0)
   (message-setup-fill-variables)
   ;; Allow using comment commands to add/remove quoting.
-  (set (make-local-variable 'comment-start) message-yank-prefix)
+  ;; (set (make-local-variable 'comment-start) message-yank-prefix)
+  (when message-yank-prefix
+    (set (make-local-variable 'comment-start) message-yank-prefix)
+    (set (make-local-variable 'comment-start-skip)
+        (concat "^" (regexp-quote message-yank-prefix) "[ \t]*")))
   (if (featurep 'xemacs)
       (message-setup-toolbar)
     (set (make-local-variable 'font-lock-defaults)
@@ -2590,7 +2673,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
 (defun message-goto-mail-followup-to ()
   "Move point to the Mail-Followup-To header."
   (interactive)
-  (message-position-on-field "Mail-Followup-To" "From"))
+  (message-position-on-field "Mail-Followup-To" "To"))
 
 (defun message-goto-keywords ()
   "Move point to the Keywords header."
@@ -2688,6 +2771,7 @@ prefix FORCE is given."
 E.g., if this list contains a member list with elements `Cc' and `To',
 then `message-carefully-insert-headers' will not insert a `To' header
 when the message is already `Cc'ed to the recipient."
+  :version "22.1"
   :group 'message-headers
   :link '(custom-manual "(message)Message Headers")
   :type '(repeat sexp))
@@ -2699,6 +2783,7 @@ or in the synonym headers, defined by `message-header-synonyms'."
   ;; FIXME: Should compare only the address and not the full name.  Comparison
   ;; should be done case-folded (and with `string=' rather than
   ;; `string-match').
+  ;; (mail-strip-quoted-names "Foo Bar <foo@bar>, bla@fasel (Bla Fasel)")
   (dolist (header headers)
     (let* ((header-name (symbol-name (car header)))
            (new-header (cdr header))
@@ -3228,8 +3313,7 @@ prefix, and don't delete any headers."
        ;; Insert a blank line if it is peeled off.
        (insert "\n")))
     (goto-char start)
-    (while functions
-      (funcall (pop functions)))
+    (mapc 'funcall functions)
     (when message-citation-line-function
       (unless (bolp)
        (insert "\n"))
@@ -3266,14 +3350,13 @@ prefix, and don't delete any headers."
                      0 0 ""))))
       (mml-quote-region start end)
       (goto-char start)
-      (while functions
-       (funcall (pop functions)))
+      (mapc 'funcall functions)
       (when message-citation-line-function
        (unless (bolp)
          (insert "\n"))
        (funcall message-citation-line-function))
       (when (and x-no-archive
-                message-cite-articles-with-x-no-archive
+                (not message-cite-articles-with-x-no-archive)
                 (string-match "yes" x-no-archive))
        (undo-boundary)
        (delete-region (point) (mark t))
@@ -3382,8 +3465,15 @@ Instead, just auto-save the buffer and then bury it."
                          (file-exists-p auto-save-file-name))
                     (and file-name
                          (file-exists-p file-name)))
-              (yes-or-no-p (format "Remove the backup file%s? "
-                                   (if modified " too" ""))))
+                (progn
+                  ;; If the message buffer has lived in a dedicated window,
+                  ;; `kill-buffer' has killed the frame.  Thus the
+                  ;; `yes-or-no-p' may show up in a lowered frame.  Make sure
+                  ;; that the user can see the question by raising the
+                  ;; current frame:
+                  (raise-frame)
+                  (yes-or-no-p (format "Remove the backup file%s? "
+                                       (if modified " too" "")))))
        (ignore-errors
          (delete-file auto-save-file-name))
        (let ((message-draft-article draft-article))
@@ -3394,8 +3484,7 @@ Instead, just auto-save the buffer and then bury it."
   "Bury this mail BUFFER."
   (let ((newbuf (other-buffer buffer)))
     (bury-buffer buffer)
-    (if (and (fboundp 'frame-parameters)
-            (cdr (assq 'dedicated (frame-parameters)))
+    (if (and (window-dedicated-p (selected-window))
             (not (null (delq (selected-frame) (visible-frame-list)))))
        (delete-frame (selected-frame))
       (switch-to-buffer newbuf))))
@@ -3483,16 +3572,31 @@ It should typically alter the sending method in some way or other."
 (put 'message-check 'lisp-indent-function 1)
 (put 'message-check 'edebug-form-spec '(form body))
 
-(defun message-text-with-property (prop)
-  "Return a list of all points where the text has PROP."
-  (let ((points nil)
-       (point (point-min)))
-    (save-excursion
-      (while (< point (point-max))
-       (when (get-text-property point prop)
-         (push point points))
-       (incf point)))
-    (nreverse points)))
+(defun message-text-with-property (prop &optional start end reverse)
+  "Return a list of start and end positions where the text has PROP.
+START and END bound the search, they default to `point-min' and
+`point-max' respectively.  If REVERSE is non-nil, find text which does
+not have PROP."
+  (unless start
+    (setq start (point-min)))
+  (unless end
+    (setq end (point-max)))
+  (let (next regions)
+    (if reverse
+       (while (and start
+                   (setq start (text-property-any start end prop nil)))
+         (setq next (next-single-property-change start prop nil end))
+         (push (cons start (or next end)) regions)
+         (setq start next))
+      (while (and start
+                 (or (get-text-property start prop)
+                     (and (setq start (next-single-property-change
+                                       start prop nil end))
+                          (get-text-property start prop))))
+       (setq next (text-property-any start end prop nil))
+       (push (cons start (or next end)) regions)
+       (setq start next)))
+    (nreverse regions)))
 
 (defun message-fix-before-sending ()
   "Do various things to make the message nice before sending it."
@@ -3501,22 +3605,22 @@ It should typically alter the sending method in some way or other."
   (unless (bolp)
     (insert "\n"))
   ;; Make the hidden headers visible.
-  (let ((points (message-text-with-property 'message-hidden)))
-    (when points
-      (goto-char (car points))
-      (dolist (point points)
-       (add-text-properties point (1+ point)
-                            '(invisible nil intangible nil)))))
+  (widen)
+  ;; Sort headers before sending the message.
+  (message-sort-headers)
   ;; Make invisible text visible.
   ;; It doesn't seem as if this is useful, since the invisible property
   ;; is clobbered by an after-change hook anyhow.
   (message-check 'invisible-text
-    (let ((points (message-text-with-property 'invisible)))
-      (when points
-       (goto-char (car points))
-       (dolist (point points)
-         (put-text-property point (1+ point) 'invisible nil)
-         (message-overlay-put (message-make-overlay point (1+ point))
+    (let ((regions (message-text-with-property 'invisible))
+         from to)
+      (when regions
+       (while regions
+         (setq from (caar regions)
+               to (cdar regions)
+               regions (cdr regions))
+         (put-text-property from to 'invisible nil)
+         (message-overlay-put (message-make-overlay from to)
                               'face 'highlight))
        (unless (yes-or-no-p
                 "Invisible text found and made visible; continue sending? ")
@@ -3587,16 +3691,15 @@ It should typically alter the sending method in some way or other."
 (defun message-do-actions (actions)
   "Perform all actions in ACTIONS."
   ;; Now perform actions on successful sending.
-  (while actions
+  (dolist (action actions)
     (ignore-errors
       (cond
        ;; A simple function.
-       ((functionp (car actions))
-       (funcall (car actions)))
+       ((functionp action)
+       (funcall action))
        ;; Something to be evaled.
        (t
-       (eval (car actions)))))
-    (pop actions)))
+       (eval action))))))
 
 (defun message-send-mail-partially ()
   "Send mail as message/partial."
@@ -3681,6 +3784,14 @@ It should typically alter the sending method in some way or other."
              (gnus-setup-posting-charset nil)
            message-posting-charset))
         (headers message-required-mail-headers))
+    (when message-generate-hashcash
+      (message "Generating hashcash...")
+      ;; Wait for calculations already started to finish...
+      (hashcash-wait-async)
+      ;; ...and do calculations not already done.  mail-add-payment
+      ;; will leave existing X-Hashcash headers alone.
+      (mail-add-payment)
+      (message "Generating hashcash...done"))
     (save-restriction
       (message-narrow-to-headers)
       ;; Generate the Mail-Followup-To header if the header is not there...
@@ -3748,13 +3859,13 @@ It should typically alter the sending method in some way or other."
                                   "content-transfer-encoding")))))))
            (message-insert-courtesy-copy))
          (if (or (not message-send-mail-partially-limit)
-                 (< (point-max) message-send-mail-partially-limit)
+                 (< (buffer-size) message-send-mail-partially-limit)
                  (not (message-y-or-n-p
                        "The message size is too large, split? "
                        t
                        "\
 The message size, "
-                       (/ (point-max) 1000) "KB, is too large.
+                       (/ (buffer-size) 1000) "KB, is too large.
 
 Some mail gateways (MTA's) bounce large messages.  To avoid the
 problem, answer `y', and the message will be split into several
@@ -3807,8 +3918,7 @@ If you always want Gnus to send messages in one piece, set
            (when (eval message-mailer-swallows-blank-line)
              (newline))
            (when message-interactive
-             (save-excursion
-               (set-buffer errbuf)
+             (with-current-buffer errbuf
                (erase-buffer))))
          (let* ((default-directory "/")
                 (coding-system-for-write message-send-coding-system)
@@ -3843,7 +3953,7 @@ If you always want Gnus to send messages in one piece, set
            (save-excursion
              (set-buffer errbuf)
              (goto-char (point-min))
-             (while (re-search-forward "\n\n* *" nil t)
+             (while (re-search-forward "\n+ *" nil t)
                (replace-match "; "))
              (if (not (zerop (buffer-size)))
                  (error "Sending...failed to %s"
@@ -3865,8 +3975,8 @@ to find out how to use this."
   (case
       (let ((coding-system-for-write message-send-coding-system))
        (apply
-        'call-process-region 1 (point-max) message-qmail-inject-program
-        nil nil nil
+        'call-process-region (point-min) (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.
@@ -3925,7 +4035,7 @@ manual for details."
 (defun message-canlock-generate ()
   "Return a string that is non-trivial to guess.
 Do not use this for anything important, it is cryptographically weak."
-  (require 'sha1-el)
+  (require 'sha1)
   (let (sha1-maximum-internal-length)
     (sha1 (concat (message-unique-id)
                  (format "%x%x%x" (random) (random t) (random))
@@ -4396,7 +4506,9 @@ Otherwise, generate and save a value for `canlock-password' first."
             nil))))
    ;; 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
+         (mm-string-as-multibyte "[\000-\007\013\015-\032\034-\037\200-\237]")
+         nil t)
         (y-or-n-p
          "The article contains control characters.  Really post? ")
        t))
@@ -4552,24 +4664,8 @@ Otherwise, generate and save a value for `canlock-password' first."
 (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
-     ;; The day name of the %a spec is locale-specific.  Pfff.
-     (format "%s, " (capitalize (car (rassoc (nth 6 (decode-time now))
-                                            parse-time-weekdays))))
-     (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) 60)))))
+  (let ((system-time-locale "C"))
+    (format-time-string "%a, %d %b %Y %T %z" now)))
 
 (defun message-make-message-id ()
   "Make a unique Message-ID."
@@ -4912,7 +5008,7 @@ subscribed address (and not the additional To and Cc header contents)."
     (when field
       (dolist (address (mail-header-parse-addresses field))
        (setq address (car address)
-             rhs (downcase (cadr (split-string address "@")))
+             rhs (downcase (or (cadr (split-string address "@")) ""))
              ace (downcase (idna-to-ascii rhs)))
        (when (and (not (equal rhs ace))
                   (or (not (eq message-use-idna 'ask))
@@ -4935,6 +5031,7 @@ See `message-idna-encode'."
        (message-narrow-to-head)
        (message-idna-to-ascii-rhs-1 "From")
        (message-idna-to-ascii-rhs-1 "To")
+       (message-idna-to-ascii-rhs-1 "Reply-To")
        (message-idna-to-ascii-rhs-1 "Cc")))))
 
 (defun message-generate-headers (headers)
@@ -5143,7 +5240,7 @@ Headers already prepared in the buffer are not modified."
 If the current line has `message-yank-prefix', insert it on the new line."
   (interactive "*")
   (condition-case nil
-      (split-line message-yank-prefix) ;; Emacs 21.3.50+ supports arg.
+      (split-line message-yank-prefix) ;; Emacs 22.1+ supports arg.
     (error
      (split-line))))
 
@@ -5179,7 +5276,7 @@ If the current line has `message-yank-prefix', insert it on the new line."
              (insert "\n\t"))
            (setq last (1+ (point))))
        (setq last (1+ (point)))))))
-  
+
 (defun message-fill-field-general ()
   (let ((begin (point))
        (fill-column 78)
@@ -5193,7 +5290,7 @@ If the current line has `message-yank-prefix', insert it on the new line."
     (when (looking-at "[ \t]*$")
       (message-delete-line))
     (goto-char begin)
-    (re-search-forward ":" nil t)
+    (search-forward ":" nil t)
     (when (looking-at "\n[ \t]+")
       (replace-match " " t t))
     (goto-char (point-max))))
@@ -5232,7 +5329,7 @@ they are."
     ;; When sending via news, make sure the total folded length will
     ;; be less than 998 characters.  This is to cater to broken INN
     ;; 2.3 which counts the total number of characters in a header
-    ;; rather than the physical line length of each line, as it shuld.
+    ;; rather than the physical line length of each line, as it should.
     ;;
     ;; This hack should be removed when it's believed than INN 2.3 is
     ;; no longer widely used.
@@ -5272,6 +5369,7 @@ they are."
 (defcustom message-beginning-of-line t
   "Whether \\<message-mode-map>\\[message-beginning-of-line]\
  goes to beginning of header values."
+  :version "22.1"
   :group 'message-buffers
   :link '(custom-manual "(message)Movement")
   :type 'boolean)
@@ -5285,10 +5383,10 @@ outside the message header or if the option `message-beginning-of-line'
 is nil.
 
 If point is in the message header and on a (non-continued) header
-line, move point to the beginning of the header value.  If point
-is already there, move point to beginning of line.  Therefore,
-repeated calls will toggle point between beginning of field and
-beginning of line."
+line, move point to the beginning of the header value or the beginning of line,
+whichever is closer.  If point is already at beginning of line, move point to
+beginning of header value.  Therefore, repeated calls will toggle point
+between beginning of field and beginning of line."
   (interactive "p")
   (let ((zrs 'zmacs-region-stays))
     (when (and (interactive-p) (boundp zrs))
@@ -5299,9 +5397,9 @@ beginning of line."
             (bol (progn (beginning-of-line n) (point)))
             (eol (point-at-eol))
             (eoh (re-search-forward ": *" eol t)))
-       (if (or (not eoh) (equal here eoh))
-           (goto-char bol)
-         (goto-char eoh)))
+       (goto-char
+        (if (and eoh (or (< eoh here) (= bol here)))
+            eoh bol)))
     (beginning-of-line n)))
 
 (defun message-buffer-name (type &optional to group)
@@ -5511,6 +5609,9 @@ are not included."
     (run-hooks 'message-header-setup-hook))
   (set-buffer-modified-p nil)
   (setq buffer-undo-list nil)
+  (when message-generate-hashcash
+    ;; Generate hashcash headers for recipients already known
+    (mail-add-payment-async))
   (run-hooks 'message-setup-hook)
   (message-position-point)
   (undo-boundary))
@@ -5597,7 +5698,7 @@ OTHER-HEADERS is an alist of header/value pairs."
                     (Subject . ,(or subject ""))))))
 
 (defun message-get-reply-headers (wide &optional to-address address-headers)
-  (let (follow-to mct never-mct to cc author mft recipients)
+  (let (follow-to mct never-mct to cc author mft recipients extra)
     ;; Find all relevant headers we need.
     (save-restriction
       (message-narrow-to-headers-or-head)
@@ -5609,6 +5710,11 @@ OTHER-HEADERS is an alist of header/value pairs."
                              return t)
                        (message-fetch-field "original-to")))
            cc (message-fetch-field "cc")
+           extra (when message-extra-wide-headers
+                   (mapconcat 'identity
+                              (mapcar 'message-fetch-field
+                                      message-extra-wide-headers)
+                              ", "))
            mct (message-fetch-field "mail-copies-to")
            author (or (message-fetch-field "mail-reply-to")
                       (message-fetch-field "reply-to")
@@ -5668,8 +5774,9 @@ responses here are directed to other addresses.")))
        (if mct (setq recipients (concat recipients ", " mct))))
        (t
        (setq recipients (if never-mct "" (concat ", " author)))
-       (if to  (setq recipients (concat recipients ", " to)))
-       (if cc  (setq recipients (concat recipients ", " cc)))
+       (if to (setq recipients (concat recipients ", " to)))
+       (if cc (setq recipients (concat recipients ", " cc)))
+       (if extra (setq recipients (concat recipients ", " extra)))
        (if mct (setq recipients (concat recipients ", " mct)))))
       (if (>= (length recipients) 2)
          ;; Strip the leading ", ".
@@ -6124,18 +6231,17 @@ the message."
                      subject
                    (mail-decode-encoded-word-string subject))
                ""))
-       (if message-wash-forwarded-subjects
-           (setq subject (message-wash-subject subject)))
+       (when message-wash-forwarded-subjects
+         (setq subject (message-wash-subject subject)))
        ;; Make sure funcs is a list.
        (and funcs
             (not (listp funcs))
             (setq funcs (list funcs)))
        ;; Apply funcs in order, passing subject generated by previous
        ;; func to the next one.
-       (while funcs
-         (when (functionp (car funcs))
-           (setq subject (funcall (car funcs) subject)))
-         (setq funcs (cdr funcs)))
+       (dolist (func funcs)
+         (when (functionp func)
+           (setq subject (funcall func subject))))
        subject))))
 
 (eval-when-compile
@@ -6178,8 +6284,7 @@ Optional DIGEST will use digest to forward."
     (setq e (point))
     (insert
      "\n-------------------- End of forwarded message --------------------\n")
-    (when (and (not current-prefix-arg)
-              message-forward-ignored-headers)
+    (when message-forward-ignored-headers
       (save-restriction
        (narrow-to-region b e)
        (goto-char b)
@@ -6225,7 +6330,7 @@ Optional DIGEST will use digest to forward."
        (goto-char (point-max))))
     (setq e (point))
     (insert "<#/mml>\n")
-    (when (and (not current-prefix-arg)
+    (when (and (not message-forward-decoded-p)
               message-forward-ignored-headers)
       (save-restriction
        (narrow-to-region b e)
@@ -6492,7 +6597,7 @@ which specify the range to operate on."
     (let ((end1 (make-marker)))
       (move-marker end1 (max start end))
       (goto-char (min start end))
-      (while (re-search-forward "\b" end1 t)
+      (while (search-forward "\b" end1 t)
        (if (eq (char-after) (char-after (- (point) 2)))
            (delete-char -2))))))
 
@@ -6578,6 +6683,7 @@ which specify the range to operate on."
        '("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
          . message-expand-name))
   "Alist of (RE . FUN).  Use FUN for completion on header lines matching RE."
+  :version "22.1"
   :group 'message
   :type '(alist :key-type regexp :value-type function))
 
@@ -6591,6 +6697,7 @@ Each element is a symbol and can be `bbdb' or `eudc'."
 (defcustom message-tab-body-function nil
   "*Function to execute when `message-tab' (TAB) is executed in the body.
 If nil, the function bound in `text-mode-map' or `global-map' is executed."
+  :version "22.1"
   :group 'message
   :link '(custom-manual "(message)Various Commands")
   :type 'function)
@@ -6707,7 +6814,7 @@ regexp VARSTR."
   (let ((locals (save-excursion
                  (set-buffer buffer)
                  (buffer-local-variables)))
-       (regexp "^gnus\\|^nn\\|^message\\|^user-mail-address"))
+       (regexp "^gnus\\|^nn\\|^message\\|^sendmail\\|^smtp\\|^user-mail-address"))
     (mapcar
      (lambda (local)
        (when (and (consp local)
@@ -6784,7 +6891,7 @@ regexp VARSTR."
 
 (defun message-use-alternative-email-as-from ()
   (require 'mail-utils)
-  (let* ((fields '("To" "Cc"))
+  (let* ((fields '("To" "Cc" "From"))
         (emails
          (split-string
           (mail-strip-quoted-names
@@ -6798,7 +6905,8 @@ regexp VARSTR."
       (pop emails))
     (unless (or (not email) (equal email user-mail-address))
       (goto-char (point-max))
-      (insert "From: " email "\n"))))
+      (insert "From: " (let ((user-mail-address email)) (message-make-from))
+             "\n"))))
 
 (defun message-options-get (symbol)
   (cdr (assq symbol message-options)))
@@ -6837,7 +6945,8 @@ regexp VARSTR."
                     (list message-hidden-headers)
                   message-hidden-headers))
        (inhibit-point-motion-hooks t)
-       (after-change-functions nil))
+       (after-change-functions nil)
+       (end-of-headers 0))
     (when regexps
       (save-excursion
        (save-restriction
@@ -6846,11 +6955,17 @@ regexp VARSTR."
          (while (not (eobp))
            (if (not (message-hide-header-p regexps))
                (message-next-header)
-             (let ((begin (point)))
+             (let ((begin (point))
+                   header header-len)
                (message-next-header)
-               (add-text-properties
-                begin (point)
-                '(invisible t message-hidden t))))))))))
+               (setq header (buffer-substring begin (point))
+                     header-len (- (point) begin))
+               (delete-region begin (point))
+               (goto-char (1+ end-of-headers))
+               (insert header)
+               (setq end-of-headers
+                     (+ end-of-headers header-len))))))))
+    (narrow-to-region (1+ end-of-headers) (point-max))))
 
 (defun message-hide-header-p (regexps)
   (let ((result nil)
@@ -6876,5 +6991,5 @@ regexp VARSTR."
 ;; coding: iso-8859-1
 ;; End:
 
-;;; arch-tag: 94b32cac-4504-4b6c-8181-030ebf380ee0
+;; arch-tag: 94b32cac-4504-4b6c-8181-030ebf380ee0
 ;;; message.el ends here