*** empty log message ***
[gnus] / lisp / gnus-msg.el
index 8bbfe3f..6f71d16 100644 (file)
 (require 'gnus)
 (require 'sendmail)
 (require 'gnus-ems)
-(require 'rmail)
+(eval-when-compile (require 'cl))
 
 (defvar gnus-organization-file "/usr/lib/news/organization"
   "*Local news organization file.")
 
-(defvar gnus-prepare-article-hook (list 'gnus-inews-insert-signature)
-  "*A hook called after preparing body, but before preparing header headers.
-The default hook (`gnus-inews-insert-signature') inserts a signature
-file specified by the variable `gnus-signature-file'.")
+(defvar gnus-prepare-article-hook nil
+  "*A hook called after preparing body, but before preparing header headers.")
 
 (defvar gnus-post-prepare-function nil
   "*Function that is run after a post buffer has been prepared.
@@ -122,12 +120,26 @@ message in, you can set this variable to a function that checks the
 current newsgroup name and then returns a suitable group name (or list
 of names).")
 
+(defvar gnus-mailing-list-groups nil
+  "*Regexp matching groups that are really mailing lists.
+This is useful when you're reading a mailing list that has been
+gatewayed to a newsgroup, and you want to followup to an article in
+the group.")
+
 (defvar gnus-draft-group-directory 
   (expand-file-name
    (concat (file-name-as-directory gnus-article-save-directory)
           "drafts"))
   "*The directory where draft messages will be stored.")
 
+(defvar gnus-posting-styles nil
+  "*Alist of styles to use when posting.")
+
+(defvar gnus-posting-style-alist
+  '((organization . gnus-organization-file)
+    (signature . gnus-signature-file)
+    (from . gnus-user-from-line)))
+
 (defvar gnus-user-login-name nil
   "*The login name of the user.
 Got from the function `user-login-name' if undefined.")
@@ -165,6 +177,17 @@ string itself is inserted.
 If the function returns nil, the `gnus-signature-file' variable will
 be used instead.")
 
+(defvar gnus-forward-start-separator 
+  "------- Start of forwarded message -------\n"
+  "*Delimiter inserted before forwarded messages.")
+
+(defvar gnus-forward-end-separator
+  "------- End of forwarded message -------\n"
+  "*Delimiter inserted after forwarded messages.")
+
+(defvar gnus-signature-before-forwarded-message t
+  "*If non-nil, put the signature before any included forwarded message.")
+
 (defvar gnus-required-headers
   '(From Date Newsgroups Subject Message-ID Organization Lines X-Newsreader)
   "*Headers to be generated or prompted for when posting an article.
@@ -174,7 +197,7 @@ optional.  If you want Gnus not to insert some header, remove it from
 this list.")
 
 (defvar gnus-required-mail-headers 
-  '(From Date To Subject In-Reply-To Message-ID Organization Lines)
+  '(From Date To Subject (optional . In-Reply-To) Message-ID Organization Lines)
   "*Headers to be generated or prompted for when mailing a message.
 RFC822 required that From, Date, To, Subject and Message-ID be
 included.  Organization, Lines and X-Mailer are optional.")
@@ -194,19 +217,16 @@ If this variable is t, Gnus will check everything it can.  If it is a
 list, then those elements in that list will be checked.")
 
 (defvar gnus-delete-supersedes-headers
-  "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Supersedes:"
+  "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Supersedes:\\|^Xref:\\|^Lines:"
   "*Header lines matching this regexp will be deleted before posting.
-It's best to delete old Path and Date headers before psoting to avoid
+It's best to delete old Path and Date headers before posting to avoid
 any confusion.")
 
 (defvar gnus-auto-mail-to-author nil
   "*If non-nil, mail the authors of articles a copy of your follow-ups.
 If this variable is `ask', the user will be prompted for whether to
 mail a copy.  The string given by `gnus-mail-courtesy-message' will be
-inserted at the beginning of the mail copy.
-
-Mail is sent using the function specified by the
-`gnus-mail-send-method' variable.")
+inserted at the beginning of the mail copy.")
 
 ;; Added by Ethan Bradford <ethanb@ptolemy.astro.washington.edu>.
 (defvar gnus-mail-courtesy-message
@@ -230,11 +250,6 @@ Three pre-made functions are `gnus-mail-other-window-using-mail'
 (sendmail); `gnus-mail-other-window-using-mhe' (MH-E); and
 `gnus-mail-other-window-using-vm'.")
 
-(defvar gnus-mail-send-method send-mail-function
-  "*Function to mail a message which is also being posted as an article.
-The message must have To or Cc header.  The default is copied from
-the variable `send-mail-function'.")
-
 (defvar gnus-inews-article-function 'gnus-inews-article
   "*Function to post an article.")
 
@@ -262,6 +277,7 @@ headers.")
 (defvar gnus-post-news-buffer "*post-news*")
 (defvar gnus-mail-buffer "*mail*")
 (defvar gnus-summary-send-map nil)
+(defvar gnus-send-bounce-map nil)
 (defvar gnus-article-copy nil)
 (defvar gnus-reply-subject nil)
 (defvar gnus-add-to-address nil)
@@ -270,7 +286,8 @@ headers.")
 (eval-and-compile
   (autoload 'gnus-uu-post-news "gnus-uu" nil t)
   (autoload 'news-setup "rnewspost")
-  (autoload 'news-reply-mode "rnewspost"))
+  (autoload 'news-reply-mode "rnewspost")
+  (autoload 'rmail-output "rmailout"))
 
 \f
 ;;;
@@ -289,14 +306,18 @@ headers.")
 (define-key gnus-summary-send-map "r" 'gnus-summary-reply)
 (define-key gnus-summary-send-map "R" 'gnus-summary-reply-with-original)
 (define-key gnus-summary-send-map "m" 'gnus-summary-mail-other-window)
-(define-key gnus-summary-send-map "Db" 'gnus-summary-resend-bounced-mail)
-(define-key gnus-summary-send-map "Dc" 'gnus-summary-send-draft)
 (define-key gnus-summary-send-map "u" 'gnus-uu-post-news)
 (define-key gnus-summary-send-map "om" 'gnus-summary-mail-forward)
 (define-key gnus-summary-send-map "op" 'gnus-summary-post-forward)
 (define-key gnus-summary-send-map "Om" 'gnus-uu-digest-mail-forward)
 (define-key gnus-summary-send-map "Op" 'gnus-uu-digest-post-forward)
 
+(define-prefix-command 'gnus-send-bounce-map)
+(define-key gnus-summary-send-map "D" 'gnus-send-bounce-map)
+(define-key gnus-send-bounce-map "b" 'gnus-summary-resend-bounced-mail)
+(define-key gnus-send-bounce-map "c" 'gnus-summary-send-draft)
+(define-key gnus-send-bounce-map "r" 'gnus-summary-resend-message)
+
 ;;; Internal functions.
 
 (defun gnus-number-base36 (num len)
@@ -311,13 +332,31 @@ headers.")
 (defun gnus-group-mail ()
   "Start composing a mail."
   (interactive)
-  (gnus-new-mail))
-
-(defun gnus-group-post-news ()
-  "Post an article."
-  (interactive)
-  (let ((gnus-newsgroup-name nil))
-    (gnus-post-news 'post nil nil gnus-article-buffer)))
+  (gnus-new-mail
+   ;; We might want to prompt here.
+   (when (and gnus-interactive-post
+             (not gnus-expert-user))
+     (read-string "To: "))))
+
+(defun gnus-group-post-news (&optional arg)
+  "Post an article.
+The newsgroup under the cursor is used as the group to post to.
+
+If you wish to get an empty post buffer, use a prefix ARG.  You can
+also do this by calling this function from the bottom of the Group
+buffer."
+  (interactive "P")
+  (let ((gnus-newsgroup-name nil)
+       (group (unless arg (gnus-group-group-name)))
+       subject)
+    ;; We might want to prompt here.
+    (when (and gnus-interactive-post
+              (not gnus-expert-user))
+      (setq gnus-newsgroup-name
+           (setq group 
+                 (completing-read "Group: " gnus-active-hashtb nil nil
+                                  (cons group 0)))))
+    (gnus-post-news 'post group nil gnus-article-buffer)))
 
 (defun gnus-summary-post-news ()
   "Post an article."
@@ -344,6 +383,7 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
                       "Do you want to ignore `Followup-To: poster'? "))))
        ;; Mail to the poster. 
        (gnus-summary-reply yank)
+      ;; Send a followup.
       (gnus-post-news nil gnus-newsgroup-name
                      headers gnus-article-buffer 
                      (or yank-articles (not (not yank)))))))
@@ -358,7 +398,7 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
   "Compose a followup and do an auto mail to author."
   (interactive "P")
   (gnus-set-global-variables)
-  (let ((gnus-auto-mail-to-author t))
+  (let ((gnus-auto-mail-to-author 'force))
     (gnus-summary-followup yank yank-articles)))
 
 (defun gnus-summary-followup-and-reply-with-original (n)
@@ -386,38 +426,28 @@ header line with the old Message-ID."
   (interactive)
   (gnus-set-global-variables)
   (gnus-summary-select-article t)
-  (if (not
-       (string-equal
-       (downcase (mail-strip-quoted-names 
-                  (mail-header-from gnus-current-headers)))
-       (downcase (mail-strip-quoted-names (gnus-inews-user-name)))))
-      (error "This article is not yours."))
-  (save-excursion
-    (set-buffer gnus-article-buffer)
-    (let ((buffer-read-only nil))
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
-      (if (not (re-search-backward "^Message-ID: " nil t))
-         (error "No Message-ID in this article"))))
-  (if (gnus-post-news 'post gnus-newsgroup-name)
-      (progn
-       (erase-buffer)
-       (insert-buffer gnus-article-buffer)
-       (if (search-forward "\n\n" nil t)
-           (forward-char -1)
-         (goto-char (point-max)))
-       (narrow-to-region (point-min) (point))
-       (goto-char (point-min))
-       (and gnus-delete-supersedes-headers
-            (delete-matching-lines gnus-delete-supersedes-headers))
-       (goto-char (point-min))
-       (if (not (re-search-forward "^Message-ID: " nil t))
-           (error "No Message-ID in this article")
-         (replace-match "Supersedes: " t t))
-       (goto-char (point-max))
-       (insert mail-header-separator)
-       (widen)
-       (forward-line 1))))
+  ;; Check whether the user owns the article that is to be superseded. 
+  (unless (string-equal
+          (downcase (mail-strip-quoted-names 
+                     (mail-header-from gnus-current-headers)))
+          (downcase (mail-strip-quoted-names (gnus-inews-user-name))))
+    (error "This article is not yours."))
+  ;; Get a normal *post-news* buffer.
+  (gnus-new-news gnus-newsgroup-name t)
+  (erase-buffer)
+  (insert-buffer-substring gnus-original-article-buffer)
+  (gnus-narrow-to-headers)
+  ;; Remove unwanted headers.
+  (when gnus-delete-supersedes-headers
+    (nnheader-remove-header gnus-delete-supersedes-headers t))
+  (goto-char (point-min))
+  (if (not (re-search-forward "^Message-ID: " nil t))
+      (error "No Message-ID in this article")
+    (replace-match "Supersedes: " t t))
+  (goto-char (point-max))
+  (insert mail-header-separator)
+  (widen)
+  (forward-line 1))
 
 \f
 ;;;###autoload
@@ -450,32 +480,43 @@ header line with the old Message-ID."
 Type \\[describe-mode] in the buffer to get a list of commands."
   (interactive (list t))
   (let* ((group (or group gnus-newsgroup-name))
-        (to-address 
-         (assq 'to-address 
-               (nth 5 (nth 2 (gnus-gethash group gnus-newsrc-hashtb))))))
-    (if (and (gnus-member-of-valid 'post (or group gnus-newsgroup-name))
-            (not to-address))
+        (pgroup group)
+        to-address to-group mailing-list to-list)
+    (when group
+      (setq to-address (gnus-group-get-parameter group 'to-address)
+           to-group (gnus-group-get-parameter group 'to-group)
+           to-list (gnus-group-get-parameter group 'to-list)
+           mailing-list (when gnus-mailing-list-groups
+                          (string-match gnus-mailing-list-groups group))
+           group (gnus-group-real-name group)))
+    (if (or to-group
+           (and (gnus-member-of-valid 'post (or pgroup gnus-newsgroup-name))
+                (not mailing-list)
+                (not to-list)
+                (not to-address)))
+       ;; This is news.
        (if post
-           (gnus-new-news group)
-         (gnus-news-followup yank group))
+           (gnus-new-news (or to-group group))
+         (gnus-news-followup yank (or to-group group)))
+      ;; The is mail.
       (if post
          (progn
-           (gnus-new-mail)
+           (gnus-new-mail (or to-address to-list))
            ;; Arrange for mail groups that have no `to-address' to
            ;; get that when the user sends off the mail.
-           (or to-address
-               (progn
-                 (make-local-variable 'gnus-add-to-address)
-                 (setq gnus-add-to-address group))))
-       (gnus-mail-reply yank (and to-address (cdr to-address)) 'followup)))))
+           (unless to-address
+             (make-local-variable 'gnus-add-to-address)
+             (setq gnus-add-to-address group)))
+       (gnus-mail-reply yank to-address 'followup)))))
 
 (defun gnus-inews-news (&optional use-group-method)
   "Send a news message.
 If given a prefix, and the group is a foreign group, this function
 will attempt to use the foreign server to post the article."
   (interactive "P")
+  (or gnus-current-select-method
+      (setq gnus-current-select-method gnus-select-method))
   (let* ((case-fold-search nil)
-        (server-running (gnus-server-opened gnus-current-select-method))
         (reply gnus-article-reply)
         error post-result)
     (save-excursion
@@ -503,15 +544,16 @@ will attempt to use the foreign server to post the article."
             ;; We cannot signal an error.
             (setq error t)
             (ding)
-            (gnus-message 1 "Article rejected: %s" 
-                          (gnus-status-message gnus-select-method)))))
+            (gnus-message 
+             1 "Article rejected: %s" 
+             (gnus-status-message
+              (gnus-post-method gnus-newsgroup-name use-group-method))))))
 
     (let ((conf gnus-prev-winconf))
-      (if (not error)
-         (progn
-           (bury-buffer)
-           ;; Restore last window configuration.
-           (and conf (set-window-configuration conf)))))))
+      (unless error
+       (bury-buffer)
+       ;; Restore last window configuration.
+       (and conf (set-window-configuration conf))))))
 
 (defun gnus-inews-narrow-to-headers ()
   (widen)
@@ -546,14 +588,22 @@ will attempt to use the foreign server to post the article."
          ;; We copy the article over to a temp buffer since we are
          ;; going to modify it a little.  
          (nnheader-set-temp-buffer " *Gnus-mailing*")
-         (insert-buffer buffer)
+         (insert-buffer-substring buffer)
          ;; We remove Fcc, because we don't want the mailer to see
          ;; that header.  
          (gnus-inews-narrow-to-headers)
          (nnheader-remove-header "fcc")
 
+         ;; Insert the X-Courtesy-Message header.
+         (and (or (member "to" types)
+                  (member "cc" types))
+              (progn
+               (goto-char (point-max))
+               (insert "Posted-To: " 
+                       (mail-fetch-field "newsgroups") "\n")))
+         
          (widen)
-           
+         
          (if (and gnus-mail-courtesy-message
                   (or (member "to" types)
                       (member "cc" types)))
@@ -576,8 +626,38 @@ will attempt to use the foreign server to post the article."
 (defun gnus-inews-remove-headers-after-mail ()
   (save-excursion
     (save-restriction
-      (gnus-inews-narrow-to-headers)
-      (nnheader-remove-header "bcc"))))
+      (let ((case-fold-search t))
+       (gnus-inews-narrow-to-headers)
+       ;; Remove Bcc completely.
+       (nnheader-remove-header "bcc")
+       ;; We transform To and Cc headers to avoid re-mailing if the user
+       ;; accidentally (or purposefully) leans on the `C-c C-c' keys
+       ;; and the news server rejects the posting.
+       (while (re-search-forward "^\\(to\\|[bcf]cc\\|cc\\):" nil t)
+         (beginning-of-line)
+         (insert "X-"))
+       (widen)))))
+
+(defun gnus-inews-dex-headers ()
+  "Remove \"X-\" prefixes from To and Cc headers."
+  (save-excursion
+    (save-restriction
+      (let ((case-fold-search t))
+       (gnus-narrow-to-headers)
+       (while (re-search-forward "^X-\\(to\\|[bcf]cc\\|cc\\):" nil t)
+         (beginning-of-line)
+         (delete-char 2))
+       (widen)))))
+
+(defun gnus-inews-remove-empty-headers ()
+  "Remove empty headers from news and mail.
+The buffer should be narrowed to the headers before this function is
+called."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "^[^ \t:]+:\\([ \t]*\n\\)+[^ \t]" nil t)
+      (delete-region (match-beginning 0) (1- (match-end 0)))
+      (beginning-of-line))))
 
 (defun gnus-inews-check-post ()
   "Check whether the post looks ok."
@@ -667,6 +747,15 @@ will attempt to use the foreign server to post the article."
                    (format
                     "The From header looks strange: \"%s\". Really post? " 
                     from)))
+                 ((string-match "<[^>]+> *$" from)
+                  (let ((name (substring from 0 (match-beginning 0))))
+                    (or 
+                     (string-match "^ *\"[^\"]*\" *$" name)
+                     (not (string-match "[][.!()<>@,;:\\]" name))
+                     (gnus-y-or-n-p
+                      (format
+                       "The From header name has bogus characters.  Really post? " 
+                       from)))))
                  (t t)))))
         )))
     ;; Check for long lines.
@@ -714,7 +803,7 @@ will attempt to use the foreign server to post the article."
          (goto-char (point-max))
          (if (not (re-search-backward gnus-signature-separator nil t))
              t
-           (if (> (count-lines (point) (point-max)) 4)
+           (if (> (count-lines (point) (point-max)) 5)
                (gnus-y-or-n-p
                 (format
                  "Your .sig is %d lines; it should be max 4.  Really post? "
@@ -865,6 +954,8 @@ will attempt to use the foreign server to post the article."
        (re-search-forward
         (concat "^" (regexp-quote mail-header-separator) "$"))
        (replace-match "" t t)
+       ;; Remove X- prefixes to headers.
+       (gnus-inews-dex-headers)
        ;; Run final inews hooks.  This hook may do FCC.
        ;; The article must be saved before being posted because
        ;; `gnus-request-post' modifies the buffer.
@@ -872,19 +963,10 @@ will attempt to use the foreign server to post the article."
        ;; Copy the article over to some group, possibly.
        (and gcc (gnus-inews-do-gcc gcc))
        ;; Post the article.
-       (setq result
-             (gnus-request-post 
-              (if use-group-method
-                  (gnus-find-method-for-group gnus-newsgroup-name)
-                gnus-select-method) use-group-method))
+       (let ((method (gnus-post-method gnus-newsgroup-name use-group-method)))
+         (setq result (gnus-request-post method)))
        (kill-buffer (current-buffer)))
       (run-hooks 'gnus-message-sent-hook)
-      ;; We remove To and Cc headers to avoid re-mailing if the user
-      ;; accidentally (or purposefully) leans on the `C-c C-c' keys
-      ;; and the news server rejects the posting.
-      (gnus-inews-narrow-to-headers)
-      (nnheader-remove-header "^\\(to\\|[bcf]cc\\|cc\\):" t)
-      (widen)
       ;; If the posting was unsuccessful (that it, it was rejected) we
       ;; put it into the draft group.
       (or result (gnus-put-in-draft-group))
@@ -964,7 +1046,28 @@ will attempt to use the foreign server to post the article."
           (delete-region (progn (beginning-of-line) (point))
                          (progn (forward-line 1) (point))))
       (setq headers (cdr headers)))))
-  
+
+;;; Since the X-Newsreader/X-Mailer are ``vanity'' headers, they might
+;;; as well include the Emacs version as well.
+;;; The following function works with later GNU Emacs, and XEmacs.
+(defun gnus-extended-version ()
+  "Stringified Gnus version and Emacs version"
+  (interactive)
+  (concat
+   gnus-version
+   "/"
+   (cond
+    ((string-match "^\\([0-9]+\\.[0-9]+\\)\\.[.0-9]+$" emacs-version)
+     (concat "Emacs " (substring emacs-version
+                                (match-beginning 1)
+                                (match-end 1))))
+    ((string-match "\\([A-Z]*[Mm][Aa][Cc][Ss]\\)" emacs-version)
+     (concat (substring emacs-version
+                       (match-beginning 1)
+                       (match-end 1))
+            (format " %d.%d" emacs-major-version emacs-minor-version)))
+    (t emacs-version))))
+
 (defun gnus-inews-insert-headers (&optional headers)
   "Prepare article headers.
 Headers already prepared in the buffer are not modified.
@@ -976,12 +1079,12 @@ Headers in `gnus-required-headers' will be generated."
        (Path (gnus-inews-path))
        (Subject nil)
        (Newsgroups nil)
-       (In-Reply-To (gnus-inews-in-reply-yo))
+       (In-Reply-To (gnus-inews-in-reply-to))
        (To nil)
        (Distribution nil)
        (Lines (gnus-inews-lines))
-       (X-Newsreader gnus-version)
-       (X-Mailer gnus-version)
+       (X-Newsreader (gnus-extended-version))
+       (X-Mailer (gnus-extended-version))
        (headers (or headers gnus-required-headers))
        (case-fold-search t)
        header value elem)
@@ -1015,50 +1118,64 @@ Headers in `gnus-required-headers' will be generated."
     ;; Distribution. 
     (while headers
       (goto-char (point-min))
-      (setq elem (car headers))
+      (setq elem (pop headers))
       (if (consp elem)
          (setq header (car elem))
        (setq header elem))
-      (if (or (not (re-search-forward 
-                   (concat "^" (downcase (symbol-name header)) ":") nil t))
-             (progn
-               ;; The header was found. We insert a space after the
-               ;; colon, if there is none.
-               (if (/= (following-char) ? ) (insert " "))
-               ;; Find out whether the header is empty...
-               (looking-at "[ \t]*$")))
-         ;; So we find out what value we should insert.
-         (progn
-           (setq value 
-                 (or (if (consp elem)
-                         ;; The element is a cons.  Either the cdr is
-                         ;; a string to be inserted verbatim, or it
-                         ;; is a function, and we insert the value
-                         ;; returned from this function.
-                         (or (and (stringp (cdr elem)) (cdr elem))
-                             (and (fboundp (cdr elem)) (funcall (cdr elem))))
-                       ;; The element is a symbol.  We insert the
-                       ;; value of this symbol, if any.
-                       (and (boundp header) (symbol-value header)))
-                     ;; We couldn't generate a value for this header,
-                     ;; so we just ask the user.
-                     (read-from-minibuffer
-                      (format "Empty header for %s; enter value: " header))))
-           ;; Finally insert the header.
-           (save-excursion
-             (if (bolp)
-                 (progn
-                   (goto-char (point-max))
-                   (insert (symbol-name header) ": " value "\n")
-                   (forward-line -1))
-               (replace-match value t t))
-             ;; Add the deletable property to the headers that require it.
-             (and (memq header gnus-deletable-headers)
-                  (progn (beginning-of-line) (looking-at "[^:]+: "))
-                  (add-text-properties 
-                   (point) (match-end 0)
-                   '(gnus-deletable t face italic) (current-buffer))))))
-      (setq headers (cdr headers)))
+      (when (or (not (re-search-forward 
+                     (concat "^" (downcase (symbol-name header)) ":") nil t))
+               (progn
+                 ;; The header was found. We insert a space after the
+                 ;; colon, if there is none.
+                 (if (/= (following-char) ? ) (insert " "))
+                 ;; Find out whether the header is empty...
+                 (looking-at "[ \t]*$")))
+       ;; So we find out what value we should insert.
+       (setq value
+             (cond 
+              ((and (consp elem) (eq (car elem) 'optional))
+               ;; This is an optional header.  If the cdr of this
+               ;; is something that is nil, then we do not insert
+               ;; this header.
+               (setq header (cdr elem))
+               (or (and (fboundp (cdr elem)) (funcall (cdr elem)))
+                   (and (boundp (cdr elem)) (symbol-value (cdr elem)))))
+              ((consp elem)
+               ;; The element is a cons.  Either the cdr is a
+               ;; string to be inserted verbatim, or it is a
+               ;; function, and we insert the value returned from
+               ;; this function.
+               (or (and (stringp (cdr elem)) (cdr elem))
+                   (and (fboundp (cdr elem)) (funcall (cdr elem)))))
+              ((and (boundp header) (symbol-value header))
+               ;; The element is a symbol.  We insert the value
+               ;; of this symbol, if any.
+               (symbol-value header))
+              (t
+               ;; We couldn't generate a value for this header,
+               ;; so we just ask the user.
+               (read-from-minibuffer
+                (format "Empty header for %s; enter value: " header)))))
+       ;; Finally insert the header.
+       (when (and value 
+                  (not (equal value "")))
+         (save-excursion
+           (if (bolp)
+               (progn
+                 ;; This header didn't exist, so we insert it.
+                 (goto-char (point-max))
+                 (insert (symbol-name header) ": " value "\n")
+                 (forward-line -1))
+             ;; 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))
+           ;; Add the deletable property to the headers that require it.
+           (and (memq header gnus-deletable-headers)
+                (progn (beginning-of-line) (looking-at "[^:]+: "))
+                (add-text-properties 
+                 (point) (match-end 0)
+                 '(gnus-deletable t face italic) (current-buffer)))))))
     ;; Insert new Sender if the From is strange. 
     (let ((from (mail-fetch-field "from"))
          (sender (mail-fetch-field "sender")))
@@ -1119,11 +1236,19 @@ nil."
 
 ;; Written by "Mr. Per Persson" <pp@solace.mh.se>.
 (defun gnus-inews-insert-mime-headers ()
-  (let ((mail-header-separator ""))
+  (goto-char (point-min))
+  (let ((mail-header-separator 
+        (progn 
+          (goto-char (point-min))
+          (if (and (search-forward (concat "\n" mail-header-separator "\n")
+                                   nil t)
+                   (not (search-backward "\n\n" nil t)))
+              mail-header-separator
+            ""))))
     (or (mail-position-on-field "Mime-Version")
        (insert "1.0")
-       (cond ((save-excursion
-                (beginning-of-buffer)
+       (cond ((progn
+                (goto-char (point-min))
                 (re-search-forward "[\200-\377]" nil t))
               (or (mail-position-on-field "Content-Type")
                   (insert "text/plain; charset=ISO-8859-1"))
@@ -1135,55 +1260,39 @@ nil."
                     (insert "7bit")))))))
 
 (defun gnus-inews-do-fcc ()
-  "Process FCC: fields in current article buffer.
+  "Process Fcc headers in the current buffer.
 Unless the first character of the field is `|', the article is saved
 to the specified file using the function specified by the variable
 gnus-author-copy-saver.  The default function rmail-output saves in
 Unix mailbox format.
-If the first character is `|', the contents of the article is send to
+
+If the first character is `|', the contents of the article is sent to
 a program specified by the rest of the value."
-  (let ((fcc-list nil)
-       (fcc-file nil)
-       (case-fold-search t))           ;Should ignore case.
+  (let ((case-fold-search t)           ;Should ignore case.
+       list file)
     (save-excursion
       (save-restriction
-       (goto-char (point-min))
-       (search-forward "\n\n")
-       (narrow-to-region (point-min) (point))
-       (goto-char (point-min))
-       (while (re-search-forward "^FCC:[ \t]*" nil t)
-         (setq fcc-list
-               (cons (buffer-substring
-                      (point)
-                      (progn
-                        (end-of-line)
-                        (skip-chars-backward " \t")
-                        (point)))
-                     fcc-list))
-         (delete-region (match-beginning 0)
-                        (progn (forward-line 1) (point))))
+       (gnus-narrow-to-headers)
+       (while (setq file (mail-fetch-field "fcc"))
+         (push file list)
+         (nnheader-remove-header "fcc" nil t))
        ;; Process FCC operations.
        (widen)
-       (while fcc-list
-         (setq fcc-file (car fcc-list))
-         (setq fcc-list (cdr fcc-list))
-         (cond ((string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" fcc-file)
-                (let ((program (substring fcc-file
-                                          (match-beginning 1) (match-end 1))))
-                  ;; Suggested by yuki@flab.fujitsu.junet.
-                  ;; Send article to named program.
-                  (call-process-region (point-min) (point-max) shell-file-name
-                                       nil nil nil "-c" program)))
-               (t
-                ;; Suggested by hyoko@flab.fujitsu.junet.
-                ;; Save article in Unix mail format by default.
-                (gnus-make-directory (file-name-directory fcc-file))
-                (if (and gnus-author-copy-saver
-                         (not (eq gnus-author-copy-saver 'rmail-output)))
-                    (funcall gnus-author-copy-saver fcc-file)
-                  (if (and (file-readable-p fcc-file) (rmail-file-p fcc-file))
-                      (gnus-output-to-rmail fcc-file)
-                    (rmail-output fcc-file 1 t t))))))))))
+       (while list
+         (setq file (pop list))
+         (if (string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" file)
+             ;; Pipe the article to the program in question.
+             (call-process-region (point-min) (point-max) shell-file-name
+                                  nil nil nil "-c" (match-string 1 file))
+           ;; Save the article.
+           (setq file (expand-file-name file))
+           (gnus-make-directory (file-name-directory file))
+           (if (and gnus-author-copy-saver
+                    (not (eq gnus-author-copy-saver 'rmail-output)))
+               (funcall gnus-author-copy-saver file)
+             (if (and (file-readable-p file) (mail-file-babyl-p file))
+                 (gnus-output-to-rmail file)
+               (rmail-output file 1 t t)))))))))
 
 (defun gnus-inews-path ()
   "Return uucp path."
@@ -1241,8 +1350,10 @@ domain is undefined, the domain name is got from it."
                  gnus-local-domain
                  ;; Function `system-name' may return full internet name.
                  ;; Suggested by Mike DeCorte <mrd@sun.soe.clarkson.edu>.
-                 (if (string-match "\\." system-name)
-                     (substring system-name (match-end 0)))
+                 (if (string-match "\\.." system-name)
+                     ;; Some machines return "name.", and that's not
+                     ;; very nice. 
+                     (substring system-name (1- (match-end 0))))
                  (read-string "Domain name (no host): ")))
             (host (or (if (string-match "\\." system-name)
                           (substring system-name 0 (match-beginning 0)))
@@ -1321,8 +1432,7 @@ organization."
   (let* ((organization 
          (or (getenv "ORGANIZATION")
              (if gnus-local-organization
-                 (if (and (symbolp gnus-local-organization)
-                          (fboundp gnus-local-organization))
+                 (if (gnus-functionp gnus-local-organization)
                      (funcall gnus-local-organization gnus-newsgroup-name)
                    gnus-local-organization))
              gnus-organization-file
@@ -1331,7 +1441,7 @@ organization."
         (> (length organization) 0)
         (or (file-exists-p organization)
             (string-match " " organization)
-            (not (string-match "^/usr/lib/" organization)))
+            (not (string-match "^/usr/lib/\\|^~/" organization)))
         (save-excursion
           (gnus-set-work-buffer)
           (if (file-exists-p organization)
@@ -1394,6 +1504,35 @@ Customize the variable gnus-mail-forward-method to use another mailer."
       (gnus-forward-using-post gnus-article-copy)
     (gnus-mail-forward gnus-article-copy)))
 
+(defun gnus-summary-resend-message (address)
+  "Resend the current article to ADDRESS."
+  (interactive "sResend message to: ")
+  (gnus-summary-select-article)
+  (save-excursion
+    (let (resent)
+      ;; We first set up a normal mail buffer.
+      (nnheader-set-temp-buffer " *Gnus resend*")
+      (gnus-mail-setup 'new address)
+      ;; Insert our usual headers.
+      (gnus-inews-narrow-to-headers)
+      (let ((headers '(From Date To Message-ID Organization)))
+       (gnus-inews-insert-headers headers))
+      (goto-char (point-min))
+      ;; Rename them all to "Resent-*".
+      (while (re-search-forward "^" nil t)
+       (insert "Resent-"))
+      (widen)
+      (delete-region (point) (point-max))
+      ;; Insert the message to be resent.
+      (insert-buffer-substring gnus-original-article-buffer)
+      (goto-char (point-min))
+      (search-forward "\n\n")
+      (forward-char -1)
+      (insert mail-header-separator)
+      ;; Send it.
+      (mail-send)
+      (kill-buffer (current-buffer)))))
+
 (defun gnus-summary-post-forward ()
   "Forward the current article to a newsgroup."
   (interactive)
@@ -1422,12 +1561,22 @@ Customize the variable `gnus-mail-other-window-method' to use another
 mailer."
   (interactive)
   (gnus-set-global-variables)
-  (gnus-new-mail))
+  (gnus-new-mail
+   ;; We might want to prompt here.
+   (when (and gnus-interactive-post
+             (not gnus-expert-user))
+     (read-string "To: ")))
+  (gnus-configure-windows 'summary-mail 'force))
 
 (defun gnus-new-mail (&optional to)
-  (pop-to-buffer gnus-mail-buffer)
-  (erase-buffer)
-  (gnus-mail-setup to nil nil nil nil nil))
+  (let (subject)
+    (when (and gnus-interactive-post
+              (not gnus-expert-user))
+      (setq subject (read-string "Subject: ")))
+    (pop-to-buffer gnus-mail-buffer)
+    (erase-buffer)
+    (gnus-mail-setup 'new to subject)
+    (run-hooks 'gnus-mail-hook)))
 
 (defun gnus-mail-reply (&optional yank to-address followup)
   (save-excursion
@@ -1436,7 +1585,8 @@ mailer."
          (cur (cons (current-buffer) (cdr gnus-article-current)))
          (winconf (current-window-configuration))
          from subject date reply-to message-of to cc
-         references message-id sender follow-to sendto elt new-cc)
+         references message-id sender follow-to sendto elt new-cc new-to
+         mct mctdo)
       (set-buffer (get-buffer-create gnus-mail-buffer))
       (mail-mode)
       (if (and (buffer-modified-p)
@@ -1452,24 +1602,17 @@ mailer."
            (gnus-narrow-to-headers)
            (if (not followup)
                ;; This is a regular reply.
-               (if (and (symbolp gnus-reply-to-function)
-                        (fboundp gnus-reply-to-function))
+               (if (gnus-functionp gnus-reply-to-function)
                    (setq follow-to (funcall gnus-reply-to-function group)))
              ;; This is a followup.
-             (if (and (symbolp gnus-followup-to-function)
-                      (fboundp gnus-followup-to-function))
+             (if (gnus-functionp gnus-followup-to-function)
                  (save-excursion
                    (setq follow-to
                          (funcall gnus-followup-to-function group)))))
            (setq from (mail-fetch-field "from"))
            (setq date (or (mail-fetch-field "date") 
                           (mail-header-date gnus-current-headers)))
-           (and from
-                (let ((stop-pos 
-                       (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
-                  (setq message-of
-                        (concat (if stop-pos (substring from 0 stop-pos) from)
-                                "'s message of " date))))
+           (setq message-of (gnus-message-of from date))
            (setq sender (mail-fetch-field "sender"))
            (setq subject (or (mail-fetch-field "subject") "none"))
            ;; Remove any (buggy) Re:'s that are present and make a
@@ -1478,22 +1621,40 @@ mailer."
                 (setq subject (substring subject (match-end 0))))
            (setq subject (concat "Re: " subject))
            (setq to (mail-fetch-field "to"))
-           (setq to (mail-fetch-field "cc"))
+           (setq cc (mail-fetch-field "cc"))
+           (setq mct (mail-fetch-field "mail-copies-to"))
            (setq reply-to (mail-fetch-field "reply-to"))
            (setq references (mail-fetch-field "references"))
            (setq message-id (mail-fetch-field "message-id"))
+           
+           (setq mctdo (not (equal mct "never")))
 
-           (if (not followup)
-               ()
-             ;; When we followup, we want all the headers, I would think.
-             (setq new-cc (rmail-dont-reply-to 
-                           (concat (or to "")
-                                   (if cc (concat (if to ", " "") cc) ""))))
-             (let ((rmail-dont-reply-to-names 
-                    (regexp-quote (mail-strip-quoted-names
-                                   (or to-address reply-to from "")))))
-               (setq new-cc (rmail-dont-reply-to new-cc))))
-
+           (if (not (and followup (not to-address)))
+               (setq new-to (or reply-to from))
+             (let (ccalist)
+               (save-excursion
+                 (gnus-set-work-buffer)
+                 (unless (equal mct "never")
+                   (insert (or reply-to from "")))
+                 (insert (if (bolp) "" ", ")
+                         (or to "")
+                         (if (or (not mct) (not mctdo)) ""
+                           (concat (if (bolp) "" ", ") mct))
+                         (if cc (concat (if (bolp) "" ", ") cc) ""))
+                 (goto-char (point-min))
+                 (setq ccalist
+                       (mapcar
+                        (lambda (addr)
+                          (cons (mail-strip-quoted-names addr) addr))
+                        (nreverse (mail-parse-comma-list))))
+                 (let ((s ccalist))
+                   (while s
+                     (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
+               (setq new-to (cdr (pop ccalist)))
+               (setq new-cc 
+                     (mapconcat 
+                      (lambda (addr) (cdr addr))
+                      ccalist ", "))))
            (widen)))
 
        (setq news-reply-yank-from (or from "(nobody)"))
@@ -1508,12 +1669,13 @@ mailer."
              (setq follow-to (delq elt follow-to))))
 
        (gnus-mail-setup 
+        (if followup 'followup 'reply)
         (or to-address 
             (if (and follow-to (not (stringp follow-to))) sendto
-              (or follow-to reply-to from sender "")))
-        subject nil
+              (or follow-to new-to sender "")))
+        subject message-of
         (if (zerop (length new-cc)) nil new-cc)
-        gnus-article-copy nil)
+        gnus-article-copy)
 
        (make-local-variable 'gnus-article-reply)
        (setq gnus-article-reply cur)
@@ -1525,7 +1687,6 @@ mailer."
        (setq gnus-in-reply-to message-of)
 
        (auto-save-mode auto-save-default)
-       (gnus-inews-modify-mail-mode-map)
 
        (if (and follow-to (listp follow-to))
            (progn
@@ -1549,6 +1710,7 @@ mailer."
                end)
            (if (not (listp yank))
                (progn
+                 ;; Just a single article being yanked.
                  (save-excursion
                    (mail-yank-original nil))
                  (or mail-yank-hooks mail-citation-hook
@@ -1561,29 +1723,63 @@ mailer."
                (save-excursion
                  (gnus-copy-article-buffer)
                  (mail-yank-original nil)
-                 (setq end (point)))
-               (or mail-yank-hooks mail-citation-hook
-                   (run-hooks 'news-reply-header-hook))
+                 (save-restriction
+                   (narrow-to-region (point-min) (point))
+                   (goto-char (mark))
+                   (let ((news-reply-yank-from
+                          (save-excursion 
+                            (set-buffer gnus-article-buffer)
+                            (or (mail-fetch-field "from") "(nobody)")))
+                         (news-reply-yank-message-id
+                          (save-excursion 
+                            (set-buffer gnus-article-buffer)
+                            (or (mail-fetch-field "message-id")
+                                "(unknown Message-ID)"))))
+                     (or mail-yank-hooks mail-citation-hook
+                         (run-hooks 'news-reply-header-hook))
+                     (setq end (point-max)))))
                (goto-char end)
                (setq yank (cdr yank))))
            (goto-char last))
+         (forward-line 2)
          (gnus-configure-windows 'reply-yank 'force))
        (run-hooks 'gnus-mail-hook)))))
 
-(defun gnus-new-news (&optional group)
-  (let (subject)
-    (and gnus-interactive-post
-        (not gnus-expert-user)
-        (not group)
-        (progn
-          (setq gnus-newsgroup-name
-                (setq group 
-                      (completing-read "Group: " gnus-active-hashtb)))
-          (setq subject (read-string "Subject: "))))
-    (pop-to-buffer "*post-news*")  
+(defun gnus-new-news (&optional group inhibit-prompt)
+  "Set up a *post-news* buffer that points to GROUP.
+If INHIBIT-PROMPT, never prompt for a Subject."
+  (let ((winconf (current-window-configuration))
+       subject)
+    (when (and gnus-interactive-post
+              (not inhibit-prompt)
+              (not gnus-expert-user))
+      (setq subject (read-string "Subject: ")))
+    (pop-to-buffer gnus-post-news-buffer)  
     (erase-buffer)
     (news-reply-mode)
-    (news-setup nil subject nil group nil)
+    ;; Let posting styles be configured.
+    (gnus-configure-posting-styles)
+    (news-setup nil subject nil (and group (gnus-group-real-name group)) nil)
+    (goto-char (point-min))
+
+    (unless (re-search-forward 
+            (concat "^" (regexp-quote mail-header-separator) "$") nil t)
+      (goto-char (point-max)))
+    (insert "\n\n")
+
+    (gnus-inews-insert-bfcc)
+    (gnus-inews-insert-signature)
+    (and gnus-post-prepare-function
+        (gnus-functionp gnus-post-prepare-function)
+        (funcall gnus-post-prepare-function group))
+    (goto-char (point-min))
+    (if group
+       (re-search-forward "^Subject: " nil t)
+      (re-search-forward "^Newsgroups: " nil t))
+    (run-hooks 'gnus-post-prepare-hook)
+    (make-local-variable 'gnus-prev-winconf)
+    (setq gnus-prev-winconf winconf)
+    (gnus-inews-modify-mail-mode-map)
     (local-set-key "\C-c\C-c" 'gnus-inews-news)))
 
 (defun gnus-news-followup (&optional yank group)
@@ -1599,8 +1795,8 @@ mailer."
            (winconf (current-window-configuration))
            from subject date reply-to message-of
            references message-id sender follow-to sendto elt 
-           followup-to distribution)
-       (set-buffer (get-buffer-create gnus-mail-buffer))
+           followup-to distribution newsgroups)
+       (set-buffer (get-buffer-create gnus-post-news-buffer))
        (news-reply-mode)
        (if (and (buffer-modified-p)
                 (> (buffer-size) 0)
@@ -1613,21 +1809,14 @@ mailer."
            (save-restriction
              (set-buffer gnus-article-copy)
              (gnus-narrow-to-headers)
-             (if (and (symbolp gnus-followup-to-function)
-                      (fboundp gnus-followup-to-function))
+             (if (gnus-functionp gnus-followup-to-function)
                  (save-excursion
                    (setq follow-to
                          (funcall gnus-followup-to-function group))))
              (setq from (mail-fetch-field "from"))
              (setq date (or (mail-fetch-field "date") 
                             (mail-header-date gnus-current-headers)))
-             (and from
-                  (let ((stop-pos 
-                         (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
-                    (setq message-of
-                          (concat 
-                           (if stop-pos (substring from 0 stop-pos) from)
-                           "'s message of " date))))
+             (setq message-of (gnus-message-of from date))
              (setq subject (or (mail-fetch-field "subject") "none"))
              ;; Remove any (buggy) Re:'s that are present and make a
              ;; proper one.
@@ -1637,6 +1826,7 @@ mailer."
              (setq references (mail-fetch-field "references"))
              (setq message-id (mail-fetch-field "message-id"))
              (setq followup-to (mail-fetch-field "followup-to"))
+             (setq newsgroups (mail-fetch-field "newsgroups"))
              (setq distribution (mail-fetch-field "distribution"))
              ;; Remove bogus distribution.
              (and (stringp distribution)
@@ -1655,15 +1845,19 @@ mailer."
                (setq sendto (concat sendto (and sendto ", ") (cdr elt)))
                (setq follow-to (delq elt follow-to))))
 
+         ;; Let posting styles be configured.
+         (gnus-configure-posting-styles)
+
          (news-setup nil subject nil 
-                     (or group sendto 
-                         (and follow-to
+                     (or sendto 
+                         (and followup-to
                               gnus-use-followup-to
                               (or (not (eq gnus-use-followup-to 'ask))
                                   (gnus-y-or-n-p 
                                    (format
-                                    "Use Followup-To %s? " follow-to))))
-                         group "")
+                                    "Use Followup-To %s? " followup-to)))
+                              followup-to)
+                         newsgroups group "")
                      gnus-article-copy)
 
          (make-local-variable 'gnus-article-reply)
@@ -1675,6 +1869,12 @@ mailer."
          (make-local-variable 'gnus-in-reply-to)
          (setq gnus-in-reply-to message-of)
 
+         (gnus-inews-insert-signature)
+
+         (and gnus-post-prepare-function
+              (gnus-functionp gnus-post-prepare-function)
+              (funcall gnus-post-prepare-function group))
+         (run-hooks 'gnus-post-prepare-hook)
 
          (auto-save-mode auto-save-default)
          (gnus-inews-modify-mail-mode-map)
@@ -1707,7 +1907,18 @@ mailer."
                        (or (save-excursion
                              (set-buffer gnus-article-copy)
                              (gnus-fetch-field "reply-to"))
-                           from))))
+                           from)))
+               (x-mail (save-excursion
+                         (set-buffer gnus-article-copy)
+                         (gnus-fetch-field "x-mail-copy-to"))))
+           ;; Deny sending copy if there's a negative X-Mail-Copy-To
+           ;; header. 
+           (if x-mail
+               (if (and (string= x-mail "never")
+                        (not (eq gnus-auto-mail-to-author 'force)))
+                   (setq to nil)
+                 (setq to x-mail)))
+           ;; Insert a To or Cc header.
            (if to
                (if (mail-fetch-field "To")
                    (progn
@@ -1716,27 +1927,18 @@ mailer."
                  (mail-position-on-field "To")
                  (insert to))))
 
-         ;; Handle author copy using BCC field.
-         (if (and gnus-mail-self-blind
-                  (not (mail-fetch-field "bcc")))
-             (progn
-               (mail-position-on-field "Bcc")
-               (insert (if (stringp gnus-mail-self-blind)
-                           gnus-mail-self-blind
-                         (user-login-name)))))
-         ;; Handle author copy using FCC field.
-         (if gnus-author-copy
-             (progn
-               (mail-position-on-field "Fcc")
-               (insert gnus-author-copy)))
-       
+         (gnus-inews-insert-bfcc)
+
          ;; Now the headers should be ok, so we do the yanking.
          (goto-char (point-min))
          (re-search-forward
           (concat "^" (regexp-quote mail-header-separator) "$"))
          (forward-line 1)
          (if (not yank)
-             (gnus-configure-windows 'reply 'force)
+             (progn
+               (gnus-configure-windows 'followup 'force)
+               (insert "\n\n")
+               (forward-line -2))
            (let ((last (point))
                  end)
              (if (not (listp yank))
@@ -1759,12 +1961,25 @@ mailer."
                  (goto-char end)
                  (setq yank (cdr yank))))
              (goto-char last))
-           (gnus-configure-windows 'reply-yank 'force))
+           (gnus-configure-windows 'followup-yank 'force))
        
          (make-local-variable 'gnus-article-check-size)
          (setq gnus-article-check-size
                (cons (buffer-size) (gnus-article-checksum))))))))
 
+(defun gnus-message-of (from date)
+  "Take a FROM and a DATE and create an IN-REPLY-TO."
+  (cond 
+   ((not from)
+    nil)
+   (t
+    (let ((stop-pos 
+          (string-match "  *at \\|  *@ \\| *(\\| *<" from)))
+      (concat (if stop-pos (substring from 0 stop-pos) from)
+             "'s message of " 
+             (if (or (not date) (string= date ""))
+                 "(unknown date)" date))))))
+
 (defun gnus-mail-yank-original ()
   (interactive)
   (save-excursion
@@ -1836,7 +2051,6 @@ mailer."
                      (cdr reply)))))
          (and winconf (set-window-configuration winconf))))))
 
-
 (defun gnus-forward-make-subject (buffer)
   (save-excursion
     (set-buffer buffer)
@@ -1849,38 +2063,52 @@ mailer."
            "] " (or (gnus-fetch-field "Subject") ""))))
 
 (defun gnus-forward-insert-buffer (buffer)
-  (let ((beg (goto-char (point-max))))
-    (insert "------- Start of forwarded message -------\n")
-    (insert-buffer buffer)
-    (goto-char (point-max))
-    (insert "------- End of forwarded message -------\n")
-    ;; Suggested by Sudish Joseph <joseph@cis.ohio-state.edu>. 
-    (goto-char beg)
-    (while (setq beg (next-single-property-change (point) 'invisible))
-      (goto-char beg)
-      (delete-region beg (or (next-single-property-change 
-                             (point) 'invisible)
-                            (point-max))))))
+  (save-excursion
+    (save-restriction
+      (if gnus-signature-before-forwarded-message
+         (goto-char (point-max))
+       (goto-char (point-min))
+       (re-search-forward
+        (concat "^" (regexp-quote mail-header-separator) "$"))
+       (forward-line 1))
+      ;; Narrow to the area we are to insert.
+      (narrow-to-region (point) (point))
+      ;; Insert the separators and the forwarded buffer.
+      (insert gnus-forward-start-separator)
+      (insert-buffer-substring buffer)
+      (goto-char (point-max))
+      (insert gnus-forward-end-separator)
+      ;; Delete any invisible text.
+      (goto-char (point-min))
+      (let (beg)
+       (while (setq beg (next-single-property-change (point) 'invisible))
+         (goto-char beg)
+         (delete-region beg (or (next-single-property-change 
+                                 (point) 'invisible)
+                                (point-max))))))))
 
 (defun gnus-mail-forward (&optional buffer)
   "Forward the current message to another user using mail."
-  ;; This is almost a carbon copy of rmail-forward in rmail.el.
   (let* ((forward-buffer (or buffer (current-buffer)))
         (winconf (current-window-configuration))
         (subject (gnus-forward-make-subject forward-buffer)))
-    (set-buffer forward-buffer)
-    (gnus-mail-setup nil subject nil nil nil nil 'forward)
-    (mail nil nil subject)
-    (gnus-inews-modify-mail-mode-map)
-    (make-local-variable 'gnus-prev-winconf)
-    (setq gnus-prev-winconf winconf)
-    (gnus-forward-insert-buffer forward-buffer)
-    (goto-char (point-min))
-    (re-search-forward "^To: " nil t)
-    (gnus-configure-windows 'mail-forward 'force)
-    ;; You have a chance to arrange the message.
-    (run-hooks 'gnus-mail-forward-hook)
-    (run-hooks 'gnus-mail-hook)))
+    (set-buffer (get-buffer-create gnus-mail-buffer))
+    (if (and (buffer-modified-p)
+            (> (buffer-size) 0)
+            (not (gnus-y-or-n-p 
+                  "Unsent message being composed; erase it? ")))
+       ()
+      (erase-buffer)
+      (gnus-mail-setup 'forward nil subject)
+      (make-local-variable 'gnus-prev-winconf)
+      (setq gnus-prev-winconf winconf)
+      (gnus-forward-insert-buffer forward-buffer)
+      (goto-char (point-min))
+      (re-search-forward "^To: ?" nil t)
+      (gnus-configure-windows 'mail-forward 'force)
+      ;; You have a chance to arrange the message.
+      (run-hooks 'gnus-mail-forward-hook)
+      (run-hooks 'gnus-mail-hook))))
 
 (defun gnus-forward-using-post (&optional buffer)
   (save-excursion
@@ -2027,7 +2255,7 @@ this is a reply."
   ;; Create a mail buffer.
   (gnus-new-mail)
   (erase-buffer)
-  (insert-buffer gnus-article-buffer)
+  (insert-buffer-substring gnus-article-buffer)
   (goto-char (point-min))
   (search-forward "\n\n")
   ;; We remove everything before the bounced mail.
@@ -2065,7 +2293,8 @@ Headers will be generated before sending."
     (save-restriction
       (widen)
       (gnus-inews-narrow-to-headers)
-      (gnus-inews-insert-headers gnus-required-mail-headers)))
+      (gnus-inews-insert-headers gnus-required-mail-headers)
+      (gnus-inews-remove-empty-headers)))
   (widen)
   ;; Remove the header separator.
   (goto-char (point-min))
@@ -2091,12 +2320,14 @@ Headers will be generated before sending."
   (local-set-key "\C-c\C-p" 'gnus-put-message)
   (local-set-key "\C-c\C-d" 'gnus-enter-into-draft-group))
 
-(defun gnus-mail-setup (to subject in-reply-to cc replybuffer actions
-                          &optional type)
+(defun gnus-mail-setup (type &optional to subject in-reply-to cc
+                            replybuffer actions)
+  ;; Let posting styles be configured.
+  (gnus-configure-posting-styles)
   (funcall
    (cond
     ((or 
-      (and (eq type 'reply) 
+      (and (or (eq type 'reply) (eq type 'followup))
           (eq gnus-mail-reply-method 'gnus-mail-reply-using-mhe))
       (and (eq type 'forward)
           (eq gnus-mail-forward-method 'gnus-mail-forward-using-mhe))
@@ -2105,7 +2336,7 @@ Headers will be generated before sending."
               'gnus-mail-other-window-using-mhe)))
      'gnus-mh-mail-setup)
     ((or 
-      (and (eq type 'reply
+      (and (or (eq type 'reply) (eq type 'followup)
           (eq gnus-mail-reply-method 'gnus-mail-reply-using-vm))
       (and (eq type 'forward)
           (eq gnus-mail-forward-method 'gnus-mail-forward-using-vm))
@@ -2118,7 +2349,14 @@ Headers will be generated before sending."
 
 (defun gnus-sendmail-mail-setup (to subject in-reply-to cc replybuffer actions)
   (mail-mode)
-  (mail-setup to subject in-reply-to cc replybuffer actions))
+  (mail-setup to subject nil cc replybuffer actions)
+  (goto-char (point-min))
+  (if (re-search-forward 
+       (concat "^" (regexp-quote mail-header-separator) "$") nil t)
+      (forward-line 1)
+    (goto-char (point-max)))
+;  (insert "\n\n")
+  (gnus-inews-modify-mail-mode-map))
   
 ;;; Gcc handling.
 
@@ -2142,15 +2380,29 @@ Headers will be generated before sending."
              (error nil))
            (setq gcc (substring gcc end))))))))
 
+(defun gnus-inews-insert-bfcc ()
+  "Insert Bcc and Fcc headers."
+  (save-excursion
+    ;; Handle author copy using BCC field.
+    (when (and gnus-mail-self-blind
+              (not (mail-fetch-field "bcc")))
+      (mail-position-on-field "Bcc")
+      (insert (if (stringp gnus-mail-self-blind)
+                 gnus-mail-self-blind
+               (user-login-name))))
+    ;; Handle author copy using FCC field.
+    (when gnus-author-copy
+      (mail-position-on-field "Fcc")
+      (insert gnus-author-copy))))
+
 (defun gnus-inews-insert-gcc ()
   (let* ((group gnus-outgoing-message-group)
         (gcc (cond 
-              ((and (symbolp group) (fboundp group))
+              ((gnus-functionp group)
                (funcall group))
               ((or (stringp group) (list group))
                group))))
-    (if (not gcc)
-       () ; Insert no Gcc.
+    (when gcc
       (insert "Gcc: "
              (if (stringp group) group
                (mapconcat 'identity group " "))
@@ -2191,7 +2443,7 @@ Headers will be generated before sending."
     (widen)
     (save-excursion
       (nnheader-set-temp-buffer " *enter-draft*")
-      (insert-buffer buf)
+      (insert-buffer-substring buf)
       (save-restriction
        (widen)
        (gnus-inews-narrow-to-headers)
@@ -2251,10 +2503,10 @@ Headers will be generated before sending."
           (`
            (lambda ()
              (gnus-request-expire-articles 
-              (, (list (cdr gnus-article-current)))
+              (quote (, (list (cdr gnus-article-current))))
               (, gnus-newsgroup-name) t)))))
     ;; Insert the draft.
-    (insert-buffer gnus-article-buffer)
+    (insert-buffer-substring gnus-article-buffer)
     ;; Insert the separator.
     (goto-char (point-min))
     (search-forward "\n\n")
@@ -2270,6 +2522,64 @@ Headers will be generated before sending."
     ;; Put point where you left it.
     (goto-char (nth 3 type))))
   
+(defun gnus-configure-posting-styles ()
+  "Configure posting styles according to `gnus-posting-styles'."
+  (let ((styles gnus-posting-styles)
+       (gnus-newsgroup-name (or gnus-newsgroup-name ""))
+       style match variable attribute value value-value)
+    ;; Go through all styles and look for matches.
+    (while styles
+      (setq style (pop styles)
+           match (pop style))
+      (when (cond ((stringp match)
+                  ;; Regexp string match on the group name.
+                  (string-match match gnus-newsgroup-name))
+                 ((or (symbolp match)
+                      (gnus-functionp match))
+                  (cond ((gnus-functionp match)
+                         ;; Function to be called.
+                         (funcall match))
+                        ((boundp match)
+                         ;; Variable to be checked.
+                         (symbol-value match))))
+                 ((listp match)
+                  ;; This is a form to be evaled.
+                  (eval match)))
+       ;; We have a match, so we set the variables.
+       (while style
+         (setq attribute (pop style)
+               value (cdr attribute))
+         ;; We find the variable that is to be modified.
+         (if (and (not (stringp (car attribute)))
+                  (not (setq variable (cdr (assq (car attribute) 
+                                                 gnus-posting-style-alist)))))
+             (message "Couldn't find attribute %s" (car attribute))
+           ;; We set the variable.
+           (setq value-value
+                 (cond ((stringp value)
+                        value)
+                       ((or (symbolp value)
+                            (gnus-functionp value))
+                        (cond ((gnus-functionp value)
+                               (funcall value))
+                              ((boundp value)
+                               (symbol-value value))))
+                       ((listp value)
+                        (eval value))))
+           (if variable
+               (progn
+                 ;; This is an ordinary variable.
+                 (make-local-variable variable)
+                 (set variable value-value))
+             ;; This is a header to be added to the headers when
+             ;; posting. 
+             (when value-value
+               (make-local-variable gnus-required-headers)
+               (make-local-variable gnus-required-mail-headers)
+               (push (cons (car attribute) value-value) 
+                     gnus-required-headers)
+               (push (cons (car attribute) value-value) 
+                     gnus-required-mail-headers)))))))))
 
 ;;; Allow redefinition of functions.