2000-11-01 07:39:24 ShengHuo ZHU <zsh@cs.rochester.edu>
[gnus] / lisp / gnus-sum.el
index 20f3b47..3de2d20 100644 (file)
@@ -37,6 +37,7 @@
 (require 'gnus-util)
 (require 'mm-decode)
 (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
+(autoload 'gnus-cache-write-active "gnus-cache")
 
 (defcustom gnus-kill-summary-on-exit t
   "*If non-nil, kill the summary buffer when you exit from it.
@@ -885,10 +886,20 @@ For example: ((1 . cn-gb-2312) (2 . big5))."
   :type '(choice (const nil)
                 integer))
 
+(defcustom gnus-summary-save-parts-default-mime "image/.*"
+  "*A regexp to match MIME parts when saving multiple parts of a message
+with gnus-summary-save-parts (X m). This regexp will be used by default
+when prompting the user for which type of files to save."
+  :group 'gnus-summary
+  :type 'regexp)
+
+
 ;;; Internal variables
 
 (defvar gnus-article-mime-handles nil)
 (defvar gnus-article-decoded-p nil)
+(defvar gnus-article-charset nil)
+(defvar gnus-article-ignored-charsets nil)
 (defvar gnus-scores-exclude-files nil)
 (defvar gnus-page-broken nil)
 (defvar gnus-inhibit-mime-unbuttonizing nil)
@@ -902,6 +913,9 @@ For example: ((1 . cn-gb-2312) (2 . big5))."
 (defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
   "Function called to sort the articles within a thread after it has been gathered together.")
 
+(defvar gnus-summary-save-parts-type-history nil)
+(defvar gnus-summary-save-parts-last-directory nil)
+
 ;; Avoid highlighting in kill files.
 (defvar gnus-summary-inhibit-highlight nil)
 (defvar gnus-newsgroup-selected-overlay nil)
@@ -1540,10 +1554,11 @@ increase the score of each group you read."
     "6" gnus-article-de-base64-unreadable
     "Z" gnus-article-decode-HZ
     "h" gnus-article-wash-html
+    "s" gnus-summary-force-verify-and-decrypt
     "f" gnus-article-display-x-face
     "l" gnus-summary-stop-page-breaking
     "r" gnus-summary-caesar-message
-    "t" gnus-article-hide-headers
+    "t" gnus-summary-toggle-header
     "v" gnus-summary-verbose-headers
     "H" gnus-article-strip-headers-in-body
     "d" gnus-article-treat-dumbquotes)
@@ -1691,7 +1706,8 @@ increase the score of each group you read."
              ["Charset" gnus-article-decode-charset t]
              ["QP" gnus-article-de-quoted-unreadable t]
              ["Base64" gnus-article-de-base64-unreadable t]
-             ["View all" gnus-mime-view-all-parts t])
+             ["View all" gnus-mime-view-all-parts t]
+             ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt])
              ("Date"
               ["Local" gnus-article-date-local t]
               ["ISO8601" gnus-article-date-iso8601 t]
@@ -2092,7 +2108,7 @@ The following commands are available:
   (make-local-hook 'pre-command-hook)
   (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
   (gnus-run-hooks 'gnus-summary-mode-hook)
-  (mm-enable-multibyte)
+  (mm-enable-multibyte-mule4)
   (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
   (gnus-update-summary-mark-positions))
 
@@ -2429,12 +2445,13 @@ marks of articles."
 
 (defun gnus-restore-hidden-threads-configuration (config)
   "Restore hidden threads configuration from CONFIG."
-  (let (point buffer-read-only)
-    (while (setq point (pop config))
-      (when (and (< point (point-max))
-                (goto-char point)
-                (eq (char-after) ?\n))
-       (subst-char-in-region point (1+ point) ?\n ?\r)))))
+  (save-excursion
+    (let (point buffer-read-only)
+      (while (setq point (pop config))
+       (when (and (< point (point-max))
+                  (goto-char point)
+                  (eq (char-after) ?\n))
+         (subst-char-in-region point (1+ point) ?\n ?\r))))))
 
 ;; Various summary mode internalish functions.
 
@@ -2651,9 +2668,8 @@ buffer that was in action when the last article was fetched."
          (cond
           ((string-match "<[^>]+> *$" gnus-tmp-from)
            (let ((beg (match-beginning 0)))
-             (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
-                      (substring gnus-tmp-from (1+ (match-beginning 0))
-                                 (1- (match-end 0))))
+             (or (and (string-match "^\".+\"" gnus-tmp-from)
+                      (substring gnus-tmp-from 1 (1- (match-end 0))))
                  (substring gnus-tmp-from 0 beg))))
           ((string-match "(.+)" gnus-tmp-from)
            (substring gnus-tmp-from
@@ -3063,7 +3079,7 @@ If NO-DISPLAY, don't generate a summary buffer."
     result))
 
 (defun gnus-sort-gathered-threads (threads)
-  "Sort subtreads inside each gathered thread by article number."
+  "Sort subtreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
   (let ((result threads))
     (while threads
       (when (stringp (caar threads))
@@ -3299,7 +3315,9 @@ Returns HEADER if it was entered in the DEPENDENCIES.  Returns nil otherwise."
                 (nnheader-nov-read-integer) ; chars
                 (nnheader-nov-read-integer) ; lines
                 (unless (eobp)
-                  (nnheader-nov-field)) ; misc
+                  (if (looking-at "Xref: ")
+                      (goto-char (match-end 0)))
+                  (nnheader-nov-field)) ; Xref
                 (nnheader-nov-parse-extra)))) ; extra
 
       (widen))
@@ -3638,13 +3656,22 @@ If LINE, insert the rebuilt thread starting on line LINE."
              (1+ (gnus-point-at-eol))
            (gnus-delete-line)))))))
 
