2001-01-21 00:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
[gnus] / lisp / gnus-msg.el
index 83684e8..2b7442b 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-msg.el --- mail and post interface for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
@@ -101,8 +101,11 @@ the second with the current group name.")
 (defvar gnus-posting-styles nil
   "*Alist of styles to use when posting.")
 
+(defvar gnus-inews-mark-gcc-as-read nil
+  "If non-nil, automatically mark Gcc articles as read.")
+
 (defcustom gnus-group-posting-charset-alist
-  '(("^\\(no\\|fr\\|dk\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\|dk\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
+  '(("^\\(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))
@@ -116,7 +119,7 @@ BODY-LIST is a list of charsets which may be encoded using 8bit
 content-transfer encoding in the body, or one of the special values
 nil (always encode using quoted-printable) or t (always use 8bit).
 
-Note that any value other tha nil for HEADER infringes some RFCs, so
+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"
@@ -140,6 +143,7 @@ use this option with care."
 
 (defvar gnus-message-buffer "*Mail Gnus*")
 (defvar gnus-article-copy nil)
+(defvar gnus-check-before-posting nil)
 (defvar gnus-last-posting-server nil)
 (defvar gnus-message-group-art nil)
 
@@ -216,7 +220,9 @@ Thank you for your help in stamping out bugs.
           (,group gnus-newsgroup-name)
           (message-header-setup-hook
            (copy-sequence message-header-setup-hook))
+          (mbl mml-buffer-list)
           (message-mode-hook (copy-sequence message-mode-hook)))
+       (setq mml-buffer-list nil)
        (add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc)
        (add-hook 'message-header-setup-hook 'gnus-inews-insert-archive-gcc)
        (add-hook 'message-mode-hook 'gnus-configure-posting-styles)
@@ -224,15 +230,62 @@ Thank you for your help in stamping out bugs.
           (progn
             ,@forms)
         (gnus-inews-add-send-actions ,winconf ,buffer ,article)
