(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.
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.
"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)
(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)
(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)
;; 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)
(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
"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.
(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)))
(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
(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))
(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)))
(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)))))
(setq scores news
news nil)
(when (and gnus-summary-default-score
- scores
- (> (length gnus-newsgroup-headers)
- (length gnus-newsgroup-scored)))
+ scores)
(let* ((entries gnus-header-index)
(now (gnus-day-number (current-time-string)))
(expire (and gnus-score-expiry-days
;; Add articles to `gnus-newsgroup-scored'.
(while gnus-scores-articles
- (or (= gnus-summary-default-score (cdr (car gnus-scores-articles)))
+ (or (= gnus-summary-default-score (cdar gnus-scores-articles))
(setq gnus-newsgroup-scored
(cons (cons (mail-header-number
- (car (car gnus-scores-articles)))
- (cdr (car gnus-scores-articles)))
+ (caar gnus-scores-articles))
+ (cdar gnus-scores-articles))
gnus-newsgroup-scored)))
(setq gnus-scores-articles (cdr gnus-scores-articles)))
;; 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
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.
;; 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
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.
(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
(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))
()
(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
;; Don't enter a score if there already is one.
(while (setq entry (pop scores))
(and (equal "references" (car entry))
- (or (null (nth 3 (car (cdr entry))))
- (eq 's (nth 3 (car (cdr entry)))))
+ (or (null (nth 3 (cadr entry)))
+ (eq 's (nth 3 (cadr entry))))
(assoc id entry)
(setq dont t)))
(unless dont
(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)))
()
(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
(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."
(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)))
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.
(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))
;; 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."
(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