Move image files to etc/gnus.
[gnus] / lisp / message.el
index ebea5f5..170e7b7 100644 (file)
@@ -1,4 +1,4 @@
-;;; message.el --- composing mail and news messages
+;;; message.el --- composing mail and news messages  -*- coding: iso-latin-1 -*-
 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000
 ;;        Free Software Foundation, Inc.
 
@@ -33,7 +33,6 @@
 (eval-when-compile
   (require 'cl)
   (defvar gnus-list-identifiers))      ; gnus-sum is required where necessary
-
 (require 'mailheader)
 (require 'nnheader)
 ;; This is apparently necessary even though things are autoloaded:
@@ -260,7 +259,8 @@ should return the new buffer name."
   :group 'message-buffers
   :type 'boolean)
 
-(defvar gnus-local-organization)
+(eval-when-compile
+  (defvar gnus-local-organization))
 (defcustom message-user-organization
   (or (and (boundp 'gnus-local-organization)
           (stringp gnus-local-organization)
@@ -297,11 +297,13 @@ The provided functions are:
 
 (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."
+  :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."
+  :version "21.1"
   :group 'message-forwarding
   :type 'boolean)
 
@@ -322,6 +324,7 @@ The provided functions are:
 
 (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
   "*All headers that match this regexp will be deleted when forwarding a message."
+  :version "21.1"
   :group 'message-forwarding
   :type '(choice (const :tag "None" nil)
                 regexp))
@@ -428,8 +431,9 @@ might set this variable to '(\"-f\" \"you@some.where\")."
 Folding `References' makes ancient versions of INN create incorrect
 NOV lines.")
 
-(defvar gnus-post-method)
-(defvar gnus-select-method)
+(eval-when-compile
+  (defvar gnus-post-method)
+  (defvar gnus-select-method))
 (defcustom message-post-method
   (cond ((and (boundp 'gnus-post-method)
              (listp gnus-post-method)
@@ -493,7 +497,8 @@ the signature is inserted."
 
 ;;;###autoload
 (defcustom message-yank-prefix "> "
-  "*Prefix inserted on the lines of yanked messages."
+  "*Prefix inserted on the lines of yanked messages.
+Fix `message-cite-prefix-regexp' if it is set to an abnormal value."
   :type 'string
   :group 'message-insertion)
 
@@ -581,7 +586,7 @@ If stringp, use this; if non-nil, use no host name (user name only)."
 
 (define-widget 'message-header-lines 'text
   "All header lines must be LFD terminated."
-  :format "%t:%n%v"
+  :format "%{%t%}:%n%v"
   :valid-regexp "^\\'"
   :error "All header lines must be newline terminated")
 
@@ -653,13 +658,17 @@ a message of type TYPE; and FUNCTION is a function to be called if
 PREDICATE returns non-nil.  FUNCTION is called with one parameter --
 the prefix.")
 
-(defvar message-mail-alias-type 'abbrev
+(defcustom message-mail-alias-type 'abbrev
   "*What alias expansion type to use in Message buffers.
 The default is `abbrev', which uses mailabbrev.  nil switches
-mail aliases off.")
+mail aliases off."
+  :group 'message
+  :link '(custom-manual "(message)Mail Aliases")
+  :type '(choice (const :tag "Use Mailabbrev" abbrev)
+                (const :tag "No expansion" nil)))
 
 (defcustom message-auto-save-directory
-  (nnheader-concat message-directory "drafts/")
+  (file-name-as-directory (nnheader-concat message-directory "drafts"))
   "*Directory where Message auto-saves buffers if Gnus isn't running.
 If nil, Message won't auto-save."
   :group 'message-buffers
@@ -668,6 +677,7 @@ If nil, Message won't auto-save."
 (defcustom message-buffer-naming-style 'unique
   "*The way new message buffers are named.
 Valid valued are `unique' and `unsent'."
+  :version "21.1"
   :group 'message-buffers
   :type '(choice (const :tag "unique" unique)
                 (const :tag "unsent" unsent)))
@@ -676,6 +686,7 @@ Valid valued are `unique' and `unsent'."
   (and (not (mm-multibyte-p)) 'iso-8859-1)
   "Default charset used in non-MULE Emacsen.
 If nil, you might be asked to input the charset."
+  :version "21.1"
   :group 'message
   :type 'symbol)
 
@@ -683,10 +694,25 @@ If nil, you might be asked to input the charset."
   (and (boundp 'rmail-dont-reply-to-names) rmail-dont-reply-to-names)
   "*A regexp specifying names to prune when doing wide replies.
 A value of nil means exclude your own name only."
+  :version "21.1"
   :group 'message
   :type '(choice (const :tag "Yourself" nil)
                 regexp))
 
+(defvar message-shoot-gnksa-feet nil
+  "*A list of GNKSA feet you are allowed to shoot.  
+Gnus gives you all the opportunity you could possibly want for
+shooting yourself in the foot.  Also, Gnus allows you to shoot the
+feet of Good Net-Keeping Seal of Approval. The following are foot
+candidates:
+`empty-article'     Allow you to post an empty article;
+`quoted-text-only'  Allow you to post quoted text only;
+`multiple-copies'   Allow you to post multiple copies.")
+
+(defsubst message-gnksa-enable-p (feature)
+  (or (not (listp message-shoot-gnksa-feet))
+      (memq feature message-shoot-gnksa-feet)))
+
 ;;; Internal variables.
 ;;; Well, not really internal.
 
@@ -701,10 +727,6 @@ A value of nil means exclude your own name only."
 (defvar message-mode-abbrev-table text-mode-abbrev-table
   "Abbrev table used in Message mode buffers.
 Defaults to `text-mode-abbrev-table'.")
-(defgroup message-headers nil
-  "Message headers."
-  :link '(custom-manual "(message)Variables")
-  :group 'message)
 
 (defface message-header-to-face
   '((((class color)
@@ -902,6 +924,7 @@ The cdr of ech entry is a function for applying the face to a region.")
   "The limitation of messages sent as message/partial.
 The lower bound of message size in characters, beyond which the message 
 should be sent in several parts. If it is nil, the size is unlimited."
+  :version "21.1"
   :group 'message-buffers
   :type '(choice (const :tag "unlimited" nil)
                 (integer 1000000)))
@@ -913,6 +936,26 @@ The first matched address (not primary one) is used in the From field."
   :type '(choice (const :tag "Always use primary" nil)
                 regexp))
 
+(defcustom message-mail-user-agent nil
+  "Like `mail-user-agent'.
+Except if it is `nil', use Gnus native MUA; if it is t, use
+`mail-user-agent'."
+  :type '(radio (const :tag "Gnus native"
+                      :format "%t\n"
+                      nil)
+               (const :tag "`mail-user-agent'"
+                      :format "%t\n"
+                      t)
+               (function-item :tag "Default Emacs mail"
+                              :format "%t\n"
+                              sendmail-user-agent)
+               (function-item :tag "Emacs interface to MH"
+                              :format "%t\n"
+                              mh-e-user-agent)
+               (function :tag "Other"))
+  :version "21.1"
+  :group 'message)
+
 ;;; Internal variables.
 
 (defvar message-sending-message "Sending...")
@@ -924,8 +967,9 @@ The first matched address (not primary one) is used in the From field."
 (defvar message-posting-charset nil)
 
 ;; Byte-compiler warning
-(defvar gnus-active-hashtb)
-(defvar gnus-read-active-file)
+(eval-when-compile
+  (defvar gnus-active-hashtb)
+  (defvar gnus-read-active-file))
 
 ;;; Regexp matching the delimiter of messages in UNIX mail format
 ;;; (UNIX From lines), minus the initial ^.  It should be a copy
@@ -1240,10 +1284,8 @@ Return the number of headers removed."
      (point-max)))
   (goto-char (point-min)))
 
-(defun message-narrow-to-head ()
-  "Narrow the buffer to the head of the message.
-Point is left at the beginning of the narrowed-to region."
-  (widen)
+(defun message-narrow-to-head-1 ()
+  "Like `message-narrow-to-head'. Don't widen."
   (narrow-to-region
    (goto-char (point-min))
    (if (search-forward "\n\n" nil 1)
@@ -1251,6 +1293,12 @@ Point is left at the beginning of the narrowed-to region."
      (point-max)))
   (goto-char (point-min)))
 
+(defun message-narrow-to-head ()
+  "Narrow the buffer to the head of the message.
+Point is left at the beginning of the narrowed-to region."
+  (widen)
+  (message-narrow-to-head-1))
+
 (defun message-narrow-to-headers-or-head ()
   "Narrow the buffer to the head of the message."
   (widen)
@@ -1380,6 +1428,7 @@ Point is left at the beginning of the narrowed-to region."
   (define-key message-mode-map "\C-c\C-v" 'message-delete-not-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 "\C-c\C-a" 'mml-attach-file)
 
@@ -1387,7 +1436,7 @@ Point is left at the beginning of the narrowed-to region."
 
 (easy-menu-define
  message-mode-menu message-mode-map "Message Menu."
'("Message"
`("Message"
    ["Sort Headers" message-sort-headers t]
    ["Yank Original" message-yank-original t]
    ["Fill Yanked Message" message-fill-yanked-message t]
@@ -1399,12 +1448,22 @@ Point is left at the beginning of the narrowed-to region."
    ["Kill To Signature" message-kill-to-signature t]
    ["Newline and Reformat" message-newline-and-reformat t]
    ["Rename buffer" message-rename-buffer t]
-   ["Spellcheck" ispell-message t]
-   ["Attach file as MIME" mml-attach-file t]
+   ["Spellcheck" ispell-message
+    ,@(if (featurep 'xemacs) nil
+       '(:help "Spellcheck this message"))]
+   ["Attach file as MIME" mml-attach-file
+    ,@(if (featurep 'xemacs) nil
+       '(:help "Attach a file at point"))]
    "----"
-   ["Send Message" message-send-and-exit t]
-   ["Abort Message" message-dont-send t]
-   ["Kill Message" message-kill-buffer t]))
+   ["Send Message" message-send-and-exit
+    ,@(if (featurep 'xemacs) nil
+       '(:help "Send this message"))]
+   ["Abort Message" message-dont-send
+    ,@(if (featurep 'xemacs) nil
+       '(:help "File this draft message and exit"))]
+   ["Kill Message" message-kill-buffer
+    ,@(if (featurep 'xemacs) nil
+       '(:help "Delete this message without sending"))]))
 
 (easy-menu-define
  message-mode-field-menu message-mode-map ""
@@ -1424,15 +1483,18 @@ Point is left at the beginning of the narrowed-to region."
    ["Body" message-goto-body t]
    ["Signature" message-goto-signature t]))
 
-(defvar facemenu-add-face-function)
-(defvar facemenu-remove-face-function)
+(defvar message-tool-bar-map nil)
+
+(eval-when-compile
+  (defvar facemenu-add-face-function)
+  (defvar facemenu-remove-face-function))
 
 ;;;###autoload
 (defun message-mode ()
   "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-d  Postpone 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
@@ -1489,12 +1551,16 @@ 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)
+  ;; Allow using comment commands to add/remove quoting.
+  (set (make-local-variable 'comment-start) message-yank-prefix)
   ;;(when (fboundp 'mail-hist-define-keys)
   ;;  (mail-hist-define-keys))
   (if (featurep 'xemacs)
       (message-setup-toolbar)
     (set (make-local-variable 'font-lock-defaults)
-        '(message-font-lock-keywords t)))
+        '(message-font-lock-keywords t))
+    (if (boundp 'tool-bar-map)
+       (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)
   ;; Allow mail alias things.
@@ -1519,12 +1585,9 @@ M-RET    message-newline-and-reformat (break the line and reformat)."
   (make-local-variable 'adaptive-fill-first-line-regexp)
   (make-local-variable 'auto-fill-inhibit-regexp)
   (let ((quote-prefix-regexp
-         (concat
-         "\\("
-         (regexp-quote message-yank-prefix)  ; user's prefix
-         "\\)?\\("
-         message-cite-prefix-regexp    ; various prefix
-          "\\)[ \t]*")))                ; possible space after each prefix
+        ;; User should change message-cite-prefix-regexp if
+        ;; message-yank-prefix is set to an abnormal value.
+         (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))      
     (setq paragraph-start
           (concat
            (regexp-quote mail-header-separator) "$\\|"
@@ -1711,40 +1774,88 @@ With the prefix argument FORCE, insert the header anyway."
     (unless (bolp)
       (insert "\n"))))
 
-(defun message-newline-and-reformat ()
+(defun message-newline-and-reformat (&optional not-break)
   "Insert four newlines, and then reformat if inside quoted text."
   (interactive)
-  (let (quoted point end leading-space)
-    (save-excursion
-      (beginning-of-line)
-      (while (and (not end) (looking-at message-cite-prefix-regexp))
-       (if quoted
-           (unless (equal quoted (match-string 0))
-             (setq end (point)))
-         (setq quoted (match-string 0)))
-       (unless end
-         (goto-char (match-end 0))
-         (looking-at "[ \t]*")
-         (if (or (not leading-space) 
-                 (> (length leading-space) (length (match-string 0))))
-             (setq leading-space (match-string 0))))
-       (forward-line 1)))
-    (if (< (- (point) (gnus-point-at-bol)) (length quoted))
+  (let (quoted point beg end leading-space)
+    (setq point (point))
+    (beginning-of-line)
+    (setq beg (point))
+    ;; Find first line of the paragraph.
+    (if not-break
+       (while (and (not (eobp)) 
+                   (not (looking-at message-cite-prefix-regexp))
+               (looking-at paragraph-start))
+         (forward-line 1)))
+    ;; Find the prefix
+    (when (looking-at message-cite-prefix-regexp)
+      (setq quoted (match-string 0))
+      (goto-char (match-end 0))
+      (looking-at "[ \t]*")
+      (setq leading-space (match-string 0)))
+    (if (and quoted
+            (not not-break)
+            (< (- point beg) (length quoted)))
        ;; break in the cite prefix.
        (setq quoted nil
              end nil))
+    (if quoted
+       (progn
+         (forward-line 1)
+         (while (and (not (eobp))
+                     (not (looking-at paragraph-separate))
+                     (looking-at message-cite-prefix-regexp)
+                     (equal quoted (match-string 0)))
+           (goto-char (match-end 0))
+           (looking-at "[ \t]*")
+           (if (> (length leading-space) (length (match-string 0)))
+               (setq leading-space (match-string 0)))
+           (forward-line 1))
+         (setq end (point))
+         (goto-char beg)
+         (while (and (if (bobp) nil (forward-line -1) t)
+                     (not (looking-at paragraph-start))
+                     (looking-at message-cite-prefix-regexp)
+                     (equal quoted (match-string 0)))
+           (setq beg (point))
+           (goto-char (match-end 0))
+           (looking-at "[ \t]*")
+           (if (> (length leading-space) (length (match-string 0)))
+               (setq leading-space (match-string 0)))))
+      (while (and (not (eobp))
+                 (not (looking-at paragraph-separate))
+                 (not (looking-at message-cite-prefix-regexp)))
+       (forward-line 1))
+      (setq end (point))
+      (goto-char beg)
+      (while (and (if (bobp) nil (forward-line -1) t)
+                 (not (looking-at paragraph-start))
+                 (not (looking-at message-cite-prefix-regexp)))
+       (setq beg (point))))
+    (goto-char point)
     (save-restriction
-      (if end
-         (narrow-to-region (point) end))
-      (insert "\n")
-      (setq point (point))
-      (insert "\n\n\n")
-      (delete-region (point) (re-search-forward "[ \t]*"))
-      (when quoted
-       (insert quoted (or leading-space "")))
-      (fill-paragraph nil)
-      (goto-char point)
-      (forward-line 1))))
+      (narrow-to-region beg end)
+      (if not-break
+         (setq point nil)
+       (insert "\n\n")
+       (setq point (point))
+       (insert "\n\n")
+       (delete-region (point) (re-search-forward "[ \t]*"))
+       (when quoted
+         (insert quoted leading-space)))
+      (if quoted
+         (let* ((adaptive-fill-regexp 
+                (regexp-quote (concat quoted leading-space)))
+                (adaptive-fill-first-line-regexp 
+                 adaptive-fill-regexp ))
+           (fill-paragraph nil))
+       (fill-paragraph nil))
+      (if point (goto-char point)))))
+
+(defun message-fill-paragraph ()
+  "Like `fill-paragraph'."
+  (interactive)
+  (message-newline-and-reformat t))
 
 (defun message-insert-signature (&optional force)
   "Insert a signature.  See documentation for the `message-signature' variable."
@@ -1999,7 +2110,7 @@ prefix, and don't delete any headers."
        (insert "\n"))
       (funcall message-citation-line-function))))
 
-(defvar mail-citation-hook)            ;Compiler directive
+(eval-when-compile (defvar mail-citation-hook))                ;Compiler directive
 (defun message-cite-original ()
   "Cite function in the standard Message manner."
   (if (and (boundp 'mail-citation-hook)
@@ -2152,10 +2263,13 @@ 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))
-                      (y-or-n-p
-                       (format
-                        "Already sent message via %s; resend? "
-                        (car elem))))
+                      (if (or (message-gnksa-enable-p 'multiple-copies)
+                              (not (eq (car elem) 'news)))
+                          (y-or-n-p
+                           (format
+                            "Already sent message via %s; resend? "
+                            (car elem)))
+                        (error "Denied posting -- multiple copies.")))
                   (setq success (funcall (caddr elem) arg)))
          (setq sent t))))
     (unless (or sent (not success))
@@ -2323,10 +2437,8 @@ It should typically alter the sending method in some way or other."
          (set-buffer tembuf)
          (erase-buffer)
          ;; Avoid copying text props.
-         (insert (format
-                  "%s" (save-excursion
-                         (set-buffer mailbuf)
-                         (buffer-string))))
+         (insert (with-current-buffer mailbuf
+                   (buffer-substring-no-properties (point-min) (point-max))))
          ;; Remove some headers.
          (message-encode-message-body)
          (save-restriction
@@ -2533,10 +2645,9 @@ to find out how to use this."
              (buffer-disable-undo)
              (erase-buffer)
              ;; Avoid copying text props.
-             (insert (format
-                      "%s" (save-excursion
-                             (set-buffer messbuf)
-                             (buffer-string))))
+             (insert (with-current-buffer messbuf
+                       (buffer-substring-no-properties 
+                        (point-min) (point-max))))
              (message-encode-message-body)
              ;; Remove some headers.
              (save-restriction
@@ -2813,7 +2924,10 @@ to find out how to use this."
        (re-search-backward message-signature-separator nil t)
        (beginning-of-line)
        (or (re-search-backward "[^ \n\t]" b t)
-          (y-or-n-p "Empty article.  Really post? "))))
+          (if (message-gnksa-enable-p 'empty-article)
+              (y-or-n-p "Empty article.  Really post? ")
+            (message "Denied posting -- Empty article.")
+            nil))))
    ;; Check for control characters.
    (message-check 'control-chars
      (if (re-search-forward "[\000-\007\013\015-\032\034-\037\200-\237]" nil t)
@@ -2832,8 +2946,11 @@ to find out how to use this."
      (or
       (not message-checksum)
       (not (eq (message-checksum) message-checksum))
-      (y-or-n-p
-       "It looks like no new text has been added.  Really post? ")))
+      (if (message-gnksa-enable-p 'quoted-text-only)
+         (y-or-n-p
+          "It looks like no new text has been added.  Really post? ")
+       (message "Denied posting -- no new text has been added.")
+       nil)))
    ;; Check the length of the signature.
    (message-check 'signature
      (goto-char (point-max))
@@ -2847,15 +2964,20 @@ to find out how to use this."
    (message-check 'quoting-style
      (goto-char (point-max))
      (let ((no-problem t))
-       (when (search-backward-regexp "^>[^\n]*\n>" nil t)
-        (setq no-problem nil)
-        (while (not (eobp))
-          (when (and (not (eolp)) (looking-at "[^> \t]"))
-            (setq no-problem t))
-          (forward-line)))
+       (when (search-backward-regexp "^>[^\n]*\n" nil t)
+        (setq no-problem (search-forward-regexp "^[ \t]*[^>\n]" nil t)))
        (if no-problem
           t
-        (y-or-n-p "Your text should follow quoted text.  Really post? "))))))
+        (if (message-gnksa-enable-p 'quoted-text-only)
+            (y-or-n-p "Your text should follow quoted text.  Really post? ")
+          ;; Ensure that
+          (goto-char (point-min))
+          (re-search-forward
+           (concat "^" (regexp-quote mail-header-separator) "$"))
+          (if (search-forward-regexp "^[ \t]*[^>\n]" nil t)
+              (y-or-n-p "Your text should follow quoted text.  Really post? ")
+            (message "Denied posting -- only quoted text.")
+            nil)))))))
 
 (defun message-checksum ()
   "Return a \"checksum\" for the current buffer."
@@ -2988,7 +3110,6 @@ If NOW, use that time instead."
                      (mail-header-references message-reply-headers)
                      (mail-header-subject message-reply-headers)
                      psubject
-                     (mail-header-subject message-reply-headers)
                      (not (string=
                            (message-strip-subject-re
                             (mail-header-subject message-reply-headers))
@@ -3562,13 +3683,47 @@ than 988 characters long, and if they are not, trim them until they are."
     (setq message-buffer-list
          (nconc message-buffer-list (list (current-buffer))))))
 
-(defvar mc-modes-alist)
-(defun message-setup (headers &optional replybuffer actions)
-  (when (and (boundp 'mc-modes-alist)
-            (not (assq 'message-mode mc-modes-alist)))
-    (push '(message-mode (encrypt . mc-encrypt-message)
-                        (sign . mc-sign-message))
-         mc-modes-alist))
+(defun message-mail-user-agent ()
+  (let ((mua (cond
+             ((not message-mail-user-agent) nil)
+             ((eq message-mail-user-agent t) mail-user-agent)
+             (t message-mail-user-agent))))
+    (if (memq mua '(message-user-agent gnus-user-agent))
+       nil
+      mua)))
+
+(defun message-setup (headers &optional replybuffer actions switch-function)
+  (let ((mua (message-mail-user-agent))
+       subject to field yank-action)
+    (if (not (and message-this-is-mail mua))
+       (message-setup-1 headers replybuffer actions)
+      (if replybuffer
+         (setq yank-action (list 'insert-buffer replybuffer)))
+      (setq headers (copy-sequence headers))
+      (setq field (assq 'Subject headers))
+      (when field
+       (setq subject (cdr field))
+       (setq headers (delq field headers)))
+      (setq field (assq 'To headers))
+      (when field
+       (setq to (cdr field))
+       (setq headers (delq field headers)))
+      (let ((mail-user-agent mua))
+       (compose-mail to subject 
+                     (mapcar (lambda (item)
+                               (cons
+                                (format "%s" (car item))
+                                (cdr item)))
+                             headers)
+                     nil switch-function yank-action actions))))) 
+
+;;;(defvar mc-modes-alist)
+(defun message-setup-1 (headers &optional replybuffer actions)
+;;;   (when (and (boundp 'mc-modes-alist)
+;;;         (not (assq 'message-mode mc-modes-alist)))
+;;;     (push '(message-mode (encrypt . mc-encrypt-message)
+;;;                     (sign . mc-sign-message))
+;;;      mc-modes-alist))
   (when actions
     (setq message-send-actions actions))
   (setq message-reply-buffer replybuffer)
@@ -3628,6 +3783,9 @@ than 988 characters long, and if they are not, trim them until they are."
 (defun message-set-auto-save-file-name ()
   "Associate the message buffer with a file in the drafts directory."
   (when message-auto-save-directory
+    (unless (file-directory-p
+            (directory-file-name message-auto-save-directory))
+      (gnus-make-directory message-auto-save-directory))
     (if (gnus-alive-p)
        (setq message-draft-article
              (nndraft-request-associate-buffer "drafts"))
@@ -3674,7 +3832,8 @@ than 988 characters long, and if they are not, trim them until they are."
 OTHER-HEADERS is an alist of header/value pairs."
   (interactive)
   (let ((message-this-is-mail t))
-    (message-pop-to-buffer (message-buffer-name "mail" to))
+    (unless (message-mail-user-agent)
+      (message-pop-to-buffer (message-buffer-name "mail" to)))
     (message-setup
      (nconc
       `((To . ,(or to "")) (Subject . ,(or subject "")))
@@ -3774,6 +3933,7 @@ responses here are directed to other addresses.")))
            (push ccs follow-to)))))
     follow-to))
 
+
 ;;;###autoload
 (defun message-reply (&optional to-address wide)
   "Start editing a reply to the article in the current buffer."
@@ -3786,7 +3946,7 @@ responses here are directed to other addresses.")))
        (message-this-is-mail t)
        gnus-warning)
     (save-restriction
-      (message-narrow-to-head)
+      (message-narrow-to-head-1)
       ;; Allow customizations to have their say.
       (if (not wide)
          ;; This is a regular reply.
@@ -3813,10 +3973,11 @@ responses here are directed to other addresses.")))
     (unless follow-to
       (setq follow-to (message-get-reply-headers wide to-address))))
 
-    (message-pop-to-buffer
-     (message-buffer-name
-      (if wide "wide reply" "reply") from
-      (if wide to-address nil)))
+    (unless (message-mail-user-agent)
+      (message-pop-to-buffer
+       (message-buffer-name
+       (if wide "wide reply" "reply") from
+       (if wide to-address nil))))
 
     (setq message-reply-headers
          (vector 0 subject from date message-id references 0 0 ""))
@@ -3961,7 +4122,7 @@ If ARG, allow editing of the cancellation message."
       (save-excursion
        ;; Get header info from original article.
        (save-restriction
-         (message-narrow-to-head)
+         (message-narrow-to-head-1)
          (setq from (message-fetch-field "from")
                sender (message-fetch-field "sender")
                newsgroups (message-fetch-field "newsgroups")
@@ -4023,7 +4184,7 @@ header line with the old Message-ID."
     (message-pop-to-buffer (message-buffer-name "supersede"))
     (insert-buffer-substring cur)
     (mime-to-mml)
-    (message-narrow-to-head)
+    (message-narrow-to-head-1)
     ;; Remove unwanted headers.
     (when message-ignored-supersedes-headers
       (message-remove-header message-ignored-supersedes-headers t))
@@ -4111,13 +4272,15 @@ the message."
   "Return a Subject header suitable for the message in the current buffer."
   (save-excursion
     (save-restriction
-      (current-buffer)
-      (message-narrow-to-head)
+      (message-narrow-to-head-1)
       (let ((funcs message-make-forward-subject-function)
-           (subject (if message-wash-forwarded-subjects
-                        (message-wash-subject
-                         (or (message-fetch-field "Subject") ""))
-                      (or (message-fetch-field "Subject") ""))))
+           (subject (message-fetch-field "Subject")))
+       (setq subject
+             (if subject
+                 (mail-decode-encoded-word-string subject)
+               ""))
+       (if message-wash-forwarded-subjects
+           (setq subject (message-wash-subject subject)))
        ;; Make sure funcs is a list.
        (and funcs
             (not (listp funcs))
@@ -4137,10 +4300,7 @@ Optional NEWS will use news to forward instead of mail.
 Optional DIGEST will use digest to forward."
   (interactive "P")
   (let* ((cur (current-buffer))
-        (subject (if message-forward-show-mml
-                     (message-make-forward-subject)
-                   (mail-decode-encoded-word-string
-                    (message-make-forward-subject))))
+        (subject (message-make-forward-subject))
         art-beg)
     (if news
        (message-news nil subject)
@@ -4163,8 +4323,31 @@ Optional DIGEST will use digest to forward."
              (insert-buffer-substring cur)
            (mml-insert-buffer cur))
        (if message-forward-show-mml
-           (insert-buffer-substring cur)
-         (mml-insert-buffer cur)))
+           (let ((target (current-buffer)) tmp)
+             (with-temp-buffer
+               (mm-disable-multibyte) ;; Must copy buffer in unibyte mode
+               (setq tmp (current-buffer))
+               (set-buffer cur)
+               (mm-with-unibyte-current-buffer
+                 (set-buffer tmp)
+                 (insert-buffer-substring cur)
+                 (set-buffer cur))
+               (set-buffer tmp)
+               (mm-enable-multibyte)
+               (mime-to-mml)
+               (goto-char (point-min))
+               (when (looking-at "From ")
+                 (replace-match "X-From-Line: "))
+               (set-buffer target)
+               (insert-buffer-substring tmp)
+               (set-buffer tmp)))
+         (save-restriction
+           (narrow-to-region (point) (point))
+           (mml-insert-buffer cur)
+           (goto-char (point-min))
+           (when (looking-at "From ")
+             (replace-match "X-From-Line: "))
+           (goto-char (point-max)))))
       (setq e (point))
       (if message-forward-as-mime
          (if digest
@@ -4200,9 +4383,11 @@ Optional DIGEST will use digest to forward."
     (let ((cur (current-buffer))
          beg)
       ;; We first set up a normal mail buffer.
-      (set-buffer (get-buffer-create " *message resend*"))
-      (erase-buffer)
-      (message-setup `((To . ,address)))
+      (unless (message-mail-user-agent)
+       (set-buffer (get-buffer-create " *message resend*"))
+       (erase-buffer))
+      (let ((message-this-is-mail t))
+       (message-setup `((To . ,address))))
       ;; Insert our usual headers.
       (message-generate-headers '(From Date To))
       (message-narrow-to-headers)
@@ -4270,7 +4455,7 @@ you."
     (mm-enable-multibyte)
     (mime-to-mml)
     (save-restriction
-      (message-narrow-to-head)
+      (message-narrow-to-head-1)
       (message-remove-header message-ignored-bounced-headers t)
       (goto-char (point-max))
       (insert mail-header-separator))
@@ -4284,27 +4469,31 @@ you."
 (defun message-mail-other-window (&optional to subject)
   "Like `message-mail' command, but display mail buffer in another window."
   (interactive)
-  (let ((pop-up-windows t)
-       (special-display-buffer-names nil)
-       (special-display-regexps nil)
-       (same-window-buffer-names nil)
-       (same-window-regexps nil))
-    (message-pop-to-buffer (message-buffer-name "mail" to)))
+  (unless (message-mail-user-agent)
+    (let ((pop-up-windows t)
+         (special-display-buffer-names nil)
+         (special-display-regexps nil)
+         (same-window-buffer-names nil)
+         (same-window-regexps nil))
+      (message-pop-to-buffer (message-buffer-name "mail" to))))
   (let ((message-this-is-mail t))
-    (message-setup `((To . ,(or to "")) (Subject . ,(or subject ""))))))
+    (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+                  nil nil 'switch-to-buffer-other-window)))
 
 ;;;###autoload
 (defun message-mail-other-frame (&optional to subject)
   "Like `message-mail' command, but display mail buffer in another frame."
   (interactive)
-  (let ((pop-up-frames t)
-       (special-display-buffer-names nil)
-       (special-display-regexps nil)
-       (same-window-buffer-names nil)
-       (same-window-regexps nil))
-    (message-pop-to-buffer (message-buffer-name "mail" to)))
+  (unless (message-mail-user-agent)
+    (let ((pop-up-frames t)
+         (special-display-buffer-names nil)
+         (special-display-regexps nil)
+         (same-window-buffer-names nil)
+         (same-window-regexps nil))
+      (message-pop-to-buffer (message-buffer-name "mail" to))))
   (let ((message-this-is-mail t))
-    (message-setup `((To . ,(or to "")) (Subject . ,(or subject ""))))))
+    (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
+                  nil nil 'switch-to-buffer-other-frame)))
 
 ;;;###autoload
 (defun message-news-other-window (&optional newsgroups subject)
@@ -4371,8 +4560,36 @@ which specify the range to operate on."
 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
 
 ;; Support for toolbar
-(when (featurep 'xemacs)
-  (require 'messagexmas))
+(if (featurep 'xemacs)
+    (require 'messagexmas))
+
+(eval-when-compile 
+  (defvar tool-bar-map)
+  (defvar tool-bar-mode))
+
+(defun message-tool-bar-map ()
+  (or message-tool-bar-map
+      (setq message-tool-bar-map
+           (and (fboundp 'tool-bar-add-item-from-menu)
+                tool-bar-mode
+                (let ((tool-bar-map (copy-keymap tool-bar-map))
+                      (load-path (mm-image-load-path)))
+                  ;; Zap some items which aren't so relevant and take
+                  ;; up space.
+                  (dolist (key '(print-buffer kill-buffer save-buffer 
+                                              write-file dired open-file))
+                    (define-key tool-bar-map (vector key) nil))
+                  (tool-bar-add-item-from-menu
+                   'message-send-and-exit "mail_send" message-mode-map)
+                  (tool-bar-add-item-from-menu
+                   'message-kill-buffer "close" message-mode-map)
+                  (tool-bar-add-item-from-menu
+                   'message-dont-send "cancel" message-mode-map)
+                  (tool-bar-add-item-from-menu
+                   'mml-attach-file "attach" message-mode-map)
+                  (tool-bar-add-item-from-menu
+                   'ispell-message "spell" message-mode-map)
+                  tool-bar-map)))))
 
 ;;; Group name completion.
 
@@ -4389,7 +4606,6 @@ Do a `tab-to-tab-stop' if not in those headers."
       (message-expand-group)
     (tab-to-tab-stop)))
 
-(defvar gnus-active-hashtb)
 (defun message-expand-group ()
   "Expand the group name under point."
   (let* ((b (save-excursion