* gnus-sieve.el (gnus-sieve-crosspost): Fix type.
[gnus] / lisp / message.el
index d82916d..abd30b9 100644 (file)
@@ -32,6 +32,7 @@
 
 (eval-when-compile
   (require 'cl)
+  (defvar gnus-message-group-art)
   (defvar gnus-list-identifiers)) ; gnus-sum is required where necessary
 (require 'canlock)
 (require 'mailheader)
@@ -46,7 +47,9 @@
 (require 'mml)
 (require 'rfc822)
 (eval-and-compile
-  (autoload 'sha1 "sha1-el"))
+  (autoload 'sha1 "sha1-el")
+  (autoload 'gnus-find-method-for-group "gnus")
+  (autoload 'nnvirtual-find-group-art "nnvirtual"))
 
 (defgroup message '((user-mail-address custom-variable)
                    (user-full-name custom-variable))
@@ -142,9 +145,10 @@ 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 'string)
+  :type '(radio (string :format "%t: %v\n" :size 0) (const nil)))
 
-(defcustom message-ignored-bounced-headers "^\\(Received\\|Return-Path\\):"
+(defcustom message-ignored-bounced-headers
+  "^\\(Received\\|Return-Path\\|Delivered-To\\):"
   "*Regexp that matches headers to be removed in resent bounced mail."
   :group 'message-interface
   :type 'regexp)
@@ -189,14 +193,16 @@ Checks include `subject-cmsg', `multiple-headers', `sendsys',
 `approved', `sender', `empty', `empty-headers', `message-id', `from',
 `subject', `shorten-followup-to', `existing-newsgroups',
 `buffer-file-name', `unchanged', `newsgroups', `reply-to',
-'continuation-headers', and `long-header-lines'."
+`continuation-headers', `long-header-lines', `invisible-text' and
+`illegible-text'."
   :group 'message-news
   :type '(repeat sexp))                        ; Fixme: improve this
 
-(defcustom message-required-headers '((optional . References) From)
-  "*Headers to be generated or promted for when sending a message.
+(defcustom message-required-headers '((optional . References)
+                                     From)
+  "*Headers to be generated or prompted for when sending a message.
 Also see `message-required-news-headers' and
-1message-required-mail-headers'."
+`message-required-mail-headers'."
   :group 'message-news
   :group 'message-headers
   :type '(repeat sexp))
@@ -302,6 +308,8 @@ few false positives here."
   :group 'message-various
   :type 'regexp)
 
+;; Fixme: Why are all these things autoloaded?
+
 ;;; marking inserted text
 
 ;;;###autoload
@@ -322,7 +330,7 @@ few false positives here."
 (defcustom message-archive-header
   "X-No-Archive: Yes\n"
   "Header to insert when you don't want your article to be archived.
-Archives \(such as groups.googgle.com\) respect this header."
+Archives \(such as groups.google.com\) respect this header."
   :type 'string
   :group 'message-various)
 
@@ -331,7 +339,8 @@ Archives \(such as groups.googgle.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 'string
+  :type '(radio (string :format "%t: %v\n" :size 0)
+               (const nil))
   :group 'message-various)
 
 ;;; Crossposts and Followups
@@ -432,7 +441,7 @@ If t, use `message-user-organization-file'."
   :group 'message-headers)
 
 (defcustom message-make-forward-subject-function
-  'message-forward-subject-author-subject
+  'message-forward-subject-name-subject
   "*List of functions called to generate subject headers for forwarded messages.
 The subject generated by the previous function is passed into each
 successive function.
@@ -441,32 +450,38 @@ The provided functions are:
 
 * `message-forward-subject-author-subject' (Source of article (author or
       newsgroup)), in brackets followed by the subject
+* `message-forward-subject-name-subject' (Source of article (name of author
+      or newsgroup)), in brackets followed by the subject
 * `message-forward-subject-fwd' (Subject of article with 'Fwd:' prepended
       to it."
   :group 'message-forwarding
   :type '(radio (function-item message-forward-subject-author-subject)
                (function-item message-forward-subject-fwd)
+               (function-item message-forward-subject-name-subject)
                (repeat :tag "List of functions" function)))
 
 (defcustom message-forward-as-mime t
-  "*If non-nil, forward messages as an inline/rfc822 MIME section.  Otherwise, directly inline the old message in the forwarded message."
+  "*Non-nil means forward messages as an inline/rfc822 MIME section.
+Otherwise, directly inline the old message in the forwarded message."
   :version "21.1"
   :group 'message-forwarding
   :type 'boolean)
 
 (defcustom message-forward-show-mml t
-  "*If non-nil, forward messages are shown as mml.  Otherwise, forward messages are unchanged."
+  "*Non-nil means show forwarded messages as mml.
+Otherwise, forwarded messages are unchanged."
   :version "21.1"
   :group 'message-forwarding
   :type 'boolean)
 
 (defcustom message-forward-before-signature t
-  "*If non-nil, put forwarded message before signature, else after."
+  "*Non-nil means put forwarded message before signature, else after."
   :group 'message-forwarding
   :type 'boolean)
 
 (defcustom message-wash-forwarded-subjects nil
-  "*If non-nil, try to remove as much old cruft as possible from the subject of messages before generating the new subject of a forward."
+  "*Non-nil means try to remove as much cruft as possible from the subject.
+Done before generating the new subject of a forward."
   :group 'message-forwarding
   :type 'boolean)
 
@@ -589,7 +604,7 @@ always use the value."
 
 (defcustom message-subscribed-address-functions nil
   "*Specifies functions for determining list subscription.
-If nil, do not attempt to determine list subscribtion with functions.
+If nil, do not attempt to determine list subscription with functions.
 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
@@ -602,12 +617,13 @@ conjunction with `message-subscribed-regexps' and
 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."
   :group 'message-interface
-  :type 'string)
+  :type '(radio (file :format "%t: %v\n" :size 0)
+               (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 conjuction with
+addresses can be used in conjunction with
 `message-subscribed-address-functions' and `message-subscribed-regexps'."
   :group 'message-interface
   :type '(repeat string))
@@ -615,7 +631,7 @@ addresses can be used in conjuction with
 (defcustom message-subscribed-regexps nil
   "*Specifies a list of addresses the user is subscribed to.
 If nil, do not use any predefined list subscriptions.  This list of
-regular expressions can be used in conjuction with
+regular expressions can be used in conjunction with
 `message-subscribed-address-functions' and `message-subscribed-addresses'."
   :group 'message-interface
   :type '(repeat regexp))
@@ -636,6 +652,15 @@ Doing so would be even more evil than leaving it out."
   :group 'message-sending
   :type 'boolean)
 
+(defcustom message-sendmail-envelope-from nil
+  "*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."
+  :type '(choice (string :tag "From name")
+                (const :tag "Use From: header from message" header)
+                (const :tag "Use `user-mail-address'" nil))
+  :group 'message-sending)
+
 ;; qmail-related stuff
 (defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
   "Location of the qmail-inject program."
@@ -679,7 +704,11 @@ variable isn't used."
   ;; create a dependence to `gnus.el'.
   :type 'sexp)
 
-(defcustom message-generate-headers-first nil
+;; 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)
   "*If non-nil, generate all required headers before composing.
 The variables `message-required-news-headers' and
 `message-required-mail-headers' specify which headers to generate.
@@ -691,6 +720,7 @@ are to be deleted and then re-generated before sending, so this variable
 will not have a visible effect for those headers."
   :group 'message-headers
   :type '(choice (const :tag "None" nil)
+                 (const :tag "References" '(references))
                  (const :tag "All" t)
                  (repeat (sexp :tag "Header"))))
 
@@ -973,6 +1003,13 @@ candidates:
   (or (not (listp message-shoot-gnksa-feet))
       (memq feature message-shoot-gnksa-feet)))
 
+(defcustom message-hidden-headers nil
+  "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.."
+  :group 'message
+  :type '(repeat regexp))
+
 ;;; Internal variables.
 ;;; Well, not really internal.
 
@@ -1178,18 +1215,23 @@ candidates:
 The cdr of each entry is a function for applying the face to a region.")
 
 (defcustom message-send-hook nil
-  "Hook run before sending messages."
+  "Hook run before sending messages.
+This hook is run quite early when sending."
   :group 'message-various
   :options '(ispell-message)
   :type 'hook)
 
 (defcustom message-send-mail-hook nil
-  "Hook run before sending mail messages."
+  "Hook run before sending mail messages.
+This hook is run very late -- just before the message is sent as
+mail."
   :group 'message-various
   :type 'hook)
 
 (defcustom message-send-news-hook nil
-  "Hook run before sending news messages."
+  "Hook run before sending news messages.
+This hook is run very late -- just before the message is sent as
+news."
   :group 'message-various
   :type 'hook)
 
@@ -1268,6 +1310,24 @@ no, only reply back to the author."
   :group 'message-headers
   :type 'boolean)
 
+(defcustom message-user-fqdn nil
+  "*Domain part of Messsage-Ids."
+  :group 'message-headers
+  :link '(custom-manual "(message)News Headers")
+  :type '(radio (const :format "%v  " nil)
+               (string :format "FQDN: %v\n" :size 0)))
+
+(defcustom message-use-idna (and (condition-case nil (require 'idna)
+                                  (file-error))
+                                (mm-coding-system-p 'utf-8)
+                                (executable-find idna-program)
+                                'ask)
+  "Whether to encode non-ASCII in domain names into ASCII according to IDNA."
+  :group 'message-headers
+  :type '(choice (const :tag "Ask" ask)
+                (const :tag "Never" nil)
+                (const :tag "Always" t)))
+
 ;;; Internal variables.
 
 (defvar message-sending-message "Sending...")
@@ -1314,7 +1374,7 @@ no, only reply back to the author."
      ;; We want to match the results of any of these manglings.
      ;; The following regexp rejects names whose first characters are
      ;; obviously bogus, but after that anything goes.
-     "\\([^\0-\b\n-\r\^?].*\\)? "
+     "\\([^\0-\b\n-\r\^?].*\\)?"
 
      ;; The time the message was sent.
      "\\([^\0-\r \^?]+\\) +"           ; day of the week
@@ -1376,6 +1436,19 @@ no, only reply back to the author."
 (defvar message-bogus-system-names "^localhost\\."
   "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
+         "\\|biz\\|com\\|edu\\|gov\\|int\\|mil\\|net\\|org"
+         "\\|aero\\|coop\\|info\\|name\\|museum"
+         "\\|arpa\\|pro\\|uucp\\|bitnet\\|bofh" ;; old style?
+         "\\)")
+  "Regular expression that matches a valid FQDN."
+  ;; see also: gnus-button-valid-fqdn-regexp
+  :group 'message-headers
+  :type 'regexp)
+
 (eval-and-compile
   (autoload 'message-setup-toolbar "messagexmas")
   (autoload 'mh-new-draft-name "mh-comp")
@@ -1394,7 +1467,8 @@ no, only reply back to the author."
   (autoload 'gnus-group-name-decode "gnus-group")
   (autoload 'gnus-groups-from-server "gnus")
   (autoload 'rmail-output "rmailout")
-  (autoload 'gnus-delay-article "gnus-delay"))
+  (autoload 'gnus-delay-article "gnus-delay")
+  (autoload 'gnus-make-local-hook "gnus-util"))
 
 \f
 
@@ -1411,6 +1485,10 @@ no, only reply back to the author."
   `(delete-region (progn (beginning-of-line) (point))
                  (progn (forward-line ,(or n 1)) (point))))
 
+(defun message-mark-active-p ()
+  "Non-nil means the mark and region are currently active in this buffer."
+  mark-active)
+
 (defun message-unquote-tokens (elems)
   "Remove double quotes (\") from strings in list ELEMS."
   (mapcar (lambda (item)
@@ -1430,8 +1508,8 @@ is used by default."
          (beg 1)
          (first t)
          quoted elems paren)
-      (save-excursion
-       (message-set-work-buffer)
+      (with-temp-buffer
+       (mm-enable-multibyte)
        (insert header)
        (goto-char (point-min))
        (while (not (eobp))
@@ -1466,7 +1544,9 @@ is used by default."
       (looking-at message-unix-mail-delimiter))))
 
 (defun message-fetch-field (header &optional not-all)
-  "The same as `mail-fetch-field', only remove all newlines."
+  "The same as `mail-fetch-field', only remove all newlines.
+The buffer is expected to be narrowed to just the header of the message;
+see `message-narrow-to-headers-or-head'."
   (let* ((inhibit-point-motion-hooks t)
         (case-fold-search t)
         (value (mail-fetch-field header nil (not not-all))))
@@ -1520,22 +1600,9 @@ is used by default."
 (defun message-fetch-reply-field (header)
   "Fetch field HEADER from the message we're replying to."
   (message-with-reply-buffer
-    (message-fetch-field header)))
-
-(defun message-set-work-buffer ()
-  (if (get-buffer " *message work*")
-      (progn
-       (set-buffer " *message work*")
-       (erase-buffer))
-    (set-buffer (get-buffer-create " *message work*"))
-    (kill-all-local-variables)
-    (mm-enable-multibyte)))
-
-(defun message-functionp (form)
-  "Return non-nil if FORM is funcallable."
-  (or (and (symbolp form) (fboundp form))
-      (and (listp form) (eq (car form) 'lambda))
-      (byte-code-function-p form)))
+    (save-restriction
+      (mail-narrow-to-head)
+      (message-fetch-field header))))
 
 (defun message-strip-list-identifiers (subject)
   "Remove list identifiers in `gnus-list-identifiers' from string SUBJECT."
@@ -1604,7 +1671,10 @@ Leading \"Re: \" is not stripped by this function.  Use the function
                       (zerop (string-width new-subject))
                       (string-match "^[ \t]*$" new-subject))))
         (save-excursion
-          (let ((old-subject (message-fetch-field "Subject")))
+          (let ((old-subject
+                 (save-restriction
+                   (message-narrow-to-headers)
+                   (message-fetch-field "Subject"))))
             (cond ((not old-subject)
                    (error "No current subject"))
                   ((not (string-match
@@ -1700,7 +1770,7 @@ With prefix-argument just set Follow-Up, don't cross-post."
              (not (string-match (regexp-quote target-group)
                                 (message-fetch-field "Newsgroups"))))
         (end-of-line)
-        (insert-string (concat "," target-group))))
+        (insert (concat "," target-group))))
   (end-of-line) ; ensure Followup: comes after Newsgroups:
   ;; unless new followup would be identical to Newsgroups line
   ;; make a new Followup-To line
@@ -1790,19 +1860,26 @@ With prefix-argument just set Follow-Up, don't cross-post."
 (defun message-reduce-to-to-cc ()
  "Replace contents of To: header with contents of Cc: or Bcc: header."
  (interactive)
- (let ((cc-content (message-fetch-field "cc"))
+ (let ((cc-content
+       (save-restriction (message-narrow-to-headers)
+                         (message-fetch-field "cc")))
        (bcc nil))
    (if (and (not cc-content)
-           (setq cc-content (message-fetch-field "bcc")))
+           (setq cc-content
+                 (save-restriction
+                   (message-narrow-to-headers)
+                   (message-fetch-field "bcc"))))
        (setq bcc t))
    (cond (cc-content
          (save-excursion
            (message-goto-to)
            (message-delete-line)
            (insert (concat "To: " cc-content "\n"))
-           (message-remove-header (if bcc
-                                      "bcc"
-                                    "cc")))))))
+           (save-restriction
+             (message-narrow-to-headers)
+             (message-remove-header (if bcc
+                                        "bcc"
+                                      "cc"))))))))
 
 ;;; End of functions adopted from `message-utils.el'.
 
@@ -2013,7 +2090,7 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
 
   (define-key message-mode-map "\C-c\C-t" 'message-insert-to)
-  (define-key message-mode-map "\C-c\M-t" 'message-insert-wide-reply)
+  (define-key message-mode-map "\C-c\C-fw" 'message-insert-wide-reply)
   (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
   (define-key message-mode-map "\C-c\C-l" 'message-to-list-only)
 
@@ -2041,6 +2118,7 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
   (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
   ;;(define-key message-mode-map "\M-q" 'message-fill-paragraph)
+  (define-key message-mode-map [remap split-line]  'message-split-line)
 
   (define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
 
@@ -2051,13 +2129,19 @@ Point is left at the beginning of the narrowed-to region."
 (easy-menu-define
   message-mode-menu message-mode-map "Message Menu."
   `("Message"
-    ["Yank Original" message-yank-original t]
+    ["Yank Original" message-yank-original message-reply-buffer]
     ["Fill Yanked Message" message-fill-yanked-message t]
     ["Insert Signature" message-insert-signature t]
     ["Caesar (rot13) Message" message-caesar-buffer-body t]
-    ["Caesar (rot13) Region" message-caesar-region (mark t)]
-    ["Elide Region" message-elide-region (mark t)]
-    ["Delete Outside Region" message-delete-not-region (mark t)]
+    ["Caesar (rot13) Region" message-caesar-region (message-mark-active-p)]
+    ["Elide Region" message-elide-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Replace text in region with an ellipsis"))]
+    ["Delete Outside Region" message-delete-not-region
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
+        '(:help "Delete all quoted text outside region"))]
     ["Kill To Signature" message-kill-to-signature t]
     ["Newline and Reformat" message-newline-and-reformat t]
     ["Rename buffer" message-rename-buffer t]
@@ -2066,7 +2150,8 @@ Point is left at the beginning of the narrowed-to region."
         '(:help "Spellcheck this message"))]
     "----"
     ["Insert Region Marked" message-mark-inserted-region
-     ,@(if (featurep 'xemacs) '(t)
+     :active (message-mark-active-p)
+     ,@(if (featurep 'xemacs) nil
         '(:help "Mark region with enclosing tags"))]
     ["Insert File Marked..." message-mark-insert-file
      ,@(if (featurep 'xemacs) '(t)
@@ -2087,7 +2172,7 @@ Point is left at the beginning of the narrowed-to region."
 
 (easy-menu-define
   message-mode-field-menu message-mode-map ""
-  '("Field"
+  `("Field"
     ["Fetch To" message-insert-to t]
     ["Fetch Newsgroups" message-insert-newsgroups t]
     "----"
@@ -2126,6 +2211,7 @@ Point is left at the beginning of the narrowed-to region."
     ["Reduce To: to Cc:" message-reduce-to-to-cc t]
     "----"
     ["Sort Headers" message-sort-headers t]
+    ["Encode non-ASCII domain names" message-idna-to-ascii-rhs t]
     ["Goto Body" message-goto-body t]
     ["Goto Signature" message-goto-signature t]))
 
@@ -2157,7 +2243,7 @@ message composition doesn't break too bad."
   ;; 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'.
-  '(field nil read-only nil intangible nil invisible nil
+  '(field nil read-only nil invisible nil intangible nil
          mouse-face nil modification-hooks nil insert-in-front-hooks nil
          insert-behind-hooks nil point-entered nil point-left nil)
   ;; Other special properties:
@@ -2188,7 +2274,11 @@ 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))
-    (remove-text-properties begin end message-forbidden-properties)))
+    (while (not (= begin end))
+      (when (not (get-text-property begin 'message-hidden))
+       (remove-text-properties begin (1+ begin)
+                               message-forbidden-properties))
+      (incf begin))))
 
 ;;;###autoload
 (define-derived-mode message-mode text-mode "Message"
@@ -2252,6 +2342,11 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
   (set (make-local-variable 'message-checksum) nil)
   (set (make-local-variable 'message-mime-part) 0)
   (message-setup-fill-variables)
+  (set
+   (make-local-variable 'paragraph-separate)
+   (format "\\(%s\\)\\|\\(%s\\)"
+          paragraph-separate
+          "<#!*/?\\(multipart\\|part\\|external\\|mml\\|secure\\)"))
   ;; Allow using comment commands to add/remove quoting.
   (set (make-local-variable 'comment-start) message-yank-prefix)
   (if (featurep 'xemacs)
@@ -2262,9 +2357,7 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
        (set (make-local-variable 'tool-bar-map) (message-tool-bar-map))))
   (easy-menu-add message-mode-menu message-mode-map)
   (easy-menu-add message-mode-field-menu message-mode-map)
-  ;; make-local-hook is harmless though obsolete in Emacs 21.
-  ;; Emacs 20 and XEmacs need make-local-hook.
-  (make-local-hook 'after-change-functions)
+  (gnus-make-local-hook 'after-change-functions)
   ;; Mmmm... Forbidden properties...
   (add-hook 'after-change-functions 'message-strip-forbidden-properties
            nil 'local)
@@ -2272,7 +2365,8 @@ M-RET    `message-newline-and-reformat' (break the line and reformat)."
   (when (eq message-mail-alias-type 'abbrev)
     (if (fboundp 'mail-abbrevs-setup)
        (mail-abbrevs-setup)
-      (mail-aliases-setup)))
+      (if (fboundp 'mail-aliases-setup)        ; warning avoidance
+         (mail-aliases-setup))))
   (unless buffer-file-name
     (message-set-auto-save-file-name))
   (unless (buffer-base-buffer)
@@ -2436,11 +2530,14 @@ If the optional argument INCLUDE-CC is non-nil, the addresses in the
 Cc: header are also put into the MFT."
 
   (interactive "P")
-  (message-remove-header "Mail-Followup-To")
-  (let* ((cc (and include-cc (message-fetch-field "Cc")))
-        (tos (if cc
-                 (concat (message-fetch-field "To") "," cc)
-               (message-fetch-field "To"))))
+  (let* (cc tos)
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Mail-Followup-To")
+      (setq cc (and include-cc (message-fetch-field "Cc")))
+      (setq tos (if cc
+                   (concat (message-fetch-field "To") "," cc)
+                 (message-fetch-field "To"))))
     (message-goto-mail-followup-to)
     (insert (concat tos ", " user-mail-address))))
 
@@ -2544,7 +2641,7 @@ With the prefix argument FORCE, insert the header anyway."
   (let ((point (point)))
     (message-goto-signature)
     (unless (eobp)
-      (forward-line -2))
+      (end-of-line -1))
     (kill-region point (point))
     (unless (bolp)
       (insert "\n"))))
@@ -2627,6 +2724,7 @@ Prefix arg means justify as well."
        (delete-region (point) (re-search-forward "[ \t]*"))
        (when (and quoted (not bolp))
          (insert quoted leading-space)))
+      (undo-boundary)
       (if quoted
          (let* ((adaptive-fill-regexp
                  (regexp-quote (concat quoted leading-space)))
@@ -2639,7 +2737,7 @@ Prefix arg means justify as well."
 (defun message-fill-paragraph (&optional arg)
   "Like `fill-paragraph'."
   (interactive (list (if current-prefix-arg 'full)))
-  (if (and (boundp 'filladapt-mode) filladapt-mode)
+  (if (if (boundp 'filladapt-mode) filladapt-mode)
       nil
     (message-newline-and-reformat arg t)
     t))
@@ -2672,7 +2770,7 @@ Prefix arg means justify as well."
           ((and (null message-signature)
                 force)
            t)
-          ((message-functionp message-signature)
+          ((functionp message-signature)
            (funcall message-signature))
           ((listp message-signature)
            (eval message-signature))
@@ -2702,7 +2800,9 @@ Prefix arg means justify as well."
   "Insert header to mark message as important."
   (interactive)
   (save-excursion
-    (message-remove-header "Importance")
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Importance"))
     (message-goto-eoh)
     (insert "Importance: high\n")))
 
@@ -2710,7 +2810,9 @@ Prefix arg means justify as well."
   "Insert header to mark message as unimportant."
   (interactive)
   (save-excursion
-    (message-remove-header "Importance")
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Importance"))
     (message-goto-eoh)
     (insert "Importance: low\n")))
 
@@ -2723,14 +2825,16 @@ and `low'."
     (let ((valid '("high" "normal" "low"))
          (new "high")
          cur)
-      (when (setq cur (message-fetch-field "Importance"))
-       (message-remove-header "Importance")
-       (setq new (cond ((string= cur "high")
-                        "low")
-                       ((string= cur "low")
-                        "normal")
-                       (t
-                        "high"))))
+      (save-restriction
+       (message-narrow-to-headers)
+       (when (setq cur (message-fetch-field "Importance"))
+         (message-remove-header "Importance")
+         (setq new (cond ((string= cur "high")
+                          "low")
+                         ((string= cur "low")
+                          "normal")
+                         (t
+                          "high")))))
       (message-goto-eoh)
       (insert (format "Importance: %s\n" new)))))
 
@@ -2739,10 +2843,16 @@ and `low'."
 Note that this should not be used in newsgroups."
   (interactive)
   (save-excursion
-    (message-remove-header "Disposition-Notification-To")
+    (save-restriction
+      (message-narrow-to-headers)
+      (message-remove-header "Disposition-Notification-To"))
     (message-goto-eoh)
     (insert (format "Disposition-Notification-To: %s\n"
-                   (or (message-fetch-field "From") (message-make-from))))))
+                   (or (save-excursion
+                         (save-restriction
+                           (message-narrow-to-headers)
+                           (message-fetch-field "From")))
+                       (message-make-from))))))
 
 (defun message-elide-region (b e)
   "Elide the text in the region.
@@ -3134,6 +3244,7 @@ It should typically alter the sending method in some way or other."
       (when (funcall (cadr elem))
        (when (and (or (not (memq (car elem)
                                  message-sent-message-via))
+                      (not (message-fetch-field "supersedes"))
                       (if (or (message-gnksa-enable-p 'multiple-copies)
                               (not (eq (car elem) 'news)))
                           (y-or-n-p
@@ -3207,16 +3318,26 @@ It should typically alter the sending method in some way or other."
   (goto-char (point-max))
   (unless (bolp)
     (insert "\n"))
-  ;; Delete all invisible text.
+  ;; 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)))))
+  ;; 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)
-         (add-text-properties point (1+ point)
-                              '(invisible nil highlight t)))
+         (put-text-property point (1+ point) 'invisible nil)
+         (message-overlay-put (message-make-overlay point (1+ point))
+                              'face 'highlight))
        (unless (yes-or-no-p
-                "Invisible text found and made visible; continue posting? ")
+                "Invisible text found and made visible; continue sending? ")
          (error "Invisible text found and made visible")))))
   (message-check 'illegible-text
     (let (found choice)
@@ -3226,37 +3347,41 @@ It should typically alter the sending method in some way or other."
        (when (let ((char (char-after)))
                (or (< (mm-char-int char) 128)
                    (and (mm-multibyte-p)
-                        (memq (char-charset char)
-                              '(eight-bit-control eight-bit-graphic
-                                                  control-1)))))
-         (add-text-properties (point) (1+ (point)) '(highlight t))
+                        (> (length (mm-find-mime-charset-region
+                                    (point) (point-max)))
+                           1))))
+         (message-overlay-put (message-make-overlay (point) (1+ (point)))
+                              'face 'highlight)
          (setq found t))
        (forward-char)
        (skip-chars-forward mm-7bit-chars))
       (when found
        (setq choice
              (gnus-multiple-choice
-              "Illegible text found. Continue posting? "
-              '((?d "Remove and continue posting")
-                (?r "Replace with dots and continue posting")
-                (?i "Ignore and continue posting")
+              "Non-printable characters found.  Continue sending?"
+              '((?d "Remove non-printable characters and send")
+                (?r "Replace non-printable characters with dots and send")
+                (?i "Ignore non-printable characters and send")
                 (?e "Continue editing"))))
        (if (eq choice ?e)
-         (error "Illegible text found"))
+         (error "Non-printable characters"))
        (message-goto-body)
        (skip-chars-forward mm-7bit-chars)
        (while (not (eobp))
          (when (let ((char (char-after)))
                  (or (< (mm-char-int char) 128)
                      (and (mm-multibyte-p)
+                          ;; Fixme: Wrong for Emacs 22 and for things
+                          ;; like undecable utf-8.  Should at least
+                          ;; use find-coding-systems-region.
                           (memq (char-charset char)
                                 '(eight-bit-control eight-bit-graphic
                                                     control-1)))))
            (if (eq choice ?i)
-               (remove-text-properties (point) (1+ (point)) '(highlight t))
+               (message-kill-all-overlays)
              (delete-char 1)
-             (if (eq choice ?r)
-                 (insert "."))))
+             (when (eq choice ?r)
+               (insert "."))))
          (forward-char)
          (skip-chars-forward mm-7bit-chars))))))
 
@@ -3280,7 +3405,7 @@ It should typically alter the sending method in some way or other."
     (ignore-errors
       (cond
        ;; A simple function.
-       ((message-functionp (car actions))
+       ((functionp (car actions))
        (funcall (car actions)))
        ;; Something to be evaled.
        (t
@@ -3336,7 +3461,7 @@ It should typically alter the sending method in some way or other."
              (message-remove-header "Lines")
              (goto-char (point-max))
              (insert "Mime-Version: 1.0\n")
-             (setq header (buffer-substring (point-min) (point-max))))
+             (setq header (buffer-string)))
            (goto-char (point-max))
            (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n\n"
                            id n total))
@@ -3412,19 +3537,29 @@ It should typically alter the sending method in some way or other."
          (or (= (preceding-char) ?\n)
              (insert ?\n))
          (message-cleanup-headers)
+         ;; FIXME: we're inserting the courtesy copy after encoding.
+         ;; This is wrong if the courtesy copy string contains
+         ;; non-ASCII characters. -- jh
          (when
              (save-restriction
                (message-narrow-to-headers)
                (and news
                     (or (message-fetch-field "cc")
+                        (message-fetch-field "bcc")
                         (message-fetch-field "to"))
-                    (let ((content-type (message-fetch-field "content-type")))
-                      (or
-                       (not content-type)
-                       (string= "text/plain"
-                                (car
-                                 (mail-header-parse-content-type
-                                  content-type)))))))
+                    (let ((content-type (message-fetch-field
+                                         "content-type")))
+                      (and
+                       (or
+                        (not content-type)
+                        (string= "text/plain"
+                                 (car
+                                  (mail-header-parse-content-type
+                                   content-type))))
+                       (not
+                        (string= "base64"
+                                 (message-fetch-field
+                                  "content-transfer-encoding")))))))
            (message-insert-courtesy-copy))
          (if (or (not message-send-mail-partially-limit)
                  (< (point-max) message-send-mail-partially-limit)
@@ -3448,7 +3583,7 @@ sent in one piece.
 
 The size limit is controlled by `message-send-mail-partially-limit'.
 If you always want Gnus to send messages in one piece, set
-`message-send-mail-partially-limit' to `nil'.
+`message-send-mail-partially-limit' to nil.
 ")))
              (mm-with-unibyte-current-buffer
                (message "Sending via mail...")
@@ -3504,7 +3639,7 @@ If you always want Gnus to send messages in one piece, set
                        ;; But some systems are more broken with -f, so
                        ;; we'll let users override this.
                        (if (null message-sendmail-f-is-evil)
-                           (list "-f" (message-make-address)))
+                           (list "-f" (message-sendmail-envelope-from)))
                        ;; These mean "report errors by mail"
                        ;; and "deliver in background".
                        (if (null message-interactive) '("-oem" "-odb"))
@@ -3516,7 +3651,7 @@ If you always want Gnus to send messages in one piece, set
                        (if resend-to-addresses
                            (list resend-to-addresses)
                          '("-t"))))))
-           (unless (or (null cpr) (zerop cpr))
+           (unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
              (error "Sending...failed with exit value %d" cpr)))
          (when message-interactive
            (save-excursion
@@ -3526,7 +3661,7 @@ If you always want Gnus to send messages in one piece, set
                (replace-match "; "))
              (if (not (zerop (buffer-size)))
                  (error "Sending...failed to %s"
-                        (buffer-substring (point-min) (point-max)))))))
+                        (buffer-string))))))
       (when (bufferp errbuf)
        (kill-buffer errbuf)))))
 
@@ -3563,7 +3698,7 @@ to find out how to use this."
         ;; free for -inject-arguments -- a big win for the user and for us
         ;; since we don't have to play that double-guessing game and the user
         ;; gets full control (no gestapo'ish -f's, for instance).  --sj
-         (if (message-functionp message-qmail-inject-args)
+         (if (functionp message-qmail-inject-args)
              (funcall message-qmail-inject-args)
            message-qmail-inject-args)))
     ;; qmail-inject doesn't say anything on it's stdout/stderr,
@@ -3602,7 +3737,7 @@ documentation for the function `mail-source-touch-pop'."
   (smtpmail-send-it))
 
 (defun message-canlock-generate ()
-  "Return a string that is non-trival to guess.
+  "Return a string that is non-trivial to guess.
 Do not use this for anything important, it is cryptographically weak."
   (let (sha1-maximum-internal-length)
     (sha1 (concat (message-unique-id)
@@ -3627,7 +3762,7 @@ Otherwise, generate and save a value for `canlock-password' first."
 (defun message-send-news (&optional arg)
   (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
         (case-fold-search nil)
-        (method (if (message-functionp message-post-method)
+        (method (if (functionp message-post-method)
                     (funcall message-post-method arg)
                   message-post-method))
         (newsgroups-field (save-restriction
@@ -3779,16 +3914,20 @@ Otherwise, generate and save a value for `canlock-password' first."
    ;; Check long header lines.
    (message-check 'long-header-lines
      (let ((start (point))
+          (header nil)
+          (length 0)
           found)
        (while (and (not found)
                   (re-search-forward "^\\([^ \t:]+\\): " nil t))
-        (when (> (- (point) start) 998)
-          (setq found t))
+        (if (> (- (point) (match-beginning 0)) 998)
+            (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.  Really post? "
-                            (match-string 1)))
+          (y-or-n-p (format "Your %s header is too long (%d).  Really post? "
+                            header length))
         t)))
    ;; Check for multiple identical headers.
    (message-check 'multiple-headers
@@ -3829,7 +3968,7 @@ Otherwise, generate and save a value for `canlock-password' first."
                    (length
                     (setq to (completing-read
                               "Followups to (default: no Followup-To header) "
-                              (mapcar (lambda (g) (list g))
+                              (mapcar #'list
                                       (cons "poster"
                                             (message-tokenize-header
                                              newsgroups)))))))))
@@ -3839,7 +3978,7 @@ Otherwise, generate and save a value for `canlock-password' first."
    ;; Check "Shoot me".
    (message-check 'shoot
      (if (re-search-forward
-         "Message-ID.*.i-did-not-set--mail-host-address--so-shoot-me" nil t)
+         "Message-ID.*.i-did-not-set--mail-host-address--so-tickle-me" nil t)
         (y-or-n-p "You appear to have a misconfigured system.  Really post? ")
        t))
    ;; Check for Approved.
@@ -3870,7 +4009,7 @@ Otherwise, generate and save a value for `canlock-password' first."
                     (if followup-to
                         (concat newsgroups "," followup-to)
                       newsgroups)))
-           (post-method (if (message-functionp message-post-method)
+           (post-method (if (functionp message-post-method)
                             (funcall message-post-method)
                           message-post-method))
            ;; KLUDGE to handle nnvirtual groups.  Doing this right
@@ -3892,8 +4031,9 @@ Otherwise, generate and save a value for `canlock-password' first."
                     (gnus-groups-from-server method)))
            errors)
        (while groups
-        (unless (or (equal (car groups) "poster")
-                    (member (car groups) known-groups))
+        (when (and (not (equal (car groups) "poster"))
+                   (not (member (car groups) known-groups))
+                   (not (member (car groups) errors)))
           (push (car groups) errors))
         (pop groups))
        (cond
@@ -3908,7 +4048,7 @@ Otherwise, generate and save a value for `canlock-password' first."
              errors)
         (y-or-n-p
          (format
-          "Really post to %s possibly unknown group%s: %s? "
+          "Really use %s possibly unknown group%s: %s? "
           (if (= (length errors) 1) "this" "these")
           (if (= (length errors) 1) "" "s")
           (mapconcat 'identity errors ", "))))
@@ -4290,9 +4430,9 @@ If NOW, use that time instead."
                               (lsh (% message-unique-id-char 25) 16)) 4)
      (message-number-base36 (+ (nth 1 tm)
                               (lsh (/ message-unique-id-char 25) 16)) 4)
-     ;; Append the newsreader name, because while the generated
-     ;; ID is unique to this newsreader, other newsreaders might
-     ;; otherwise generate the same ID via another algorithm.
+     ;; Append a given name, because while the generated ID is unique
+     ;; to this newsreader, other newsreaders might otherwise generate
+     ;; the same ID via another algorithm.
      ".fsf")))
 
 (defun message-number-base36 (num len)
@@ -4308,11 +4448,11 @@ If NOW, use that time instead."
   "Make an Organization header."
   (let* ((organization
          (when message-user-organization
-           (if (message-functionp message-user-organization)
+           (if (functionp message-user-organization)
                (funcall message-user-organization)
              message-user-organization))))
-    (save-excursion
-      (message-set-work-buffer)
+    (with-temp-buffer
+      (mm-enable-multibyte)
       (cond ((stringp organization)
             (insert organization))
            ((and (eq t organization)
@@ -4351,12 +4491,10 @@ If NOW, use that time instead."
          (date (mail-header-date message-reply-headers))
          (msg-id (mail-header-message-id message-reply-headers)))
       (when from
-       (let ((stop-pos
-              (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+       (let ((name (mail-extract-address-components from)))
          (concat msg-id (if msg-id " (")
-                 (if (and stop-pos
-                          (not (zerop stop-pos)))
-                     (substring from 0 stop-pos) from)
+                 (or (car name)
+                     (nth 1 name))
                  "'s message of \""
                  (if (or (not date) (string= date ""))
                      "(unknown date)" date)
@@ -4365,7 +4503,7 @@ If NOW, use that time instead."
 (defun message-make-distribution ()
   "Make a Distribution header."
   (let ((orig-distribution (message-fetch-reply-field "distribution")))
-    (cond ((message-functionp message-distribution-function)
+    (cond ((functionp message-distribution-function)
           (funcall message-distribution-function))
          (t orig-distribution))))
 
@@ -4398,8 +4536,8 @@ If NOW, use that time instead."
              (user-full-name))))
     (when (string= fullname "&")
       (setq fullname (user-login-name)))
-    (save-excursion
-      (message-set-work-buffer)
+    (with-temp-buffer
+      (mm-enable-multibyte)
       (cond
        ((or (null style)
            (equal fullname ""))
@@ -4415,6 +4553,16 @@ If NOW, use that time instead."
                         (aset tmp (1- (match-end 0)) ?-))
                       (string-match "[\\()]" tmp)))))
        (insert fullname)
+       (goto-char (point-min))
+       ;; Look for a character that cannot appear unquoted
+       ;; according to RFC 822.
+       (when (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" nil 1)
+         ;; Quote fullname, escaping specials.
+         (goto-char (point-min))
+         (insert "\"")
+         (while (re-search-forward "[\"\\]" nil 1)
+           (replace-match "\\\\\\&" t))
+         (insert "\""))
        (insert " <" login ">"))
        (t                              ; 'parens or default
        (insert login " (")
@@ -4450,33 +4598,57 @@ give as trustworthy answer as possible."
 
 (defun message-user-mail-address ()
   "Return the pertinent part of `user-mail-address'."
-  (when user-mail-address
+  (when (and user-mail-address
+            (string-match "@.*\\." user-mail-address))
     (if (string-match " " user-mail-address)
        (nth 1 (mail-extract-address-components user-mail-address))
       user-mail-address)))
 
+(defun message-sendmail-envelope-from ()
+  "Return the envelope from."
+  (cond ((eq message-sendmail-envelope-from 'header)
+        (nth 1 (mail-extract-address-components
+                (message-fetch-field "from"))))
+       ((stringp message-sendmail-envelope-from)
+        message-sendmail-envelope-from)
+       (t
+        (message-make-address))))
+
 (defun message-make-fqdn ()
   "Return user's fully qualified domain name."
-  (let ((system-name (system-name))
-       (user-mail (message-user-mail-address)))
+  (let* ((system-name (system-name))
+        (user-mail (message-user-mail-address))
+        (user-domain
+         (if (and user-mail
+                  (string-match "@\\(.*\\)\\'" user-mail))
+             (match-string 1 user-mail))))
     (cond
-     ((and (string-match "[^.]\\.[^.]" system-name)
+     ((and message-user-fqdn
+          (stringp message-user-fqdn)
+          (string-match message-valid-fqdn-regexp message-user-fqdn)
+          (not (string-match message-bogus-system-names message-user-fqdn)))
+      message-user-fqdn)
+     ;; `message-user-fqdn' seems to be valid
+     ((and (string-match message-valid-fqdn-regexp system-name)
           (not (string-match message-bogus-system-names system-name)))
       ;; `system-name' returned the right result.
       system-name)
      ;; Try `mail-host-address'.
      ((and (boundp 'mail-host-address)
           (stringp mail-host-address)
-          (string-match "\\." mail-host-address))
+          (string-match message-valid-fqdn-regexp mail-host-address)
+          (not (string-match message-bogus-system-names mail-host-address)))
       mail-host-address)
      ;; We try `user-mail-address' as a backup.
-     ((and user-mail
-          (string-match "\\." user-mail)
-          (string-match "@\\(.*\\)\\'" user-mail))
-      (match-string 1 user-mail))
+     ((and user-domain
+          (stringp user-domain)
+          (string-match message-valid-fqdn-regexp user-domain)
+          (not (string-match message-bogus-system-names user-domain)))
+      user-domain)
      ;; Default to this bogus thing.
      (t
-      (concat system-name ".i-did-not-set--mail-host-address--so-tickle-me")))))
+      (concat system-name
+             ".i-did-not-set--mail-host-address--so-tickle-me")))))
 
 (defun message-make-host-name ()
   "Return the name of the host."
@@ -4545,6 +4717,70 @@ subscribed address (and not the additional To and Cc header contents)."
              list
            msg-recipients))))))
 
+(defun message-idna-inside-rhs-p ()
+  "Return t iff point is inside a RHS (heuristically).
+Only works properly if header contains mailbox-list or address-list.
+I.e., calling it on a Subject: header is useless."
+  (save-restriction
+    (narrow-to-region (save-excursion (or (re-search-backward "^[^ \t]" nil t)
+                                         (point-min)))
+                     (save-excursion (or (re-search-forward "^[^ \t]" nil t)
+                                         (point-max))))
+    (if (re-search-backward "[\\\n\r\t ]"
+                           (save-excursion (search-backward "@" nil t)) t)
+       ;; whitespace between @ and point
+       nil
+      (let ((dquote 1) (paren 1))
+       (while (save-excursion (re-search-backward "[^\\]\"" nil t dquote))
+         (incf dquote))
+       (while (save-excursion (re-search-backward "[^\\]\(" nil t paren))
+         (incf paren))
+       (and (= (% dquote 2) 1) (= (% paren 2) 1))))))
+
+(autoload 'idna-to-ascii "idna")
+
+(defun message-idna-to-ascii-rhs-1 (header)
+  "Interactively potentially IDNA encode domain names in HEADER."
+  (let (rhs ace start startpos endpos ovl)
+    (goto-char (point-min))
+    (while (re-search-forward (concat "^" header) nil t)
+      (while (re-search-forward "@\\([^ \t\r\n>]+\\)"
+                               (or (save-excursion
+                                     (re-search-forward "^[^ \t]" nil t))
+                                   (point-max))
+                               t)
+       (setq rhs (match-string-no-properties 1)
+             startpos (match-beginning 1)
+             endpos (match-end 1))
+       (when (save-match-data
+               (and (message-idna-inside-rhs-p)
+                    (setq ace (idna-to-ascii rhs))
+                    (not (string= rhs ace))
+                    (if (eq message-use-idna 'ask)
+                        (unwind-protect
+                            (progn
+                              (setq ovl (message-make-overlay startpos
+                                                              endpos))
+                              (message-overlay-put ovl 'face 'highlight)
+                              (y-or-n-p
+                               (format "Replace with `%s'? " ace)))
+                          (message "")
+                          (message-delete-overlay ovl))
+                      message-use-idna)))
+         (replace-match (concat "@" ace)))))))
+
+(defun message-idna-to-ascii-rhs ()
+  "Possibly IDNA encode non-ASCII domain names in From:, To: and Cc: headers.
+See `message-idna-encode'."
+  (interactive)
+  (when message-use-idna
+    (save-excursion
+      (save-restriction
+       (message-narrow-to-head)
+       (message-idna-to-ascii-rhs-1 "From")
+       (message-idna-to-ascii-rhs-1 "To")
+       (message-idna-to-ascii-rhs-1 "Cc")))))
+
 (defun message-generate-headers (headers)
   "Prepare article HEADERS.
 Headers already prepared in the buffer are not modified."
@@ -4566,6 +4802,7 @@ Headers already prepared in the buffer are not modified."
           (User-Agent message-newsreader)
           (Expires (message-make-expires))
           (case-fold-search t)
+          (optionalp nil)
           header value elem)
       ;; First we remove any old generated headers.
       (let ((headers message-deletable-headers))
@@ -4587,7 +4824,8 @@ Headers already prepared in the buffer are not modified."
        (setq elem (pop headers))
        (if (consp elem)
            (if (eq (car elem) 'optional)
-               (setq header (cdr elem))
+               (setq header (cdr elem)
+                     optionalp t)
              (setq header (car elem)))
          (setq header elem))
        (when (or (not (re-search-forward
@@ -4603,7 +4841,7 @@ Headers already prepared in the buffer are not modified."
                    ;; The header was found.  We insert a space after the
                    ;; colon, if there is none.
                    (if (/= (char-after) ? ) (insert " ") (forward-char 1))
-                   ;; Find out whether the header is empty...
+                   ;; Find out whether the header is empty.
                    (looking-at "[ \t]*\n[^ \t]")))
          ;; So we find out what value we should insert.
          (setq value
@@ -4614,7 +4852,7 @@ Headers already prepared in the buffer are not modified."
                  ;; is something that is nil, then we do not insert
                  ;; this header.
                  (setq header (cdr elem))
-                 (or (and (message-functionp (cdr elem))
+                 (or (and (functionp (cdr elem))
                           (funcall (cdr elem)))
                      (and (boundp (cdr elem))
                           (symbol-value (cdr elem)))))
@@ -4625,7 +4863,7 @@ Headers already prepared in the buffer are not modified."
                  ;; this function.
                  (or (and (stringp (cdr elem))
                           (cdr elem))
-                     (and (message-functionp (cdr elem))
+                     (and (functionp (cdr elem))
                           (funcall (cdr elem)))))
                 ((and (boundp header)
                       (symbol-value header))
@@ -4660,7 +4898,10 @@ Headers already prepared in the buffer are not modified."
                ;; The value of this header was empty, so we clear
                ;; totally and insert the new value.
                (delete-region (point) (gnus-point-at-eol))
-               (insert value))
+               ;; If the header is optional, and the header was
+               ;; empty, we con't insert it anyway.
+               (unless optionalp
+                 (insert value)))
              ;; Add the deletable property to the headers that require it.
              (and (memq header message-deletable-headers)
                   (progn (beginning-of-line) (looking-at "[^:]+: "))
@@ -4691,7 +4932,9 @@ Headers already prepared in the buffer are not modified."
            (beginning-of-line))
          (when (or (message-news-p)
                    (string-match "@.+\\.." secure-sender))
-           (insert "Sender: " secure-sender "\n")))))))
+           (insert "Sender: " secure-sender "\n"))))
+      ;; Check for IDNA
+      (message-idna-to-ascii-rhs))))
 
 (defun message-insert-courtesy-copy ()
   "Insert a courtesy message in mail copies of combined messages."
@@ -4744,6 +4987,16 @@ Headers already prepared in the buffer are not modified."
     (widen)
     (forward-line 1)))
 
+(defun message-split-line ()
+  "Split current line, moving portion beyond point vertically down.
+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.
+    (error
+     (split-line))))
+     
+
 (defun message-fill-header (header value)
   (let ((begin (point))
        (fill-column 78)
@@ -4843,12 +5096,24 @@ than 988 characters long, and if they are not, trim them until they are."
    (sit-for 0)))
 
 (defcustom message-beginning-of-line t
-  "Whether C-a goes to beginning of header values."
+  "Whether \\<message-mode-map>\\[message-beginning-of-line]\
+ goes to beginning of header values."
   :group 'message-buffers
   :type 'boolean)
 
 (defun message-beginning-of-line (&optional n)
-  "Move point to beginning of header value or to beginning of line."
+  "Move point to beginning of header value or to beginning of line.
+The prefix argument N is passed directly to `beginning-of-line'.
+
+This command is identical to `beginning-of-line' if point is
+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."
   (interactive "p")
   (let ((zrs 'zmacs-region-stays))
     (when (and (interactive-p) (boundp zrs))
@@ -4880,7 +5145,7 @@ than 988 characters long, and if they are not, trim them until they are."
             "*")))
    ;; Check whether `message-generate-new-buffers' is a function,
    ;; and if so, call it.
-   ((message-functionp message-generate-new-buffers)
+   ((functionp message-generate-new-buffers)
     (funcall message-generate-new-buffers type to group))
    ((eq message-generate-new-buffers 'unsent)
     (generate-new-buffer-name
@@ -5058,6 +5323,10 @@ are not included."
     (when message-default-mail-headers
       (insert message-default-mail-headers)
       (or (bolp) (insert ?\n)))
+    (save-restriction
+      (message-narrow-to-headers)
+      (if message-alternative-emails
+         (message-use-alternative-email-as-from)))
     (when message-generate-headers-first
       (message-generate-headers
        (message-headers-to-generate
@@ -5069,8 +5338,6 @@ are not included."
   (message-insert-signature)
   (save-restriction
     (message-narrow-to-headers)
-    (if message-alternative-emails
-       (message-use-alternative-email-as-from))
     (run-hooks 'message-header-setup-hook))
   (set-buffer-modified-p nil)
   (setq buffer-undo-list nil)
@@ -5295,11 +5562,11 @@ responses here are directed to other addresses.")))
       ;; Allow customizations to have their say.
       (if (not wide)
          ;; This is a regular reply.
-         (when (message-functionp message-reply-to-function)
+         (when (functionp message-reply-to-function)
            (save-excursion
              (setq follow-to (funcall message-reply-to-function))))
        ;; This is a followup.
-       (when (message-functionp message-wide-reply-to-function)
+       (when (functionp message-wide-reply-to-function)
          (save-excursion
            (setq follow-to
                  (funcall message-wide-reply-to-function)))))
@@ -5359,7 +5626,7 @@ If TO-NEWSGROUPS, use that as the new Newsgroups line."
        (if (search-forward "\n\n" nil t)
           (1- (point))
         (point-max)))
-      (when (message-functionp message-followup-to-function)
+      (when (functionp message-followup-to-function)
        (setq follow-to
              (funcall message-followup-to-function)))
       (setq from (message-fetch-field "from")
@@ -5452,6 +5719,48 @@ responses here are directed to other newsgroups."))
 
      cur)))
 
+(defun message-is-yours-p ()
+  "Non-nil means current article is yours.
+If you have added 'cancel-messages to 'message-shoot-gnksa-feet', all articles
+are yours except those that have Cancel-Lock header not belonging to you.
+Instead of shooting GNKSA feet, you should modify 'message-alternative-emails'
+regexp to match all of yours addresses."
+  ;; Canlock-logic as suggested by Per Abrahamsen
+  ;; <abraham@dina.kvl.dk>
+  ;;
+  ;; IF article has cancel-lock THEN
+  ;;   IF we can verify it THEN
+  ;;     issue cancel
+  ;;   ELSE
+  ;;     error: cancellock: article is not yours
+  ;; ELSE
+  ;;   Use old rules, comparing sender...
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-head-1)
+      (if (message-fetch-field "Cancel-Lock")
+         (if (null (canlock-verify))
+             t
+           (error "Failed to verify Cancel-lock: This article is not yours"))
+       (let (sender from)
+         (or
+          (message-gnksa-enable-p 'cancel-messages)
+          (and (setq sender (message-fetch-field "sender"))
+               (string-equal (downcase sender)
+                             (downcase (message-make-sender))))
+          ;; Email address in From field equals to our address
+          (and (setq from (message-fetch-field "from"))
+               (string-equal
+                (downcase (cadr (mail-extract-address-components from)))
+                (downcase (cadr (mail-extract-address-components
+                                 (message-make-from))))))
+          ;; Email address in From field matches
+          ;; 'message-alternative-emails' regexp
+          (and from
+               message-alternative-emails
+               (string-match
+                message-alternative-emails
+                (cadr (mail-extract-address-components from))))))))))
 
 ;;;###autoload
 (defun message-cancel-news (&optional arg)
@@ -5460,42 +5769,17 @@ If ARG, allow editing of the cancellation message."
   (interactive "P")
   (unless (message-news-p)
     (error "This is not a news article; canceling is impossible"))
-  (let (from newsgroups message-id distribution buf sender)
+  (let (from newsgroups message-id distribution buf)
     (save-excursion
       ;; Get header info from original article.
       (save-restriction
        (message-narrow-to-head-1)
        (setq from (message-fetch-field "from")
-             sender (message-fetch-field "sender")
              newsgroups (message-fetch-field "newsgroups")
              message-id (message-fetch-field "message-id" t)
              distribution (message-fetch-field "distribution")))
       ;; Make sure that this article was written by the user.
-      (unless (or
-              ;; Canlock-logic as suggested by Per Abrahamsen
-              ;; <abraham@dina.kvl.dk>
-              ;;
-              ;; IF article has cancel-lock THEN
-              ;;   IF we can verify it THEN
-              ;;     issue cancel
-              ;;   ELSE
-              ;;     error: cancellock: article is not yours
-              ;; ELSE
-              ;;   Use old rules, comparing sender...
-              (if (message-fetch-field "Cancel-Lock")
-                  (if (null (canlock-verify))
-                      t
-                    (error "Failed to verify Cancel-lock: This article is not yours"))
-                nil)
-              (message-gnksa-enable-p 'cancel-messages)
-              (and sender
-                   (string-equal
-                    (downcase sender)
-                    (downcase (message-make-sender))))
-              (string-equal
-               (downcase (cadr (mail-extract-address-components from)))
-               (downcase (cadr (mail-extract-address-components
-                                (message-make-from))))))
+      (unless (message-is-yours-p)
        (error "This article is not yours"))
       (when (yes-or-no-p "Do you really want to cancel this article? ")
        ;; Make control message.
@@ -5527,35 +5811,9 @@ If ARG, allow editing of the cancellation message."
 This is done simply by taking the old article and adding a Supersedes
 header line with the old Message-ID."
   (interactive)
-  (let ((cur (current-buffer))
-       (sender (message-fetch-field "sender"))
-       (from (message-fetch-field "from")))
+  (let ((cur (current-buffer)))
     ;; Check whether the user owns the article that is to be superseded.
-    (unless (or
-            ;; Canlock-logic as suggested by Per Abrahamsen
-            ;; <abraham@dina.kvl.dk>
-            ;;
-            ;; IF article has cancel-lock THEN
-            ;;   IF we can verify it THEN
-            ;;     issue cancel
-            ;;   ELSE
-            ;;     error: cancellock: article is not yours
-            ;; ELSE
-            ;;   Use old rules, comparing sender...
-            (if (message-fetch-field "Cancel-Lock")
-                (if (null (canlock-verify))
-                    t
-                  (error "Failed to verify Cancel-lock: This article is not yours"))
-              nil)
-            (message-gnksa-enable-p 'cancel-messages)
-               (and sender
-                    (string-equal
-                     (downcase sender)
-                     (downcase (message-make-sender))))
-               (string-equal
-                (downcase (cadr (mail-extract-address-components from)))
-                (downcase (cadr (mail-extract-address-components
-                                 (message-make-from))))))
+    (unless (message-is-yours-p)
       (error "This article is not yours"))
     ;; Get a normal message buffer.
     (message-pop-to-buffer (message-buffer-name "supersede"))
@@ -5647,6 +5905,23 @@ the list of newsgroups is was posted to."
              (mail-decode-encoded-word-string prefix)))
          "] " subject))
 
+(defun message-forward-subject-name-subject (subject)
+  "Generate a SUBJECT for a forwarded message.
+The form is: [Source] Subject, where if the original message was mail,
+Source is the name of the sender, and if the original message was
+news, Source is the list of newsgroups is was posted to."
+  (concat "["
+         (let ((prefix
+                (or (message-fetch-field "newsgroups")
+                    (let ((from (message-fetch-field "from")))
+                      (and from
+                           (cdr (mail-header-parse-address from))))
+                    "(nowhere)")))
+           (if message-forward-decoded-p
+               prefix
+             (mail-decode-encoded-word-string prefix)))
+         "] " subject))
+
 (defun message-forward-subject-fwd (subject)
   "Generate a SUBJECT for a forwarded message.
 The form is: Fwd: Subject, where Subject is the original subject of
@@ -5675,7 +5950,7 @@ the message."
        ;; Apply funcs in order, passing subject generated by previous
        ;; func to the next one.
        (while funcs
-         (when (message-functionp (car funcs))
+         (when (functionp (car funcs))
            (setq subject (funcall (car funcs) subject)))
          (setq funcs (cdr funcs)))
        subject))))
@@ -5724,11 +5999,11 @@ Optional DIGEST will use digest to forward."
               (not message-forward-decoded-p))
          (insert
           (with-temp-buffer
-            (mm-disable-multibyte-mule4)
+            (mm-disable-multibyte)
             (insert
              (with-current-buffer forward-buffer
-               (mm-string-as-unibyte (buffer-string))))
-            (mm-enable-multibyte-mule4)
+               (mm-with-unibyte-current-buffer (buffer-string))))
+            (mm-enable-multibyte)
             (mime-to-mml)
             (goto-char (point-min))
             (when (looking-at "From ")
@@ -5778,9 +6053,12 @@ Optional DIGEST will use digest to forward."
        (rmail-msg-restore-non-pruned-header)))
   (message-forward-make-body forward-buffer))
 
+(eval-when-compile (defvar rmail-enable-mime-composing))
+
+;; Fixme: Should have defcustom.
 ;;;###autoload
 (defun message-insinuate-rmail ()
-  "Let RMAIL uses message to forward."
+  "Let RMAIL use message to forward."
   (interactive)
   (setq rmail-enable-mime-composing t)
   (setq rmail-insert-mime-forwarded-message-function
@@ -5799,12 +6077,16 @@ Optional DIGEST will use digest to forward."
       (unless (message-mail-user-agent)
        (set-buffer (get-buffer-create " *message resend*"))
        (erase-buffer))
-      (let ((message-this-is-mail t))
+      (let ((message-this-is-mail t)
+           message-setup-hook)
        (message-setup `((To . ,address))))
       ;; Insert our usual headers.
       (message-generate-headers '(From Date To))
       (message-narrow-to-headers)
+      ;; Remove X-Draft-From header etc.
+      (message-remove-header message-ignored-mail-headers t)
       ;; Rename them all to "Resent-*".
+      (goto-char (point-min))
       (while (re-search-forward "^[A-Za-z]" nil t)
        (forward-char -1)
        (insert "Resent-"))
@@ -5973,6 +6255,13 @@ which specify the range to operate on."
            (delete-char -2))))))
 
 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
+(defalias 'message-make-overlay 'make-overlay)
+(defalias 'message-delete-overlay 'delete-overlay)
+(defalias 'message-overlay-put 'overlay-put)
+(defun message-kill-all-overlays ()
+  (if (featurep 'xemacs)
+      (map-extents (lambda (extent ignore) (delete-extent extent)))
+    (mapcar #'delete-overlay (overlays-in (point-min) (point-max)))))
 
 ;; Support for toolbar
 (eval-when-compile
@@ -6011,6 +6300,9 @@ which specify the range to operate on."
                'mml-attach-file "attach" tool-bar-map mml-mode-map)
               (message-tool-bar-local-item-from-menu
                'ispell-message "spell" tool-bar-map message-mode-map)
+              (message-tool-bar-local-item-from-menu
+               'mml-preview "preview"
+               tool-bar-map mml-mode-map)
               (message-tool-bar-local-item-from-menu
                'message-insert-importance-high "important"
                tool-bar-map message-mode-map)
@@ -6138,10 +6430,10 @@ The following arguments may contain lists of values."
         (list list))))
 
 (defun message-generate-new-buffer-clone-locals (name &optional varstr)
-  "Create and return a buffer with name based on NAME using `generate-new-buffer.'
+  "Create and return a buffer with name based on NAME using `generate-new-buffer'.
 Then clone the local variables and values from the old buffer to the
 new one, cloning only the locals having a substring matching the
-regexp varstr."
+regexp VARSTR."
   (let ((oldbuf (current-buffer)))
     (save-excursion
       (set-buffer (generate-new-buffer name))
@@ -6166,11 +6458,6 @@ regexp varstr."
                (cdr local)))))
      locals)))
 
-;;; Miscellaneous functions
-
-(defsubst message-replace-chars-in-string (string from to)
-  (mm-subst-char-in-string from to string))
-
 ;;;
 ;;; MIME functions
 ;;;
@@ -6282,6 +6569,39 @@ regexp varstr."
                             (if (and (or to cc) bcc) ", ")
                             (or bcc "")))))))
 
+(defun message-hide-headers ()
+  "Hide headers based on the `message-hidden-headers' variable."
+  (let ((regexps (if (stringp message-hidden-headers)
+                    (list message-hidden-headers)
+                  message-hidden-headers))
+       (inhibit-point-motion-hooks t)
+       (after-change-functions nil))
+    (when regexps
+      (save-excursion
+       (save-restriction
+         (message-narrow-to-headers)
+         (goto-char (point-min))
+         (while (not (eobp))
+           (if (not (message-hide-header-p regexps))
+               (message-next-header)
+             (let ((begin (point)))
+               (message-next-header)
+               (add-text-properties
+                begin (point)
+                '(invisible t message-hidden t))))))))))
+
+(defun message-hide-header-p (regexps)
+  (let ((result nil)
+       (reverse nil))
+    (when (eq (car regexps) 'not)
+      (setq reverse t)
+      (pop regexps))
+    (dolist (regexp regexps)
+      (setq result (or result (looking-at regexp))))
+    (if reverse
+       (not result)
+      result)))
+
 (when (featurep 'xemacs)
   (require 'messagexmas)
   (message-xmas-redefine))