T-gnus 6.15.18 revision 00.
[elisp/gnus.git-] / lisp / gnus-msg.el
index bcfedf6..3f3eca3 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-msg.el --- mail and post interface for Semi-gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -38,6 +38,7 @@
 (require 'gnus-ems)
 (require 'message)
 (require 'gnus-art)
+(require 'gnus-util)
 
 (defcustom gnus-post-method 'current
   "*Preferred method for posting USENET news.
@@ -74,12 +75,13 @@ of names)."
                 (function)))
 
 (defcustom gnus-mailing-list-groups nil
-  "*Regexp matching groups that are really mailing lists.
+  "*If non-nil a 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."
   :group 'gnus-message
-  :type 'regexp)
+  :type '(choice (regexp)
+                (const nil)))
 
 (defcustom gnus-add-to-list nil
   "*If non-nil, add a `to-list' parameter automatically."
@@ -120,6 +122,7 @@ the second with the current group name."
   "*Alist of styles to use when posting.
 See Info node `(gnus)Posting Styles'."
   :group 'gnus-message
+  :link '(custom-manual "(gnus)Posting Styles")
   :type '(repeat (cons (choice (regexp)
                               (variable)
                               (list (const header)
@@ -135,6 +138,27 @@ See Info node `(gnus)Posting Styles'."
                                        (const x-face-file)
                                        (const name)
                                        (const body)
+                                       (const import)
+                                       (symbol)
+                                       (string :tag "Header"))
+                               (choice (string)
+                                       (function)
+                                       (variable)
+                                       (sexp)))))))
+
+(defcustom gnus-named-posting-styles nil
+  "Alist mapping names to the user-defined posting styles."
+  :group 'gnus-message
+  :type '(repeat (cons string
+                      (repeat (list
+                               (choice (const signature)
+                                       (const signature-file)
+                                       (const organization)
+                                       (const address)
+                                       (const x-face-file)
+                                       (const name)
+                                       (const body)
+                                       (const import)
                                        (symbol)
                                        (string :tag "Header"))
                                (choice (string)
@@ -158,19 +182,26 @@ See Info node `(gnus)Posting Styles'."
   "Should local-file attachments be included as external parts in Gcc copies?
 If it is `all', attach files as external parts;
 if a regexp and matches the Gcc group name, attach files as external parts;
-If nil, attach files as normal parts."
+if nil, attach files as normal parts."
   :version "21.1"
   :group 'gnus-message
   :type '(choice (const nil :tag "None")
                 (const all :tag "Any")
                 (string :tag "Regexp")))
 
-(defcustom gnus-group-posting-charset-alist
-  '(("^\\(no\\|fr\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
-    ("^\\(fido7\\|relcom\\)\\.[^,]*\\(,[ \t\n]*\\(fido7\\|relcom\\)\\.[^,]*\\)*$" koi8-r (koi8-r))
-    (message-this-is-mail nil nil)
-    (message-this-is-news nil t))
-  "Alist of regexps and permitted unencoded charsets for posting.
+(gnus-define-group-parameter
+ posting-charset-alist
+ :type list
+ :function-document
+ "Return the permitted unencoded charsets for posting of GROUP."
+ :variable gnus-group-posting-charset-alist
+ :variable-default
+ '(("^\\(no\\|fr\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
+   ("^\\(fido7\\|relcom\\)\\.[^,]*\\(,[ \t\n]*\\(fido7\\|relcom\\)\\.[^,]*\\)*$" koi8-r (koi8-r))
+   (message-this-is-mail nil nil)
+   (message-this-is-news nil t))
+ :variable-document
+ "Alist of regexps and permitted unencoded charsets for posting.
 Each element of the alist has the form (TEST HEADER BODY-LIST), where
 TEST is either a regular expression matching the newsgroup header or a
 variable to query,
@@ -182,22 +213,26 @@ nil (always encode using quoted-printable) or t (always use 8bit).
 
 Note that any value other than nil for HEADER infringes some RFCs, so
 use this option with care."
-  :type '(repeat (list :tag "Permitted unencoded charsets"
-                      (choice :tag "Where"
-                              (regexp :tag "Group")
-                              (const :tag "Mail message"
-                                     :value message-this-is-mail)
-                              (const :tag "News article"
-                                     :value message-this-is-news))
-                      (choice :tag "Header"
-                              (const :tag "None" nil)
-                              (symbol :tag "Charset"))
-                      (choice :tag "Body"
-                              (const :tag "Any" :value t)
-                              (const :tag "None" :value nil)
-                              (repeat :tag "Charsets"
-                                      (symbol :tag "Charset")))))
-  :group 'gnus-charset)
+ :variable-group gnus-charset
+ :variable-type
+ '(repeat (list :tag "Permitted unencoded charsets"
+               (choice :tag "Where"
+                       (regexp :tag "Group")
+                       (const :tag "Mail message" :value message-this-is-mail)
+                       (const :tag "News article" :value message-this-is-news))
+               (choice :tag "Header"
+                       (const :tag "None" nil)
+                       (symbol :tag "Charset"))
+               (choice :tag "Body"
+                       (const :tag "Any" :value t)
+                       (const :tag "None" :value nil)
+                       (repeat :tag "Charsets"
+                               (symbol :tag "Charset")))))
+ :parameter-type '(choice :tag "Permitted unencoded charsets"
+                         :value nil
+                         (repeat (symbol)))
+ :parameter-document       "\
+List of charsets that are permitted to be unencoded.")
 
 (defcustom gnus-debug-files
   '("gnus.el" "gnus-sum.el" "gnus-group.el"
@@ -228,29 +263,78 @@ This variable is used only when `gnus-post-method' is `current'."
 
 (defcustom gnus-message-replysign
   nil
-  "Automatically sign replys to signed messages.
+  "Automatically sign replies to signed messages.
 See also the `mml-default-sign-method' variable."
   :group 'gnus-message
   :type 'boolean)
 
 (defcustom gnus-message-replyencrypt
   nil
-  "Automatically encrypt replys to encrypted messages.
+  "Automatically encrypt replies to encrypted messages.
 See also the `mml-default-encrypt-method' variable."
   :group 'gnus-message
   :type 'boolean)
 
 (defcustom gnus-message-replysignencrypted
-  nil
+  t
   "Setting this causes automatically encryped messages to also be signed."
   :group 'gnus-message
   :type 'boolean)
 
+(defcustom gnus-confirm-mail-reply-to-news nil
+  "If non-nil, Gnus requests confirmation when replying to news.
+This is done because new users often reply by mistake when reading
+news.
+This can also be a function receiving the group name as the only
+parameter which should return non-nil iff a confirmation is needed, or
+a regexp, in which case a confirmation is asked for iff the group name
+matches the regexp."
+  :group 'gnus-message
+  :type '(choice (const :tag "No" nil)
+                (const :tag "Yes" t)
+                (regexp :tag "Iff group matches regexp")
+                (function :tag "Iff function evaluates to non-nil")))
+
+(defcustom gnus-confirm-treat-mail-like-news
+  nil
+  "If non-nil, Gnus will treat mail like news with regard to confirmation
+when replying by mail.  See the `gnus-confirm-mail-reply-to-news' variable
+for fine-tuning this.
+If nil, Gnus will never ask for confirmation if replying to mail."
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-summary-resend-default-address t
+  "If non-nil, Gnus tries to suggest a default address to resend to.
+If nil, the address field will always be empty after invoking
+`gnus-summary-resend-message'."
+  :group 'gnus-message
+  :type 'boolean)
+
+(defcustom gnus-user-agent 'emacs-gnus-type
+  "Which information should be exposed in the User-Agent header.
+
+It can be one of the symbols `gnus' \(show only Gnus version\), `emacs-gnus'
+\(show only Emacs and Gnus versions\), `emacs-gnus-config' \(same as
+`emacs-gnus' plus system configuration\), `emacs-gnus-type' \(same as
+`emacs-gnus' plus system type\) or a custom string.  If you set it to a
+string, be sure to use a valid format, see RFC 2616."
+  :group 'gnus-message
+  :type '(choice
+         (item :tag "Show Gnus and Emacs versions and system type"
+               emacs-gnus-type)
+         (item :tag "Show Gnus and Emacs versions and system configuration"
+               emacs-gnus-config)
+         (item :tag "Show Gnus and Emacs versions" emacs-gnus)
+         (item :tag "Show only Gnus version" gnus)
+         (string :tag "Other")))
+
 ;;; Internal variables.
 
 (defvar gnus-inhibit-posting-styles nil
   "Inhibit the use of posting styles.")
 
+(defvar gnus-article-yanked-articles nil)
 (defvar gnus-message-buffer "*Mail Gnus*")
 (defvar gnus-article-copy nil)
 (defvar gnus-check-before-posting nil)
@@ -326,7 +410,8 @@ Thank you for your help in stamping out bugs.
   "om" gnus-summary-mail-forward
   "op" gnus-summary-post-forward
   "Om" gnus-summary-digest-mail-forward
-  "Op" gnus-summary-digest-post-forward)
+  "Op" gnus-summary-digest-post-forward
+  "P" gnus-summary-execute-command-with-posting-style)
 
 (gnus-define-keys (gnus-send-bounce-map "D" gnus-summary-send-map)
   "b" gnus-summary-resend-bounced-mail
@@ -336,15 +421,22 @@ Thank you for your help in stamping out bugs.
 
 ;;; Internal functions.
 
+(defun gnus-inews-make-draft ()
+  `(lambda ()
+     (gnus-inews-make-draft-meta-information
+      ,gnus-newsgroup-name ',gnus-article-reply)))
+
 (defvar gnus-article-reply nil)
 (defmacro gnus-setup-message (config &rest forms)
   (let ((winconf (make-symbol "gnus-setup-message-winconf"))
        (buffer (make-symbol "gnus-setup-message-buffer"))
        (article (make-symbol "gnus-setup-message-article"))
+       (yanked (make-symbol "gnus-setup-yanked-articles"))
        (group (make-symbol "gnus-setup-message-group")))
     `(let ((,winconf (current-window-configuration))
           (,buffer (buffer-name (current-buffer)))
           (,article gnus-article-reply)
+          (,yanked gnus-article-yanked-articles)
           (,group gnus-newsgroup-name)
           (message-header-setup-hook
            (copy-sequence message-header-setup-hook))
@@ -365,34 +457,38 @@ Thank you for your help in stamping out bugs.
        (add-hook 'message-mode-hook
                 (lambda ()
                   (gnus-configure-posting-styles ,group)))
+       (gnus-pull ',(intern gnus-draft-meta-information-header)
+                 message-required-headers)
+       (when (and ,group
+                 (not (string= ,group "")))
+        (push (cons
+               (intern gnus-draft-meta-information-header)
+               (gnus-inews-make-draft))
+              message-required-headers))
        (unwind-protect
           (progn
             ,@forms)
-        (gnus-inews-add-send-actions ,winconf ,buffer ,article ,config)
-        (gnus-inews-insert-draft-meta-information ,group ,article)
+        (gnus-inews-add-send-actions ,winconf ,buffer ,article ,config
+                                     ,yanked)
         (setq gnus-message-buffer (current-buffer))
         (set (make-local-variable 'gnus-message-group-art)
              (cons ,group ,article))
         (set (make-local-variable 'gnus-newsgroup-name) ,group)
         (gnus-maybe-setup-default-charset)
         (gnus-run-hooks 'gnus-message-setup-hook))
+       (message-hide-headers)
        (gnus-add-buffer)
        (gnus-configure-windows ,config t)
        (run-hooks 'post-command-hook)
        (set-buffer-modified-p nil))))
 
-(defun gnus-inews-insert-draft-meta-information (group article)
-  (save-excursion
-    (when (and group
-              (not (string= group ""))
-              (not (message-fetch-field gnus-draft-meta-information-header)))
-      (goto-char (point-min))
-      (insert gnus-draft-meta-information-header ": (\"" group "\" "
-             (if article (number-to-string
-                          (if (listp article)
-                              (car article)
-                            article)) "\"\"")
-             ")\n"))))
+(defun gnus-inews-make-draft-meta-information (group article)
+  (concat "(\"" group "\" "
+         (if article (number-to-string
+                      (if (listp article)
+                          (car article)
+                        article)) "\"\"")
+         ")"))
 
 ;;;###autoload
 (defun gnus-msg-mail (&optional to subject other-headers continue
@@ -455,7 +551,8 @@ Gcc: header for archiving purposes."
                         (symbol-value (car elem))))
            (throw 'found (cons (cadr elem) (caddr elem)))))))))
 
-(defun gnus-inews-add-send-actions (winconf buffer article &optional config)
+(defun gnus-inews-add-send-actions (winconf buffer article
+                                           &optional config yanked)
   (make-local-hook 'message-sent-hook)
   (add-hook 'message-sent-hook (if gnus-agent 'gnus-agent-possibly-do-gcc
                                 'gnus-inews-do-gcc) nil t)
@@ -466,18 +563,24 @@ Gcc: header for archiving purposes."
        `(lambda (arg)
           (gnus-post-method arg ,gnus-newsgroup-name)))
   (setq message-user-agent (gnus-extended-version))
-  (when (not message-use-multi-frames)
+  (unless message-use-multi-frames
     (message-add-action
-     `(set-window-configuration ,winconf) 'exit 'postpone 'kill))
-  (message-add-action
-   `(when (gnus-buffer-exists-p ,buffer)
-      (save-excursion
-       (set-buffer ,buffer)
-       ,(when article
-          (if (eq config 'forward)
-              `(gnus-summary-mark-article-as-forwarded ',article)
-            `(gnus-summary-mark-article-as-replied ',article)))))
-   'send))
+     `(if (gnus-buffer-exists-p ,buffer)
+         (set-window-configuration ,winconf))
+     'exit 'postpone 'kill))
+  (let ((to-be-marked (cond
+                      (yanked yanked)
+                      (article (if (listp article) article (list article)))
+                      (t nil))))
+    (message-add-action
+     `(when (gnus-buffer-exists-p ,buffer)
+       (save-excursion
+         (set-buffer ,buffer)
+         ,(when to-be-marked
+            (if (eq config 'forward)
+                `(gnus-summary-mark-article-as-forwarded ',to-be-marked)
+              `(gnus-summary-mark-article-as-replied ',to-be-marked)))))
+     'send)))
 
 (put 'gnus-setup-message 'lisp-indent-function 1)
 (put 'gnus-setup-message 'edebug-form-spec '(form body))
@@ -492,6 +595,8 @@ If ARG is 1, prompt for a group name to find the posting style."
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
   (let ((group gnus-newsgroup-name)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
        (buffer (current-buffer)))
     (unwind-protect
        (progn
@@ -521,6 +626,8 @@ network.  The corresponding backend must have a 'request-post method."
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
   (let ((group gnus-newsgroup-name)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
        (buffer (current-buffer)))
     (unwind-protect
        (progn
@@ -552,8 +659,11 @@ a news."
                 (completing-read "Newsgroup: " gnus-active-hashtb nil
                                  (gnus-read-active-file-p))
               (gnus-group-group-name))
-          "")))
-    (gnus-post-news 'post gnus-newsgroup-name)))
+          ""))
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy))
+    (gnus-post-news 'post gnus-newsgroup-name nil nil nil nil
+                   (string= gnus-newsgroup-name ""))))
 
 (defun gnus-summary-mail-other-window (&optional arg)
   "Start composing a mail in another window.
@@ -564,6 +674,8 @@ posting style."
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
   (let ((group gnus-newsgroup-name)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
        (buffer (current-buffer)))
     (unwind-protect
        (progn
@@ -593,6 +705,8 @@ network.  The corresponding backend must have a 'request-post method."
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
   (let ((group gnus-newsgroup-name)
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy)
        (buffer (current-buffer)))
     (unwind-protect
        (progn
@@ -624,7 +738,9 @@ a news."
                 (completing-read "Newsgroup: " gnus-active-hashtb nil
                                  (gnus-read-active-file-p))
               "")
-          gnus-newsgroup-name)))
+          gnus-newsgroup-name))
+       ;; make sure last viewed article doesn't affect posting styles:
+       (gnus-article-copy))
     (gnus-post-news 'post gnus-newsgroup-name)))
 
 
@@ -650,7 +766,8 @@ yanked."
     ;; Send a followup.
     (gnus-post-news nil gnus-newsgroup-name
                    headers gnus-article-buffer
-                   yank nil force-news)))
+                   yank nil force-news)
+    (gnus-summary-handle-replysign)))
 
 (defun gnus-summary-followup-with-original (n &optional force-news)
   "Compose a followup to an article and include the original article."
@@ -699,7 +816,9 @@ yanked."
            (message-reply-headers
             ;; The headers are decoded.
             (with-current-buffer gnus-article-copy
-              (nnheader-parse-head t))))
+              (save-restriction
+                (nnheader-narrow-to-headers)
+                (nnheader-parse-naked-head)))))
        (message-yank-original)
        (setq beg (or beg (mark t))))
       (when articles
@@ -775,6 +894,9 @@ header line with the old Message-ID."
   ;; if ARTICLE-BUFFER is nil, gnus-article-buffer is used
   ;; this buffer should be passed to all mail/news reply/post routines.
   (setq gnus-article-copy (gnus-get-buffer-create " *gnus article copy*"))
+  (save-excursion
+    (set-buffer gnus-article-copy)
+    (set-buffer-multibyte t))
   (let ((article-buffer (or article-buffer gnus-article-buffer))
        end beg)
     (if (not (and (get-buffer article-buffer)
@@ -791,43 +913,51 @@ header line with the old Message-ID."
            ;; Copy over the (displayed) article buffer, delete
            ;; hidden text and remove text properties.
            (widen)
-           (let ((inhibit-read-only t))
-             (copy-to-buffer gnus-article-copy (point-min) (point-max))
-             (set-buffer gnus-article-copy)
-             (when yank-string
-               (message-goto-body)
-               (delete-region (point) (point-max))
-               (insert yank-string))
-             ;; Encode bitmap smileys to ordinary text.
-             ;; Possibly, the original text might be restored.
-             (static-unless (featurep 'xemacs)
-               (when (featurep 'smiley-mule)
-                 (smiley-encode-buffer)))
-             (gnus-article-delete-text-of-type 'annotation)
-             (gnus-remove-text-with-property 'gnus-prev)
-             (gnus-remove-text-with-property 'gnus-next)
-             (gnus-remove-text-with-property 'gnus-decoration)
-             (gnus-remove-text-with-property 'x-face-mule-bitmap-image)
-             (insert
-              (prog1
-                  (static-if (featurep 'xemacs)
-                      ;; Revome smiley extents for (possibly) XEmacs 21.1.
-                      (format "%s"
-                              (buffer-substring-no-properties (point-min)
-                                                              (point-max)))
-                    (buffer-substring-no-properties (point-min) (point-max)))
-                (erase-buffer))))
+           (copy-to-buffer gnus-article-copy (point-min) (point-max))
+           (set-buffer gnus-article-copy)
+           ;; There's invisible and intangible text in T-gnus.  Especially,
+           ;; if there is a boundary line (X-Boundary: ------------------),
+           ;; in the end of a header, it will cause a serious problem.
+           (add-text-properties (point-min) (point-max)
+                                '(invisible nil intangible nil))
+           (when yank-string
+             (message-goto-body)
+             (delete-region (point) (point-max))
+             (insert yank-string))
+           ;; Encode bitmap smileys to ordinary text.
+           ;; Possibly, the original text might be restored.
+           (static-unless (featurep 'xemacs)
+             (when (featurep 'smiley-mule)
+               (smiley-encode-buffer)))
+           (gnus-article-delete-text-of-type 'annotation)
+           (gnus-remove-text-with-property 'gnus-prev)
+           (gnus-remove-text-with-property 'gnus-next)
+           (gnus-remove-text-with-property 'gnus-decoration)
+           (gnus-remove-text-with-property 'x-face-mule-bitmap-image)
+           (insert
+            (prog1
+                (static-if (featurep 'xemacs)
+                    ;; Revome smiley extents for (possibly) XEmacs 21.1.
+                    (format "%s"
+                            (buffer-substring-no-properties (point-min)
+                                                            (point-max)))
+                  (buffer-substring-no-properties (point-min) (point-max)))
+              (erase-buffer)))
            ;; Find the original headers.
            (set-buffer gnus-original-article-buffer)
            (goto-char (point-min))
            (while (looking-at message-unix-mail-delimiter)
              (forward-line 1))
-           (setq beg (point)
-                 end (or (message-goto-body) beg))
+           (let ((mail-header-separator ""))
+             (setq beg (point)
+                   end (or (message-goto-body)
+                           ;; There may be just a header.
+                           (point-max))))
            ;; Delete the headers from the displayed articles.
            (set-buffer gnus-article-copy)
-           (delete-region (goto-char (point-min))
-                          (or (message-goto-body) (point-max)))
+           (let ((mail-header-separator ""))
+             (delete-region (goto-char (point-min))
+                            (or (message-goto-body) (point-max))))
            ;; Insert the original article headers.
            (insert-buffer-substring gnus-original-article-buffer beg end)
            ;; Decode charsets.
@@ -845,6 +975,7 @@ header line with the old Message-ID."
   (when article-buffer
     (gnus-copy-article-buffer))
   (let ((gnus-article-reply (and article-buffer (gnus-summary-article-number)))
+       (gnus-article-yanked-articles yank)
        (add-to-list gnus-add-to-list))
     (gnus-setup-message (cond (yank 'reply-yank)
                              (article-buffer 'reply)
@@ -903,7 +1034,7 @@ header line with the old Message-ID."
          (gnus-inews-yank-articles yank))))))
 
 (defun gnus-msg-treat-broken-reply-to (&optional force)
-  "Remove the Reply-to header iff broken-reply-to."
+  "Remove the Reply-to header if broken-reply-to."
   (when (or force
            (gnus-group-find-parameter
             gnus-newsgroup-name 'broken-reply-to))
@@ -1091,51 +1222,67 @@ If VERY-WIDE, make a very wide reply."
   (interactive
    (list (and current-prefix-arg
              (gnus-summary-work-articles 1))))
-  (let* ((article
-         (if (listp (car yank))
-             (caar yank)
-           (car yank)))
-        (gnus-article-reply (or article (gnus-summary-article-number)))
-        (headers ""))
-    ;; Stripping headers should be specified with mail-yank-ignored-headers.
-    (when yank
-      (gnus-summary-goto-subject article))
-    (gnus-setup-message (if yank 'reply-yank 'reply)
-      (if (not very-wide)
-         (gnus-summary-select-article)
-       (dolist (article very-wide)
-         (gnus-summary-select-article nil nil nil article)
-         (save-excursion
-           (set-buffer (gnus-copy-article-buffer))
-           (gnus-msg-treat-broken-reply-to)
-           (save-restriction
-             (message-narrow-to-head)
-             (setq headers (concat headers (buffer-string)))))))
-      (set-buffer (gnus-copy-article-buffer))
-      (gnus-msg-treat-broken-reply-to gnus-msg-force-broken-reply-to)
-      (save-restriction
-       (message-narrow-to-head)
-       (when very-wide
-         (erase-buffer)
-         (insert headers))
-       (goto-char (point-max)))
-      (message-reply nil wide)
+  ;; Allow user to require confirmation before replying by mail to the
+  ;; author of a news article (or mail message).
+  (when (or 
+           (not (or (gnus-news-group-p gnus-newsgroup-name)
+                    gnus-confirm-treat-mail-like-news))
+           (not (cond ((stringp gnus-confirm-mail-reply-to-news)
+                       (string-match gnus-confirm-mail-reply-to-news
+                                     gnus-newsgroup-name))
+                      ((functionp gnus-confirm-mail-reply-to-news)
+                       (funcall gnus-confirm-mail-reply-to-news gnus-newsgroup-name))
+                      (t gnus-confirm-mail-reply-to-news)))
+           (y-or-n-p "Really reply by mail to article author? "))
+    (let* ((article
+           (if (listp (car yank))
+               (caar yank)
+             (car yank)))
+          (gnus-article-reply (or article (gnus-summary-article-number)))
+          (gnus-article-yanked-articles yank)
+          (headers ""))
+      ;; Stripping headers should be specified with mail-yank-ignored-headers.
       (when yank
-       (gnus-inews-yank-articles yank))
-;;      (when (or gnus-message-replysign gnus-message-replyencrypt)
-;;     (let (signed encrypted)
-;;       (save-excursion
-;;         (set-buffer gnus-article-buffer)
-;;         (setq signed (memq 'signed gnus-article-wash-types))
-;;         (setq encrypted (memq 'encrypted gnus-article-wash-types)))
-;;       (cond ((and gnus-message-replysign signed)
-;;              (mml-secure-message mml-default-sign-method 'sign))
-;;             ((and gnus-message-replyencrypt encrypted)
-;;              (mml-secure-message mml-default-encrypt-method
-;;                                  (if gnus-message-replysignencrypted
-;;                                      'signencrypt
-;;                                    'encrypt))))))
-      )))
+       (gnus-summary-goto-subject article))
+      (gnus-setup-message (if yank 'reply-yank 'reply)
+       (if (not very-wide)
+           (gnus-summary-select-article)
+         (dolist (article very-wide)
+           (gnus-summary-select-article nil nil nil article)
+           (save-excursion
+             (set-buffer (gnus-copy-article-buffer))
+             (gnus-msg-treat-broken-reply-to)
+             (save-restriction
+               (message-narrow-to-head)
+               (setq headers (concat headers (buffer-string)))))))
+       (set-buffer (gnus-copy-article-buffer))
+       (gnus-msg-treat-broken-reply-to gnus-msg-force-broken-reply-to)
+       (save-restriction
+         (message-narrow-to-head)
+         (when very-wide
+           (erase-buffer)
+           (insert headers))
+         (goto-char (point-max)))
+       (message-reply nil wide)
+       (when yank
+         (gnus-inews-yank-articles yank))
+       (gnus-summary-handle-replysign)))))
+
+(defun gnus-summary-handle-replysign ()
+  "Check the various replysign variables and take action accordingly."
+  (when nil;;(or gnus-message-replysign gnus-message-replyencrypt)
+    (let (signed encrypted)
+      (save-excursion
+       (set-buffer gnus-article-buffer)
+       (setq signed (memq 'signed gnus-article-wash-types))
+       (setq encrypted (memq 'encrypted gnus-article-wash-types)))
+      (cond ((and gnus-message-replyencrypt encrypted)
+            (mml-secure-message mml-default-encrypt-method
+                                (if gnus-message-replysignencrypted
+                                    'signencrypt
+                                  'encrypt)))
+           ((and gnus-message-replysign signed)
+            (mml-secure-message mml-default-sign-method 'sign))))))
 
 (defun gnus-summary-reply-with-original (n &optional wide)
   "Start composing a reply mail to the current message.
@@ -1200,17 +1347,22 @@ If FULL-HEADERS (the prefix), include full headers when forwarding.
 Note that this function definition for T-gnus is totally different
 from the original Gnus."
   (interactive "P")
-  (if (null (cdr (gnus-summary-work-articles nil)))
+  (if (cdr (gnus-summary-work-articles nil))
+      ;; Process marks are given.
+      (gnus-summary-digest-mail-forward nil post)
+    ;; No process marks.
+    (let* ((gnus-article-reply (gnus-summary-article-number))
+          (gnus-article-yanked-articles (list gnus-article-reply))
+          charset
+          (message-included-forward-headers
+           (if full-headers "" message-included-forward-headers)))
       (gnus-setup-message 'forward
        (gnus-summary-select-article)
-       (let ((charset default-mime-charset))
-         (set-buffer gnus-original-article-buffer)
-         (make-local-variable 'default-mime-charset)
-         (setq default-mime-charset charset))
-       (let ((message-included-forward-headers
-              (if full-headers "" message-included-forward-headers)))
-         (message-forward post)))
-    (gnus-summary-digest-mail-forward nil post)))
+       (setq charset default-mime-charset)
+       (set-buffer gnus-original-article-buffer)
+       (make-local-variable 'default-mime-charset)
+       (setq default-mime-charset charset)
+       (message-forward post)))))
 
 (defun gnus-summary-digest-mail-forward (&optional n post)
   "Digests and forwards all articles in this series.
@@ -1220,9 +1372,10 @@ If N is nil and any articles have been marked with the process mark,
 forward those articles instead.
 Optional POST will use news to forward instead of mail."
   (interactive "P")
-  (let ((articles (gnus-summary-work-articles n))
-       (topics "Topics:\n")
-       subject article frame)
+  (let* ((articles (gnus-summary-work-articles n))
+        (gnus-article-yanked-articles (copy-sequence articles))
+        (topics "Topics:\n")
+        subject article frame)
     (when (car articles)
       (gnus-setup-message 'forward
        (gnus-summary-select-article)
@@ -1275,7 +1428,8 @@ forward those articles instead."
   (interactive
    (list (message-read-from-minibuffer
          "Resend message(s) to: "
-         (when (gnus-buffer-live-p gnus-original-article-buffer)
+         (when (and gnus-summary-resend-default-address
+                    (gnus-buffer-live-p gnus-original-article-buffer))
            ;; If some other article is currently selected, the
            ;; initial-contents is wrong. Whatever, it is just the
            ;; initial-contents.
@@ -1459,7 +1613,9 @@ The current group name will be inserted at \"%s\".")
               message-required-news-headers
             message-required-mail-headers)))
        (goto-char (point-max))
-       (insert "Gcc: " group "\n")
+       (if (string-match " " group)
+           (insert "Gcc: \"" group "\"\n")
+         (insert "Gcc: " group "\n"))
        (widen)))
     (gnus-inews-do-gcc)
     (when (and (get-buffer gnus-group-buffer)
@@ -1602,17 +1758,15 @@ The source file has to be in the Emacs load path."
       (insert ";----------------- Environment follows ------------------\n\n"))
     (while olist
       (if (boundp (car olist))
-         (condition-case ()
-             (pp `(setq ,(car olist)
-                        ,(if (or (consp (setq sym (symbol-value (car olist))))
-                                 (and (symbolp sym)
-                                      (not (or (eq sym nil)
-                                               (eq sym t)))))
-                             (list 'quote (symbol-value (car olist)))
-                           (symbol-value (car olist))))
-                 (current-buffer))
-           (error
-            (format "(setq %s 'whatever)\n" (car olist))))
+         (ignore-errors
+           (pp `(setq ,(car olist)
+                      ,(if (or (consp (setq sym (symbol-value (car olist))))
+                               (and (symbolp sym)
+                                    (not (or (eq sym nil)
+                                             (eq sym t)))))
+                           (list 'quote (symbol-value (car olist)))
+                         (symbol-value (car olist))))
+               (current-buffer)))
        (insert ";; (makeunbound '" (symbol-name (car olist)) ")\n"))
       (setq olist (cdr olist)))
     ;; Remove any control chars - they seem to cause trouble for some
@@ -1708,6 +1862,9 @@ this is a reply."
                              group (gnus-status-message method))
                (sit-for 2))
              (when (and group-art
+                        ;; FIXME: Should gcc-mark-as-read work when
+                        ;; Gnus is not running?
+                        (gnus-alive-p)
                         (or gnus-gcc-mark-as-read
                             gnus-inews-mark-gcc-as-read))
                (gnus-group-mark-article-read group (cdr group-art)))
@@ -1726,8 +1883,15 @@ this is a reply."
                    group))))
        (when gcc
          (insert "Gcc: "
-                 (if (stringp gcc) gcc
-                   (mapconcat 'identity gcc " "))
+                 (if (stringp gcc)
+                     (if (string-match " " gcc)
+                         (concat "\"" gcc "\"")
+                       gcc)
+                   (mapconcat (lambda (group)
+                                (if (string-match " " group)
+                                    (concat "\"" group "\"")
+                                  group))
+                              gcc " "))
                  "\n"))))))
 
 (defun gnus-inews-insert-archive-gcc (&optional group)
@@ -1788,23 +1952,38 @@ this is a reply."
              (progn
                (insert
                 (if (stringp gcc-self-val)
-                    gcc-self-val
-                  group))
+                    (if (string-match " " gcc-self-val)
+                        (concat "\"" gcc-self-val "\"")
+                      gcc-self-val)
+                  (if (string-match " " group)
+                      (concat "\"" group "\"")
+                    group)))
                (if (not (eq gcc-self-val 'none))
                    (insert "\n")
-                 (progn
-                   (beginning-of-line)
-                   (kill-line))))
+                 (gnus-delete-line)))
            ;; Use the list of groups.
            (while (setq name (pop groups))
-             (insert (if (string-match ":" name)
-                         name
-                       (gnus-group-prefixed-name
-                        name gnus-message-archive-method)))
+             (let ((str (if (string-match ":" name)
+                            name
+                          (gnus-group-prefixed-name
+                           name gnus-message-archive-method))))
+               (insert (if (string-match " " str)
+                           (concat "\"" str "\"")
+                         str)))
              (when groups
                (insert " ")))
            (insert "\n")))))))
 
+(defun gnus-mailing-list-followup-to ()
+  "Look at the headers in the current buffer and return a Mail-Followup-To address."
+  (let ((x-been-there (gnus-fetch-original-field "x-beenthere"))
+       (list-post (gnus-fetch-original-field "list-post")))
+    (when (and list-post
+              (string-match "mailto:\\([^>]+\\)" list-post))
+      (setq list-post (match-string 1 list-post)))
+    (or list-post
+       x-been-there)))
+
 ;;; Posting styles.
 
 (defun gnus-configure-posting-styles (&optional group-name)
@@ -1812,8 +1991,8 @@ this is a reply."
   (unless gnus-inhibit-posting-styles
     (let ((group (or group-name gnus-newsgroup-name ""))
          (styles gnus-posting-styles)
-         style match variable attribute value v results
-         filep name address element)
+         style match attribute results
+         name address)
       ;; If the group has a posting-style parameter, add it at the end with a
       ;; regexp matching everything, to be sure it takes precedence over all
       ;; the others.
@@ -1858,56 +2037,18 @@ this is a reply."
                  ;; This is a form to be evaled.
                  (eval match)))))
          ;; We have a match, so we set the variables.
+         (setq style (gnus-configure-posting-style style nil))
          (dolist (attribute style)
-           (setq element (pop attribute)
-                 variable nil
-                 filep nil)
-           (setq value
-                 (cond
-                  ((eq (car attribute) ':file)
-                   (setq filep t)
-                   (cadr attribute))
-                  ((eq (car attribute) :value)
-                   (cadr attribute))
-                  (t
-                   (car attribute))))
-           ;; We get the value.
-           (setq v
-                 (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))))
-           ;; Translate obsolescent value.
-           (cond
-            ((eq element 'signature-file)
-             (setq element 'signature
-                   filep t))
-            ((eq element 'x-face-file)
-             (setq element 'x-face
-                   filep t)))
-           ;; Get the contents of file elems.
-           (when (and filep v)
-             (setq v (with-temp-buffer
-                       (insert-file-contents v)
-                       (goto-char (point-max))
-                       (while (bolp)
-                         (delete-char -1))
-                       (buffer-string))))
-           (setq results (delq (assoc element results) results))
-           (push (cons element v) results))))
+           (setq results (delq (assoc (car attribute) results) results))
+           (push attribute results))))
       ;; Now we have all the styles, so we insert them.
       (setq name (assq 'name results)
            address (assq 'address results))
       (setq results (delq name (delq address results)))
       ;; make-local-hook is not obsolete in Emacs 20 or XEmacs.
       (make-local-hook 'message-setup-hook)
+      (setq results (sort results (lambda (x y)
+                                   (string-lessp (car x) (car y)))))
       (dolist (result results)
        (add-hook 'message-setup-hook
                  (cond
@@ -1939,7 +2080,9 @@ this is a reply."
                           (let ((value ,(cdr result)))
                             (when value
                               (message-goto-eoh)
-                              (insert ,header ": " value "\n"))))))))
+                              (insert ,header ": " value)
+                              (unless (bolp)
+                                (insert "\n")))))))))
                  nil 'local))
       (when (or name address)
        (add-hook 'message-setup-hook
@@ -1955,6 +2098,76 @@ this is a reply."
                         (insert "From: " (message-make-from) "\n"))))
                  nil 'local)))))
 
+;; splitted from gnus-configure-posting-styles to allow recursive traversal.
+(defun gnus-configure-posting-style (style stack)
+  "Parse one posting style STYLE and returns the value as an alist."
+  (let (results element variable filep value v)
+    (dolist (attribute style)
+      (setq element (pop attribute)
+           variable nil
+           filep nil)
+      (setq value
+           (cond
+            ((eq (car attribute) ':file)
+             (setq filep t)
+             (cadr attribute))
+            ((eq (car attribute) :value)
+             (cadr attribute))
+            (t
+             (car attribute))))
+      ;; We get the value.
+      (setq v
+           (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))))
+      ;; Translate obsolescent value.
+      (cond
+       ((eq element 'signature-file)
+       (setq element 'signature
+             filep t))
+       ((eq element 'x-face-file)
+       (setq element 'x-face
+             filep t)))
+      ;; Get the contents of file elems.
+      (when (and filep v)
+       (setq v (with-temp-buffer
+                 (insert-file-contents v)
+                 (goto-char (point-max))
+                 (while (bolp)
+                   (delete-char -1))
+                 (buffer-string))))
+      (if (eq element 'import)
+         (progn
+           (if (member v stack)
+               (error "Circular import of \"%s\"" v))
+           (setq results
+                 (nconc (nreverse (gnus-configure-posting-style
+                                   (cdr (assoc v gnus-named-posting-styles))
+                                   (cons v stack)))
+                        results)))
+       (push (cons element v) results)))
+    (nreverse results)))
+
+(defun gnus-summary-execute-command-with-posting-style (style command)
+  "Temporarily select a posting-style named STYLE and execute COMMAND."
+  (interactive
+   (let ((style (completing-read "Posting style: "
+                                gnus-named-posting-styles nil t)))
+     (list style
+          (key-binding
+           (read-key-sequence
+            (format "Command to execute with %s: " style))))))
+  (let ((gnus-posting-styles (list (list ".*" (list 'import style)))))
+    (call-interactively command)))
+
 
 ;;; @ for MIME Edit mode
 ;;;