*** empty log message ***
[gnus] / lisp / gnus-score.el
index 6676473..dd4d1c9 100644 (file)
@@ -124,7 +124,7 @@ will be expired along with non-matching score entries.")
 (defvar gnus-score-exact-adapt-limit 10
   "*Number that says how long a match has to be before using substring matching.
 When doing adaptive scoring, one normally uses fuzzy or substring
-matching. However, if the header one matches is short, the possibility
+matching.  However, if the header one matches is short, the possibility
 for false positives is great, so if the length of the match is less
 than this variable, exact matching will be used.
 
@@ -183,6 +183,9 @@ Should be one of the following symbols.
 
 If nil, the user will be asked for a duration.")
 
+(defvar gnus-score-after-write-file-function nil
+  "*Function called with the name of the score file just written to disk.")
+
 \f
 
 ;; Internal variables.
@@ -219,8 +222,7 @@ of the last successful match.")
 (defvar gnus-score-index nil)
 
 (eval-and-compile
-  (autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap)
-  (autoload 'appt-select-lowest-window "appt.el"))
+  (autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap))
 
 ;;; Summary mode score maps.
 
@@ -233,7 +235,7 @@ of the last successful match.")
  "m" gnus-score-set-mark-below
  "x" gnus-score-set-expunge-below
  "R" gnus-summary-rescore
- "e" gnus-score-edit-alist
+ "e" gnus-score-edit-current-scores
  "f" gnus-score-edit-file
  "t" gnus-score-find-trace
  "C" gnus-score-customize)
@@ -311,7 +313,7 @@ used as score."
                     (aref (symbol-name gnus-score-default-type) 0)))
         (pchar (and gnus-score-default-duration
                     (aref (symbol-name gnus-score-default-duration) 0)))
-        entry temporary end type match)
+        entry temporary type match)
 
     ;; First we read the header to score.
     (while (not hchar)
@@ -334,8 +336,8 @@ used as score."
     (when (/= (downcase hchar) hchar)
       ;; This was a majuscle, so we end reading and set the defaults.
       (if mimic (message "%c %c" prefix hchar) (message ""))
-      (setq tchar (or gnus-score-default-type ?s)
-           pchar (or gnus-score-default-duration ?t)))
+      (setq tchar (or tchar ?s)
+           pchar (or pchar ?t)))
     
     ;; We continue reading - the type.
     (while (not tchar)
@@ -364,7 +366,7 @@ used as score."
       ;; It was a majuscle, so we end reading and the the default.
       (if mimic (message "%c %c %c" prefix hchar tchar)
        (message ""))
-      (setq pchar (or gnus-score-default-duration ?p)))
+      (setq pchar (or pchar ?p)))
 
     ;; We continue reading.
     (while (not pchar)
@@ -398,6 +400,9 @@ used as score."
        (setq match (substring match (match-end 0))))
       (when (string-match "^[^:]* +" match)
        (setq match (substring match (match-end 0))))))
+    
+    (when (memq type '(r R regexp Regexp))
+      (setq match (regexp-quote match)))
 
     (gnus-summary-score-entry
      (nth 1 entry)                     ; Header
@@ -440,11 +445,11 @@ used as score."
          (insert "\n"))
        (setq pad (- width 3))
        (setq format (concat "%c: %-" (int-to-string pad) "s"))
-       (insert (format format (car (car alist)) (nth idx (car alist))))
+       (insert (format format (caar alist) (nth idx (car alist))))
        (setq alist (cdr alist))
        (setq i (1+ i))))
     ;; display ourselves in a small window at the bottom
-    (appt-select-lowest-window)
+    (gnus-appt-select-lowest-window)
     (split-window)
     (pop-to-buffer "*Score Help*")
     (shrink-window-if-larger-than-buffer)
@@ -520,6 +525,8 @@ If optional argument `SILENT' is nil, show effect of score entry."
                             (if (numberp match)
                                 (int-to-string match)
                               match))))
+
+    ;; Score the current buffer.
     (and (>= (nth 1 (assoc header gnus-header-index)) 0)
         (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-string)
         (not silent)
@@ -529,9 +536,9 @@ If optional argument `SILENT' is nil, show effect of score entry."
     (and (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer)
         (setq match (string-to-int match)))
 
