Sync up with Pterodactyl Gnus v0.95.
[elisp/gnus.git-] / lisp / message.el
index da59745..b38f228 100644 (file)
@@ -1,12 +1,13 @@
 ;;; message.el --- composing mail and news messages
-;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98,99 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;;     Shuhei KOBAYASHI <shuhei-k@jaist.ac.jp>
-;;     Keiichi Suzuki <kei-suzu@mail.wbs.ne.jp>
+;;     Keiichi Suzuki   <kei-suzu@mail.wbs.ne.jp>
 ;;     Tatsuya Ichikawa <t-ichi@po.shiojiri.ne.jp>
-;;     Katsumi Yamaoka <yamaoka@jpl.org>
+;;     Katsumi Yamaoka  <yamaoka@jpl.org>
+;;     Kiyokazu SUTO    <suto@merry.xmath.ous.ac.jp>
 ;; Keywords: mail, news, MIME
 
 ;; This file is part of GNU Emacs.
@@ -201,7 +202,8 @@ Don't touch this variable unless you really know what you're doing.
 Checks include subject-cmsg multiple-headers sendsys message-id from
 long-lines control-chars size new-text redirected-followup signature
 approved sender empty empty-headers message-id from subject
-shorten-followup-to existing-newsgroups buffer-file-name unchanged."
+shorten-followup-to existing-newsgroups buffer-file-name unchanged
+newsgroups."
   :group 'message-news)
 
 (defcustom message-required-news-headers
@@ -389,7 +391,7 @@ If t, use `message-user-organization-file'."
   :group 'message-forwarding
   :type 'regexp)
 
-(defcustom message-make-forward-subject-function 
+(defcustom message-make-forward-subject-function
   'message-forward-subject-author-subject
  "*A list of functions that are called to generate a subject header for forwarded messages.
 The subject generated by the previous function is passed into each
@@ -432,7 +434,7 @@ The provided functions are:
 The headers should be delimited by a line whose contents match the
 variable `mail-header-separator'.
 
-Legal values include `message-send-mail-with-sendmail' (the default),
+Valid values include `message-send-mail-with-sendmail' (the default),
 `message-send-mail-with-mh', `message-send-mail-with-qmail' and
 `message-send-mail-with-smtp'."
   :type '(radio (function-item message-send-mail-with-sendmail)
@@ -603,7 +605,7 @@ The function `message-supersede' runs this hook."
   :group 'message-various
   :type 'hook)
 
-(defcustom message-header-hook '(eword-encode-header)
+(defcustom message-header-hook '((lambda () (eword-encode-header t)))
   "Hook run in a message mode buffer narrowed to the headers."
   :group 'message-various
   :type 'hook)
@@ -621,11 +623,16 @@ The function `message-supersede' runs this hook."
 
 ;;;###autoload
 (defcustom message-yank-prefix "> "
-  "*Prefix inserted on the lines of yanked messages.
-nil means use indentation."
+  "*Prefix inserted on the lines of yanked messages."
   :type 'string
   :group 'message-insertion)
 
+(defcustom message-yank-add-new-references t
+  "*Non-nil means new IDs will be added to \"References\" field when an
+article is yanked by the command `message-yank-original' interactively."
+  :type 'boolean
+  :group 'message-insertion)
+
 (defcustom message-indentation-spaces 3
   "*Number of spaces to insert at the beginning of each cited line.
 Used by `message-yank-original' via `message-yank-cite'."
@@ -639,6 +646,7 @@ Predefined functions include `message-cite-original' and
 `message-cite-original-without-signature'.
 Note that `message-cite-original' uses `mail-citation-hook' if that is non-nil."
   :type '(radio (function-item message-cite-original)
+               (function-item message-cite-original-without-signature)
                (function-item sc-cite-original)
                (function :tag "Other"))
   :group 'message-insertion)
@@ -768,11 +776,10 @@ actually occur."
 ;; Ignore errors in case this is used in Emacs 19.
 ;; Don't use ignore-errors because this is copied into loaddefs.el.
 ;;;###autoload
-(condition-case nil
-    (define-mail-user-agent 'message-user-agent
-      'message-mail 'message-send-and-exit
-      'message-kill-buffer 'message-send-hook)
-  (error nil))
+(ignore-errors
+  (define-mail-user-agent 'message-user-agent
+    'message-mail 'message-send-and-exit
+    'message-kill-buffer 'message-send-hook))
 
 (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
   "If non-nil, delete the deletable headers before feeding to mh.")
@@ -810,6 +817,11 @@ Valid valued are `unique' and `unsent'."
   :type '(choice (const :tag "unique" unique)
                 (const :tag "unsent" unsent)))
 
+(defcustom message-default-charset nil
+  "Default charset used in non-MULE XEmacsen."
+  :group 'message
+  :type 'symbol)
+
 ;;; Internal variables.
 ;;; Well, not really internal.
 
@@ -1033,18 +1045,17 @@ The cdr of ech entry is a function for applying the face to a region.")
                 (const :tag "always" t)
                 (const :tag "ask" ask)))
 