+        (gnus-inews-insert-draft-meta-information ,group ,article)
         (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-run-hooks 'gnus-message-setup-hook))
+        (gnus-run-hooks 'gnus-message-setup-hook)
+        (if (eq major-mode 'message-mode)
+            (let ((mbl1 mml-buffer-list))
+              (setq mml-buffer-list mbl)  ;; Global value
+              (set (make-local-variable 'mml-buffer-list) mbl1);; Local value
+              (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
+          (mml-destroy-buffers)
+          (setq mml-buffer-list mbl)))
        (gnus-add-buffer)
        (gnus-configure-windows ,config t)
        (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 article) "\"\"") ")\n"))))
+
+;;;###autoload
+(defun gnus-msg-mail (&rest args)
+  "Start editing a mail message to be sent.
+Like `message-mail', but with Gnus paraphernalia, particularly the
+Gcc: header for archiving purposes."
+  (interactive)
+  (gnus-setup-message 'message
+    (apply 'message-mail args))
+  ;; COMPOSEFUNC should return t if succeed.  Undocumented ???
+  t)
+
+;;;###autoload
+(defun gnus-button-mailto (address)
+  "Mail to ADDRESS."
+  (set-buffer (gnus-copy-article-buffer))
+  (gnus-setup-message 'message
+    (message-reply address)))
+
+;;;###autoload
+(defun gnus-button-reply (&optional to-address wide)
+  "Like `message-reply'."
+  (interactive)
+  (gnus-setup-message 'message
+    (message-reply to-address wide)))
+
+;;;###autoload
+(define-mail-user-agent 'gnus-user-agent
+  'gnus-msg-mail 'message-send-and-exit
+  'message-kill-buffer 'message-send-hook)
+
 (defun gnus-setup-posting-charset (group)
   (let ((alist gnus-group-posting-charset-alist)
        (group (or group ""))
@@ -250,7 +303,11 @@ Thank you for your help in stamping out bugs.
 
 (defun gnus-inews-add-send-actions (winconf buffer article)
   (make-local-hook 'message-sent-hook)
-  (add-hook 'message-sent-hook 'gnus-inews-do-gcc nil t)
+  (add-hook 'message-sent-hook (if gnus-agent 'gnus-agent-possibly-do-gcc
+                                'gnus-inews-do-gcc) nil t)
+  (when gnus-agent
+    (make-local-hook 'message-header-hook)
+    (add-hook 'message-header-hook 'gnus-agent-possibly-save-gcc nil t))
   (setq message-post-method
        `(lambda (arg)
           (gnus-post-method arg ,gnus-newsgroup-name)))
@@ -358,7 +415,10 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
        (gnus-summary-remove-process-mark article))
       (gnus-copy-article-buffer)
       (let ((message-reply-buffer gnus-article-copy)
-           (message-reply-headers gnus-current-headers))
+           (message-reply-headers
+            (with-current-buffer gnus-article-copy
+              ;; The headers are decoded.
+              (nnheader-parse-head t))))
        (message-yank-original)
        (setq beg (or beg (mark t))))
       (when articles
@@ -423,33 +483,38 @@ header line with the old Message-ID."
        (error "Can't find any article buffer")
       (save-excursion
        (set-buffer article-buffer)
-       (save-restriction
-         ;; Copy over the (displayed) article buffer, delete
-         ;; hidden text and remove text properties.
-         (widen)
-         (copy-to-buffer gnus-article-copy (point-min) (point-max))
-         (set-buffer gnus-article-copy)
-         (gnus-article-delete-text-of-type 'annotation)
-         (gnus-remove-text-with-property 'gnus-prev)
-         (gnus-remove-text-with-property 'gnus-next)
-         (insert
-          (prog1
-              (format "%s" (buffer-string))
-            (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))
-         (setq end (or (search-forward "\n\n" nil t) (point)))
-         ;; Delete the headers from the displayed articles.
-         (set-buffer gnus-article-copy)
-         (delete-region (goto-char (point-min))
-                        (or (search-forward "\n\n" nil t) (point-max)))
-         ;; Insert the original article headers.
-         (insert-buffer-substring gnus-original-article-buffer beg end)
-         (article-decode-encoded-words)))
+       (let ((gnus-newsgroup-charset (or gnus-article-charset
+                                         gnus-newsgroup-charset))
+             (gnus-newsgroup-ignored-charsets
+              (or gnus-article-ignored-charsets
+                  gnus-newsgroup-ignored-charsets)))
+         (save-restriction
+           ;; Copy over the (displayed) article buffer, delete
+           ;; hidden text and remove text properties.
+           (widen)
+           (copy-to-buffer gnus-article-copy (point-min) (point-max))
+           (set-buffer gnus-article-copy)
+           (gnus-article-delete-text-of-type 'annotation)
+           (gnus-remove-text-with-property 'gnus-prev)
+           (gnus-remove-text-with-property 'gnus-next)
+           (insert
+            (prog1
+                (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))
+           (setq end (or (search-forward "\n\n" nil t) (point)))
+           ;; Delete the headers from the displayed articles.
+           (set-buffer gnus-article-copy)
+           (delete-region (goto-char (point-min))
+                          (or (search-forward "\n\n" nil t) (point-max)))
+           ;; Insert the original article headers.
+           (insert-buffer-substring gnus-original-article-buffer beg end)
+           (article-decode-encoded-words))))
       gnus-article-copy)))
 
 (defun gnus-post-news (post &optional group header article-buffer yank subject
@@ -462,6 +527,7 @@ header line with the old Message-ID."
                              (article-buffer 'reply)
                              (t 'message))
       (let* ((group (or group gnus-newsgroup-name))
+            (charset (gnus-group-name-charset nil group))
             (pgroup group)
             to-address to-group mailing-list to-list
             newsgroup-p)
@@ -472,7 +538,8 @@ header line with the old Message-ID."
                newsgroup-p (gnus-group-find-parameter group 'newsgroup)
                mailing-list (when gnus-mailing-list-groups
                               (string-match gnus-mailing-list-groups group))
-               group (gnus-group-real-name group)))
+               group (gnus-group-name-decode (gnus-group-real-name group)
+                                             charset)))
        (if (or (and to-group
                     (gnus-news-group-p to-group))
                newsgroup-p
@@ -560,7 +627,9 @@ If SILENT, don't prompt the user."
        (setq method-alist
              (mapcar
               (lambda (m)
-                (list (concat (cadr m) " (" (symbol-name (car m)) ")") m))
+                (if (equal (cadr m) "")
+                    (list (symbol-name (car m)) m)
+                  (list (concat (cadr m) " (" (symbol-name (car m)) ")") m)))
               post-methods))
        ;; Query the user.
        (cadr
@@ -589,8 +658,9 @@ If SILENT, don't prompt the user."
 \f
 
 ;; Dummies to avoid byte-compile warning.
-(defvar nnspool-rejected-article-hook)
-(defvar xemacs-codename)
+(eval-when-compile
+  (defvar nnspool-rejected-article-hook)
+  (defvar xemacs-codename))
 
 (defun gnus-extended-version ()
   "Stringified Gnus version and Emacs version."
@@ -636,6 +706,10 @@ automatically."
       (gnus-summary-select-article)
       (set-buffer (gnus-copy-article-buffer))
       (gnus-msg-treat-broken-reply-to)
+      (save-restriction
+       (message-narrow-to-head)
+       (goto-char (point-max)))
+      (mml-quote-region (point) (point-max))
       (message-reply nil wide)
       (when yank
        (gnus-inews-yank-articles yank)))))
@@ -662,18 +736,18 @@ The original article will be yanked."
   (gnus-summary-reply-with-original n t))
 
 (defun gnus-summary-mail-forward (&optional arg post)
-  "Forward the current message to another user.  
+  "Forward the current message to another user.
 If ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
 if ARG is 1, decode the message and forward directly inline;
-if ARG is 2, foward message as an rfc822 MIME section;
+if ARG is 2, forward message as an rfc822 MIME section;
 if ARG is 3, decode message and forward as an rfc822 MIME section;
-if ARG is 4, foward message directly inline;
+if ARG is 4, forward message directly inline;
 otherwise, use flipped `message-forward-as-mime'.
 If POST, post instead of mail."
   (interactive "P")
   (let ((message-forward-as-mime message-forward-as-mime)
        (message-forward-show-mml message-forward-show-mml))
-    (cond 
+    (cond
      ((null arg))
      ((eq arg 1) (setq message-forward-as-mime nil
                       message-forward-show-mml t))
@@ -687,31 +761,15 @@ If POST, post instead of mail."
     (gnus-setup-message 'forward
       (gnus-summary-select-article)
       (let ((mail-parse-charset gnus-newsgroup-charset)
-           (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
-           text)
-       (save-excursion
-         (set-buffer gnus-original-article-buffer)
-         (setq text (buffer-string)))
-       (set-buffer 
-        (if message-forward-show-mml
-            (gnus-get-buffer-create
-             (generate-new-buffer-name " *Gnus forward*"))
-          (mm-with-unibyte-current-buffer
-            ;; create an unibyte buffer
-            (gnus-get-buffer-create
-             (generate-new-buffer-name " *Gnus forward*")))))
-       (erase-buffer)
-       (insert text)
-       (goto-char (point-min))
-       (when (looking-at "From ")
-         (replace-match "X-From-Line: ") )
-       (if message-forward-show-mml
-           (mime-to-mml))
+           (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
+       (set-buffer gnus-original-article-buffer)
        (message-forward post)))))
 
 (defun gnus-summary-resend-message (address n)
   "Resend the current article to ADDRESS."
-  (interactive "sResend message(s) to: \nP")
+  (interactive
+   (list (message-read-from-minibuffer "Resend message(s) to: ")
+        current-prefix-arg))
   (let ((articles (gnus-summary-work-articles n))
        article)
     (while (setq article (pop articles))
@@ -877,15 +935,17 @@ If YANK is non-nil, include the original article."
   (interactive)
   (unless (gnus-alive-p)
     (error "Gnus has been shut down"))
-  (gnus-setup-message 'bug
-    (delete-other-windows)
-    (when gnus-bug-create-help-buffer
-      (switch-to-buffer "*Gnus Help Bug*")
-      (erase-buffer)
-      (insert gnus-bug-message)
-      (goto-char (point-min)))
-    (message-pop-to-buffer "*Gnus Bug*")
-    (message-setup `((To . ,gnus-maintainer) (Subject . "")))
+  (gnus-setup-message (if (message-mail-user-agent) 'message 'bug)
+    (unless (message-mail-user-agent)
+      (delete-other-windows)
+      (when gnus-bug-create-help-buffer
+       (switch-to-buffer "*Gnus Help Bug*")
+       (erase-buffer)
+       (insert gnus-bug-message)
+       (goto-char (point-min)))
+      (message-pop-to-buffer "*Gnus Bug*"))
+    (let ((message-this-is-mail t))
+      (message-setup `((To . ,gnus-maintainer) (Subject . ""))))
     (when gnus-bug-create-help-buffer
       (push `(gnus-bug-kill-buffer) message-send-actions))
     (goto-char (point-min))
@@ -1008,6 +1068,21 @@ this is a reply."
 
 ;;; Gcc handling.
 
+(defun gnus-inews-group-method (group)
+  (cond ((and (null (gnus-get-info group))
+             (eq (car gnus-message-archive-method)
+                 (car
+                  (gnus-server-to-method
+                   (gnus-group-method group)))))
+        ;; If the group doesn't exist, we assume
+        ;; it's an archive group...
+        gnus-message-archive-method)
+       ;; Use the method.
+       ((gnus-info-method (gnus-get-info group))
+        (gnus-info-method (gnus-get-info group)))
+       ;; Find the method.
+       (t (gnus-group-method group))))
+
 ;; Do Gcc handling, which copied the message over to some group.
 (defun gnus-inews-do-gcc (&optional gcc)
   (interactive)
@@ -1017,29 +1092,16 @@ this is a reply."
        (message-narrow-to-headers)
        (let ((gcc (or gcc (mail-fetch-field "gcc" nil t)))
              (cur (current-buffer))
-             groups group method)
+             groups group method group-art)
          (when gcc
            (message-remove-header "gcc")
            (widen)
-           (setq groups (message-tokenize-header gcc " ,"))
+           (setq groups (message-unquote-tokens
+                          (message-tokenize-header gcc " ,")))
            ;; Copy the article over to some group(s).
            (while (setq group (pop groups))
              (gnus-check-server
-              (setq method
-                    (cond ((and (null (gnus-get-info group))
-                                (eq (car gnus-message-archive-method)
-                                    (car
-                                     (gnus-server-to-method
-                                      (gnus-group-method group)))))
-                           ;; If the group doesn't exist, we assume
-                           ;; it's an archive group...
-                           gnus-message-archive-method)
-                          ;; Use the method.
-                          ((gnus-info-method (gnus-get-info group))
-                           (gnus-info-method (gnus-get-info group)))
-                          ;; Find the method.
-                          (t (gnus-group-method group)))))
-             (gnus-check-server method)
+              (setq method (gnus-inews-group-method group)))
              (unless (gnus-request-group group t method)
                (gnus-request-create-group group method))
              (save-excursion
@@ -1048,17 +1110,49 @@ this is a reply."
                (message-encode-message-body)
                (save-restriction
                  (message-narrow-to-headers)
-                 (let ((mail-parse-charset message-default-charset))
+                 (let ((mail-parse-charset message-default-charset)
+                       (rfc2047-header-encoding-alist
+                        (cons '("Newsgroups" . default)
+                              rfc2047-header-encoding-alist)))
                    (mail-encode-encoded-word-buffer)))
                (goto-char (point-min))
                (when (re-search-forward
                       (concat "^" (regexp-quote mail-header-separator) "$")
                       nil t)
                  (replace-match "" t t ))
-               (unless (gnus-request-accept-article group method t t)
+               (unless (setq group-art
+                             (gnus-request-accept-article group method t t))
                  (gnus-message 1 "Couldn't store article in group %s: %s"
                                group (gnus-status-message method))
                  (sit-for 2))
+               (when (and group-art gnus-inews-mark-gcc-as-read)
+                 (let ((active (gnus-active group)))
+                   (if active
+                       (if (< (cdr active) (cdr group-art))
+                           (gnus-set-active group (cons (car active)
+                                                        (cdr group-art))))
+                     (gnus-activate-group group)))
+                 (let ((buffer (gnus-summary-buffer-name group))
+                       (mark gnus-read-mark)
+                       (article (cdr group-art)))
+                   (unless
+                       (and
+                        (get-buffer buffer)
+                        (with-current-buffer buffer
+                          (when gnus-newsgroup-prepared
+                            (when (and gnus-newsgroup-auto-expire
+                                       (memq mark gnus-auto-expirable-marks))
+                              (setq mark gnus-expirable-mark))
+                            (setq mark (gnus-request-update-mark
+                                        group article mark))
+                            (gnus-mark-article-as-read article mark)
+                            (setq gnus-newsgroup-active (gnus-active group))
+                            t)))
+                     (gnus-group-make-articles-read group
+                                                    (list article))
+                     (when (gnus-group-auto-expirable-p group)
+                       (gnus-add-marked-articles
+                        group 'expire (list article))))))
                (kill-buffer (current-buffer))))))))))
 
 (defun gnus-inews-insert-gcc ()