+(defun gnus-sort-threads-1 (threads func)
+  (sort (mapcar (lambda (thread)
+                 (cons (car thread)
+                       (and (cdr thread)
+                            (gnus-sort-threads-1 (cdr thread) func))))
+               threads) func))
+
 (defun gnus-sort-threads (threads)
   "Sort THREADS."
   (if (not gnus-thread-sort-functions)
       threads
     (gnus-message 8 "Sorting threads...")
     (prog1
-       (sort threads (gnus-make-sort-function gnus-thread-sort-functions))
+       (gnus-sort-threads-1 
+        threads 
+        (gnus-make-sort-function gnus-thread-sort-functions))
       (gnus-message 8 "Sorting threads...done"))))
 
 (defun gnus-sort-articles (articles)
@@ -4009,9 +4036,8 @@ or a straight list of headers."
             (cond
              ((string-match "<[^>]+> *$" gnus-tmp-from)
               (setq beg-match (match-beginning 0))
-              (or (and (string-match "^\"[^\"]*\"" gnus-tmp-from)
-                       (substring gnus-tmp-from (1+ (match-beginning 0))
-                                  (1- (match-end 0))))
+              (or (and (string-match "^\".+\"" gnus-tmp-from)
+                       (substring gnus-tmp-from 1 (1- (match-end 0))))
                   (substring gnus-tmp-from 0 beg-match)))
              ((string-match "(.+)" gnus-tmp-from)
               (substring gnus-tmp-from
@@ -4279,7 +4305,9 @@ If SELECT-ARTICLES, only select those articles from GROUP."
                    (if (string-match "^[ \t]*$" input)
                        number input)))
                 (t number))
-             (quit nil))))))
+             (quit
+              (message "Quit getting the articles to read")
+              nil))))))
     (setq select (if (stringp select) (string-to-number select) select))
     (if (or (null select) (zerop select))
        select
@@ -4719,7 +4747,8 @@ The resulting hash table is returned, or nil if no Xrefs were found."
            ;; From.
            (progn
              (goto-char p)
-             (if (search-forward "\nfrom: " nil t)
+             (if (or (search-forward "\nfrom: " nil t)
+                     (search-forward "\nfrom:" nil t))
                  (funcall gnus-decode-encoded-word-function
                           (nnheader-header-value))
                "(nobody)"))
@@ -5378,7 +5407,10 @@ If FORCE (the prefix), also save the .newsrc file(s)."
   (when (gnus-buffer-live-p gnus-article-buffer)
     (save-excursion
       (set-buffer gnus-article-buffer)
-      (mm-destroy-parts gnus-article-mime-handles)))
+      (mm-destroy-parts gnus-article-mime-handles)
+      ;; Set it to nil for safety reason.
+      (setq gnus-article-mime-handle-alist nil)
+      (setq gnus-article-mime-handles nil)))
   (gnus-kill-save-kill-buffer)
   (gnus-async-halt-prefetch)
   (let* ((group gnus-newsgroup-name)
@@ -5476,7 +5508,10 @@ If FORCE (the prefix), also save the .newsrc file(s)."
       (when (gnus-buffer-live-p gnus-article-buffer)
        (save-excursion
          (set-buffer gnus-article-buffer)
-         (mm-destroy-parts gnus-article-mime-handles)))
+         (mm-destroy-parts gnus-article-mime-handles)
+         ;; Set it to nil for safety reason.
+         (setq gnus-article-mime-handle-alist nil)
+         (setq gnus-article-mime-handles nil)))
       ;; If we have several article buffers, we kill them at exit.
       (unless gnus-single-article-buffer
        (gnus-kill-buffer gnus-article-buffer)
@@ -5815,6 +5850,11 @@ Given a prefix, will force an `article' buffer configuration."
 (defun gnus-summary-display-article (article &optional all-header)
   "Display ARTICLE in article buffer."
   (gnus-set-global-variables)
+  (when (gnus-buffer-live-p gnus-article-buffer)
+    (with-current-buffer gnus-article-buffer
+      (setq gnus-article-charset gnus-newsgroup-charset)
+      (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
+      (mm-enable-multibyte-mule4)))
   (if (null article)
       nil
     (prog1
@@ -5863,14 +5903,11 @@ be displayed."
              force)
          ;; The requested article is different from the current article.
          (progn
-           (when (gnus-buffer-live-p gnus-article-buffer)
-             (with-current-buffer gnus-article-buffer
-               (mm-enable-multibyte)))
            (gnus-summary-display-article article all-headers)
            (when (gnus-buffer-live-p gnus-article-buffer)
-             (with-current-buffer gnus-article-buffer
+              (with-current-buffer gnus-article-buffer
                (if (not gnus-article-decoded-p) ;; a local variable
-                   (mm-disable-multibyte))))
+                   (mm-disable-multibyte-mule4))))
            (when (or all-headers gnus-show-all-headers)
              (gnus-article-show-all-headers))
            (gnus-article-set-window-start
@@ -5880,6 +5917,12 @@ be displayed."
          (gnus-article-show-all-headers))
        'old))))
 
+(defun gnus-summary-force-verify-and-decrypt ()
+  (interactive)
+  (let ((mm-verify-option 'known)
+       (mm-decrypt-option 'known))
+    (gnus-summary-select-article nil 'force)))
+
 (defun gnus-summary-set-current-mark (&optional current-mark)
   "Obsolete function."
   nil)
@@ -6849,7 +6892,8 @@ of what's specified by the `gnus-refer-thread-limit' variable."
    ((eq 'current gnus-refer-article-method)
     (list gnus-current-select-method))
    ;; List of select methods.
-   ((not (stringp (cadr gnus-refer-article-method)))
+   ((not (and (symbolp (car gnus-refer-article-method))
+             (assq (car gnus-refer-article-method) nnoo-definition-alist)))
     (let (out)
       (dolist (method gnus-refer-article-method)
        (push (if (eq 'current method)
@@ -6899,7 +6943,10 @@ to guess what the document format is."
        ;; the parent article.
        (when (setq to-address (or (message-fetch-field "reply-to")
                                   (message-fetch-field "from")))
-         (setq params (append (list (cons 'to-address to-address)))))
+         (setq params (append 
+                       (list (cons 'to-address 
+                                   (funcall gnus-decode-encoded-word-function
+                                            to-address))))))
        (setq dig (nnheader-set-temp-buffer " *gnus digest buffer*"))
        (insert-buffer-substring gnus-original-article-buffer)
        ;; Remove lines that may lead nndoc to misinterpret the
@@ -7220,7 +7267,26 @@ without any article massaging functions being run."
           (or (cdr (assq arg gnus-summary-show-article-charset-alist))
               (read-coding-system "Charset: ")))
          (gnus-newsgroup-ignored-charsets 'gnus-all))
-      (gnus-summary-select-article nil 'force)))
+      (gnus-summary-select-article nil 'force)
+      (let ((deps gnus-newsgroup-dependencies)
+           head header)
+       (save-excursion
+         (set-buffer gnus-original-article-buffer)
+         (save-restriction
+           (message-narrow-to-head)
+           (setq head (buffer-string)))
+         (with-temp-buffer
+           (insert (format "211 %d Article retrieved.\n"
+                           (cdr gnus-article-current)))
+           (insert head)
+           (insert ".\n")
+           (let ((nntp-server-buffer (current-buffer)))
+             (setq header (car (gnus-get-newsgroup-headers deps t))))))
+       (gnus-data-set-header
+        (gnus-data-find (cdr gnus-article-current))
+        header)
+       (gnus-summary-update-article-line
+        (cdr gnus-article-current) header))))
    ((not arg)
     ;; Select the article the normal way.
     (gnus-summary-select-article nil 'force))
@@ -7239,7 +7305,10 @@ without any article massaging functions being run."
       (when (gnus-buffer-live-p gnus-article-buffer)
        (save-excursion
          (set-buffer gnus-article-buffer)
-         (mm-destroy-parts gnus-article-mime-handles)))
+         (mm-destroy-parts gnus-article-mime-handles)
+         ;; Set it to nil for safety reason.
+         (setq gnus-article-mime-handle-alist nil)
+         (setq gnus-article-mime-handles nil)))
       (gnus-summary-select-article nil 'force))))
   (gnus-summary-goto-subject gnus-current-article)
   (gnus-summary-position-point))
@@ -7682,6 +7751,9 @@ This will be the case if the article has both been mailed and posted."
           (expiry-wait (if now 'immediate
                          (gnus-group-find-parameter
                           gnus-newsgroup-name 'expiry-wait)))
+          (nnmail-expiry-target
+           (or (gnus-group-find-parameter gnus-newsgroup-name 'expiry-target)
+               nnmail-expiry-target))
           es)
       (when expirable
        ;; There are expirable articles in this group, so we run them
@@ -7697,19 +7769,19 @@ This will be the case if the article has both been mailed and posted."
                (setq es (gnus-request-expire-articles
                          expirable gnus-newsgroup-name)))
            (setq es (gnus-request-expire-articles
-                     expirable gnus-newsgroup-name))))
-       (unless total
-         (setq gnus-newsgroup-expirable es))
-       ;; We go through the old list of expirable, and mark all
-       ;; really expired articles as nonexistent.
-       (unless (eq es expirable)       ;If nothing was expired, we don't mark.
-         (let ((gnus-use-cache nil))
-           (while expirable
-             (unless (memq (car expirable) es)
-               (when (gnus-data-find (car expirable))
-                 (gnus-summary-mark-article
-                  (car expirable) gnus-canceled-mark)))
-             (setq expirable (cdr expirable)))))
+                     expirable gnus-newsgroup-name)))
+         (unless total
+           (setq gnus-newsgroup-expirable es))
+         ;; We go through the old list of expirable, and mark all
+         ;; really expired articles as nonexistent.
+         (unless (eq es expirable)     ;If nothing was expired, we don't mark.
+           (let ((gnus-use-cache nil))
+             (while expirable
+               (unless (memq (car expirable) es)
+                 (when (gnus-data-find (car expirable))
+                   (gnus-summary-mark-article
+                    (car expirable) gnus-canceled-mark)))
+               (setq expirable (cdr expirable))))))
        (gnus-message 6 "Expiring articles...done")))))
 
 (defun gnus-summary-expire-articles-now ()
@@ -7736,6 +7808,8 @@ delete these instead."
   (unless (gnus-check-backend-function 'request-expire-articles
                                       gnus-newsgroup-name)
     (error "The current newsgroup does not support article deletion"))
+  (unless (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
+    (error "Couldn't open server"))
   ;; Compute the list of articles to delete.
   (let ((articles (sort (copy-sequence (gnus-summary-work-articles n)) '<))
        not-deleted)
@@ -7791,7 +7865,7 @@ groups."
        (gnus-summary-show-article t)
        (when (and (not raw) (gnus-buffer-live-p gnus-article-buffer))
          (with-current-buffer gnus-article-buffer
-           (mm-enable-multibyte)))
+           (mm-enable-multibyte-mule4)))
        (if (equal gnus-newsgroup-name "nndraft:drafts")
            (setq raw t))
        (gnus-article-edit-article
@@ -7807,6 +7881,8 @@ groups."
                 (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))))
         `(lambda (no-highlight)
            (let ((mail-parse-charset ',gnus-newsgroup-charset)
+                 (message-options message-options)
+                 (message-options-set-recipient)
                  (mail-parse-ignored-charsets 
                   ',gnus-newsgroup-ignored-charsets))
              ,(if (not raw) '(progn 
@@ -8687,14 +8763,16 @@ is non-nil or the Subject: of both articles are the same."
        (unless (and message-id (not (equal message-id "")))
          (error "No message-id in desired parent"))
        (gnus-with-article current-article
-         (goto-char (point-min))
-         (if (re-search-forward "^References: " nil t)
-             (progn
-               (re-search-forward "^[^ \t]" nil t)
-               (forward-line -1)
-               (end-of-line)
-               (insert " " message-id))
-           (insert "References: " message-id "\n")))
+         (save-restriction
+           (goto-char (point-min))
+           (message-narrow-to-head)
+           (if (re-search-forward "^References: " nil t)
+               (progn
+                 (re-search-forward "^[^ \t]" nil t)
+                 (forward-line -1)
+                 (end-of-line)
+                 (insert " " message-id))
+             (insert "References: " message-id "\n"))))
        (set-buffer gnus-summary-buffer)
        (gnus-summary-unmark-all-processable)
        (gnus-summary-update-article current-article)
@@ -8946,6 +9024,8 @@ Argument REVERSE means reverse order."
              thread
            `(lambda (t1 t2)
               (,thread t2 t1))))
+        (gnus-sort-gathered-threads-function
+         gnus-thread-sort-functions)
         (gnus-article-sort-functions
          (if (not reverse)
              article
@@ -9079,7 +9159,7 @@ save those articles instead."
        (set-buffer gnus-original-article-buffer)
        (save-restriction
          (nnheader-narrow-to-headers)
-         (while methods
+         (while (and methods (not split-name))
            (goto-char (point-min))
            (setq method (pop methods))
            (setq match (car method))
@@ -9098,7 +9178,7 @@ save those articles instead."
                    (save-restriction
                      (widen)
                      (setq result (eval match)))))
-             (setq split-name (append (cdr method) split-name))
+             (setq split-name (cdr method))
              (cond ((stringp result)
                     (push (expand-file-name
                            result gnus-article-save-directory)
@@ -9167,8 +9247,14 @@ save those articles instead."
   "Save parts matching TYPE to DIR.
 If REVERSE, save parts that do not match TYPE."
   (interactive
-   (list (read-string "Save parts of type: " "image/.*")
-        (read-file-name "Save to directory: " nil nil t)
+   (list (read-string "Save parts of type: " 
+                     (or (car gnus-summary-save-parts-type-history)
+                         gnus-summary-save-parts-default-mime)
+                     'gnus-summary-save-parts-type-history)
+        (setq gnus-summary-save-parts-last-directory
+              (read-file-name "Save to directory: " 
+                              gnus-summary-save-parts-last-directory
+                              nil t))
         current-prefix-arg))
   (gnus-summary-iterate n
     (let ((gnus-display-mime-function nil)
@@ -9176,10 +9262,12 @@ If REVERSE, save parts that do not match TYPE."
       (gnus-summary-select-article))
     (save-excursion
       (set-buffer gnus-article-buffer)
-      (let ((handles (or (mm-dissect-buffer) (mm-uu-dissect))))
+      (let ((handles (or gnus-article-mime-handles
+                        (mm-dissect-buffer) (mm-uu-dissect))))
        (when handles
          (gnus-summary-save-parts-1 type dir handles reverse)
-         (mm-destroy-parts handles))))))
+         (unless gnus-article-mime-handles ;; Don't destroy this case.
+           (mm-destroy-parts handles)))))))
 
 (defun gnus-summary-save-parts-1 (type dir handle reverse)
   (if (stringp (car handle))
@@ -9485,23 +9573,32 @@ If REVERSE, save parts that do not match TYPE."
       (if compute
          read
        (save-excursion
-         (set-buffer gnus-group-buffer)
-         (gnus-undo-register
-           `(progn
-              (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
-              (gnus-info-set-read ',info ',(gnus-info-read info))
-              (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
-              (gnus-group-update-group ,group t))))
-       ;; Propagate the read marks to the backend.
-       (if (gnus-check-backend-function 'request-set-mark group)
-           (let ((del (gnus-remove-from-range (gnus-info-read info) read))
-                 (add (gnus-remove-from-range read (gnus-info-read info))))
-             (when (or add del)
-               (unless (gnus-check-group group)
-                 (error "Can't open server for %s" group))
-               (gnus-request-set-mark
-                group (delq nil (list (if add (list add 'add '(read)))
-                                      (if del (list del 'del '(read)))))))))
+         (let (setmarkundo)
+           ;; Propagate the read marks to the backend.
+           (when (gnus-check-backend-function 'request-set-mark group)
+             (let ((del (gnus-remove-from-range (gnus-info-read info) read))
+                   (add (gnus-remove-from-range read (gnus-info-read info))))
+               (when (or add del)
+                 (unless (gnus-check-group group)
+                   (error "Can't open server for %s" group))
+                 (gnus-request-set-mark
+                  group (delq nil (list (if add (list add 'add '(read)))
+                                        (if del (list del 'del '(read))))))
+                 (setq setmarkundo
+                       `(gnus-request-set-mark
+                         ,group
+                         ',(delq nil (list
+                                      (if del (list del 'add '(read)))
+                                      (if add (list add 'del '(read))))))))))
+           (set-buffer gnus-group-buffer)
+           (gnus-undo-register
+             `(progn
+                (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
+                (gnus-info-set-read ',info ',(gnus-info-read info))
+                (gnus-get-unread-articles-in-group ',info 
+                                                   (gnus-active ,group))
+                (gnus-group-update-group ,group t)
+                ,setmarkundo))))
        ;; Enter this list into the group info.
        (gnus-info-set-read info read)
        ;; Set the number of unread articles in gnus-newsrc-hashtb.