-(defvar message-send-coding-system 'binary
-  "Coding system to encode outgoing mail.")
-
-(defvar message-draft-coding-system 
-  (if (string-match "XEmacs\\|Lucid" emacs-version)
-      'escape-quoted 'emacs-mule)
+(defvar message-draft-coding-system
+  (cond
+   ((not (fboundp 'find-coding-system)) nil)
+   ((find-coding-system 'emacs-mule)
+    (if (memq system-type '(windows-nt ms-dos ms-windows))
+       'emacs-mule-dos 'emacs-mule))
+   ((find-coding-system 'escape-quoted) 'escape-quoted)
+   ((find-coding-system 'no-conversion) 'no-conversion)
+   (t nil))
   "Coding system to compose mail.")
 
-(defvar message-default-charset 'iso-8859-1
-  "Default charset assumed to be used when viewing non-ASCII characters.
-This variable is used only in non-Mule Emacsen.")
-
 ;;; Internal variables.
 
 (defvar message-buffer-list nil)
@@ -1052,6 +1063,7 @@ This variable is used only in non-Mule Emacsen.")
 (defvar message-this-is-mail nil)
 (defvar message-draft-article nil)
 (defvar message-mime-part nil)
+(defvar message-posting-charset nil)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
@@ -1136,7 +1148,7 @@ This variable is used only in non-Mule Emacsen.")
     (Lines)
     (Expires)
     (Message-ID)
-    (References . message-fill-header)
+    (References . message-shorten-references)
     (User-Agent))
   "Alist used for formatting headers.")
 
@@ -1176,7 +1188,7 @@ This variable is used only in non-Mule Emacsen.")
   (cdr (assq key alist)))
 
 (defmacro message-get-parameter-with-eval (key &optional alist)
-  `(message-eval-parameter (message-get-parameter ,alist ,key)))
+  `(message-eval-parameter (message-get-parameter ,key ,alist)))
 
 (defmacro message-y-or-n-p (question show &rest text)
   "Ask QUESTION, displaying the rest of the arguments in a temp. buffer if SHOW"
@@ -1412,6 +1424,7 @@ Point is left at the beginning of the narrowed-to region."
 (defun message-sort-headers-1 ()
   "Sort the buffer as headers using `message-rank' text props."
   (goto-char (point-min))
+  (require 'sort)
   (sort-subr
    nil 'message-next-header
    (lambda ()
@@ -1480,6 +1493,7 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
   (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
   (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
+  (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
   (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
   (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
   (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
@@ -1514,6 +1528,7 @@ Point is left at the beginning of the narrowed-to region."
    ["Newline and Reformat" message-newline-and-reformat t]
    ["Rename buffer" message-rename-buffer t]
    ["Spellcheck" ispell-message t]
+   ["Attach file as MIME" mime-edit-insert-file t]
    "----"
    ["Send Message" message-send-and-exit t]
    ["Abort Message" message-dont-send t]
@@ -1548,6 +1563,7 @@ Point is left at the beginning of the narrowed-to region."
   "Major mode for editing mail and news to be sent.
 Like Text Mode but with these additional commands:
 C-c C-s  message-send (send the message)    C-c C-c  message-send-and-exit
+C-c C-d  Pospone sending the message        C-c C-k  Kill the message
 C-c C-f  move to a header field (and create it if there isn't):
         C-c C-f C-t  move to To        C-c C-f C-s  move to Subject
         C-c C-f C-c  move to Cc        C-c C-f C-b  move to Bcc
@@ -1570,8 +1586,8 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (interactive)
   (kill-all-local-variables)
   (set (make-local-variable 'message-reply-buffer) nil)
-  (make-local-variable 'message-send-actions) 
-  (make-local-variable 'message-exit-actions) 
+  (make-local-variable 'message-send-actions)
+  (make-local-variable 'message-exit-actions)
   (make-local-variable 'message-kill-actions)
   (make-local-variable 'message-postpone-actions)
   (make-local-variable 'message-draft-article)
@@ -1639,6 +1655,8 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (setq adaptive-fill-first-line-regexp
        (concat "[ \t]*[-a-z0-9A-Z]*>+[ \t]*\\|"
                adaptive-fill-first-line-regexp))
+  (make-local-variable 'indent-tabs-mode) ;Turn off tabs for indentation.
+  (setq indent-tabs-mode nil)
   (run-hooks 'text-mode-hook 'message-mode-hook))
 
 \f
@@ -1724,13 +1742,14 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (interactive)
   (if (looking-at "[ \t]*\n") (expand-abbrev))
   (goto-char (point-min))
-  (search-forward (concat "\n" mail-header-separator "\n") nil t))
+  (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
+      (search-forward "\n\n" nil t)))
 
 (defun message-goto-eoh ()
   "Move point to the end of the headers."
   (interactive)
   (message-goto-body)
-  (forward-line -2))
+  (forward-line -1))
 
 (defun message-goto-signature ()
   "Move point to the beginning of the message signature.
@@ -1829,8 +1848,7 @@ With the prefix argument FORCE, insert the header anyway."
                 (eq force 0))
            (save-excursion
              (goto-char (point-max))
-             (not (re-search-backward
-                   message-signature-separator nil t))))
+             (not (re-search-backward message-signature-separator nil t))))
           ((and (null message-signature)
                 force)
            t)
@@ -1969,7 +1987,7 @@ Numeric argument means justify as well."
     (goto-char (point-min))
     (search-forward (concat "\n" mail-header-separator "\n") nil t)
     (let ((fill-prefix message-yank-prefix))
-      (fill-individual-paragraphs (point) (point-max) justifyp t))))
+      (fill-individual-paragraphs (point) (point-max) justifyp))))
 
 (defun message-indent-citation ()
   "Modify text just inserted from a message to be cited.
@@ -2017,6 +2035,28 @@ However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
          (forward-line 1))))
     (goto-char start)))
 
+(defun message-list-references (refs-list &rest refs-strs)
+  "Add `Message-ID's which appear in REFS-STRS but not in REFS-LIST,
+to REFS-LIST."
+  (let (refs ref id)
+    (while refs-strs
+      (setq refs (car refs-strs)
+           refs-strs (cdr refs-strs))
+      (when refs
+       (setq refs (std11-parse-msg-ids (std11-lexical-analyze refs)))
+       (while refs
+         (setq ref (car refs)
+               refs (cdr refs))
+         (when (eq (car ref) 'msg-id)
+           (setq id (concat "<"
+                            (mapconcat
+                             (function (lambda (p) (cdr p)))
+                             (cdr ref) "")
+                            ">"))
+           (or (member id refs-list)
+               (push id refs-list))))))
+    refs-list))
+
 (defvar gnus-article-copy)
 (defun message-yank-original (&optional arg)
   "Insert the message being replied to, if any.
@@ -2027,14 +2067,52 @@ if `message-yank-prefix' is non-nil, insert that prefix on each line.
 This function uses `message-cite-function' to do the actual citing.
 
 Just \\[universal-argument] as argument means don't indent, insert no
-prefix, and don't delete any headers."
+prefix, and don't delete any headers.
+
+In addition, if `message-yank-add-new-references' is non-nil and this
+command is called interactively, new IDs from the yanked article will
+be added to \"References\" field."
   (interactive "P")
   (let ((modified (buffer-modified-p))
-       (buffer (message-eval-parameter message-reply-buffer)))
+       (buffer (message-eval-parameter message-reply-buffer))
+       start end refs)
     (when (and buffer
               message-cite-function)
       (delete-windows-on buffer t)
-      (insert-buffer buffer)
+      (insert-buffer buffer) ; mark will be set at the end of article.
+      (setq start (point)
+           end (mark t))
+
+      ;; Add new IDs to References field.
+      (when (and message-yank-add-new-references (interactive-p))
+       (save-excursion
+         (save-restriction
+           (message-narrow-to-headers)
+           (setq refs (message-list-references
+                       nil
+                       (message-fetch-field "References")))
+           (widen)
+           (narrow-to-region start end)
+           (std11-narrow-to-header)
+           (when (setq refs (message-list-references
+                             refs
+                             (or (message-fetch-field "References")
+                                 (message-fetch-field "In-Reply-To"))
+                             (message-fetch-field "Message-ID")))
+             (widen)
+             (message-narrow-to-headers)
+             (goto-char (point-min))
+             (let ((case-fold-search t))
+               (if (re-search-forward "^References:\\([\t ]+.+\n\\)+" nil t)
+                   (replace-match "")
+                 (goto-char (point-max))))
+             (mail-header-format
+              (list (or (assq 'References message-header-format-alist)
+                        '(References . message-fill-references)))
+              (list (cons 'References
+                          (mapconcat 'identity (nreverse refs) " "))))
+             (backward-delete-char 1)))))
+
       (funcall message-cite-function)
       (message-exchange-point-and-mark)
       (unless (bolp)
@@ -2051,9 +2129,8 @@ prefix, and don't delete any headers."
           (if (listp message-indent-citation-function)
               message-indent-citation-function
             (list message-indent-citation-function)))))
-    (mml-quote-region start end)
     (goto-char end)
-    (when (re-search-backward "^-- $" start t)
+    (when (re-search-backward message-signature-separator start t)
       ;; Also peel off any blank lines before the signature.
       (forward-line -1)
       (while (looking-at "^[ \t]*$")
@@ -2068,7 +2145,7 @@ prefix, and don't delete any headers."
        (insert "\n"))
       (funcall message-citation-line-function))))
 
-(defvar mail-citation-hook) ;Compiler directive
+(defvar mail-citation-hook)            ;Compiler directive
 (defun message-cite-original ()
   "Cite function in the standard Message manner."
   (if (and (boundp 'mail-citation-hook)
@@ -2081,7 +2158,6 @@ prefix, and don't delete any headers."
             (if (listp message-indent-citation-function)
                 message-indent-citation-function
               (list message-indent-citation-function)))))
-      (mml-quote-region start end)
       (goto-char start)
       (while functions
        (funcall (pop functions)))
@@ -2285,21 +2361,26 @@ the user from the mailer."
                                    (car elem))))
                              (setq success (funcall (caddr elem) arg)))))
            (setq sent t))))
-      (when (and success sent)
-       (message-do-fcc)
-       ;;(when (fboundp 'mail-hist-put-headers-into-history)
-       ;; (mail-hist-put-headers-into-history))
-       (run-hooks 'message-sent-hook)
-       (message "Sending...done")
-       ;; Mark the buffer as unmodified and delete autosave.
-       (set-buffer-modified-p nil)
-       (delete-auto-save-file-if-necessary t)
-       (message-disassociate-draft)
-       ;; Delete other mail buffers and stuff.
-       (message-do-send-housekeeping)
-       (message-do-actions message-send-actions)
-       ;; Return success.
-       t))))
+      (unless sent
+       (error "No methods specified to send by"))
+      (prog1
+         (when (and success sent)
+           (message-do-fcc)
+           ;;(when (fboundp 'mail-hist-put-headers-into-history)
+           ;; (mail-hist-put-headers-into-history))
+           (save-excursion
+             (run-hooks 'message-sent-hook))
+           (message "Sending...done")
+           ;; Mark the buffer as unmodified and delete autosave.
+           (set-buffer-modified-p nil)
+           (delete-auto-save-file-if-necessary t)
+           (message-disassociate-draft)
+           ;; Delete other mail buffers and stuff.
+           (message-do-send-housekeeping)
+           (message-do-actions message-send-actions)
+           ;; Return success.
+           t)
+       (kill-buffer message-encoding-buffer)))))
 
 (defun message-send-via-mail (arg)
   "Send the current message via mail."
@@ -2328,7 +2409,8 @@ the user from the mailer."
   (message-check 'invisible-text
     (when (text-property-any (point-min) (point-max) 'invisible t)
       (put-text-property (point-min) (point-max) 'invisible nil)
-      (unless (yes-or-no-p "Invisible text found and made visible; continue posting? ")
+      (unless (yes-or-no-p
+              "Invisible text found and made visible; continue posting? ")
        (error "Invisible text found and made visible")))))
 
 (defun message-add-action (action &rest types)
@@ -2422,6 +2504,10 @@ This sub function is for exclusive use of `message-send-mail'."
            ;; Remove some headers.
            (save-restriction
              (message-narrow-to-headers)
+;; We Semi-gnus people have no use for it.
+;;           ;; We (re)generate the Lines header.
+;;           (when (memq 'Lines message-required-mail-headers)
+;;             (message-generate-headers '(Lines)))
              ;; Remove some headers.
              (message-remove-header message-ignored-mail-headers t))
            (goto-char (point-max))
@@ -2468,31 +2554,31 @@ This sub function is for exclusive use of `message-send-mail'."
        (save-excursion
          (set-buffer errbuf)
          (erase-buffer))))
-    (let ((default-directory "/")
-         (coding-system-for-write message-send-coding-system))
-      (apply 'call-process-region
-            (append (list (point-min) (point-max)
-                          (if (boundp 'sendmail-program)
-                              sendmail-program
-                            "/usr/lib/sendmail")
-                          nil errbuf nil "-oi")
-                    ;; Always specify who from,
-                    ;; since some systems have broken sendmails.
-                    ;; But some systems are more broken with -f, so
-                    ;; we'll let users override this.
-                    (if (null message-sendmail-f-is-evil)
-                        (list "-f" (user-login-name)))
-                    ;; These mean "report errors by mail"
-                    ;; and "deliver in background".
-                    (if (null message-interactive) '("-oem" "-odb"))
-                    ;; Get the addresses from the message
-                    ;; unless this is a resend.
-                    ;; We must not do that for a resend
-                    ;; because we would find the original addresses.
-                    ;; For a resend, include the specific addresses.
-                    (if resend-to-addresses
-                        (list resend-to-addresses)
-                      '("-t")))))
+    (let ((default-directory "/"))
+      (as-binary-process
+       (apply 'call-process-region
+             (append (list (point-min) (point-max)
+                           (if (boundp 'sendmail-program)
+                               sendmail-program
+                             "/usr/lib/sendmail")
+                           nil errbuf nil "-oi")
+                     ;; Always specify who from,
+                     ;; since some systems have broken sendmails.
+                     ;; But some systems are more broken with -f, so
+                     ;; we'll let users override this.
+                     (if (null message-sendmail-f-is-evil)
+                         (list "-f" (user-login-name)))
+                     ;; These mean "report errors by mail"
+                     ;; and "deliver in background".
+                     (if (null message-interactive) '("-oem" "-odb"))
+                     ;; Get the addresses from the message
+                     ;; unless this is a resend.
+                     ;; We must not do that for a resend
+                     ;; because we would find the original addresses.
+                     ;; For a resend, include the specific addresses.
+                     (if resend-to-addresses
+                         (list resend-to-addresses)
+                       '("-t"))))))
     (when message-interactive
       (save-excursion
        (set-buffer errbuf)
@@ -2518,28 +2604,28 @@ to find out how to use this."
   (run-hooks 'message-send-mail-hook)
   ;; send the message
   (case
-      (let ((coding-system-for-write message-send-coding-system))
-       (apply
-        'call-process-region 1 (point-max) message-qmail-inject-program
-        nil nil nil
-        ;; qmail-inject's default behaviour is to look for addresses on the
-        ;; command line; if there're none, it scans the headers.
-        ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
-        ;;
-        ;; in general, ALL of qmail-inject's defaults are perfect for simply
-        ;; reading a formatted (i. e., at least a To: or Resent-To header)
-        ;; message from stdin.
-        ;;
-        ;; qmail also has the advantage of not having been raped by
-        ;; various vendors, so we don't have to allow for that, either --
-        ;; compare this with message-send-mail-with-sendmail and weep
-        ;; for sendmail's lost innocence.
-        ;;
-        ;; all this is way cool coz it lets us keep the arguments entirely
-        ;; free for -inject-arguments -- a big win for the user and for us
-        ;; since we don't have to play that double-guessing game and the user
-        ;; gets full control (no gestapo'ish -f's, for instance).  --sj
-        message-qmail-inject-args))
+      (as-binary-process
+       (apply
+       'call-process-region 1 (point-max) message-qmail-inject-program
+       nil nil nil
+       ;; qmail-inject's default behaviour is to look for addresses on the
+       ;; command line; if there're none, it scans the headers.
+       ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
+       ;;
+       ;; in general, ALL of qmail-inject's defaults are perfect for simply
+       ;; reading a formatted (i. e., at least a To: or Resent-To header)
+       ;; message from stdin.
+       ;;
+       ;; qmail also has the advantage of not having been raped by
+       ;; various vendors, so we don't have to allow for that, either --
+       ;; compare this with message-send-mail-with-sendmail and weep
+       ;; for sendmail's lost innocence.
+       ;;
+       ;; all this is way cool coz it lets us keep the arguments entirely
+       ;; free for -inject-arguments -- a big win for the user and for us
+       ;; since we don't have to play that double-guessing game and the user
+       ;; gets full control (no gestapo'ish -f's, for instance).  --sj
+       message-qmail-inject-args))
     ;; qmail-inject doesn't say anything on it's stdout/stderr,
     ;; we have to look at the retval instead
     (0 nil)
@@ -2656,6 +2742,10 @@ This sub function is for exclusive use of `message-send-news'."
            ;; Remove some headers.
            (save-restriction
              (message-narrow-to-headers)
+;; We Semi-gnus people have no use for it.
+;;           ;; We (re)generate the Lines header.
+;;           (when (memq 'Lines message-required-mail-headers)
+;;             (message-generate-headers '(Lines)))
              ;; Remove some headers.
              (message-remove-header message-ignored-news-headers t))
            (goto-char (point-max))
@@ -2682,12 +2772,6 @@ This sub function is for exclusive use of `message-send-news'."
     (replace-match "\n")
     (backward-char 1)
     (run-hooks 'message-send-news-hook)
-    ;;(require (car method))
-    ;;(funcall (intern (format "%s-open-server" (car method)))
-    ;;(cadr method) (cddr method))
-    ;;(setq result
-    ;;   (funcall (intern (format "%s-request-post" (car method)))
-    ;;            (cadr method)))
     (gnus-open-server method)
     (gnus-request-post method)
     ))
@@ -2722,6 +2806,15 @@ This sub function is for exclusive use of `message-send-news'."
 
 (defun message-check-news-header-syntax ()
   (and
+   ;; Check Newsgroups header.
+   (message-check 'newsgroyps
+     (let ((group (message-fetch-field "newsgroups")))
+       (or
+       (and group
+            (not (string-match "\\`[ \t]*\\'" group)))
+       (ignore
+        (message
+         "The newsgroups field is empty or missing.  Posting is denied.")))))
    ;; Check the Subject header.
    (message-check 'subject
      (let* ((case-fold-search t)
@@ -2884,12 +2977,15 @@ This sub function is for exclusive use of `message-send-news'."
    (message-check 'from
      (let* ((case-fold-search t)
            (from (message-fetch-field "from"))
-           (ad (nth 1 (std11-extract-address-components from))))
+           ad)
        (cond
        ((not from)
         (message "There is no From line.  Posting is denied.")
         nil)
-       ((or (not (string-match "@[^\\.]*\\." ad)) ;larsi@ifi
+       ((or (not (string-match
+                  "@[^\\.]*\\."
+                  (setq ad (nth 1 (mail-extract-address-components
+                                   from))))) ;larsi@ifi
             (string-match "\\.\\." ad) ;larsi@ifi..uio
             (string-match "@\\." ad)   ;larsi@.ifi.uio
             (string-match "\\.$" ad)   ;larsi@ifi.uio.
@@ -2954,15 +3050,12 @@ This sub function is for exclusive use of `message-send-news'."
    ;; Check the length of the signature.
    (message-check 'signature
      (goto-char (point-max))
-     (if (or (not (re-search-backward message-signature-separator nil t))
-            (search-forward message-forward-end-separator nil t))
-        t
-       (if (> (count-lines (point) (point-max)) 5)
-          (y-or-n-p
-           (format
-            "Your .sig is %d lines; it should be max 4.  Really post? "
-            (1- (count-lines (point) (point-max)))))
-        t)))))
+     (if (> (count-lines (point) (point-max)) 5)
+        (y-or-n-p
+         (format
+          "Your .sig is %d lines; it should be max 4.  Really post? "
+          (1- (count-lines (point) (point-max)))))
+       t))))
 
 (defun message-check-mail-syntax ()
   "Check the syntax of the message."
@@ -3120,7 +3213,7 @@ If NOW, use that time instead."
                                      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)))))
+     (format "%s%02d%02d" sign (/ zone 3600) (/ (% zone 3600) 60)))))
 
 (defun message-make-followup-subject (subject)
   "Make a followup Subject."
@@ -3460,7 +3553,7 @@ Headers already prepared in the buffer are not modified."
                    ;; colon, if there is none.
                    (if (/= (char-after) ? ) (insert " ") (forward-char 1))
                    ;; Find out whether the header is empty...
-                   (looking-at "[ \t]*$")))
+                   (looking-at "[ \t]*\n[^ \t]")))
          ;; So we find out what value we should insert.
          (setq value
                (cond
@@ -3821,6 +3914,23 @@ Headers already prepared in the buffer are not modified."
     (nndraft-request-expire-articles
      (list message-draft-article) "drafts" nil t)))
 
+(defun message-insert-headers ()
+  "Generate the headers for the article."
+  (interactive)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-headers)
+      (when (message-news-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-news-headers)))))
+      (when (message-mail-p)
+       (message-generate-headers
+        (delq 'Lines
+              (delq 'Subject
+                    (copy-sequence message-required-mail-headers))))))))
+
 \f
 
 ;;;
@@ -3858,7 +3968,8 @@ OTHER-HEADERS is an alist of header/value pairs."
        from subject date to cc
        references message-id follow-to
        (inhibit-point-motion-hooks t)
-       mct never-mct mft mrt gnus-warning)
+       (message-this-is-mail t)
+       mct never-mct mft mrt gnus-warning in-reply-to)
     (save-restriction
       (message-narrow-to-head)
       ;; Allow customizations to have their say.
@@ -3889,6 +4000,12 @@ OTHER-HEADERS is an alist of header/value pairs."
            gnus-warning (message-fetch-field "gnus-warning"))
       (when (and gnus-warning (string-match "<[^>]+>" gnus-warning))
        (setq message-id (match-string 0 gnus-warning)))
+      ;; Get the references from "In-Reply-To" field if there were
+      ;; no references and "In-Reply-To" field looks promising.
+      (unless references
+       (when (and (setq in-reply-to (message-fetch-field "in-reply-to"))
+                  (string-match "<[^>]+>" in-reply-to))
+         (setq references (match-string 0 in-reply-to))))
       ;; Remove any (buggy) Re:'s that are present and make a
       ;; proper one.
       (setq subject (message-make-followup-subject subject))
@@ -3919,7 +4036,7 @@ You should normally obey the Mail-Copies-To: header.
 sends a copy of your response to the author.")))
        (setq mct (or mrt from)))
        ((and (eq message-use-mail-copies-to 'ask)
-            (not 
+            (not
              (message-y-or-n-p
               (concat "Obey Mail-Copies-To: " mct " ? ") t "\
 You should normally obey the Mail-Copies-To: header.
@@ -4082,7 +4199,7 @@ You should normally obey the Mail-Copies-To: header.
 sends a copy of your response to the author.")))
        (setq mct (or mrt from)))
        ((and (eq message-use-mail-copies-to 'ask)
-            (not 
+            (not
              (message-y-or-n-p
               (concat "Obey Mail-Copies-To: " mct " ? ") t "\
 You should normally obey the Mail-Copies-To: header.
@@ -4317,7 +4434,7 @@ header line with the old Message-ID."
       (replace-match ""))
 
     (buffer-string)))
-    
+
 ;;; Forwarding messages.
 
 (defun message-forward-subject-author-subject (subject)
@@ -4344,14 +4461,14 @@ the message."
       (current-buffer)
       (message-narrow-to-head)
       (let ((funcs message-make-forward-subject-function)
-           (subject (if message-wash-forwarded-subjects
-                        (message-wash-subject
-                         (or (nnheader-decode-subject
-                              (message-fetch-field "Subject"))
-                             ""))
-                      (or (nnheader-decode-subject
-                           (message-fetch-field "Subject"))
-                          ""))))
+           (subject (message-fetch-field "Subject")))
+       (setq subject
+             (if subject
+                 (if message-wash-forwarded-subjects
+                     (message-wash-subject
+                      (nnheader-decode-subject subject))
+                   (nnheader-decode-subject subject))
+               "(none)"))
        ;; Make sure funcs is a list.
        (and funcs
             (not (listp funcs))
@@ -4372,7 +4489,9 @@ Optional NEWS will use news to forward instead of mail."
   (let ((cur (current-buffer))
        (subject (message-make-forward-subject))
        art-beg)
-    (if news (message-news nil subject) (message-mail nil subject))
+    (if news
+       (message-news nil subject)
+      (message-mail nil subject))
     ;; Put point where we want it before inserting the forwarded
     ;; message.
     (if message-signature-before-forwarded-message
@@ -4717,9 +4836,14 @@ regexp varstr."
 
 (defun message-maybe-encode ()
   (when message-mime-mode
+    ;; Inherit the buffer local variable `mime-edit-pgp-processing'.
+    (let ((pgp-processing (with-current-buffer message-edit-buffer
+                           mime-edit-pgp-processing)))
+      (setq mime-edit-pgp-processing pgp-processing))
     (run-hooks 'mime-edit-translate-hook)
     (if (catch 'mime-edit-error
          (save-excursion
+           (mime-edit-pgp-enclose-buffer)
            (mime-edit-translate-body)
            ))
        (error "Translation error!")
@@ -4768,98 +4892,51 @@ regexp varstr."
 ;;; MIME functions
 ;;;
 
-
-;; I really think this function should be renamed.  It is only useful
-;; for inserting file attachments.
-
-(defun message-insert-mime-part (file type description)
-  "Attach a file to the outgoing MIME message.
-The file is not inserted or encoded until you send the message with
-`\\[message-send-and-exit]' or `\\[message-send]'.
-
-FILE is the name of the file to attach.  TYPE is its content-type, a
-string of the form \"type/subtype\".  DESCRIPTION is a one-line
-description of the attachment."
-  (interactive
-   (let* ((file (read-file-name "Attach file: " nil nil t))
-         (type (completing-read
-                (format "Content type (default %s): "
-                        (or (mm-default-file-encoding file)
-                            ;; Perhaps here we should check
-                            ;; what the file looks like, and
-                            ;; offer text/plain if it looks
-                            ;; like text/plain.
-                            "application/octet-stream"))
-                (delete-duplicates
-                 (mapcar (lambda (m) (list (cdr m))) mailcap-mime-extensions)
-                 :test 'equal)))
-         (description (read-string "One line description: ")))
-     (list file type description)))
-  (when (string-match "\\`[ \t]*\\'" description)
-    (setq description nil))
-  (when (string-match "\\`[ \t]*\\'" type)
-    (setq type (mm-default-file-encoding file))) nil
-  ;; Prevent some common errors.  This is inspired by similar code in
-  ;; VM.
-  (when (file-directory-p file)
-    (error "%s is a directory, cannot attach" file))
-  (unless (file-exists-p file)
-    (error "No such file: %s" file))
-  (unless (file-readable-p file)
-    (error "Permission denied: %s" file))
-  (insert (format "<#part type=%s filename=%s%s><#/part>\n"
-                 type (prin1-to-string file)
-                 (if description
-                     (format " description=%s" (prin1-to-string description))
-                   ""))))
-
-(defun message-mime-insert-external (file type)
-  "Insert a message/external-body part into the buffer."
-  (interactive
-   (let* ((file (read-file-name "Insert file: "))
-         (type (mm-default-file-encoding file)))
-     (list file
-          (completing-read
-           (format "MIME type for %s: " file)
-           (delete-duplicates
-            (mapcar (lambda (m) (list (cdr m))) mailcap-mime-extensions))
-           nil nil type))))
-  (insert (format "<#external type=%s name=\"%s\"><#/external>\n"
-                 type file)))
+(defvar message-inhibit-body-encoding t)
 
 (defun message-encode-message-body ()
-  (let ((mm-default-charset message-default-charset)
-       lines multipart-p)
-    (message-goto-body)
-    (save-restriction
-      (narrow-to-region (point) (point-max))
-      (let ((new (mml-generate-mime)))
-       (when new
-         (delete-region (point-min) (point-max))
-         (insert new)
-         (goto-char (point-min))
-         (if (eq (aref new 0) ?\n)
-             (delete-char 1)
-           (search-forward "\n\n")
-           (setq lines (buffer-substring (point-min) (1- (point))))
-           (delete-region (point-min)  (point))))))
-    (save-restriction
-      (message-narrow-to-headers-or-head)
-      (message-remove-header "Mime-Version")
-      (goto-char (point-max))
-      (insert "Mime-Version: 1.0\n")
-      (when lines
-       (insert lines))
-      (setq multipart-p
-           (re-search-backward "^Content-Type: multipart/" nil t)))
-    (when multipart-p
+  (unless message-inhibit-body-encoding
+    (let ((mail-parse-charset (or mail-parse-charset
+                                 message-default-charset
+                                 message-posting-charset))
+         (case-fold-search t)
+         lines content-type-p)
+      (message-goto-body)
+      (save-restriction
+       (narrow-to-region (point) (point-max))
+       (let ((new (mml-generate-mime)))
+         (when new
+           (delete-region (point-min) (point-max))
+           (insert new)
+           (goto-char (point-min))
+           (if (eq (aref new 0) ?\n)
+               (delete-char 1)
+             (search-forward "\n\n")
+             (setq lines (buffer-substring (point-min) (1- (point))))
+             (delete-region (point-min)  (point))))))
+      (save-restriction
+       (message-narrow-to-headers-or-head)
+       (message-remove-header "Mime-Version")
+       (goto-char (point-max))
+       (insert "MIME-Version: 1.0\n")
+       (when lines
+         (insert lines))
+       (setq content-type-p
+             (re-search-backward "^Content-Type:" nil t)))
       (save-restriction
        (message-narrow-to-headers-or-head)
        (message-remove-first-header "Content-Type")
        (message-remove-first-header "Content-Transfer-Encoding"))
-      (message-goto-body)
-      (insert "This is a MIME multipart message.  If you are reading\n")
-      (insert "this, you shouldn't.\n"))))
+      ;; We always make sure that the message has a Content-Type header.
+      ;; This is because some broken MTAs and MUAs get awfully confused
+      ;; when confronted with a message with a MIME-Version header and
+      ;; without a Content-Type header.  For instance, Solaris'
+      ;; /usr/bin/mail.
+      (unless content-type-p
+       (goto-char (point-min))
+       (re-search-forward "^MIME-Version:")
+       (forward-line 1)
+       (insert "Content-Type: text/plain; charset=us-ascii\n")))))
 
 (defvar message-save-buffer " *encoding")
 (defun message-save-drafts ()