-    (if (eq date 'now)
-       ()
-      (and (= score gnus-score-interactive-default-score)
+    (unless (eq date 'now)
+      ;; Add the score entry to the score file.
+      (when (= score gnus-score-interactive-default-score)
           (setq score nil))
       (let ((new (cond 
                  (type
@@ -558,8 +565,9 @@ If optional argument `SILENT' is nil, show effect of score entry."
                                  (or (nth 1 new)
                                      gnus-score-interactive-default-score)))
          ;; Nope, we have to add a new elem.
-         (gnus-score-set header (if old (cons new old) (list new)))))
-      (gnus-score-set 'touched '(t)))))
+         (gnus-score-set header (if old (cons new old) (list new))))
+       (gnus-score-set 'touched '(t))
+       new))))
 
 (defun gnus-summary-score-effect (header match type score)
   "Simulate the effect of a score file entry.
@@ -580,8 +588,12 @@ SCORE is the score to add."
     (goto-char (point-min))
     (let ((regexp (cond ((eq type 'f)
                         (gnus-simplify-subject-fuzzy match))
-                       (type match)
-                       (t (concat "\\`.*" (regexp-quote match) ".*\\'")))))
+                       ((eq type 'r) 
+                        match)
+                       ((eq type 'e)
+                        (concat "\\`" (regexp-quote match) "\\'"))
+                       (t 
+                        (regexp-quote match)))))
       (while (not (eobp))
        (let ((content (gnus-summary-header header 'noerr))
              (case-fold-search t))
@@ -665,27 +677,31 @@ SCORE is the score to add."
   "Add SCORE to all followups to the article in the current buffer."
   (interactive "P")
   (setq score (gnus-score-default score))
-  (save-excursion
-    (save-restriction
-      (goto-char (point-min))
-      (let ((id (mail-fetch-field "message-id")))
-       (when id
-         (gnus-summary-score-entry
-          "references" (concat id "[ \t]*$") 'r
-          score (current-time-string) nil t))))))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (save-restriction
+       (goto-char (point-min))
+       (let ((id (mail-fetch-field "message-id")))
+         (when id
+           (gnus-summary-score-entry
+            "references" (concat id "[ \t]*$") 'r
+            score (current-time-string) nil t)))))))
 
 (defun gnus-score-followup-thread (&optional score)
   "Add SCORE to all later articles in the thread the current buffer is part of."
   (interactive "P")
   (setq score (gnus-score-default score))
-  (save-excursion
-    (save-restriction
-      (goto-char (point-min))
-      (let ((id (mail-fetch-field "message-id")))
-       (when id
-         (gnus-summary-score-entry
-          "references" id 's
-          score (current-time-string)))))))
+  (when (gnus-buffer-live-p gnus-summary-buffer)
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (save-restriction
+       (goto-char (point-min))
+       (let ((id (mail-fetch-field "message-id")))
+         (when id
+           (gnus-summary-score-entry
+            "references" id 's
+            score (current-time-string))))))))
 
 (defun gnus-score-set (symbol value &optional alist)
   ;; Set SYMBOL to VALUE in ALIST.
@@ -714,7 +730,7 @@ SCORE is the score to add."
   (gnus-score-load-file file)
   (gnus-set-mode-line 'summary))
 
-(defun gnus-score-edit-alist (file)
+(defun gnus-score-edit-current-scores (file)
   "Edit the current score alist."
   (interactive (list gnus-current-score-file))
   (let ((winconf (current-window-configuration)))
@@ -812,10 +828,10 @@ SCORE is the score to add."
          (set-buffer gnus-summary-buffer)
          (while local
            (and (consp (car local))
-                (symbolp (car (car local)))
+                (symbolp (caar local))
                 (progn
-                  (make-local-variable (car (car local)))
-                  (set (car (car local)) (nth 1 (car local)))))
+                  (make-local-variable (caar local))
+                  (set (caar local) (nth 1 (car local)))))
            (setq local (cdr local)))))
       (if orphan (setq gnus-orphan-score orphan))
       (setq gnus-adaptive-score-alist
@@ -903,9 +919,9 @@ SCORE is the score to add."
         (cond
          ((not (listp (car a)))
           (format "Illegal score element %s in %s" (car a) file))
-         ((stringp (car (car a)))
+         ((stringp (caar a))
           (cond 
-           ((not (listp (setq sr (cdr (car a)))))
+           ((not (listp (setq sr (cdar a))))
             (format "Illegal header match %s in %s" (nth 1 (car a)) file))
            (t
             (setq type (caar a))
@@ -946,7 +962,7 @@ SCORE is the score to add."
            (setq out (cons entry out))
            (while scor
              (setcar scor
-                     (list (car (car scor)) (nth 2 (car scor))
+                     (list (caar scor) (nth 2 (car scor))
                            (and (nth 3 (car scor))
                                 (gnus-day-number (nth 3 (car scor))))
                            (if (nth 1 (car scor)) 'r 's)))
@@ -993,9 +1009,10 @@ SCORE is the score to add."
              (if (zerop (buffer-size))
                  (delete-file file)
                ;; There are scores, so we write the file. 
-               (and (file-writable-p file)
-                    (write-region (point-min) (point-max) 
-                                  file nil 'silent))))
+               (when (file-writable-p file)
+                 (write-region (point-min) (point-max) file nil 'silent)
+                 (and gnus-score-after-write-file-function
+                      (funcall gnus-score-after-write-file-function file)))))
            (and gnus-score-uncacheable-files
                 (string-match gnus-score-uncacheable-files file)
                 (gnus-score-remove-from-cache file)))))
@@ -1003,7 +1020,7 @@ SCORE is the score to add."
   
 (defun gnus-score-headers (score-files &optional trace)
   ;; Score `gnus-newsgroup-headers'.
-  (let (scores)
+  (let (scores news)
     ;; PLM: probably this is not the best place to clear orphan-score
     (setq gnus-orphan-score nil)
     (setq gnus-scores-articles nil)
@@ -1027,69 +1044,70 @@ SCORE is the score to add."
               (member (car c) gnus-scores-exclude-files)
               (setq scores (delq (car s) scores)))
          (setq s (cdr s)))))
+    (setq news scores)
     ;; Do the scoring.
-    (when (and gnus-summary-default-score
-              scores
-              (> (length gnus-newsgroup-headers)
-                 (length gnus-newsgroup-scored)))
-      (let* ((entries gnus-header-index)
-            (now (gnus-day-number (current-time-string)))
-            (expire (and gnus-score-expiry-days
-                         (- now gnus-score-expiry-days)))
-            (headers gnus-newsgroup-headers)
-            (current-score-file gnus-current-score-file)
-            entry header)
-       (gnus-message 5 "Scoring...")
-       ;; Create articles, an alist of the form `(HEADER . SCORE)'.
-       (while headers
-         (setq header (car headers)
-               headers (cdr headers))
-         ;; WARNING: The assq makes the function O(N*S) while it could
-         ;; be written as O(N+S), where N is (length gnus-newsgroup-headers)
-         ;; and S is (length gnus-newsgroup-scored).
-         (or (assq (mail-header-number header) gnus-newsgroup-scored)
-             (setq gnus-scores-articles ;Total of 2 * N cons-cells used.
-                   (cons (cons header (or gnus-summary-default-score 0))
-                         gnus-scores-articles))))
-
-       (save-excursion
-         (set-buffer (get-buffer-create "*Headers*"))
-         (buffer-disable-undo (current-buffer))
-
-         ;; Set the global variant of this variable.
-         (setq gnus-current-score-file current-score-file)
-          ;; score orphans
-          (if gnus-orphan-score 
-              (progn
-                (setq gnus-score-index 
-                      (nth 1 (assoc "references" gnus-header-index)))
-                (gnus-score-orphans gnus-orphan-score)))
-         ;; Run each header through the score process.
-         (while entries
-           (setq entry (car entries)
-                 header (downcase (nth 0 entry))
-                 entries (cdr entries))
-           (setq gnus-score-index (nth 1 (assoc header gnus-header-index)))
-           (if (< 0 (apply 'max (mapcar
-                                 (lambda (score)
-                                   (length (gnus-score-get header score)))
-                                 scores)))
+    (while news
+      (setq scores news
+           news nil)
+      (when (and gnus-summary-default-score
+                scores)
+       (let* ((entries gnus-header-index)
+              (now (gnus-day-number (current-time-string)))
+              (expire (and gnus-score-expiry-days
+                           (- now gnus-score-expiry-days)))
+              (headers gnus-newsgroup-headers)
+              (current-score-file gnus-current-score-file)
+              entry header new)
+         (gnus-message 5 "Scoring...")
+         ;; Create articles, an alist of the form `(HEADER . SCORE)'.
+         (while (setq header (pop headers))
+           ;; WARNING: The assq makes the function O(N*S) while it could
+           ;; be written as O(N+S), where N is (length gnus-newsgroup-headers)
+           ;; and S is (length gnus-newsgroup-scored).
+           (or (assq (mail-header-number header) gnus-newsgroup-scored)
+               (setq gnus-scores-articles ;Total of 2 * N cons-cells used.
+                     (cons (cons header (or gnus-summary-default-score 0))
+                           gnus-scores-articles))))
+
+         (save-excursion
+           (set-buffer (get-buffer-create "*Headers*"))
+           (buffer-disable-undo (current-buffer))
+
+           ;; Set the global variant of this variable.
+           (setq gnus-current-score-file current-score-file)
+           ;; score orphans
+           (when gnus-orphan-score 
+             (setq gnus-score-index 
+                   (nth 1 (assoc "references" gnus-header-index)))
+             (gnus-score-orphans gnus-orphan-score))
+           ;; Run each header through the score process.
+           (while entries
+             (setq entry (car entries)
+                   header (downcase (nth 0 entry))
+                   entries (cdr entries))
+             (setq gnus-score-index (nth 1 (assoc header gnus-header-index)))
+             (when (< 0 (apply 'max (mapcar
+                                     (lambda (score)
+                                       (length (gnus-score-get header score)))
+                                     scores)))
                ;; Call the scoring function for this type of "header".
-               (funcall (nth 2 entry) scores header now expire trace)))
-         ;; Remove the buffer.
-         (kill-buffer (current-buffer)))
+               (when (setq new (funcall (nth 2 entry) scores header
+                                        now expire trace))
+                 (push new news))))
+           ;; Remove the buffer.
+           (kill-buffer (current-buffer)))
 
-       ;; Add articles to `gnus-newsgroup-scored'.
-       (while gnus-scores-articles
-         (or (= gnus-summary-default-score (cdr (car gnus-scores-articles)))
-             (setq gnus-newsgroup-scored
-                   (cons (cons (mail-header-number 
-                                (car (car gnus-scores-articles)))
-                               (cdr (car gnus-scores-articles)))
-                         gnus-newsgroup-scored)))
-         (setq gnus-scores-articles (cdr gnus-scores-articles)))
+         ;; Add articles to `gnus-newsgroup-scored'.
+         (while gnus-scores-articles
+           (or (= gnus-summary-default-score (cdar gnus-scores-articles))
+               (setq gnus-newsgroup-scored
+                     (cons (cons (mail-header-number 
+                                  (caar gnus-scores-articles))
+                                 (cdar gnus-scores-articles))
+                           gnus-newsgroup-scored)))
+           (setq gnus-scores-articles (cdr gnus-scores-articles)))
 
-       (gnus-message 5 "Scoring...done")))))
+         (gnus-message 5 "Scoring...done"))))))
 
 
 (defun gnus-get-new-thread-ids (articles)
@@ -1191,7 +1209,7 @@ SCORE is the score to add."
          ;; time than one would gain.
          (while articles
            (and (funcall match-func 
-                         (or (aref (car (car articles)) gnus-score-index) 0)
+                         (or (aref (caar articles) gnus-score-index) 0)
                          match)
                 (progn
                   (and trace (setq gnus-score-trace 
@@ -1201,7 +1219,7 @@ SCORE is the score to add."
                                      kill)
                                     gnus-score-trace)))
                   (setq found t)
-                  (setcdr (car articles) (+ score (cdr (car articles))))))
+                  (setcdr (car articles) (+ score (cdar articles)))))
            (setq articles (cdr articles)))
          ;; Update expire date
          (cond ((null date))           ;Permanent entry.
@@ -1212,7 +1230,8 @@ SCORE is the score to add."
                 (gnus-score-set 'touched '(t) alist)
                 (setcdr entries (cdr rest))
                 (setq rest entries)))
-         (setq entries rest))))))
+         (setq entries rest)))))
+  nil)
 
 (defun gnus-score-date (scores header now expire &optional trace)
   (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
@@ -1245,7 +1264,7 @@ SCORE is the score to add."
          ;; time than one would gain.
          (while articles
            (and
-            (setq l (aref (car (car articles)) gnus-score-index))
+            (setq l (aref (caar articles) gnus-score-index))
             (funcall match-func match (timezone-make-date-sortable l))
             (progn
               (and trace (setq gnus-score-trace 
@@ -1255,7 +1274,7 @@ SCORE is the score to add."
                                  kill)
                                 gnus-score-trace)))
               (setq found t)
-              (setcdr (car articles) (+ score (cdr (car articles))))))
+              (setcdr (car articles) (+ score (cdar articles)))))
            (setq articles (cdr articles)))
          ;; Update expire date
          (cond ((null date))           ;Permanent entry.
@@ -1266,22 +1285,31 @@ SCORE is the score to add."
                 (gnus-score-set 'touched '(t) alist)
                 (setcdr entries (cdr rest))
                 (setq rest entries)))
-         (setq entries rest))))))
+         (setq entries rest)))))
+  nil)
 
 (defun gnus-score-body (scores header now expire &optional trace)
   (save-excursion
     (set-buffer nntp-server-buffer)
+    (setq gnus-scores-articles
+         (sort gnus-scores-articles
+               (lambda (a1 a2)
+                 (< (mail-header-number (car a1))
+                    (mail-header-number (car a2))))))
     (save-restriction
       (let* ((buffer-read-only nil)
             (articles gnus-scores-articles)
-            (last (mail-header-number (car (car gnus-scores-articles))))
             (all-scores scores)
             (request-func (cond ((string= "head" (downcase header))
                                  'gnus-request-head)
                                 ((string= "body" (downcase header))
                                  'gnus-request-body)
                                 (t 'gnus-request-article)))
-            entries alist ofunc article)
+            entries alist ofunc article last)
+       (while (cdr articles)
+         (setq articles (cdr articles)))
+       (setq last (mail-header-number (caar articles)))
+       (setq articles gnus-scores-articles)
        ;; Not all backends support partial fetching.  In that case,
        ;; we just fetch the entire article.
        (or (gnus-check-backend-function 
@@ -1293,7 +1321,7 @@ SCORE is the score to add."
              (setq ofunc request-func)
              (setq request-func 'gnus-request-article)))
        (while articles
-         (setq article (mail-header-number (car (car articles))))
+         (setq article (mail-header-number (caar articles)))
          (gnus-message 7 "Scoring on article %s of %s..." article last)
          (if (not (funcall request-func article gnus-newsgroup-name))
              ()
@@ -1341,7 +1369,7 @@ SCORE is the score to add."
                  (if (funcall search-func match nil t)
                      ;; Found a match, update scores.
                      (progn
-                       (setcdr (car articles) (+ score (cdr (car articles))))
+                       (setcdr (car articles) (+ score (cdar articles)))
                        (setq found t)
                        (and trace (setq gnus-score-trace 
                                         (cons
@@ -1361,7 +1389,8 @@ SCORE is the score to add."
                    (setcdr entries (cdr rest))
                    (setq rest entries)))
                  (setq entries rest)))))
-         (setq articles (cdr articles)))))))
+         (setq articles (cdr articles))))))
+  nil)
 
 (defun gnus-score-followup (scores header now expire &optional trace thread)
   ;; Insert the unique article headers in the buffer.
@@ -1369,12 +1398,17 @@ SCORE is the score to add."
        (current-score-file gnus-current-score-file)
        (all-scores scores)
        ;; gnus-score-index is used as a free variable.
-       alike last this art entries alist articles)
+       alike last this art entries alist articles
+       new news)
 
     ;; Change score file to the adaptive score file.  All entries that
     ;; this function makes will be put into this file.
-    (gnus-score-load-file (gnus-score-file-name 
-                          gnus-newsgroup-name gnus-adaptive-file-suffix))
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (gnus-score-load-file
+       (or gnus-newsgroup-adaptive-score-file
+          (gnus-score-file-name 
+           gnus-newsgroup-name gnus-adaptive-file-suffix))))
 
     (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<)
          articles gnus-scores-articles)
@@ -1439,10 +1473,10 @@ SCORE is the score to add."
              (end-of-line)
              (setq found (setq arts (get-text-property (point) 'articles)))
              ;; Found a match, update scores.
-             (while arts
-               (setq art (car arts)
-                     arts (cdr arts))
-               (gnus-score-add-followups (car art) score all-scores thread))))
+             (while (setq art (pop arts))
+               (when (setq new (gnus-score-add-followups
+                                (car art) score all-scores thread))
+                 (push new news)))))
          ;; Update expire date
          (cond ((null date))           ;Permanent entry.
                ((and found gnus-update-score-entry-dates) ;Match, update date.
@@ -1454,29 +1488,29 @@ SCORE is the score to add."
                 (setq rest entries)))
          (setq entries rest))))
     ;; We change the score file back to the previous one.
-    (gnus-score-load-file current-score-file)))
+    (save-excursion
+      (set-buffer gnus-summary-buffer)
+      (gnus-score-load-file current-score-file))
+    (list (cons "references" news))))
 
 (defun gnus-score-add-followups (header score scores &optional thread)
+  "Add a score entry to the adapt file."
   (save-excursion
     (set-buffer gnus-summary-buffer)
     (let* ((id (mail-header-id header))
           (scores (car scores))
           entry dont)
       ;; Don't enter a score if there already is one.
-      (while scores
-       (setq entry (car scores))
+      (while (setq entry (pop scores))
        (and (equal "references" (car entry))
-            (or (null (nth 3 (car (cdr entry))))
-                (eq 's (nth 3 (car (cdr entry)))))
-            (progn
-              (if (assoc id entry)
-                  (setq dont t))))
-       (setq scores (cdr scores)))
-      (or dont
-         (gnus-summary-score-entry 
-          (if thread "thread" "references")
-          id 's score (current-time-string) nil t)))))
-
+            (or (null (nth 3 (cadr entry)))
+                (eq 's (nth 3 (cadr entry))))
+            (assoc id entry)
+            (setq dont t)))
+      (unless dont
+       (gnus-summary-score-entry 
+        (if thread "thread" "references")
+        id 's score (current-time-string) nil t)))))
 
 (defun gnus-score-string (score-list header now expire &optional trace)
   ;; Score ARTICLES according to HEADER in SCORE-LIST.
@@ -1662,7 +1696,8 @@ SCORE is the score to add."
                  (gnus-score-set 'touched '(t) alist)
                  (setcdr entries (cdr rest))
                  (setq rest entries)))))
-           (setq entries rest)))))))
+           (setq entries rest))))))
+  nil)
 
 (defun gnus-score-string< (a1 a2)
   ;; Compare headers in articles A2 and A2.
@@ -1713,17 +1748,17 @@ SCORE is the score to add."
        (setq elem (cdr elem))
        (while elem
          (setcdr (car elem) 
-                 (cons (if (eq (car (car elem)) 'followup)
+                 (cons (if (eq (caar elem) 'followup)
                            "references"
-                         (symbol-name (car (car elem))))
-                       (cdr (car elem))))
+                         (symbol-name (caar elem)))
+                       (cdar elem)))
          (setcar (car elem) 
                  `(lambda (h)
                     (,(intern 
                        (concat "mail-header-" 
-                               (if (eq (car (car elem)) 'followup)
+                               (if (eq (caar elem) 'followup)
                                    "message-id"
-                                 (downcase (symbol-name (car (car elem)))))))
+                                 (downcase (symbol-name (caar elem))))))
                      h)))
          (setq elem (cdr elem)))
        (setq malist (cdr malist)))
@@ -1740,7 +1775,7 @@ SCORE is the score to add."
            ()
          (when (setq headers (gnus-data-header (car data)))
            (while elem 
-             (setq match (funcall (car (car elem)) headers))
+             (setq match (funcall (caar elem) headers))
              (gnus-summary-score-entry 
               (nth 1 (car elem)) match
               (cond
@@ -1810,7 +1845,7 @@ This mode is an extended emacs-lisp mode.
 (defun gnus-score-edit-insert-date ()
   "Insert date in numerical format."
   (interactive)
-  (insert (int-to-string (gnus-day-number (current-time-string)))))
+  (princ (gnus-day-number (current-time-string)) (current-buffer)))
 
 (defun gnus-score-pretty-print ()
   "Format the current score file."
@@ -1849,8 +1884,8 @@ This mode is an extended emacs-lisp mode.
     (gnus-add-current-to-buffer-list)
     (erase-buffer)
     (while trace
-      (insert (format "%S  ->  %s\n"  (cdr (car trace))
-                     (file-name-nondirectory (car (car trace)))))
+      (insert (format "%S  ->  %s\n" (cdar trace)
+                     (file-name-nondirectory (caar trace))))
       (setq trace (cdr trace)))
     (goto-char (point-min))
     (pop-to-buffer buf)))
@@ -1871,10 +1906,14 @@ This mode is an extended emacs-lisp mode.
        gnus-short-name-score-file-cache nil)
   (gnus-message 6 "The score cache is now flushed"))
 
+(gnus-add-shutdown 'gnus-score-close 'gnus)
+
 (defun gnus-score-close ()
   "Clear all internal score variables."
   (setq gnus-score-cache nil
-       gnus-internal-global-score-files nil))
+       gnus-internal-global-score-files nil
+       gnus-score-file-list nil
+       gnus-score-file-alist-cache nil))
 
 ;; Summary score marking commands.
 
@@ -1955,9 +1994,12 @@ This mode is an extended emacs-lisp mode.
        (setq gnus-score-file-list 
              (cons nil 
                    (or gnus-short-name-score-file-cache
-                       (setq gnus-short-name-score-file-cache
-                             (gnus-score-score-files-1
-                              gnus-kill-files-directory)))))
+                       (prog2
+                           (gnus-message 6 "Finding all score files...")
+                           (setq gnus-short-name-score-file-cache
+                                 (gnus-score-score-files-1
+                                  gnus-kill-files-directory))
+                         (gnus-message 6 "Finding all score files...done")))))
       ;; We want long file names.
       (when (or (not gnus-score-file-list)
                (not (car gnus-score-file-list))
@@ -1987,7 +2029,9 @@ This mode is an extended emacs-lisp mode.
        ;; Add files to the list of score files.
        ((string-match regexp file)
        (push file out))))
-    out))
+    (or out
+       ;; Return a dummy value.
+       (list "~/News/this.file.does.not.exist.SCORE"))))
        
 (defun gnus-score-file-regexp ()
   "Return a regexp that match all score files."
@@ -2070,7 +2114,8 @@ GROUP using BNews sys file syntax."
 
 (defun gnus-score-find-single (group)
   "Return list containing the score file for GROUP."
-  (list (gnus-score-file-name group gnus-adaptive-file-suffix)
+  (list (or gnus-newsgroup-adaptive-score-file
+           (gnus-score-file-name group gnus-adaptive-file-suffix))
        (gnus-score-file-name group)))
 
 (defun gnus-score-find-hierarchical (group)
@@ -2100,21 +2145,21 @@ The list is determined from the variable gnus-score-file-alist."
        (cdr score-files)               ;ensures caching groups with no matches
       ;; handle the multiple match alist
       (while alist
-       (and (string-match (car (car alist)) group)
+       (and (string-match (caar alist) group)
             (setq score-files
-                  (nconc score-files (copy-sequence (cdr (car alist))))))
+                  (nconc score-files (copy-sequence (cdar alist)))))
        (setq alist (cdr alist)))
       (setq alist gnus-score-file-single-match-alist)
       ;; handle the single match alist
       (while alist
-       (and (string-match (car (car alist)) group)
+       (and (string-match (caar alist) group)
             ;; progn used just in case ("regexp") has no files
             ;; and score-files is still nil. -sj
             ;; this can be construed as a "stop searching here" feature :>
             ;; and used to simplify regexps in the single-alist 
             (progn
               (setq score-files
-                    (nconc score-files (copy-sequence (cdr (car alist)))))
+                    (nconc score-files (copy-sequence (cdar alist))))
               (setq alist nil)))
        (setq alist (cdr alist)))
       ;; cache the score files