Mercurial > hg > xemacs-beta
comparison lisp/gnus/gnus-score.el @ 98:0d2f883870bc r20-1b1
Import from CVS: tag r20-1b1
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:13:56 +0200 |
parents | 131b0175ea99 |
children | 4be1180a9e89 |
comparison
equal
deleted
inserted
replaced
97:498bf5da1c90 | 98:0d2f883870bc |
---|---|
1 ;;; gnus-score.el --- scoring code for Gnus | 1 ;;; gnus-score.el --- scoring code for Gnus |
2 ;; Copyright (C) 1995,96 Free Software Foundation, Inc. | 2 ;; Copyright (C) 1995,96,97 Free Software Foundation, Inc. |
3 | 3 |
4 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk> | 4 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk> |
5 ;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no> | 5 ;; Lars Magne Ingebrigtsen <larsi@ifi.uio.no> |
6 ;; Keywords: news | 6 ;; Keywords: news |
7 | 7 |
25 ;;; Commentary: | 25 ;;; Commentary: |
26 | 26 |
27 ;;; Code: | 27 ;;; Code: |
28 | 28 |
29 (require 'gnus) | 29 (require 'gnus) |
30 (eval-when-compile (require 'cl)) | 30 (require 'gnus-sum) |
31 | 31 (require 'gnus-range) |
32 (defvar gnus-global-score-files nil | 32 |
33 "*List of global score files and directories. | 33 (defcustom gnus-global-score-files nil |
34 "List of global score files and directories. | |
34 Set this variable if you want to use people's score files. One entry | 35 Set this variable if you want to use people's score files. One entry |
35 for each score file or each score file directory. Gnus will decide | 36 for each score file or each score file directory. Gnus will decide |
36 by itself what score files are applicable to which group. | 37 by itself what score files are applicable to which group. |
37 | 38 |
38 Say you want to use the single score file | 39 Say you want to use the single score file |
39 \"/ftp.ifi.uio.no@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all | 40 \"/ftp.ifi.uio.no@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all |
40 score files in the \"/ftp.some-where:/pub/score\" directory. | 41 score files in the \"/ftp.some-where:/pub/score\" directory. |
41 | 42 |
42 (setq gnus-global-score-files | 43 (setq gnus-global-score-files |
43 '(\"/ftp.ifi.uio.no:/pub/larsi/ding/score/soc.motss.SCORE\" | 44 '(\"/ftp.ifi.uio.no:/pub/larsi/ding/score/soc.motss.SCORE\" |
44 \"/ftp.some-where:/pub/score\"))") | 45 \"/ftp.some-where:/pub/score\"))" |
45 | 46 :group 'gnus-score |
46 (defvar gnus-score-file-single-match-alist nil | 47 :type '(repeat file)) |
47 "*Alist mapping regexps to lists of score files. | 48 |
49 (defcustom gnus-score-file-single-match-alist nil | |
50 "Alist mapping regexps to lists of score files. | |
48 Each element of this alist should be of the form | 51 Each element of this alist should be of the form |
49 (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... ) | 52 (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... ) |
50 | 53 |
51 If the name of a group is matched by REGEXP, the corresponding scorefiles | 54 If the name of a group is matched by REGEXP, the corresponding scorefiles |
52 will be used for that group. | 55 will be used for that group. |
53 The first match found is used, subsequent matching entries are ignored (to | 56 The first match found is used, subsequent matching entries are ignored (to |
54 use multiple matches, see gnus-score-file-multiple-match-alist). | 57 use multiple matches, see gnus-score-file-multiple-match-alist). |
55 | 58 |
56 These score files are loaded in addition to any files returned by | 59 These score files are loaded in addition to any files returned by |
57 gnus-score-find-score-files-function (which see).") | 60 gnus-score-find-score-files-function (which see)." |
58 | 61 :group 'gnus-score |
59 (defvar gnus-score-file-multiple-match-alist nil | 62 :type '(repeat (cons regexp (repeat file)))) |
60 "*Alist mapping regexps to lists of score files. | 63 |
64 (defcustom gnus-score-file-multiple-match-alist nil | |
65 "Alist mapping regexps to lists of score files. | |
61 Each element of this alist should be of the form | 66 Each element of this alist should be of the form |
62 (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... ) | 67 (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... ) |
63 | 68 |
64 If the name of a group is matched by REGEXP, the corresponding scorefiles | 69 If the name of a group is matched by REGEXP, the corresponding scorefiles |
65 will be used for that group. | 70 will be used for that group. |
66 If multiple REGEXPs match a group, the score files corresponding to each | 71 If multiple REGEXPs match a group, the score files corresponding to each |
67 match will be used (for only one match to be used, see | 72 match will be used (for only one match to be used, see |
68 gnus-score-file-single-match-alist). | 73 gnus-score-file-single-match-alist). |
69 | 74 |
70 These score files are loaded in addition to any files returned by | 75 These score files are loaded in addition to any files returned by |
71 gnus-score-find-score-files-function (which see).") | 76 gnus-score-find-score-files-function (which see)." |
72 | 77 :group 'gnus-score |
73 (defvar gnus-score-file-suffix "SCORE" | 78 :type '(repeat (cons regexp (repeat file)))) |
74 "*Suffix of the score files.") | 79 |
75 | 80 (defcustom gnus-score-file-suffix "SCORE" |
76 (defvar gnus-adaptive-file-suffix "ADAPT" | 81 "Suffix of the score files." |
77 "*Suffix of the adaptive score files.") | 82 :group 'gnus-score |
78 | 83 :type 'string) |
79 (defvar gnus-score-find-score-files-function 'gnus-score-find-bnews | 84 |
80 "*Function used to find score files. | 85 (defcustom gnus-adaptive-file-suffix "ADAPT" |
86 "Suffix of the adaptive score files." | |
87 :group 'gnus-score | |
88 :type 'string) | |
89 | |
90 (defcustom gnus-score-find-score-files-function 'gnus-score-find-bnews | |
91 "Function used to find score files. | |
81 The function will be called with the group name as the argument, and | 92 The function will be called with the group name as the argument, and |
82 should return a list of score files to apply to that group. The score | 93 should return a list of score files to apply to that group. The score |
83 files do not actually have to exist. | 94 files do not actually have to exist. |
84 | 95 |
85 Predefined values are: | 96 Predefined values are: |
90 | 101 |
91 See the documentation to these functions for more information. | 102 See the documentation to these functions for more information. |
92 | 103 |
93 This variable can also be a list of functions to be called. Each | 104 This variable can also be a list of functions to be called. Each |
94 function should either return a list of score files, or a list of | 105 function should either return a list of score files, or a list of |
95 score alists.") | 106 score alists." |
96 | 107 :group 'gnus-score |
97 (defvar gnus-score-interactive-default-score 1000 | 108 :type '(radio (function-item gnus-score-find-single) |
98 "*Scoring commands will raise/lower the score with this number as the default.") | 109 (function-item gnus-score-find-hierarchical) |
99 | 110 (function-item gnus-score-find-bnews) |
100 (defvar gnus-score-expiry-days 7 | 111 (function :tag "Other"))) |
112 | |
113 (defcustom gnus-score-interactive-default-score 1000 | |
114 "*Scoring commands will raise/lower the score with this number as the default." | |
115 :group 'gnus-score | |
116 :type 'integer) | |
117 | |
118 (defcustom gnus-score-expiry-days 7 | |
101 "*Number of days before unused score file entries are expired. | 119 "*Number of days before unused score file entries are expired. |
102 If this variable is nil, no score file entries will be expired.") | 120 If this variable is nil, no score file entries will be expired." |
103 | 121 :group 'gnus-score |
104 (defvar gnus-update-score-entry-dates t | 122 :type '(choice (const :tag "never" nil) |
123 number)) | |
124 | |
125 (defcustom gnus-update-score-entry-dates t | |
105 "*In non-nil, update matching score entry dates. | 126 "*In non-nil, update matching score entry dates. |
106 If this variable is nil, then score entries that provide matches | 127 If this variable is nil, then score entries that provide matches |
107 will be expired along with non-matching score entries.") | 128 will be expired along with non-matching score entries." |
108 | 129 :group 'gnus-score |
109 (defvar gnus-orphan-score nil | 130 :type 'boolean) |
110 "*All orphans get this score added. Set in the score file.") | 131 |
111 | 132 (defcustom gnus-orphan-score nil |
112 (defvar gnus-default-adaptive-score-alist | 133 "*All orphans get this score added. Set in the score file." |
134 :group 'gnus-score | |
135 :type 'integer) | |
136 | |
137 (defcustom gnus-decay-scores nil | |
138 "*If non-nil, decay non-permanent scores." | |
139 :group 'gnus-score | |
140 :type 'boolean) | |
141 | |
142 (defcustom gnus-decay-score-function 'gnus-decay-score | |
143 "*Function called to decay a score. | |
144 It is called with one parameter -- the score to be decayed." | |
145 :group 'gnus-score | |
146 :type '(radio (function-item gnus-decay-score) | |
147 (function :tag "Other"))) | |
148 | |
149 (defcustom gnus-score-decay-constant 3 | |
150 "*Decay all \"small\" scores with this amount." | |
151 :group 'gnus-score | |
152 :type 'integer) | |
153 | |
154 (defcustom gnus-score-decay-scale .05 | |
155 "*Decay all \"big\" scores with this factor." | |
156 :group 'gnus-score | |
157 :type 'number) | |
158 | |
159 (defcustom gnus-home-score-file nil | |
160 "Variable to control where interactive score entries are to go. | |
161 It can be: | |
162 | |
163 * A string | |
164 This file file will be used as the home score file. | |
165 | |
166 * A function | |
167 The result of this function will be used as the home score file. | |
168 The function will be passed the name of the group as its | |
169 parameter. | |
170 | |
171 * A list | |
172 The elements in this list can be: | |
173 | |
174 * `(regexp file-name ...)' | |
175 If the `regexp' matches the group name, the first `file-name' will | |
176 will be used as the home score file. (Multiple filenames are | |
177 allowed so that one may use gnus-score-file-single-match-alist to | |
178 set this variable.) | |
179 | |
180 * A function. | |
181 If the function returns non-nil, the result will be used | |
182 as the home score file. The function will be passed the | |
183 name of the group as its parameter. | |
184 | |
185 * A string. Use the string as the home score file. | |
186 | |
187 The list will be traversed from the beginning towards the end looking | |
188 for matches." | |
189 :group 'gnus-score | |
190 :type '(choice string | |
191 (repeat (choice string | |
192 (cons regexp (repeat file)) | |
193 function)) | |
194 function)) | |
195 | |
196 (defcustom gnus-home-adapt-file nil | |
197 "Variable to control where new adaptive score entries are to go. | |
198 This variable allows the same syntax as `gnus-home-score-file'." | |
199 :group 'gnus-score | |
200 :type '(choice string | |
201 (repeat (choice string | |
202 (cons regexp (repeat file)) | |
203 function)) | |
204 function)) | |
205 | |
206 (defcustom gnus-default-adaptive-score-alist | |
113 '((gnus-kill-file-mark) | 207 '((gnus-kill-file-mark) |
114 (gnus-unread-mark) | 208 (gnus-unread-mark) |
115 (gnus-read-mark (from 3) (subject 30)) | 209 (gnus-read-mark (from 3) (subject 30)) |
116 (gnus-catchup-mark (subject -10)) | 210 (gnus-catchup-mark (subject -10)) |
117 (gnus-killed-mark (from -1) (subject -20)) | 211 (gnus-killed-mark (from -1) (subject -20)) |
118 (gnus-del-mark (from -2) (subject -15))) | 212 (gnus-del-mark (from -2) (subject -15))) |
119 "*Alist of marks and scores.") | 213 "Alist of marks and scores." |
120 | 214 :group 'gnus-score |
121 (defvar gnus-score-mimic-keymap nil | 215 :type '(repeat (cons (symbol :tag "Mark") |
122 "*Have the score entry functions pretend that they are a keymap.") | 216 (repeat (list (choice :tag "Header" |
123 | 217 (const from) |
124 (defvar gnus-score-exact-adapt-limit 10 | 218 (const subject) |
219 (symbol :tag "other")) | |
220 (integer :tag "Score")))))) | |
221 | |
222 (defcustom gnus-ignored-adaptive-words nil | |
223 "List of words to be ignored when doing adaptive word scoring." | |
224 :group 'gnus-score | |
225 :type '(repeat string)) | |
226 | |
227 (defcustom gnus-default-ignored-adaptive-words | |
228 '("a" "i" "the" "to" "of" "and" "in" "is" "it" "for" "that" "if" "you" | |
229 "this" "be" "on" "with" "not" "have" "are" "or" "as" "from" "can" | |
230 "but" "by" "at" "an" "will" "no" "all" "was" "do" "there" "my" "one" | |
231 "so" "we" "they" "what" "would" "any" "which" "about" "get" "your" | |
232 "use" "some" "me" "then" "name" "like" "out" "when" "up" "time" | |
233 "other" "more" "only" "just" "end" "also" "know" "how" "new" "should" | |
234 "been" "than" "them" "he" "who" "make" "may" "people" "these" "now" | |
235 "their" "here" "into" "first" "could" "way" "had" "see" "work" "well" | |
236 "were" "two" "very" "where" "while" "us" "because" "good" "same" | |
237 "even" "much" "most" "many" "such" "long" "his" "over" "last" "since" | |
238 "right" "before" "our" "without" "too" "those" "why" "must" "part" | |
239 "being" "current" "back" "still" "go" "point" "value" "each" "did" | |
240 "both" "true" "off" "say" "another" "state" "might" "under" "start" | |
241 "try" "re") | |
242 "Default list of words to be ignored when doing adaptive word scoring." | |
243 :group 'gnus-score | |
244 :type '(repeat string)) | |
245 | |
246 (defcustom gnus-default-adaptive-word-score-alist | |
247 `((,gnus-read-mark . 30) | |
248 (,gnus-catchup-mark . -10) | |
249 (,gnus-killed-mark . -20) | |
250 (,gnus-del-mark . -15)) | |
251 "Alist of marks and scores." | |
252 :group 'gnus-score | |
253 :type '(repeat (cons (character :tag "Mark") | |
254 (integer :tag "Score")))) | |
255 | |
256 (defcustom gnus-score-mimic-keymap nil | |
257 "*Have the score entry functions pretend that they are a keymap." | |
258 :group 'gnus-score | |
259 :type 'boolean) | |
260 | |
261 (defcustom gnus-score-exact-adapt-limit 10 | |
125 "*Number that says how long a match has to be before using substring matching. | 262 "*Number that says how long a match has to be before using substring matching. |
126 When doing adaptive scoring, one normally uses fuzzy or substring | 263 When doing adaptive scoring, one normally uses fuzzy or substring |
127 matching. However, if the header one matches is short, the possibility | 264 matching. However, if the header one matches is short, the possibility |
128 for false positives is great, so if the length of the match is less | 265 for false positives is great, so if the length of the match is less |
129 than this variable, exact matching will be used. | 266 than this variable, exact matching will be used. |
130 | 267 |
131 If this variable is nil, exact matching will always be used.") | 268 If this variable is nil, exact matching will always be used." |
132 | 269 :group 'gnus-score |
133 (defvar gnus-score-uncacheable-files "ADAPT$" | 270 :type '(choice (const nil) integer)) |
134 "*All score files that match this regexp will not be cached.") | 271 |
135 | 272 (defcustom gnus-score-uncacheable-files "ADAPT$" |
136 (defvar gnus-score-default-header nil | 273 "All score files that match this regexp will not be cached." |
274 :group 'gnus-score | |
275 :type 'regexp) | |
276 | |
277 (defcustom gnus-score-default-header nil | |
137 "Default header when entering new scores. | 278 "Default header when entering new scores. |
138 | 279 |
139 Should be one of the following symbols. | 280 Should be one of the following symbols. |
140 | 281 |
141 a: from | 282 a: from |
147 x: xref | 288 x: xref |
148 l: lines | 289 l: lines |
149 d: date | 290 d: date |
150 f: followup | 291 f: followup |
151 | 292 |
152 If nil, the user will be asked for a header.") | 293 If nil, the user will be asked for a header." |
153 | 294 :group 'gnus-score |
154 (defvar gnus-score-default-type nil | 295 :type '(choice (const :tag "from" a) |
296 (const :tag "subject" s) | |
297 (const :tag "body" b) | |
298 (const :tag "head" h) | |
299 (const :tag "message-id" i) | |
300 (const :tag "references" t) | |
301 (const :tag "xref" x) | |
302 (const :tag "lines" l) | |
303 (const :tag "date" d) | |
304 (const :tag "followup" f))) | |
305 | |
306 (defcustom gnus-score-default-type nil | |
155 "Default match type when entering new scores. | 307 "Default match type when entering new scores. |
156 | 308 |
157 Should be one of the following symbols. | 309 Should be one of the following symbols. |
158 | 310 |
159 s: substring | 311 s: substring |
165 n: this date | 317 n: this date |
166 <: less than number | 318 <: less than number |
167 >: greater than number | 319 >: greater than number |
168 =: equal to number | 320 =: equal to number |
169 | 321 |
170 If nil, the user will be asked for a match type.") | 322 If nil, the user will be asked for a match type." |
171 | 323 :group 'gnus-score |
172 (defvar gnus-score-default-fold nil | 324 :type '(choice (const :tag "substring" s) |
173 "Use case folding for new score file entries iff not nil.") | 325 (const :tag "exact string" e) |
174 | 326 (const :tag "fuzzy string" f) |
175 (defvar gnus-score-default-duration nil | 327 (const :tag "regexp string" r) |
328 (const :tag "before date" b) | |
329 (const :tag "at date" a) | |
330 (const :tag "this date" n) | |
331 (const :tag "less than number" <) | |
332 (const :tag "greater than number" >) | |
333 (const :tag "equal than number" =))) | |
334 | |
335 (defcustom gnus-score-default-fold nil | |
336 "Use case folding for new score file entries iff not nil." | |
337 :group 'gnus-score | |
338 :type 'boolean) | |
339 | |
340 (defcustom gnus-score-default-duration nil | |
176 "Default duration of effect when entering new scores. | 341 "Default duration of effect when entering new scores. |
177 | 342 |
178 Should be one of the following symbols. | 343 Should be one of the following symbols. |
179 | 344 |
180 t: temporary | 345 t: temporary |
181 p: permanent | 346 p: permanent |
182 i: immediate | 347 i: immediate |
183 | 348 |
184 If nil, the user will be asked for a duration.") | 349 If nil, the user will be asked for a duration." |
185 | 350 :group 'gnus-score |
186 (defvar gnus-score-after-write-file-function nil | 351 :type '(choice (const :tag "temporary" t) |
187 "*Function called with the name of the score file just written to disk.") | 352 (const :tag "permanent" p) |
353 (const :tag "immediate" i))) | |
354 | |
355 (defcustom gnus-score-after-write-file-function nil | |
356 "Function called with the name of the score file just written to disk." | |
357 :group 'gnus-score | |
358 :type 'function) | |
188 | 359 |
189 | 360 |
190 | 361 |
191 ;; Internal variables. | 362 ;; Internal variables. |
192 | 363 |
364 (defvar gnus-adaptive-word-syntax-table | |
365 (let ((table (copy-syntax-table (standard-syntax-table))) | |
366 (numbers '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))) | |
367 (while numbers | |
368 (modify-syntax-entry (pop numbers) " " table)) | |
369 (modify-syntax-entry ?' "w" table) | |
370 table) | |
371 "Syntax table used when doing adaptive word scoring.") | |
372 | |
373 (defvar gnus-scores-exclude-files nil) | |
193 (defvar gnus-internal-global-score-files nil) | 374 (defvar gnus-internal-global-score-files nil) |
194 (defvar gnus-score-file-list nil) | 375 (defvar gnus-score-file-list nil) |
195 | 376 |
196 (defvar gnus-short-name-score-file-cache nil) | 377 (defvar gnus-short-name-score-file-cache nil) |
197 | 378 |
198 (defvar gnus-score-help-winconf nil) | 379 (defvar gnus-score-help-winconf nil) |
199 (defvar gnus-adaptive-score-alist gnus-default-adaptive-score-alist) | 380 (defvar gnus-adaptive-score-alist gnus-default-adaptive-score-alist) |
381 (defvar gnus-adaptive-word-score-alist gnus-default-adaptive-word-score-alist) | |
200 (defvar gnus-score-trace nil) | 382 (defvar gnus-score-trace nil) |
201 (defvar gnus-score-edit-buffer nil) | 383 (defvar gnus-score-edit-buffer nil) |
202 | 384 |
203 (defvar gnus-score-alist nil | 385 (defvar gnus-score-alist nil |
204 "Alist containing score information. | 386 "Alist containing score information. |
208 mark: Automatically mark articles below this. | 390 mark: Automatically mark articles below this. |
209 expunge: Automatically expunge articles below this. | 391 expunge: Automatically expunge articles below this. |
210 files: List of other score files to load when loading this one. | 392 files: List of other score files to load when loading this one. |
211 eval: Sexp to be evaluated when the score file is loaded. | 393 eval: Sexp to be evaluated when the score file is loaded. |
212 | 394 |
213 String entries have the form (HEADER (MATCH TYPE SCORE DATE) ...) | 395 String entries have the form (HEADER (MATCH TYPE SCORE DATE) ...) |
214 where HEADER is the header being scored, MATCH is the string we are | 396 where HEADER is the header being scored, MATCH is the string we are |
215 looking for, TYPE is a flag indicating whether it should use regexp or | 397 looking for, TYPE is a flag indicating whether it should use regexp or |
216 substring matching, SCORE is the score to add and DATE is the date | 398 substring matching, SCORE is the score to add and DATE is the date |
217 of the last successful match.") | 399 of the last successful match.") |
218 | 400 |
225 ;; Name to index alist. | 407 ;; Name to index alist. |
226 '(("number" 0 gnus-score-integer) | 408 '(("number" 0 gnus-score-integer) |
227 ("subject" 1 gnus-score-string) | 409 ("subject" 1 gnus-score-string) |
228 ("from" 2 gnus-score-string) | 410 ("from" 2 gnus-score-string) |
229 ("date" 3 gnus-score-date) | 411 ("date" 3 gnus-score-date) |
230 ("message-id" 4 gnus-score-string) | 412 ("message-id" 4 gnus-score-string) |
231 ("references" 5 gnus-score-string) | 413 ("references" 5 gnus-score-string) |
232 ("chars" 6 gnus-score-integer) | 414 ("chars" 6 gnus-score-integer) |
233 ("lines" 7 gnus-score-integer) | 415 ("lines" 7 gnus-score-integer) |
234 ("xref" 8 gnus-score-string) | 416 ("xref" 8 gnus-score-string) |
235 ("head" -1 gnus-score-body) | 417 ("head" -1 gnus-score-body) |
236 ("body" -1 gnus-score-body) | 418 ("body" -1 gnus-score-body) |
237 ("all" -1 gnus-score-body) | 419 ("all" -1 gnus-score-body) |
238 ("followup" 2 gnus-score-followup) | 420 ("followup" 2 gnus-score-followup) |
239 ("thread" 5 gnus-score-thread))) | 421 ("thread" 5 gnus-score-thread))) |
240 | 422 |
241 (eval-and-compile | |
242 (autoload 'gnus-uu-ctl-map "gnus-uu" nil nil 'keymap)) | |
243 | |
244 ;;; Summary mode score maps. | 423 ;;; Summary mode score maps. |
245 | 424 |
246 (gnus-define-keys | 425 (gnus-define-keys (gnus-summary-score-map "V" gnus-summary-mode-map) |
247 (gnus-summary-score-map "V" gnus-summary-mode-map) | 426 "s" gnus-summary-set-score |
248 "s" gnus-summary-set-score | 427 "a" gnus-summary-score-entry |
249 "a" gnus-summary-score-entry | 428 "S" gnus-summary-current-score |
250 "S" gnus-summary-current-score | 429 "c" gnus-score-change-score-file |
251 "c" gnus-score-change-score-file | 430 "C" gnus-score-customize |
252 "m" gnus-score-set-mark-below | 431 "m" gnus-score-set-mark-below |
253 "x" gnus-score-set-expunge-below | 432 "x" gnus-score-set-expunge-below |
254 "R" gnus-summary-rescore | 433 "R" gnus-summary-rescore |
255 "e" gnus-score-edit-current-scores | 434 "e" gnus-score-edit-current-scores |
256 "f" gnus-score-edit-file | 435 "f" gnus-score-edit-file |
257 "F" gnus-score-flush-cache | 436 "F" gnus-score-flush-cache |
258 "t" gnus-score-find-trace | 437 "t" gnus-score-find-trace |
259 "C" gnus-score-customize) | 438 "w" gnus-score-find-favourite-words) |
260 | 439 |
261 ;; Summary score file commands | 440 ;; Summary score file commands |
262 | 441 |
263 ;; Much modification of the kill (ahem, score) code and lots of the | 442 ;; Much modification of the kill (ahem, score) code and lots of the |
264 ;; functions are written by Per Abrahamsen <amanda@iesd.auc.dk>. | 443 ;; functions are written by Per Abrahamsen <amanda@iesd.auc.dk>. |
269 permanence, and the string to be used. The numerical prefix will be | 448 permanence, and the string to be used. The numerical prefix will be |
270 used as score." | 449 used as score." |
271 (interactive "P") | 450 (interactive "P") |
272 (gnus-summary-increase-score (- (gnus-score-default score)))) | 451 (gnus-summary-increase-score (- (gnus-score-default score)))) |
273 | 452 |
274 (defvar gnus-score-default-header nil | |
275 "*The default header to score on when entering a score rule interactively.") | |
276 | |
277 (defvar gnus-score-default-type nil | |
278 "*The default score type to use when entering a score rule interactively.") | |
279 | |
280 (defvar gnus-score-default-duration nil | |
281 "*The default score duration to use on when entering a score rule interactively.") | |
282 | |
283 (defun gnus-score-kill-help-buffer () | 453 (defun gnus-score-kill-help-buffer () |
284 (when (get-buffer "*Score Help*") | 454 (when (get-buffer "*Score Help*") |
285 (kill-buffer "*Score Help*") | 455 (kill-buffer "*Score Help*") |
286 (and gnus-score-help-winconf | 456 (when gnus-score-help-winconf |
287 (set-window-configuration gnus-score-help-winconf)))) | 457 (set-window-configuration gnus-score-help-winconf)))) |
288 | 458 |
289 (defun gnus-summary-increase-score (&optional score) | 459 (defun gnus-summary-increase-score (&optional score) |
290 "Make a score entry based on the current article. | 460 "Make a score entry based on the current article. |
291 The user will be prompted for header to score on, match type, | 461 The user will be prompted for header to score on, match type, |
292 permanence, and the string to be used. The numerical prefix will be | 462 permanence, and the string to be used. The numerical prefix will be |
312 '((?s s "substring" string) | 482 '((?s s "substring" string) |
313 (?e e "exact string" string) | 483 (?e e "exact string" string) |
314 (?f f "fuzzy string" string) | 484 (?f f "fuzzy string" string) |
315 (?r r "regexp string" string) | 485 (?r r "regexp string" string) |
316 (?z s "substring" body-string) | 486 (?z s "substring" body-string) |
317 (?p s "regexp string" body-string) | 487 (?p r "regexp string" body-string) |
318 (?b before "before date" date) | 488 (?b before "before date" date) |
319 (?a at "at date" date) | 489 (?a at "at date" date) |
320 (?n now "this date" date) | 490 (?n now "this date" date) |
321 (?< < "less than number" number) | 491 (?< < "less than number" number) |
322 (?> > "greater than number" number) | 492 (?> > "greater than number" number) |
323 (?= = "equal to number" number))) | 493 (?= = "equal to number" number))) |
324 (char-to-perm | 494 (char-to-perm |
325 (list (list ?t (current-time-string) "temporary") | 495 (list (list ?t (current-time-string) "temporary") |
326 '(?p perm "permanent") '(?i now "immediate"))) | 496 '(?p perm "permanent") '(?i now "immediate"))) |
327 (mimic gnus-score-mimic-keymap) | 497 (mimic gnus-score-mimic-keymap) |
328 (hchar (and gnus-score-default-header | 498 (hchar (and gnus-score-default-header |
329 (aref (symbol-name gnus-score-default-header) 0))) | 499 (aref (symbol-name gnus-score-default-header) 0))) |
330 (tchar (and gnus-score-default-type | 500 (tchar (and gnus-score-default-type |
353 (gnus-score-kill-help-buffer) | 523 (gnus-score-kill-help-buffer) |
354 (unless (setq entry (assq (downcase hchar) char-to-header)) | 524 (unless (setq entry (assq (downcase hchar) char-to-header)) |
355 (if mimic (error "%c %c" prefix hchar) (error ""))) | 525 (if mimic (error "%c %c" prefix hchar) (error ""))) |
356 | 526 |
357 (when (/= (downcase hchar) hchar) | 527 (when (/= (downcase hchar) hchar) |
358 ;; This was a majuscle, so we end reading and set the defaults. | 528 ;; This was a majuscule, so we end reading and set the defaults. |
359 (if mimic (message "%c %c" prefix hchar) (message "")) | 529 (if mimic (message "%c %c" prefix hchar) (message "")) |
360 (setq tchar (or tchar ?s) | 530 (setq tchar (or tchar ?s) |
361 pchar (or pchar ?t))) | 531 pchar (or pchar ?t))) |
362 | 532 |
363 ;; We continue reading - the type. | 533 ;; We continue reading - the type. |
366 (progn | 536 (progn |
367 (sit-for 1) (message "%c %c-" prefix hchar)) | 537 (sit-for 1) (message "%c %c-" prefix hchar)) |
368 (message "%s header '%s' with match type (%s?): " | 538 (message "%s header '%s' with match type (%s?): " |
369 (if increase "Increase" "Lower") | 539 (if increase "Increase" "Lower") |
370 (nth 1 entry) | 540 (nth 1 entry) |
371 (mapconcat (lambda (s) | 541 (mapconcat (lambda (s) |
372 (if (eq (nth 4 entry) | 542 (if (eq (nth 4 entry) |
373 (nth 3 s)) | 543 (nth 3 s)) |
374 (char-to-string (car s)) | 544 (char-to-string (car s)) |
375 "")) | 545 "")) |
376 char-to-type ""))) | 546 char-to-type ""))) |
377 (setq tchar (read-char)) | 547 (setq tchar (read-char)) |
378 (when (or (= tchar ??) (= tchar ?\C-h)) | 548 (when (or (= tchar ??) (= tchar ?\C-h)) |
379 (setq tchar nil) | 549 (setq tchar nil) |
380 (gnus-score-insert-help | 550 (gnus-score-insert-help |
381 "Match type" | 551 "Match type" |
382 (delq nil | 552 (delq nil |
383 (mapcar (lambda (s) | 553 (mapcar (lambda (s) |
384 (if (eq (nth 4 entry) | 554 (if (eq (nth 4 entry) |
385 (nth 3 s)) | 555 (nth 3 s)) |
386 s nil)) | 556 s nil)) |
387 char-to-type )) | 557 char-to-type)) |
388 2))) | 558 2))) |
389 | 559 |
390 (gnus-score-kill-help-buffer) | 560 (gnus-score-kill-help-buffer) |
391 (unless (setq type (nth 1 (assq (downcase tchar) char-to-type))) | 561 (unless (setq type (nth 1 (assq (downcase tchar) char-to-type))) |
392 (if mimic (error "%c %c" prefix hchar) (error ""))) | 562 (if mimic (error "%c %c" prefix hchar) (error ""))) |
393 | 563 |
394 (when (/= (downcase tchar) tchar) | 564 (when (/= (downcase tchar) tchar) |
395 ;; It was a majuscle, so we end reading and use the default. | 565 ;; It was a majuscule, so we end reading and use the default. |
396 (if mimic (message "%c %c %c" prefix hchar tchar) | 566 (if mimic (message "%c %c %c" prefix hchar tchar) |
397 (message "")) | 567 (message "")) |
398 (setq pchar (or pchar ?p))) | 568 (setq pchar (or pchar ?p))) |
399 | 569 |
400 ;; We continue reading. | 570 ;; We continue reading. |
412 | 582 |
413 (gnus-score-kill-help-buffer) | 583 (gnus-score-kill-help-buffer) |
414 (if mimic (message "%c %c %c" prefix hchar tchar pchar) | 584 (if mimic (message "%c %c %c" prefix hchar tchar pchar) |
415 (message "")) | 585 (message "")) |
416 (unless (setq temporary (cadr (assq pchar char-to-perm))) | 586 (unless (setq temporary (cadr (assq pchar char-to-perm))) |
587 ;; Deal with der(r)ided superannuated paradigms. | |
588 (when (and (eq (1+ prefix) 77) | |
589 (eq (+ hchar 12) 109) | |
590 (eq tchar 114) | |
591 (eq (- pchar 4) 111)) | |
592 (error "You rang?")) | |
417 (if mimic | 593 (if mimic |
418 (error "%c %c %c %c" prefix hchar tchar pchar) | 594 (error "%c %c %c %c" prefix hchar tchar pchar) |
419 (error "")))) | 595 (error "")))) |
420 ;; Always kill the score help buffer. | 596 ;; Always kill the score help buffer. |
421 (gnus-score-kill-help-buffer)) | 597 (gnus-score-kill-help-buffer)) |
437 | 613 |
438 (gnus-summary-score-entry | 614 (gnus-summary-score-entry |
439 (nth 1 entry) ; Header | 615 (nth 1 entry) ; Header |
440 match ; Match | 616 match ; Match |
441 type ; Type | 617 type ; Type |
442 (if (eq 's score) nil score) ; Score | 618 (if (eq score 's) nil score) ; Score |
443 (if (eq 'perm temporary) ; Temp | 619 (if (eq temporary 'perm) ; Temp |
444 nil | 620 nil |
445 temporary) | 621 temporary) |
446 (not (nth 3 entry))) ; Prompt | 622 (not (nth 3 entry))) ; Prompt |
447 )) | 623 )) |
448 | 624 |
449 (defun gnus-score-insert-help (string alist idx) | 625 (defun gnus-score-insert-help (string alist idx) |
450 (setq gnus-score-help-winconf (current-window-configuration)) | 626 (setq gnus-score-help-winconf (current-window-configuration)) |
459 (i 0) | 635 (i 0) |
460 n width pad format) | 636 n width pad format) |
461 ;; find the longest string to display | 637 ;; find the longest string to display |
462 (while list | 638 (while list |
463 (setq n (length (nth idx (car list)))) | 639 (setq n (length (nth idx (car list)))) |
464 (or (> max n) | 640 (unless (> max n) |
465 (setq max n)) | 641 (setq max n)) |
466 (setq list (cdr list))) | 642 (setq list (cdr list))) |
467 (setq max (+ max 4)) ; %c, `:', SPACE, a SPACE at end | 643 (setq max (+ max 4)) ; %c, `:', SPACE, a SPACE at end |
468 (setq n (/ (1- (window-width)) max)) ; items per line | 644 (setq n (/ (1- (window-width)) max)) ; items per line |
469 (setq width (/ (1- (window-width)) n)) ; width of each item | 645 (setq width (/ (1- (window-width)) n)) ; width of each item |
470 ;; insert `n' items, each in a field of width `width' | 646 ;; insert `n' items, each in a field of width `width' |
471 (while alist | 647 (while alist |
472 (if (< i n) | 648 (if (< i n) |
473 () | 649 () |
502 (error "No article on current line") | 678 (error "No article on current line") |
503 nil)))) | 679 nil)))) |
504 | 680 |
505 (defun gnus-newsgroup-score-alist () | 681 (defun gnus-newsgroup-score-alist () |
506 (or | 682 (or |
507 (let ((param-file (gnus-group-get-parameter | 683 (let ((param-file (gnus-group-find-parameter |
508 gnus-newsgroup-name 'score-file))) | 684 gnus-newsgroup-name 'score-file))) |
509 (when param-file | 685 (when param-file |
510 (gnus-score-load param-file))) | 686 (gnus-score-load param-file))) |
511 (gnus-score-load | 687 (gnus-score-load |
512 (gnus-score-file-name gnus-newsgroup-name))) | 688 (gnus-score-file-name gnus-newsgroup-name))) |
517 (cdr (assoc symbol | 693 (cdr (assoc symbol |
518 (or alist | 694 (or alist |
519 gnus-score-alist | 695 gnus-score-alist |
520 (gnus-newsgroup-score-alist))))) | 696 (gnus-newsgroup-score-alist))))) |
521 | 697 |
522 (defun gnus-summary-score-entry | 698 (defun gnus-summary-score-entry (header match type score date |
523 (header match type score date &optional prompt silent) | 699 &optional prompt silent) |
524 "Enter score file entry. | 700 "Enter score file entry. |
525 HEADER is the header being scored. | 701 HEADER is the header being scored. |
526 MATCH is the string we are looking for. | 702 MATCH is the string we are looking for. |
527 TYPE is the match type: substring, regexp, exact, fuzzy. | 703 TYPE is the match type: substring, regexp, exact, fuzzy. |
528 SCORE is the score to add. | 704 SCORE is the score to add. |
542 'now) | 718 'now) |
543 ((y-or-n-p "Expire kill? ") | 719 ((y-or-n-p "Expire kill? ") |
544 (current-time-string)) | 720 (current-time-string)) |
545 (t nil)))) | 721 (t nil)))) |
546 ;; Regexp is the default type. | 722 ;; Regexp is the default type. |
547 (if (eq type t) (setq type 'r)) | 723 (when (eq type t) |
724 (setq type 'r)) | |
548 ;; Simplify matches... | 725 ;; Simplify matches... |
549 (cond ((or (eq type 'r) (eq type 's) (eq type nil)) | 726 (cond ((or (eq type 'r) (eq type 's) (eq type nil)) |
550 (setq match (if match (gnus-simplify-subject-re match) ""))) | 727 (setq match (if match (gnus-simplify-subject-re match) ""))) |
551 ((eq type 'f) | 728 ((eq type 'f) |
552 (setq match (gnus-simplify-subject-fuzzy match)))) | 729 (setq match (gnus-simplify-subject-fuzzy match)))) |
553 (let ((score (gnus-score-default score)) | 730 (let ((score (gnus-score-default score)) |
554 (header (format "%s" (downcase header))) | 731 (header (format "%s" (downcase header))) |
555 new) | 732 new) |
556 (and prompt (setq match (read-string | 733 (when prompt |
557 (format "Match %s on %s, %s: " | 734 (setq match (read-string |
558 (cond ((eq date 'now) | 735 (format "Match %s on %s, %s: " |
559 "now") | 736 (cond ((eq date 'now) |
560 ((stringp date) | 737 "now") |
561 "temp") | 738 ((stringp date) |
562 (t "permanent")) | 739 "temp") |
563 header | 740 (t "permanent")) |
564 (if (< score 0) "lower" "raise")) | 741 header |
565 (if (numberp match) | 742 (if (< score 0) "lower" "raise")) |
566 (int-to-string match) | 743 (if (numberp match) |
567 match)))) | 744 (int-to-string match) |
745 match)))) | |
568 | 746 |
569 ;; Get rid of string props. | 747 ;; Get rid of string props. |
570 (setq match (format "%s" match)) | 748 (setq match (format "%s" match)) |
571 | 749 |
572 ;; If this is an integer comparison, we transform from string to int. | 750 ;; If this is an integer comparison, we transform from string to int. |
573 (and (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer) | 751 (when (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer) |
574 (setq match (string-to-int match))) | 752 (setq match (string-to-int match))) |
575 | 753 |
576 (unless (eq date 'now) | 754 (unless (eq date 'now) |
577 ;; Add the score entry to the score file. | 755 ;; Add the score entry to the score file. |
578 (when (= score gnus-score-interactive-default-score) | 756 (when (= score gnus-score-interactive-default-score) |
579 (setq score nil)) | 757 (setq score nil)) |
580 (let ((old (gnus-score-get header)) | 758 (let ((old (gnus-score-get header)) |
581 elem) | 759 elem) |
582 (setq new | 760 (setq new |
583 (cond | 761 (cond |
584 (type (list match score (and date (gnus-day-number date)) type)) | 762 (type |
763 (list match score | |
764 (and date (if (numberp date) date | |
765 (gnus-day-number date))) | |
766 type)) | |
585 (date (list match score (gnus-day-number date))) | 767 (date (list match score (gnus-day-number date))) |
586 (score (list match score)) | 768 (score (list match score)) |
587 (t (list match)))) | 769 (t (list match)))) |
588 ;; We see whether we can collapse some score entries. | 770 ;; We see whether we can collapse some score entries. |
589 ;; This isn't quite correct, because there may be more elements | 771 ;; This isn't quite correct, because there may be more elements |
590 ;; later on with the same key that have matching elems... Hm. | 772 ;; later on with the same key that have matching elems... Hm. |
591 (if (and old | 773 (if (and old |
592 (setq elem (assoc match old)) | 774 (setq elem (assoc match old)) |
593 (eq (nth 3 elem) (nth 3 new)) | 775 (eq (nth 3 elem) (nth 3 new)) |
594 (or (and (numberp (nth 2 elem)) (numberp (nth 2 new))) | 776 (or (and (numberp (nth 2 elem)) (numberp (nth 2 new))) |
595 (and (not (nth 2 elem)) (not (nth 2 new))))) | 777 (and (not (nth 2 elem)) (not (nth 2 new))))) |
596 ;; Yup, we just add this new score to the old elem. | 778 ;; Yup, we just add this new score to the old elem. |
597 (setcar (cdr elem) (+ (or (nth 1 elem) | 779 (setcar (cdr elem) (+ (or (nth 1 elem) |
598 gnus-score-interactive-default-score) | 780 gnus-score-interactive-default-score) |
599 (or (nth 1 new) | 781 (or (nth 1 new) |
600 gnus-score-interactive-default-score))) | 782 gnus-score-interactive-default-score))) |
601 ;; Nope, we have to add a new elem. | 783 ;; Nope, we have to add a new elem. |
602 (gnus-score-set header (if old (cons new old) (list new)))) | 784 (gnus-score-set header (if old (cons new old) (list new)))) |
615 | 797 |
616 (defun gnus-summary-score-effect (header match type score) | 798 (defun gnus-summary-score-effect (header match type score) |
617 "Simulate the effect of a score file entry. | 799 "Simulate the effect of a score file entry. |
618 HEADER is the header being scored. | 800 HEADER is the header being scored. |
619 MATCH is the string we are looking for. | 801 MATCH is the string we are looking for. |
620 TYPE is a flag indicating if it is a regexp or substring. | 802 TYPE is the score type. |
621 SCORE is the score to add." | 803 SCORE is the score to add." |
622 (interactive (list (completing-read "Header: " | 804 (interactive (list (completing-read "Header: " |
623 gnus-header-index | 805 gnus-header-index |
624 (lambda (x) (fboundp (nth 2 x))) | 806 (lambda (x) (fboundp (nth 2 x))) |
625 t) | 807 t) |
626 (read-string "Match: ") | 808 (read-string "Match: ") |
627 (y-or-n-p "Use regexp match? ") | 809 (y-or-n-p "Use regexp match? ") |
628 (prefix-numeric-value current-prefix-arg))) | 810 (prefix-numeric-value current-prefix-arg))) |
629 (save-excursion | 811 (save-excursion |
630 (or (and (stringp match) (> (length match) 0)) | 812 (unless (and (stringp match) (> (length match) 0)) |
631 (error "No match")) | 813 (error "No match")) |
632 (goto-char (point-min)) | 814 (goto-char (point-min)) |
633 (let ((regexp (cond ((eq type 'f) | 815 (let ((regexp (cond ((eq type 'f) |
634 (gnus-simplify-subject-fuzzy match)) | 816 (gnus-simplify-subject-fuzzy match)) |
635 ((eq type 'r) | 817 ((eq type 'r) |
636 match) | 818 match) |
637 ((eq type 'e) | 819 ((eq type 'e) |
638 (concat "\\`" (regexp-quote match) "\\'")) | 820 (concat "\\`" (regexp-quote match) "\\'")) |
639 (t | 821 (t |
640 (regexp-quote match))))) | 822 (regexp-quote match))))) |
641 (while (not (eobp)) | 823 (while (not (eobp)) |
642 (let ((content (gnus-summary-header header 'noerr)) | 824 (let ((content (gnus-summary-header header 'noerr)) |
643 (case-fold-search t)) | 825 (case-fold-search t)) |
644 (and content | 826 (and content |
645 (if (if (eq type 'f) | 827 (when (if (eq type 'f) |
646 (string-equal (gnus-simplify-subject-fuzzy content) | 828 (string-equal (gnus-simplify-subject-fuzzy content) |
647 regexp) | 829 regexp) |
648 (string-match regexp content)) | 830 (string-match regexp content)) |
649 (gnus-summary-raise-score score)))) | 831 (gnus-summary-raise-score score)))) |
650 (beginning-of-line 2))))) | 832 (beginning-of-line 2)))) |
833 (gnus-set-mode-line 'summary)) | |
651 | 834 |
652 (defun gnus-summary-score-crossposting (score date) | 835 (defun gnus-summary-score-crossposting (score date) |
653 ;; Enter score file entry for current crossposting. | 836 ;; Enter score file entry for current crossposting. |
654 ;; SCORE is the score to add. | 837 ;; SCORE is the score to add. |
655 ;; DATE is the expire date. | 838 ;; DATE is the expire date. |
656 (let ((xref (gnus-summary-header "xref")) | 839 (let ((xref (gnus-summary-header "xref")) |
657 (start 0) | 840 (start 0) |
658 group) | 841 group) |
659 (or xref (error "This article is not crossposted")) | 842 (unless xref |
843 (error "This article is not crossposted")) | |
660 (while (string-match " \\([^ \t]+\\):" xref start) | 844 (while (string-match " \\([^ \t]+\\):" xref start) |
661 (setq start (match-end 0)) | 845 (setq start (match-end 0)) |
662 (if (not (string= | 846 (when (not (string= |
663 (setq group | 847 (setq group |
664 (substring xref (match-beginning 1) (match-end 1))) | 848 (substring xref (match-beginning 1) (match-end 1))) |
665 gnus-newsgroup-name)) | 849 gnus-newsgroup-name)) |
666 (gnus-summary-score-entry | 850 (gnus-summary-score-entry |
667 "xref" (concat " " group ":") nil score date t))))) | 851 "xref" (concat " " group ":") nil score date t))))) |
668 | 852 |
669 | 853 |
670 ;;; | 854 ;;; |
671 ;;; Gnus Score Files | 855 ;;; Gnus Score Files |
672 ;;; | 856 ;;; |
722 (interactive "P") | 906 (interactive "P") |
723 (setq score (gnus-score-default score)) | 907 (setq score (gnus-score-default score)) |
724 (when (gnus-buffer-live-p gnus-summary-buffer) | 908 (when (gnus-buffer-live-p gnus-summary-buffer) |
725 (save-excursion | 909 (save-excursion |
726 (save-restriction | 910 (save-restriction |
727 (goto-char (point-min)) | 911 (message-narrow-to-headers) |
728 (let ((id (mail-fetch-field "message-id"))) | 912 (let ((id (mail-fetch-field "message-id"))) |
729 (when id | 913 (when id |
730 (set-buffer gnus-summary-buffer) | 914 (set-buffer gnus-summary-buffer) |
731 (gnus-summary-score-entry | 915 (gnus-summary-score-entry |
732 "references" (concat id "[ \t]*$") 'r | 916 "references" (concat id "[ \t]*$") 'r |
767 | 951 |
768 (defun gnus-summary-raise-score (n) | 952 (defun gnus-summary-raise-score (n) |
769 "Raise the score of the current article by N." | 953 "Raise the score of the current article by N." |
770 (interactive "p") | 954 (interactive "p") |
771 (gnus-set-global-variables) | 955 (gnus-set-global-variables) |
772 (gnus-summary-set-score (+ (gnus-summary-article-score) | 956 (gnus-summary-set-score (+ (gnus-summary-article-score) |
773 (or n gnus-score-interactive-default-score )))) | 957 (or n gnus-score-interactive-default-score )))) |
774 | 958 |
775 (defun gnus-summary-set-score (n) | 959 (defun gnus-summary-set-score (n) |
776 "Set the score of the current article to N." | 960 "Set the score of the current article to N." |
777 (interactive "p") | 961 (interactive "p") |
781 (let ((buffer-read-only nil)) | 965 (let ((buffer-read-only nil)) |
782 ;; Set score. | 966 ;; Set score. |
783 (gnus-summary-update-mark | 967 (gnus-summary-update-mark |
784 (if (= n (or gnus-summary-default-score 0)) ? | 968 (if (= n (or gnus-summary-default-score 0)) ? |
785 (if (< n (or gnus-summary-default-score 0)) | 969 (if (< n (or gnus-summary-default-score 0)) |
786 gnus-score-below-mark gnus-score-over-mark)) 'score)) | 970 gnus-score-below-mark gnus-score-over-mark)) |
971 'score)) | |
787 (let* ((article (gnus-summary-article-number)) | 972 (let* ((article (gnus-summary-article-number)) |
788 (score (assq article gnus-newsgroup-scored))) | 973 (score (assq article gnus-newsgroup-scored))) |
789 (if score (setcdr score n) | 974 (if score (setcdr score n) |
790 (setq gnus-newsgroup-scored | 975 (push (cons article n) gnus-newsgroup-scored))) |
791 (cons (cons article n) gnus-newsgroup-scored)))) | |
792 (gnus-summary-update-line))) | 976 (gnus-summary-update-line))) |
793 | 977 |
794 (defun gnus-summary-current-score () | 978 (defun gnus-summary-current-score () |
795 "Return the score of the current article." | 979 "Return the score of the current article." |
796 (interactive) | 980 (interactive) |
806 | 990 |
807 (defvar gnus-score-edit-exit-function) | 991 (defvar gnus-score-edit-exit-function) |
808 (defun gnus-score-edit-current-scores (file) | 992 (defun gnus-score-edit-current-scores (file) |
809 "Edit the current score alist." | 993 "Edit the current score alist." |
810 (interactive (list gnus-current-score-file)) | 994 (interactive (list gnus-current-score-file)) |
995 (gnus-set-global-variables) | |
811 (let ((winconf (current-window-configuration))) | 996 (let ((winconf (current-window-configuration))) |
812 (and (buffer-name gnus-summary-buffer) (gnus-score-save)) | 997 (when (buffer-name gnus-summary-buffer) |
998 (gnus-score-save)) | |
813 (gnus-make-directory (file-name-directory file)) | 999 (gnus-make-directory (file-name-directory file)) |
814 (setq gnus-score-edit-buffer (find-file-noselect file)) | 1000 (setq gnus-score-edit-buffer (find-file-noselect file)) |
815 (gnus-configure-windows 'edit-score) | 1001 (gnus-configure-windows 'edit-score) |
816 (gnus-score-mode) | 1002 (gnus-score-mode) |
817 (setq gnus-score-edit-exit-function 'gnus-score-edit-done) | 1003 (setq gnus-score-edit-exit-function 'gnus-score-edit-done) |
824 (defun gnus-score-edit-file (file) | 1010 (defun gnus-score-edit-file (file) |
825 "Edit a score file." | 1011 "Edit a score file." |
826 (interactive | 1012 (interactive |
827 (list (read-file-name "Edit score file: " gnus-kill-files-directory))) | 1013 (list (read-file-name "Edit score file: " gnus-kill-files-directory))) |
828 (gnus-make-directory (file-name-directory file)) | 1014 (gnus-make-directory (file-name-directory file)) |
829 (and (buffer-name gnus-summary-buffer) (gnus-score-save)) | 1015 (when (buffer-name gnus-summary-buffer) |
1016 (gnus-score-save)) | |
830 (let ((winconf (current-window-configuration))) | 1017 (let ((winconf (current-window-configuration))) |
831 (setq gnus-score-edit-buffer (find-file-noselect file)) | 1018 (setq gnus-score-edit-buffer (find-file-noselect file)) |
832 (gnus-configure-windows 'edit-score) | 1019 (gnus-configure-windows 'edit-score) |
833 (gnus-score-mode) | 1020 (gnus-score-mode) |
834 (setq gnus-score-edit-exit-function 'gnus-score-edit-done) | 1021 (setq gnus-score-edit-exit-function 'gnus-score-edit-done) |
841 (defun gnus-score-load-file (file) | 1028 (defun gnus-score-load-file (file) |
842 ;; Load score file FILE. Returns a list a retrieved score-alists. | 1029 ;; Load score file FILE. Returns a list a retrieved score-alists. |
843 (let* ((file (expand-file-name | 1030 (let* ((file (expand-file-name |
844 (or (and (string-match | 1031 (or (and (string-match |
845 (concat "^" (expand-file-name | 1032 (concat "^" (expand-file-name |
846 gnus-kill-files-directory)) | 1033 gnus-kill-files-directory)) |
847 (expand-file-name file)) | 1034 (expand-file-name file)) |
848 file) | 1035 file) |
849 (concat (file-name-as-directory gnus-kill-files-directory) | 1036 (concat (file-name-as-directory gnus-kill-files-directory) |
850 file)))) | 1037 file)))) |
851 (cached (assoc file gnus-score-cache)) | 1038 (cached (assoc file gnus-score-cache)) |
857 ;; We load the score file. | 1044 ;; We load the score file. |
858 (setq gnus-score-alist nil) | 1045 (setq gnus-score-alist nil) |
859 (setq alist (gnus-score-load-score-alist file)) | 1046 (setq alist (gnus-score-load-score-alist file)) |
860 ;; We add '(touched) to the alist to signify that it hasn't been | 1047 ;; We add '(touched) to the alist to signify that it hasn't been |
861 ;; touched (yet). | 1048 ;; touched (yet). |
862 (or (assq 'touched alist) (setq alist (cons (list 'touched nil) alist))) | 1049 (unless (assq 'touched alist) |
1050 (push (list 'touched nil) alist)) | |
863 ;; If it is a global score file, we make it read-only. | 1051 ;; If it is a global score file, we make it read-only. |
864 (and global | 1052 (and global |
865 (not (assq 'read-only alist)) | 1053 (not (assq 'read-only alist)) |
866 (setq alist (cons (list 'read-only t) alist))) | 1054 (push (list 'read-only t) alist)) |
867 (setq gnus-score-cache | 1055 (push (cons file alist) gnus-score-cache)) |
868 (cons (cons file alist) gnus-score-cache))) | |
869 (let ((a alist) | 1056 (let ((a alist) |
870 found) | 1057 found) |
871 (while a | 1058 (while a |
872 ;; Downcase all header names. | 1059 ;; Downcase all header names. |
873 (when (stringp (caar a)) | 1060 (when (stringp (caar a)) |
888 (adapt (gnus-score-get 'adapt alist)) | 1075 (adapt (gnus-score-get 'adapt alist)) |
889 (thread-mark-and-expunge | 1076 (thread-mark-and-expunge |
890 (car (gnus-score-get 'thread-mark-and-expunge alist))) | 1077 (car (gnus-score-get 'thread-mark-and-expunge alist))) |
891 (adapt-file (car (gnus-score-get 'adapt-file alist))) | 1078 (adapt-file (car (gnus-score-get 'adapt-file alist))) |
892 (local (gnus-score-get 'local alist)) | 1079 (local (gnus-score-get 'local alist)) |
1080 (decay (car (gnus-score-get 'decay alist))) | |
893 (eval (car (gnus-score-get 'eval alist)))) | 1081 (eval (car (gnus-score-get 'eval alist)))) |
1082 ;; Perform possible decays. | |
1083 (when (and gnus-decay-scores | |
1084 (gnus-decay-scores | |
1085 alist (or decay (gnus-time-to-day (current-time))))) | |
1086 (gnus-score-set 'touched '(t) alist) | |
1087 (gnus-score-set 'decay (list (gnus-time-to-day (current-time))))) | |
894 ;; We do not respect eval and files atoms from global score | 1088 ;; We do not respect eval and files atoms from global score |
895 ;; files. | 1089 ;; files. |
896 (and files (not global) | 1090 (and files (not global) |
897 (setq lists (apply 'append lists | 1091 (setq lists (apply 'append lists |
898 (mapcar (lambda (file) | 1092 (mapcar (lambda (file) |
899 (gnus-score-load-file file)) | 1093 (gnus-score-load-file file)) |
900 (if adapt-file (cons adapt-file files) | 1094 (if adapt-file (cons adapt-file files) |
901 files))))) | 1095 files))))) |
902 (and eval (not global) (eval eval)) | 1096 (and eval (not global) (eval eval)) |
903 ;; We then expand any exclude-file directives. | 1097 ;; We then expand any exclude-file directives. |
904 (setq gnus-scores-exclude-files | 1098 (setq gnus-scores-exclude-files |
905 (nconc | 1099 (nconc |
906 (mapcar | 1100 (mapcar |
907 (lambda (sfile) | 1101 (lambda (sfile) |
908 (expand-file-name sfile (file-name-directory file))) | 1102 (expand-file-name sfile (file-name-directory file))) |
909 exclude-files) gnus-scores-exclude-files)) | 1103 exclude-files) |
1104 gnus-scores-exclude-files)) | |
910 (if (not local) | 1105 (if (not local) |
911 () | 1106 () |
912 (save-excursion | 1107 (save-excursion |
913 (set-buffer gnus-summary-buffer) | 1108 (set-buffer gnus-summary-buffer) |
914 (while local | 1109 (while local |
916 (symbolp (caar local)) | 1111 (symbolp (caar local)) |
917 (progn | 1112 (progn |
918 (make-local-variable (caar local)) | 1113 (make-local-variable (caar local)) |
919 (set (caar local) (nth 1 (car local))))) | 1114 (set (caar local) (nth 1 (car local))))) |
920 (setq local (cdr local))))) | 1115 (setq local (cdr local))))) |
921 (if orphan (setq gnus-orphan-score orphan)) | 1116 (when orphan |
1117 (setq gnus-orphan-score orphan)) | |
922 (setq gnus-adaptive-score-alist | 1118 (setq gnus-adaptive-score-alist |
923 (cond ((equal adapt '(t)) | 1119 (cond ((equal adapt '(t)) |
924 (setq gnus-newsgroup-adaptive t) | 1120 (setq gnus-newsgroup-adaptive t) |
925 gnus-default-adaptive-score-alist) | 1121 gnus-default-adaptive-score-alist) |
926 ((equal adapt '(ignore)) | 1122 ((equal adapt '(ignore)) |
948 (let ((cache (assoc file gnus-score-cache))) | 1144 (let ((cache (assoc file gnus-score-cache))) |
949 (if cache | 1145 (if cache |
950 (setq gnus-score-alist (cdr cache)) | 1146 (setq gnus-score-alist (cdr cache)) |
951 (setq gnus-score-alist nil) | 1147 (setq gnus-score-alist nil) |
952 (gnus-score-load-score-alist file) | 1148 (gnus-score-load-score-alist file) |
953 (or gnus-score-alist | 1149 (unless gnus-score-alist |
954 (setq gnus-score-alist (copy-alist '((touched nil))))) | 1150 (setq gnus-score-alist (copy-alist '((touched nil))))) |
955 (setq gnus-score-cache | 1151 (push (cons file gnus-score-alist) gnus-score-cache)))) |
956 (cons (cons file gnus-score-alist) gnus-score-cache))))) | |
957 | 1152 |
958 (defun gnus-score-remove-from-cache (file) | 1153 (defun gnus-score-remove-from-cache (file) |
959 (setq gnus-score-cache | 1154 (setq gnus-score-cache |
960 (delq (assoc file gnus-score-cache) gnus-score-cache))) | 1155 (delq (assoc file gnus-score-cache) gnus-score-cache))) |
961 | 1156 |
962 (defun gnus-score-load-score-alist (file) | 1157 (defun gnus-score-load-score-alist (file) |
1158 "Read score FILE." | |
963 (let (alist) | 1159 (let (alist) |
964 (if (not (file-readable-p file)) | 1160 (if (not (file-readable-p file)) |
1161 ;; Couldn't read file. | |
965 (setq gnus-score-alist nil) | 1162 (setq gnus-score-alist nil) |
1163 ;; Read file. | |
966 (save-excursion | 1164 (save-excursion |
967 (gnus-set-work-buffer) | 1165 (gnus-set-work-buffer) |
968 (insert-file-contents file) | 1166 (insert-file-contents file) |
969 (goto-char (point-min)) | 1167 (goto-char (point-min)) |
970 ;; Only do the loading if the score file isn't empty. | 1168 ;; Only do the loading if the score file isn't empty. |
971 (when (save-excursion (re-search-forward "[()0-9a-zA-Z]" nil t)) | 1169 (when (save-excursion (re-search-forward "[()0-9a-zA-Z]" nil t)) |
972 (setq alist | 1170 (setq alist |
973 (condition-case () | 1171 (condition-case () |
974 (read (current-buffer)) | 1172 (read (current-buffer)) |
975 (error | 1173 (error |
976 (progn | 1174 (gnus-error 3.2 "Problem with score file %s" file)))))) |
977 (gnus-message 3 "Problem with score file %s" file) | |
978 (ding) | |
979 (sit-for 2) | |
980 nil)))))) | |
981 (if (eq (car alist) 'setq) | 1175 (if (eq (car alist) 'setq) |
982 ;; This is an old-style score file. | 1176 ;; This is an old-style score file. |
983 (setq gnus-score-alist (gnus-score-transform-old-to-new alist)) | 1177 (setq gnus-score-alist (gnus-score-transform-old-to-new alist)) |
984 (setq gnus-score-alist alist)) | 1178 (setq gnus-score-alist alist)) |
985 ;; Check the syntax of the score file. | 1179 ;; Check the syntax of the score file. |
1031 (progn | 1225 (progn |
1032 (ding) | 1226 (ding) |
1033 (gnus-message 3 err) | 1227 (gnus-message 3 err) |
1034 (sit-for 2) | 1228 (sit-for 2) |
1035 nil) | 1229 nil) |
1036 alist))))) | 1230 alist))))) |
1037 | 1231 |
1038 (defun gnus-score-transform-old-to-new (alist) | 1232 (defun gnus-score-transform-old-to-new (alist) |
1039 (let* ((alist (nth 2 alist)) | 1233 (let* ((alist (nth 2 alist)) |
1040 out entry) | 1234 out entry) |
1041 (if (eq (car alist) 'quote) | 1235 (when (eq (car alist) 'quote) |
1042 (setq alist (nth 1 alist))) | 1236 (setq alist (nth 1 alist))) |
1043 (while alist | 1237 (while alist |
1044 (setq entry (car alist)) | 1238 (setq entry (car alist)) |
1045 (if (stringp (car entry)) | 1239 (if (stringp (car entry)) |
1046 (let ((scor (cdr entry))) | 1240 (let ((scor (cdr entry))) |
1047 (setq out (cons entry out)) | 1241 (push entry out) |
1048 (while scor | 1242 (while scor |
1049 (setcar scor | 1243 (setcar scor |
1050 (list (caar scor) (nth 2 (car scor)) | 1244 (list (caar scor) (nth 2 (car scor)) |
1051 (and (nth 3 (car scor)) | 1245 (and (nth 3 (car scor)) |
1052 (gnus-day-number (nth 3 (car scor)))) | 1246 (gnus-day-number (nth 3 (car scor)))) |
1053 (if (nth 1 (car scor)) 'r 's))) | 1247 (if (nth 1 (car scor)) 'r 's))) |
1054 (setq scor (cdr scor)))) | 1248 (setq scor (cdr scor)))) |
1055 (setq out (cons (if (not (listp (cdr entry))) | 1249 (push (if (not (listp (cdr entry))) |
1056 (list (car entry) (cdr entry)) | 1250 (list (car entry) (cdr entry)) |
1057 entry) | 1251 entry) |
1058 out))) | 1252 out)) |
1059 (setq alist (cdr alist))) | 1253 (setq alist (cdr alist))) |
1060 (cons (list 'touched t) (nreverse out)))) | 1254 (cons (list 'touched t) (nreverse out)))) |
1061 | 1255 |
1062 (defun gnus-score-save () | 1256 (defun gnus-score-save () |
1063 ;; Save all score information. | 1257 ;; Save all score information. |
1064 (let ((cache gnus-score-cache)) | 1258 (let ((cache gnus-score-cache) |
1259 entry score file) | |
1065 (save-excursion | 1260 (save-excursion |
1066 (setq gnus-score-alist nil) | 1261 (setq gnus-score-alist nil) |
1067 (set-buffer (get-buffer-create "*Score*")) | 1262 (nnheader-set-temp-buffer " *Gnus Scores*") |
1068 (buffer-disable-undo (current-buffer)) | 1263 (while cache |
1069 (let (entry score file) | 1264 (current-buffer) |
1070 (while cache | 1265 (setq entry (pop cache) |
1071 (setq entry (car cache) | 1266 file (car entry) |
1072 cache (cdr cache) | 1267 score (cdr entry)) |
1073 file (car entry) | 1268 (if (or (not (equal (gnus-score-get 'touched score) '(t))) |
1074 score (cdr entry)) | 1269 (gnus-score-get 'read-only score) |
1075 (if (or (not (equal (gnus-score-get 'touched score) '(t))) | 1270 (and (file-exists-p file) |
1076 (gnus-score-get 'read-only score) | 1271 (not (file-writable-p file)))) |
1077 (and (file-exists-p file) | 1272 () |
1078 (not (file-writable-p file)))) | 1273 (setq score (setcdr entry (delq (assq 'touched score) score))) |
1079 () | 1274 (erase-buffer) |
1080 (setq score (setcdr entry (delq (assq 'touched score) score))) | 1275 (let (emacs-lisp-mode-hook) |
1081 (erase-buffer) | 1276 (if (string-match |
1082 (let (emacs-lisp-mode-hook) | 1277 (concat (regexp-quote gnus-adaptive-file-suffix) |
1083 (if (string-match | 1278 "$") |
1084 (concat (regexp-quote gnus-adaptive-file-suffix) | 1279 file) |
1085 "$") file) | 1280 ;; This is an adaptive score file, so we do not run |
1086 ;; This is an adaptive score file, so we do not run | 1281 ;; it through `pp'. These files can get huge, and |
1087 ;; it through `pp'. These files can get huge, and | 1282 ;; are not meant to be edited by human hands. |
1088 ;; are not meant to be edited by human hands. | 1283 (gnus-prin1 score) |
1089 (prin1 score (current-buffer)) | 1284 ;; This is a normal score file, so we print it very |
1090 ;; This is a normal score file, so we print it very | 1285 ;; prettily. |
1091 ;; prettily. | 1286 (pp score (current-buffer)))) |
1092 (pp score (current-buffer)))) | 1287 (gnus-make-directory (file-name-directory file)) |
1093 (if (not (gnus-make-directory (file-name-directory file))) | 1288 ;; If the score file is empty, we delete it. |
1094 () | 1289 (if (zerop (buffer-size)) |
1095 ;; If the score file is empty, we delete it. | 1290 (delete-file file) |
1096 (if (zerop (buffer-size)) | 1291 ;; There are scores, so we write the file. |
1097 (delete-file file) | 1292 (when (file-writable-p file) |
1098 ;; There are scores, so we write the file. | 1293 (gnus-write-buffer file) |
1099 (when (file-writable-p file) | 1294 (when gnus-score-after-write-file-function |
1100 (write-region (point-min) (point-max) file nil 'silent) | 1295 (funcall gnus-score-after-write-file-function file))))) |
1101 (and gnus-score-after-write-file-function | 1296 (and gnus-score-uncacheable-files |
1102 (funcall gnus-score-after-write-file-function file))))) | 1297 (string-match gnus-score-uncacheable-files file) |
1103 (and gnus-score-uncacheable-files | 1298 (gnus-score-remove-from-cache file))) |
1104 (string-match gnus-score-uncacheable-files file) | |
1105 (gnus-score-remove-from-cache file))))) | |
1106 (kill-buffer (current-buffer))))) | 1299 (kill-buffer (current-buffer))))) |
1107 | 1300 |
1108 (defun gnus-score-headers (score-files &optional trace) | 1301 (defun gnus-score-load-files (score-files) |
1109 ;; Score `gnus-newsgroup-headers'. | 1302 "Load all score files in SCORE-FILES." |
1110 (let (scores news) | 1303 ;; Load the score files. |
1111 ;; PLM: probably this is not the best place to clear orphan-score | 1304 (let (scores) |
1112 (setq gnus-orphan-score nil) | |
1113 (setq gnus-scores-articles nil) | |
1114 (setq gnus-scores-exclude-files nil) | |
1115 ;; Load the score files. | |
1116 (while score-files | 1305 (while score-files |
1117 (if (stringp (car score-files)) | 1306 (if (stringp (car score-files)) |
1118 ;; It is a string, which means that it's a score file name, | 1307 ;; It is a string, which means that it's a score file name, |
1119 ;; so we load the score file and add the score alist to | 1308 ;; so we load the score file and add the score alist to |
1120 ;; the list of alists. | 1309 ;; the list of alists. |
1129 (while s | 1318 (while s |
1130 (and (setq c (rassq (car s) gnus-score-cache)) | 1319 (and (setq c (rassq (car s) gnus-score-cache)) |
1131 (member (car c) gnus-scores-exclude-files) | 1320 (member (car c) gnus-scores-exclude-files) |
1132 (setq scores (delq (car s) scores))) | 1321 (setq scores (delq (car s) scores))) |
1133 (setq s (cdr s))))) | 1322 (setq s (cdr s))))) |
1323 scores)) | |
1324 | |
1325 (defun gnus-score-headers (score-files &optional trace) | |
1326 ;; Score `gnus-newsgroup-headers'. | |
1327 (let (scores news) | |
1328 ;; PLM: probably this is not the best place to clear orphan-score | |
1329 (setq gnus-orphan-score nil | |
1330 gnus-scores-articles nil | |
1331 gnus-scores-exclude-files nil | |
1332 scores (gnus-score-load-files score-files)) | |
1134 (setq news scores) | 1333 (setq news scores) |
1135 ;; Do the scoring. | 1334 ;; Do the scoring. |
1136 (while news | 1335 (while news |
1137 (setq scores news | 1336 (setq scores news |
1138 news nil) | 1337 news nil) |
1149 ;; Create articles, an alist of the form `(HEADER . SCORE)'. | 1348 ;; Create articles, an alist of the form `(HEADER . SCORE)'. |
1150 (while (setq header (pop headers)) | 1349 (while (setq header (pop headers)) |
1151 ;; WARNING: The assq makes the function O(N*S) while it could | 1350 ;; WARNING: The assq makes the function O(N*S) while it could |
1152 ;; be written as O(N+S), where N is (length gnus-newsgroup-headers) | 1351 ;; be written as O(N+S), where N is (length gnus-newsgroup-headers) |
1153 ;; and S is (length gnus-newsgroup-scored). | 1352 ;; and S is (length gnus-newsgroup-scored). |
1154 (or (assq (mail-header-number header) gnus-newsgroup-scored) | 1353 (unless (assq (mail-header-number header) gnus-newsgroup-scored) |
1155 (setq gnus-scores-articles ;Total of 2 * N cons-cells used. | 1354 (setq gnus-scores-articles ;Total of 2 * N cons-cells used. |
1156 (cons (cons header (or gnus-summary-default-score 0)) | 1355 (cons (cons header (or gnus-summary-default-score 0)) |
1157 gnus-scores-articles)))) | 1356 gnus-scores-articles)))) |
1158 | 1357 |
1159 (save-excursion | 1358 (save-excursion |
1160 (set-buffer (get-buffer-create "*Headers*")) | 1359 (set-buffer (get-buffer-create "*Headers*")) |
1161 (buffer-disable-undo (current-buffer)) | 1360 (buffer-disable-undo (current-buffer)) |
1162 | 1361 |
1183 ;; Remove the buffer. | 1382 ;; Remove the buffer. |
1184 (kill-buffer (current-buffer))) | 1383 (kill-buffer (current-buffer))) |
1185 | 1384 |
1186 ;; Add articles to `gnus-newsgroup-scored'. | 1385 ;; Add articles to `gnus-newsgroup-scored'. |
1187 (while gnus-scores-articles | 1386 (while gnus-scores-articles |
1188 (or (= gnus-summary-default-score (cdar gnus-scores-articles)) | 1387 (when (or (/= gnus-summary-default-score |
1189 (setq gnus-newsgroup-scored | 1388 (cdar gnus-scores-articles)) |
1190 (cons (cons (mail-header-number | 1389 gnus-save-score) |
1191 (caar gnus-scores-articles)) | 1390 (push (cons (mail-header-number (caar gnus-scores-articles)) |
1192 (cdar gnus-scores-articles)) | 1391 (cdar gnus-scores-articles)) |
1193 gnus-newsgroup-scored))) | 1392 gnus-newsgroup-scored)) |
1194 (setq gnus-scores-articles (cdr gnus-scores-articles))) | 1393 (setq gnus-scores-articles (cdr gnus-scores-articles))) |
1195 | 1394 |
1395 (let (score) | |
1396 (while (setq score (pop scores)) | |
1397 (while score | |
1398 (when (listp (caar score)) | |
1399 (gnus-score-advanced (car score) trace)) | |
1400 (pop score)))) | |
1401 | |
1196 (gnus-message 5 "Scoring...done")))))) | 1402 (gnus-message 5 "Scoring...done")))))) |
1197 | 1403 |
1198 | 1404 |
1199 (defun gnus-get-new-thread-ids (articles) | 1405 (defun gnus-get-new-thread-ids (articles) |
1200 (let ((index (nth 1 (assoc "message-id" gnus-header-index))) | 1406 (let ((index (nth 1 (assoc "message-id" gnus-header-index))) |
1203 (while articles | 1409 (while articles |
1204 (setq art (car articles) | 1410 (setq art (car articles) |
1205 this (aref (car art) index) | 1411 this (aref (car art) index) |
1206 tref (aref (car art) refind) | 1412 tref (aref (car art) refind) |
1207 articles (cdr articles)) | 1413 articles (cdr articles)) |
1208 (if (string-equal tref "") ;no references line | 1414 (when (string-equal tref "") ;no references line |
1209 (setq id-list (cons this id-list)))) | 1415 (push this id-list))) |
1210 id-list)) | 1416 id-list)) |
1211 | 1417 |
1212 ;; Orphan functions written by plm@atcmp.nl (Peter Mutsaers). | 1418 ;; Orphan functions written by plm@atcmp.nl (Peter Mutsaers). |
1213 (defun gnus-score-orphans (score) | 1419 (defun gnus-score-orphans (score) |
1214 (let ((new-thread-ids (gnus-get-new-thread-ids gnus-scores-articles)) | 1420 (let ((new-thread-ids (gnus-get-new-thread-ids gnus-scores-articles)) |
1222 (while articles | 1428 (while articles |
1223 (setq art (car articles) | 1429 (setq art (car articles) |
1224 this (aref (car art) gnus-score-index) | 1430 this (aref (car art) gnus-score-index) |
1225 articles (cdr articles)) | 1431 articles (cdr articles)) |
1226 ;;completely skip if this is empty (not a child, so not an orphan) | 1432 ;;completely skip if this is empty (not a child, so not an orphan) |
1227 (if (not (string= this "")) | 1433 (when (not (string= this "")) |
1228 (if (equal last this) | 1434 (if (equal last this) |
1229 ;; O(N*H) cons-cells used here, where H is the number of | 1435 ;; O(N*H) cons-cells used here, where H is the number of |
1230 ;; headers. | 1436 ;; headers. |
1231 (setq alike (cons art alike)) | 1437 (push art alike) |
1232 (if last | 1438 (when last |
1233 (progn | 1439 ;; Insert the line, with a text property on the |
1234 ;; Insert the line, with a text property on the | 1440 ;; terminating newline referring to the articles with |
1235 ;; terminating newline referring to the articles with | 1441 ;; this line. |
1236 ;; this line. | 1442 (insert last ?\n) |
1237 (insert last ?\n) | 1443 (put-text-property (1- (point)) (point) 'articles alike)) |
1238 (put-text-property (1- (point)) (point) 'articles alike))) | 1444 (setq alike (list art) |
1239 (setq alike (list art) | 1445 last this)))) |
1240 last this)))) | 1446 (when last ; Bwadr, duplicate code. |
1241 (and last ; Bwadr, duplicate code. | 1447 (insert last ?\n) |
1242 (progn | 1448 (put-text-property (1- (point)) (point) 'articles alike)) |
1243 (insert last ?\n) | |
1244 (put-text-property (1- (point)) (point) 'articles alike))) | |
1245 | 1449 |
1246 ;; PLM: now delete those lines that contain an entry from new-thread-ids | 1450 ;; PLM: now delete those lines that contain an entry from new-thread-ids |
1247 (while new-thread-ids | 1451 (while new-thread-ids |
1248 (setq this-id (car new-thread-ids) | 1452 (setq this-id (car new-thread-ids) |
1249 new-thread-ids (cdr new-thread-ids)) | 1453 new-thread-ids (cdr new-thread-ids)) |
1250 (goto-char (point-min)) | 1454 (goto-char (point-min)) |
1251 (while (search-forward this-id nil t) | 1455 (while (search-forward this-id nil t) |
1252 ;; found a match. remove this line | 1456 ;; found a match. remove this line |
1253 (beginning-of-line) | 1457 (beginning-of-line) |
1254 (kill-line 1))) | 1458 (kill-line 1))) |
1255 | 1459 |
1256 ;; now for each line: update its articles with score by moving to | 1460 ;; now for each line: update its articles with score by moving to |
1257 ;; every end-of-line in the buffer and read the articles property | 1461 ;; every end-of-line in the buffer and read the articles property |
1274 (while scores | 1478 (while scores |
1275 (setq alist (car scores) | 1479 (setq alist (car scores) |
1276 scores (cdr scores) | 1480 scores (cdr scores) |
1277 entries (assoc header alist)) | 1481 entries (assoc header alist)) |
1278 (while (cdr entries) ;First entry is the header index. | 1482 (while (cdr entries) ;First entry is the header index. |
1279 (let* ((rest (cdr entries)) | 1483 (let* ((rest (cdr entries)) |
1280 (kill (car rest)) | 1484 (kill (car rest)) |
1281 (match (nth 0 kill)) | 1485 (match (nth 0 kill)) |
1282 (type (or (nth 3 kill) '>)) | 1486 (type (or (nth 3 kill) '>)) |
1283 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 1487 (score (or (nth 1 kill) gnus-score-interactive-default-score)) |
1284 (date (nth 2 kill)) | 1488 (date (nth 2 kill)) |
1292 ;; `gnus-score-string' does to minimize searches and stuff, | 1496 ;; `gnus-score-string' does to minimize searches and stuff, |
1293 ;; I will assume that people generally will put so few | 1497 ;; I will assume that people generally will put so few |
1294 ;; matches on numbers that any cleverness will take more | 1498 ;; matches on numbers that any cleverness will take more |
1295 ;; time than one would gain. | 1499 ;; time than one would gain. |
1296 (while articles | 1500 (while articles |
1297 (and (funcall match-func | 1501 (when (funcall match-func |
1298 (or (aref (caar articles) gnus-score-index) 0) | 1502 (or (aref (caar articles) gnus-score-index) 0) |
1299 match) | 1503 match) |
1300 (progn | 1504 (when trace |
1301 (and trace (setq gnus-score-trace | 1505 (push (cons (car-safe (rassq alist gnus-score-cache)) kill) |
1302 (cons | 1506 gnus-score-trace)) |
1303 (cons | 1507 (setq found t) |
1304 (car-safe (rassq alist gnus-score-cache)) | 1508 (setcdr (car articles) (+ score (cdar articles)))) |
1305 kill) | |
1306 gnus-score-trace))) | |
1307 (setq found t) | |
1308 (setcdr (car articles) (+ score (cdar articles))))) | |
1309 (setq articles (cdr articles))) | 1509 (setq articles (cdr articles))) |
1310 ;; Update expire date | 1510 ;; Update expire date |
1311 (cond ((null date)) ;Permanent entry. | 1511 (cond ((null date)) ;Permanent entry. |
1312 ((and found gnus-update-score-entry-dates) ;Match, update date. | 1512 ((and found gnus-update-score-entry-dates) ;Match, update date. |
1313 (gnus-score-set 'touched '(t) alist) | 1513 (gnus-score-set 'touched '(t) alist) |
1319 (setq entries rest))))) | 1519 (setq entries rest))))) |
1320 nil) | 1520 nil) |
1321 | 1521 |
1322 (defun gnus-score-date (scores header now expire &optional trace) | 1522 (defun gnus-score-date (scores header now expire &optional trace) |
1323 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) | 1523 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) |
1324 entries alist) | 1524 entries alist match match-func article) |
1325 | 1525 |
1326 ;; Find matches. | 1526 ;; Find matches. |
1327 (while scores | 1527 (while scores |
1328 (setq alist (car scores) | 1528 (setq alist (car scores) |
1329 scores (cdr scores) | 1529 scores (cdr scores) |
1330 entries (assoc header alist)) | 1530 entries (assoc header alist)) |
1331 (while (cdr entries) ;First entry is the header index. | 1531 (while (cdr entries) ;First entry is the header index. |
1332 (let* ((rest (cdr entries)) | 1532 (let* ((rest (cdr entries)) |
1333 (kill (car rest)) | 1533 (kill (car rest)) |
1334 (match (timezone-make-date-sortable (nth 0 kill))) | |
1335 (type (or (nth 3 kill) 'before)) | 1534 (type (or (nth 3 kill) 'before)) |
1336 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 1535 (score (or (nth 1 kill) gnus-score-interactive-default-score)) |
1337 (date (nth 2 kill)) | 1536 (date (nth 2 kill)) |
1338 (found nil) | 1537 (found nil) |
1339 (match-func | |
1340 (cond ((eq type 'after) 'string<) | |
1341 ((eq type 'before) 'gnus-string>) | |
1342 ((eq type 'at) 'string=) | |
1343 (t (error "Illegal match type: %s" type)))) | |
1344 (articles gnus-scores-articles) | 1538 (articles gnus-scores-articles) |
1345 l) | 1539 l) |
1540 (cond | |
1541 ((eq type 'after) | |
1542 (setq match-func 'string< | |
1543 match (gnus-date-iso8601 (nth 0 kill)))) | |
1544 ((eq type 'before) | |
1545 (setq match-func 'gnus-string> | |
1546 match (gnus-date-iso8601 (nth 0 kill)))) | |
1547 ((eq type 'at) | |
1548 (setq match-func 'string= | |
1549 match (gnus-date-iso8601 (nth 0 kill)))) | |
1550 ((eq type 'regexp) | |
1551 (setq match-func 'string-match | |
1552 match (nth 0 kill))) | |
1553 (t (error "Illegal match type: %s" type))) | |
1346 ;; Instead of doing all the clever stuff that | 1554 ;; Instead of doing all the clever stuff that |
1347 ;; `gnus-score-string' does to minimize searches and stuff, | 1555 ;; `gnus-score-string' does to minimize searches and stuff, |
1348 ;; I will assume that people generally will put so few | 1556 ;; I will assume that people generally will put so few |
1349 ;; matches on numbers that any cleverness will take more | 1557 ;; matches on numbers that any cleverness will take more |
1350 ;; time than one would gain. | 1558 ;; time than one would gain. |
1351 (while articles | 1559 (while (setq article (pop articles)) |
1352 (and | 1560 (when (and |
1353 (setq l (aref (caar articles) gnus-score-index)) | 1561 (setq l (aref (car article) gnus-score-index)) |
1354 (funcall match-func match (timezone-make-date-sortable l)) | 1562 (funcall match-func match (gnus-date-iso8601 l))) |
1355 (progn | 1563 (when trace |
1356 (and trace (setq gnus-score-trace | 1564 (push (cons (car-safe (rassq alist gnus-score-cache)) kill) |
1357 (cons | 1565 gnus-score-trace)) |
1358 (cons | 1566 (setq found t) |
1359 (car-safe (rassq alist gnus-score-cache)) | 1567 (setcdr article (+ score (cdr article))))) |
1360 kill) | |
1361 gnus-score-trace))) | |
1362 (setq found t) | |
1363 (setcdr (car articles) (+ score (cdar articles))))) | |
1364 (setq articles (cdr articles))) | |
1365 ;; Update expire date | 1568 ;; Update expire date |
1366 (cond ((null date)) ;Permanent entry. | 1569 (cond ((null date)) ;Permanent entry. |
1367 ((and found gnus-update-score-entry-dates) ;Match, update date. | 1570 ((and found gnus-update-score-entry-dates) ;Match, update date. |
1368 (gnus-score-set 'touched '(t) alist) | 1571 (gnus-score-set 'touched '(t) alist) |
1369 (setcar (nthcdr 2 kill) now)) | 1572 (setcar (nthcdr 2 kill) now)) |
1370 ((and expire (< date expire)) ;Old entry, remove. | 1573 ((and expire (< date expire)) ;Old entry, remove. |
1371 (gnus-score-set 'touched '(t) alist) | 1574 (gnus-score-set 'touched '(t) alist) |
1372 (setcdr entries (cdr rest)) | 1575 (setcdr entries (cdr rest)) |
1373 (setq rest entries))) | 1576 (setq rest entries))) |
1374 (setq entries rest))))) | 1577 (setq entries rest))))) |
1375 nil) | 1578 nil) |
1376 | 1579 |
1377 (defun gnus-score-body (scores header now expire &optional trace) | 1580 (defun gnus-score-body (scores header now expire &optional trace) |
1378 (save-excursion | 1581 (save-excursion |
1379 (set-buffer nntp-server-buffer) | |
1380 (setq gnus-scores-articles | 1582 (setq gnus-scores-articles |
1381 (sort gnus-scores-articles | 1583 (sort gnus-scores-articles |
1382 (lambda (a1 a2) | 1584 (lambda (a1 a2) |
1383 (< (mail-header-number (car a1)) | 1585 (< (mail-header-number (car a1)) |
1384 (mail-header-number (car a2)))))) | 1586 (mail-header-number (car a2)))))) |
1587 (set-buffer nntp-server-buffer) | |
1385 (save-restriction | 1588 (save-restriction |
1386 (let* ((buffer-read-only nil) | 1589 (let* ((buffer-read-only nil) |
1387 (articles gnus-scores-articles) | 1590 (articles gnus-scores-articles) |
1388 (all-scores scores) | 1591 (all-scores scores) |
1389 (request-func (cond ((string= "head" header) | 1592 (request-func (cond ((string= "head" header) |
1391 ((string= "body" header) | 1594 ((string= "body" header) |
1392 'gnus-request-body) | 1595 'gnus-request-body) |
1393 (t 'gnus-request-article))) | 1596 (t 'gnus-request-article))) |
1394 entries alist ofunc article last) | 1597 entries alist ofunc article last) |
1395 (when articles | 1598 (when articles |
1396 (while (cdr articles) | 1599 (setq last (mail-header-number (caar (last articles)))) |
1397 (setq articles (cdr articles))) | |
1398 (setq last (mail-header-number (caar articles))) | |
1399 (setq articles gnus-scores-articles) | |
1400 ;; Not all backends support partial fetching. In that case, | 1600 ;; Not all backends support partial fetching. In that case, |
1401 ;; we just fetch the entire article. | 1601 ;; we just fetch the entire article. |
1402 (or (gnus-check-backend-function | 1602 (unless (gnus-check-backend-function |
1403 (and (string-match "^gnus-" (symbol-name request-func)) | 1603 (and (string-match "^gnus-" (symbol-name request-func)) |
1404 (intern (substring (symbol-name request-func) | 1604 (intern (substring (symbol-name request-func) |
1405 (match-end 0)))) | 1605 (match-end 0)))) |
1406 gnus-newsgroup-name) | 1606 gnus-newsgroup-name) |
1407 (progn | 1607 (setq ofunc request-func) |
1408 (setq ofunc request-func) | 1608 (setq request-func 'gnus-request-article)) |
1409 (setq request-func 'gnus-request-article))) | |
1410 (while articles | 1609 (while articles |
1411 (setq article (mail-header-number (caar articles))) | 1610 (setq article (mail-header-number (caar articles))) |
1412 (gnus-message 7 "Scoring on article %s of %s..." article last) | 1611 (gnus-message 7 "Scoring on article %s of %s..." article last) |
1413 (when (funcall request-func article gnus-newsgroup-name) | 1612 (when (funcall request-func article gnus-newsgroup-name) |
1414 (widen) | 1613 (widen) |
1415 (goto-char (point-min)) | 1614 (goto-char (point-min)) |
1416 ;; If just parts of the article is to be searched, but the | 1615 ;; If just parts of the article is to be searched, but the |
1417 ;; backend didn't support partial fetching, we just narrow | 1616 ;; backend didn't support partial fetching, we just narrow |
1418 ;; to the relevant parts. | 1617 ;; to the relevant parts. |
1419 (if ofunc | 1618 (when ofunc |
1420 (if (eq ofunc 'gnus-request-head) | 1619 (if (eq ofunc 'gnus-request-head) |
1421 (narrow-to-region | |
1422 (point) | |
1423 (or (search-forward "\n\n" nil t) (point-max))) | |
1424 (narrow-to-region | 1620 (narrow-to-region |
1425 (or (search-forward "\n\n" nil t) (point)) | 1621 (point) |
1426 (point-max)))) | 1622 (or (search-forward "\n\n" nil t) (point-max))) |
1623 (narrow-to-region | |
1624 (or (search-forward "\n\n" nil t) (point)) | |
1625 (point-max)))) | |
1427 (setq scores all-scores) | 1626 (setq scores all-scores) |
1428 ;; Find matches. | 1627 ;; Find matches. |
1429 (while scores | 1628 (while scores |
1430 (setq alist (car scores) | 1629 (setq alist (pop scores) |
1431 scores (cdr scores) | |
1432 entries (assoc header alist)) | 1630 entries (assoc header alist)) |
1433 (while (cdr entries) ;First entry is the header index. | 1631 (while (cdr entries) ;First entry is the header index. |
1434 (let* ((rest (cdr entries)) | 1632 (let* ((rest (cdr entries)) |
1435 (kill (car rest)) | 1633 (kill (car rest)) |
1436 (match (nth 0 kill)) | 1634 (match (nth 0 kill)) |
1437 (type (or (nth 3 kill) 's)) | 1635 (type (or (nth 3 kill) 's)) |
1438 (score (or (nth 1 kill) | 1636 (score (or (nth 1 kill) |
1439 gnus-score-interactive-default-score)) | 1637 gnus-score-interactive-default-score)) |
1440 (date (nth 2 kill)) | 1638 (date (nth 2 kill)) |
1441 (found nil) | 1639 (found nil) |
1442 (case-fold-search | 1640 (case-fold-search |
1443 (not (or (eq type 'R) (eq type 'S) | 1641 (not (or (eq type 'R) (eq type 'S) |
1450 (eq type 'string) (eq type 'String)) | 1648 (eq type 'string) (eq type 'String)) |
1451 'search-forward) | 1649 'search-forward) |
1452 (t | 1650 (t |
1453 (error "Illegal match type: %s" type))))) | 1651 (error "Illegal match type: %s" type))))) |
1454 (goto-char (point-min)) | 1652 (goto-char (point-min)) |
1455 (if (funcall search-func match nil t) | 1653 (when (funcall search-func match nil t) |
1456 ;; Found a match, update scores. | 1654 ;; Found a match, update scores. |
1457 (progn | 1655 (setcdr (car articles) (+ score (cdar articles))) |
1458 (setcdr (car articles) (+ score (cdar articles))) | 1656 (setq found t) |
1459 (setq found t) | 1657 (when trace |
1460 (and trace (setq gnus-score-trace | 1658 (push |
1461 (cons | 1659 (cons (car-safe (rassq alist gnus-score-cache)) kill) |
1462 (cons | 1660 gnus-score-trace))) |
1463 (car-safe | |
1464 (rassq alist gnus-score-cache)) | |
1465 kill) | |
1466 gnus-score-trace))))) | |
1467 ;; Update expire date | 1661 ;; Update expire date |
1468 (cond | 1662 (unless trace |
1469 ((null date)) ;Permanent entry. | 1663 (cond |
1470 ((and found gnus-update-score-entry-dates) ;Match, update date. | 1664 ((null date)) ;Permanent entry. |
1471 (gnus-score-set 'touched '(t) alist) | 1665 ((and found gnus-update-score-entry-dates) |
1472 (setcar (nthcdr 2 kill) now)) | 1666 ;; Match, update date. |
1473 ((and expire (< date expire)) ;Old entry, remove. | 1667 (gnus-score-set 'touched '(t) alist) |
1474 (gnus-score-set 'touched '(t) alist) | 1668 (setcar (nthcdr 2 kill) now)) |
1475 (setcdr entries (cdr rest)) | 1669 ((and expire (< date expire)) ;Old entry, remove. |
1476 (setq rest entries))) | 1670 (gnus-score-set 'touched '(t) alist) |
1671 (setcdr entries (cdr rest)) | |
1672 (setq rest entries)))) | |
1477 (setq entries rest))))) | 1673 (setq entries rest))))) |
1478 (setq articles (cdr articles))))))) | 1674 (setq articles (cdr articles))))))) |
1479 nil) | 1675 nil) |
1676 | |
1677 (defun gnus-score-thread (scores header now expire &optional trace) | |
1678 (gnus-score-followup scores header now expire trace t)) | |
1480 | 1679 |
1481 (defun gnus-score-followup (scores header now expire &optional trace thread) | 1680 (defun gnus-score-followup (scores header now expire &optional trace thread) |
1482 ;; Insert the unique article headers in the buffer. | 1681 ;; Insert the unique article headers in the buffer. |
1483 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) | 1682 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) |
1484 (current-score-file gnus-current-score-file) | 1683 (current-score-file gnus-current-score-file) |
1503 (while articles | 1702 (while articles |
1504 (setq art (car articles) | 1703 (setq art (car articles) |
1505 this (aref (car art) gnus-score-index) | 1704 this (aref (car art) gnus-score-index) |
1506 articles (cdr articles)) | 1705 articles (cdr articles)) |
1507 (if (equal last this) | 1706 (if (equal last this) |
1508 (setq alike (cons art alike)) | 1707 (push art alike) |
1509 (if last | 1708 (when last |
1510 (progn | 1709 (insert last ?\n) |
1511 (insert last ?\n) | 1710 (put-text-property (1- (point)) (point) 'articles alike)) |
1512 (put-text-property (1- (point)) (point) 'articles alike))) | |
1513 (setq alike (list art) | 1711 (setq alike (list art) |
1514 last this))) | 1712 last this))) |
1515 (and last ; Bwadr, duplicate code. | 1713 (when last ; Bwadr, duplicate code. |
1516 (progn | 1714 (insert last ?\n) |
1517 (insert last ?\n) | 1715 (put-text-property (1- (point)) (point) 'articles alike)) |
1518 (put-text-property (1- (point)) (point) 'articles alike))) | |
1519 | 1716 |
1520 ;; Find matches. | 1717 ;; Find matches. |
1521 (while scores | 1718 (while scores |
1522 (setq alist (car scores) | 1719 (setq alist (car scores) |
1523 scores (cdr scores) | 1720 scores (cdr scores) |
1524 entries (assoc header alist)) | 1721 entries (assoc header alist)) |
1525 (while (cdr entries) ;First entry is the header index. | 1722 (while (cdr entries) ;First entry is the header index. |
1526 (let* ((rest (cdr entries)) | 1723 (let* ((rest (cdr entries)) |
1527 (kill (car rest)) | 1724 (kill (car rest)) |
1528 (match (nth 0 kill)) | 1725 (match (nth 0 kill)) |
1529 (type (or (nth 3 kill) 's)) | 1726 (type (or (nth 3 kill) 's)) |
1530 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 1727 (score (or (nth 1 kill) gnus-score-interactive-default-score)) |
1531 (date (nth 2 kill)) | 1728 (date (nth 2 kill)) |
1567 ;; Update expire date | 1764 ;; Update expire date |
1568 (cond ((null date)) ;Permanent entry. | 1765 (cond ((null date)) ;Permanent entry. |
1569 ((and found gnus-update-score-entry-dates) ;Match, update date. | 1766 ((and found gnus-update-score-entry-dates) ;Match, update date. |
1570 (gnus-score-set 'touched '(t) alist) | 1767 (gnus-score-set 'touched '(t) alist) |
1571 (setcar (nthcdr 2 kill) now)) | 1768 (setcar (nthcdr 2 kill) now)) |
1572 ((and expire (< date expire)) ;Old entry, remove. | 1769 ((and expire (< date expire)) ;Old entry, remove. |
1573 (gnus-score-set 'touched '(t) alist) | 1770 (gnus-score-set 'touched '(t) alist) |
1574 (setcdr entries (cdr rest)) | 1771 (setcdr entries (cdr rest)) |
1575 (setq rest entries))) | 1772 (setq rest entries))) |
1576 (setq entries rest)))) | 1773 (setq entries rest)))) |
1577 ;; We change the score file back to the previous one. | 1774 ;; We change the score file back to the previous one. |
1605 ;; than EXPIRE. | 1802 ;; than EXPIRE. |
1606 | 1803 |
1607 ;; Insert the unique article headers in the buffer. | 1804 ;; Insert the unique article headers in the buffer. |
1608 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) | 1805 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) |
1609 ;; gnus-score-index is used as a free variable. | 1806 ;; gnus-score-index is used as a free variable. |
1610 alike last this art entries alist articles scores fuzzy) | 1807 alike last this art entries alist articles |
1808 fuzzies arts words kill) | |
1611 | 1809 |
1612 ;; Sorting the articles costs os O(N*log N) but will allow us to | 1810 ;; Sorting the articles costs os O(N*log N) but will allow us to |
1613 ;; only match with each unique header. Thus the actual matching | 1811 ;; only match with each unique header. Thus the actual matching |
1614 ;; will be O(M*U) where M is the number of strings to match with, | 1812 ;; will be O(M*U) where M is the number of strings to match with, |
1615 ;; and U is the number of unique headers. It is assumed (but | 1813 ;; and U is the number of unique headers. It is assumed (but |
1617 ;; factor involved with string matching. | 1815 ;; factor involved with string matching. |
1618 (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<) | 1816 (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<) |
1619 articles gnus-scores-articles) | 1817 articles gnus-scores-articles) |
1620 | 1818 |
1621 (erase-buffer) | 1819 (erase-buffer) |
1622 (while articles | 1820 (while (setq art (pop articles)) |
1623 (setq art (car articles) | 1821 (setq this (aref (car art) gnus-score-index)) |
1624 this (aref (car art) gnus-score-index) | |
1625 articles (cdr articles)) | |
1626 (if (equal last this) | 1822 (if (equal last this) |
1627 ;; O(N*H) cons-cells used here, where H is the number of | 1823 ;; O(N*H) cons-cells used here, where H is the number of |
1628 ;; headers. | 1824 ;; headers. |
1629 (setq alike (cons art alike)) | 1825 (push art alike) |
1630 (if last | 1826 (when last |
1631 (progn | 1827 ;; Insert the line, with a text property on the |
1632 ;; Insert the line, with a text property on the | 1828 ;; terminating newline referring to the articles with |
1633 ;; terminating newline referring to the articles with | 1829 ;; this line. |
1634 ;; this line. | 1830 (insert last ?\n) |
1635 (insert last ?\n) | 1831 (put-text-property (1- (point)) (point) 'articles alike)) |
1636 (put-text-property (1- (point)) (point) 'articles alike))) | |
1637 (setq alike (list art) | 1832 (setq alike (list art) |
1638 last this))) | 1833 last this))) |
1639 (and last ; Bwadr, duplicate code. | 1834 (when last ; Bwadr, duplicate code. |
1640 (progn | 1835 (insert last ?\n) |
1641 (insert last ?\n) | 1836 (put-text-property (1- (point)) (point) 'articles alike)) |
1642 (put-text-property (1- (point)) (point) 'articles alike))) | 1837 |
1643 | 1838 ;; Go through all the score alists and pick out the entries |
1644 ;; Find ordinary matches. | 1839 ;; for this header. |
1645 (setq scores score-list) | 1840 (while score-list |
1646 (while scores | 1841 (setq alist (pop score-list) |
1647 (setq alist (car scores) | 1842 ;; There's only one instance of this header for |
1648 scores (cdr scores) | 1843 ;; each score alist. |
1649 entries (assoc header alist)) | 1844 entries (assoc header alist)) |
1650 (while (cdr entries) ;First entry is the header index. | 1845 (while (cdr entries) ;First entry is the header index. |
1651 (let* ((rest (cdr entries)) | 1846 (let* ((kill (cadr entries)) |
1652 (kill (car rest)) | |
1653 (match (nth 0 kill)) | 1847 (match (nth 0 kill)) |
1654 (type (or (nth 3 kill) 's)) | 1848 (type (or (nth 3 kill) 's)) |
1655 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 1849 (score (or (nth 1 kill) gnus-score-interactive-default-score)) |
1656 (date (nth 2 kill)) | 1850 (date (nth 2 kill)) |
1657 (found nil) | 1851 (found nil) |
1658 (mt (aref (symbol-name type) 0)) | 1852 (mt (aref (symbol-name type) 0)) |
1659 (case-fold-search | 1853 (case-fold-search (not (memq mt '(?R ?S ?E ?F)))) |
1660 (not (or (= mt ?R) (= mt ?S) (= mt ?E) (= mt ?F)))) | |
1661 (dmt (downcase mt)) | 1854 (dmt (downcase mt)) |
1662 (search-func | 1855 (search-func |
1663 (cond ((= dmt ?r) 're-search-forward) | 1856 (cond ((= dmt ?r) 're-search-forward) |
1664 ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward) | 1857 ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward) |
1665 (t (error "Illegal match type: %s" type)))) | 1858 ((= dmt ?w) nil) |
1666 arts art) | 1859 (t (error "Illegal match type: %s" type))))) |
1667 (if (= dmt ?f) | 1860 (cond |
1668 (setq fuzzy t) | 1861 ;; Fuzzy matches. We save these for later. |
1669 ;; Do non-fuzzy matching. | 1862 ((= dmt ?f) |
1863 (push (cons entries alist) fuzzies)) | |
1864 ;; Word matches. Save these for even later. | |
1865 ((= dmt ?w) | |
1866 (push (cons entries alist) words)) | |
1867 ;; Exact matches. | |
1868 ((= dmt ?e) | |
1869 ;; Do exact matching. | |
1670 (goto-char (point-min)) | 1870 (goto-char (point-min)) |
1671 (if (= dmt ?e) | 1871 (while (and (not (eobp)) |
1672 ;; Do exact matching. | 1872 (funcall search-func match nil t)) |
1673 (while (and (not (eobp)) | 1873 ;; Is it really exact? |
1674 (funcall search-func match nil t)) | 1874 (and (eolp) |
1675 (and (= (progn (beginning-of-line) (point)) | 1875 (= (gnus-point-at-bol) (match-beginning 0)) |
1676 (match-beginning 0)) | 1876 ;; Yup. |
1677 (= (progn (end-of-line) (point)) | 1877 (progn |
1678 (match-end 0)) | 1878 (setq found (setq arts (get-text-property |
1679 (progn | 1879 (point) 'articles))) |
1680 (setq found (setq arts (get-text-property | 1880 ;; Found a match, update scores. |
1681 (point) 'articles))) | 1881 (if trace |
1682 ;; Found a match, update scores. | 1882 (while (setq art (pop arts)) |
1683 (if trace | 1883 (setcdr art (+ score (cdr art))) |
1684 (while arts | 1884 (push |
1685 (setq art (car arts) | 1885 (cons |
1686 arts (cdr arts)) | 1886 (car-safe (rassq alist gnus-score-cache)) |
1687 (setcdr art (+ score (cdr art))) | 1887 kill) |
1688 (setq gnus-score-trace | 1888 gnus-score-trace)) |
1689 (cons | 1889 (while (setq art (pop arts)) |
1690 (cons | 1890 (setcdr art (+ score (cdr art))))))) |
1691 (car-safe | 1891 (forward-line 1))) |
1692 (rassq alist gnus-score-cache)) | 1892 ;; Regexp and substring matching. |
1693 kill) | 1893 (t |
1694 gnus-score-trace))) | 1894 (goto-char (point-min)) |
1695 (while arts | 1895 (when (string= match "") |
1696 (setq art (car arts) | 1896 (setq match "\n")) |
1697 arts (cdr arts)) | 1897 (while (and (not (eobp)) |
1698 (setcdr art (+ score (cdr art))))))) | 1898 (funcall search-func match nil t)) |
1699 (forward-line 1)) | 1899 (goto-char (match-beginning 0)) |
1700 ;; Do regexp and substring matching. | 1900 (end-of-line) |
1701 (and (string= match "") (setq match "\n")) | 1901 (setq found (setq arts (get-text-property (point) 'articles))) |
1702 (while (and (not (eobp)) | 1902 ;; Found a match, update scores. |
1703 (funcall search-func match nil t)) | 1903 (if trace |
1704 (goto-char (match-beginning 0)) | 1904 (while (setq art (pop arts)) |
1705 (end-of-line) | 1905 (setcdr art (+ score (cdr art))) |
1706 (setq found (setq arts (get-text-property (point) 'articles))) | 1906 (push (cons (car-safe (rassq alist gnus-score-cache)) kill) |
1907 gnus-score-trace)) | |
1908 (while (setq art (pop arts)) | |
1909 (setcdr art (+ score (cdr art))))) | |
1910 (forward-line 1)))) | |
1911 ;; Update expiry date | |
1912 (if trace | |
1913 (setq entries (cdr entries)) | |
1914 (cond | |
1915 ;; Permanent entry. | |
1916 ((null date) | |
1917 (setq entries (cdr entries))) | |
1918 ;; We have a match, so we update the date. | |
1919 ((and found gnus-update-score-entry-dates) | |
1920 (gnus-score-set 'touched '(t) alist) | |
1921 (setcar (nthcdr 2 kill) now) | |
1922 (setq entries (cdr entries))) | |
1923 ;; This entry has expired, so we remove it. | |
1924 ((and expire (< date expire)) | |
1925 (gnus-score-set 'touched '(t) alist) | |
1926 (setcdr entries (cddr entries))) | |
1927 ;; No match; go to next entry. | |
1928 (t | |
1929 (setq entries (cdr entries)))))))) | |
1930 | |
1931 ;; Find fuzzy matches. | |
1932 (when fuzzies | |
1933 ;; Simplify the entire buffer for easy matching. | |
1934 (gnus-simplify-buffer-fuzzy) | |
1935 (while (setq kill (cadaar fuzzies)) | |
1936 (let* ((match (nth 0 kill)) | |
1937 (type (nth 3 kill)) | |
1938 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | |
1939 (date (nth 2 kill)) | |
1940 (mt (aref (symbol-name type) 0)) | |
1941 (case-fold-search (not (= mt ?F))) | |
1942 found) | |
1943 (goto-char (point-min)) | |
1944 (while (and (not (eobp)) | |
1945 (search-forward match nil t)) | |
1946 (when (and (= (gnus-point-at-bol) (match-beginning 0)) | |
1947 (eolp)) | |
1948 (setq found (setq arts (get-text-property (point) 'articles))) | |
1949 (if trace | |
1950 (while (setq art (pop arts)) | |
1951 (setcdr art (+ score (cdr art))) | |
1952 (push (cons | |
1953 (car-safe (rassq (cdar fuzzies) gnus-score-cache)) | |
1954 kill) | |
1955 gnus-score-trace)) | |
1707 ;; Found a match, update scores. | 1956 ;; Found a match, update scores. |
1708 (if trace | 1957 (while (setq art (pop arts)) |
1709 (while arts | 1958 (setcdr art (+ score (cdr art)))))) |
1710 (setq art (pop arts)) | 1959 (forward-line 1)) |
1711 (setcdr art (+ score (cdr art))) | 1960 ;; Update expiry date |
1712 (push (cons | 1961 (cond |
1713 (car-safe (rassq alist gnus-score-cache)) | 1962 ;; Permanent. |
1714 kill) | 1963 ((null date) |
1715 gnus-score-trace)) | 1964 ) |
1716 (while arts | 1965 ;; Match, update date. |
1717 (setq art (pop arts)) | 1966 ((and found gnus-update-score-entry-dates) |
1718 (setcdr art (+ score (cdr art))))) | 1967 (gnus-score-set 'touched '(t) (cdar fuzzies)) |
1719 (forward-line 1))) | 1968 (setcar (nthcdr 2 kill) now)) |
1720 ;; Update expire date | 1969 ;; Old entry, remove. |
1721 (cond | 1970 ((and expire (< date expire)) |
1722 ((null date)) ;Permanent entry. | 1971 (gnus-score-set 'touched '(t) (cdar fuzzies)) |
1723 ((and found gnus-update-score-entry-dates) ;Match, update date. | 1972 (setcdr (caar fuzzies) (cddaar fuzzies)))) |
1724 (gnus-score-set 'touched '(t) alist) | 1973 (setq fuzzies (cdr fuzzies))))) |
1974 | |
1975 (when words | |
1976 ;; Enter all words into the hashtb. | |
1977 (let ((hashtb (gnus-make-hashtable | |
1978 (* 10 (count-lines (point-min) (point-max)))))) | |
1979 (gnus-enter-score-words-into-hashtb hashtb) | |
1980 (while (setq kill (cadaar words)) | |
1981 (let* ((score (or (nth 1 kill) gnus-score-interactive-default-score)) | |
1982 (date (nth 2 kill)) | |
1983 found) | |
1984 (when (setq arts (intern-soft (nth 0 kill) hashtb)) | |
1985 (setq arts (symbol-value arts)) | |
1986 (setq found t) | |
1987 (if trace | |
1988 (while (setq art (pop arts)) | |
1989 (setcdr art (+ score (cdr art))) | |
1990 (push (cons | |
1991 (car-safe (rassq (cdar words) gnus-score-cache)) | |
1992 kill) | |
1993 gnus-score-trace)) | |
1994 ;; Found a match, update scores. | |
1995 (while (setq art (pop arts)) | |
1996 (setcdr art (+ score (cdr art)))))) | |
1997 ;; Update expiry date | |
1998 (cond | |
1999 ;; Permanent. | |
2000 ((null date) | |
2001 ) | |
2002 ;; Match, update date. | |
2003 ((and found gnus-update-score-entry-dates) | |
2004 (gnus-score-set 'touched '(t) (cdar words)) | |
1725 (setcar (nthcdr 2 kill) now)) | 2005 (setcar (nthcdr 2 kill) now)) |
1726 ((and expire (< date expire)) ;Old entry, remove. | 2006 ;; Old entry, remove. |
1727 (gnus-score-set 'touched '(t) alist) | 2007 ((and expire (< date expire)) |
1728 (setcdr entries (cdr rest)) | 2008 (gnus-score-set 'touched '(t) (cdar words)) |
1729 (setq rest entries)))) | 2009 (setcdr (caar words) (cddaar words)))) |
1730 (setq entries rest)))) | 2010 (setq words (cdr words)))))) |
1731 | 2011 nil)) |
1732 ;; Find fuzzy matches. | 2012 |
1733 (when fuzzy | 2013 (defun gnus-enter-score-words-into-hashtb (hashtb) |
1734 (setq scores score-list) | 2014 ;; Find all the words in the buffer and enter them into |
1735 (gnus-simplify-buffer-fuzzy) | 2015 ;; the hashtable. |
1736 (while scores | 2016 (let ((syntab (syntax-table)) |
1737 (setq alist (car scores) | 2017 word val) |
1738 scores (cdr scores) | 2018 (goto-char (point-min)) |
1739 entries (assoc header alist)) | 2019 (unwind-protect |
1740 (while (cdr entries) ;First entry is the header index. | 2020 (progn |
1741 (let* ((rest (cdr entries)) | 2021 (set-syntax-table gnus-adaptive-word-syntax-table) |
1742 (kill (car rest)) | 2022 (while (re-search-forward "\\b\\w+\\b" nil t) |
1743 (match (nth 0 kill)) | 2023 (setq val |
1744 (type (or (nth 3 kill) 's)) | 2024 (gnus-gethash |
1745 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 2025 (setq word (downcase (buffer-substring |
1746 (date (nth 2 kill)) | 2026 (match-beginning 0) (match-end 0)))) |
1747 (found nil) | 2027 hashtb)) |
1748 (mt (aref (symbol-name type) 0)) | 2028 (gnus-sethash |
1749 (case-fold-search (not (= mt ?F))) | 2029 word |
1750 (dmt (downcase mt)) | 2030 (append (get-text-property (gnus-point-at-eol) 'articles) val) |
1751 arts art) | 2031 hashtb))) |
1752 (when (= dmt ?f) | 2032 (set-syntax-table syntab)) |
1753 (goto-char (point-min)) | 2033 ;; Make all the ignorable words ignored. |
1754 (while (and (not (eobp)) | 2034 (let ((ignored (append gnus-ignored-adaptive-words |
1755 (search-forward match nil t)) | 2035 gnus-default-ignored-adaptive-words))) |
1756 (when (and (= (progn (beginning-of-line) (point)) | 2036 (while ignored |
1757 (match-beginning 0)) | 2037 (gnus-sethash (pop ignored) nil hashtb))))) |
1758 (= (progn (end-of-line) (point)) | |
1759 (match-end 0))) | |
1760 (setq found (setq arts (get-text-property | |
1761 (point) 'articles))) | |
1762 ;; Found a match, update scores. | |
1763 (if trace | |
1764 (while arts | |
1765 (setq art (pop arts)) | |
1766 (setcdr art (+ score (cdr art))) | |
1767 (push (cons | |
1768 (car-safe (rassq alist gnus-score-cache)) | |
1769 kill) | |
1770 gnus-score-trace)) | |
1771 (while arts | |
1772 (setq art (pop arts)) | |
1773 (setcdr art (+ score (cdr art)))))) | |
1774 (forward-line 1)) | |
1775 ;; Update expire date | |
1776 (unless trace | |
1777 (cond | |
1778 ((null date)) ;Permanent entry. | |
1779 ((and found gnus-update-score-entry-dates) ;Match, update date. | |
1780 (gnus-score-set 'touched '(t) alist) | |
1781 (setcar (nthcdr 2 kill) now)) | |
1782 ((and expire (< date expire)) ;Old entry, remove. | |
1783 (gnus-score-set 'touched '(t) alist) | |
1784 (setcdr entries (cdr rest)) | |
1785 (setq rest entries))))) | |
1786 (setq entries rest)))))) | |
1787 nil) | |
1788 | 2038 |
1789 (defun gnus-score-string< (a1 a2) | 2039 (defun gnus-score-string< (a1 a2) |
1790 ;; Compare headers in articles A2 and A2. | 2040 ;; Compare headers in articles A2 and A2. |
1791 ;; The header index used is the free variable `gnus-score-index'. | 2041 ;; The header index used is the free variable `gnus-score-index'. |
1792 (string-lessp (aref (car a1) gnus-score-index) | 2042 (string-lessp (aref (car a1) gnus-score-index) |
1793 (aref (car a2) gnus-score-index))) | 2043 (aref (car a2) gnus-score-index))) |
1794 | 2044 |
1795 (defun gnus-score-build-cons (article) | |
1796 ;; Build a `gnus-newsgroup-scored' type cons from ARTICLE. | |
1797 (cons (mail-header-number (car article)) (cdr article))) | |
1798 | |
1799 (defun gnus-current-score-file-nondirectory (&optional score-file) | 2045 (defun gnus-current-score-file-nondirectory (&optional score-file) |
1800 (let ((score-file (or score-file gnus-current-score-file))) | 2046 (let ((score-file (or score-file gnus-current-score-file))) |
1801 (if score-file | 2047 (if score-file |
1802 (gnus-short-group-name (file-name-nondirectory score-file)) | 2048 (gnus-short-group-name (file-name-nondirectory score-file)) |
1803 "none"))) | 2049 "none"))) |
1804 | 2050 |
1805 (defun gnus-score-adaptive () | 2051 (defun gnus-score-adaptive () |
1806 (save-excursion | 2052 "Create adaptive score rules for this newsgroup." |
1807 (let* ((malist (gnus-copy-sequence gnus-adaptive-score-alist)) | 2053 (when gnus-use-adaptive-scoring |
1808 (alist malist) | 2054 ;; We change the score file to the adaptive score file. |
1809 (date (current-time-string)) | 2055 (save-excursion |
1810 (data gnus-newsgroup-data) | 2056 (set-buffer gnus-summary-buffer) |
1811 elem headers match) | 2057 (gnus-score-load-file |
1812 ;; First we transform the adaptive rule alist into something | 2058 (or gnus-newsgroup-adaptive-score-file |
1813 ;; that's faster to process. | 2059 (gnus-score-file-name |
1814 (while malist | 2060 gnus-newsgroup-name gnus-adaptive-file-suffix)))) |
1815 (setq elem (car malist)) | 2061 ;; Perform ordinary line scoring. |
1816 (if (symbolp (car elem)) | 2062 (when (or (not (listp gnus-use-adaptive-scoring)) |
1817 (setcar elem (symbol-value (car elem)))) | 2063 (memq 'line gnus-use-adaptive-scoring)) |
1818 (setq elem (cdr elem)) | |
1819 (while elem | |
1820 (setcdr (car elem) | |
1821 (cons (if (eq (caar elem) 'followup) | |
1822 "references" | |
1823 (symbol-name (caar elem))) | |
1824 (cdar elem))) | |
1825 (setcar (car elem) | |
1826 `(lambda (h) | |
1827 (,(intern | |
1828 (concat "mail-header-" | |
1829 (if (eq (caar elem) 'followup) | |
1830 "message-id" | |
1831 (downcase (symbol-name (caar elem)))))) | |
1832 h))) | |
1833 (setq elem (cdr elem))) | |
1834 (setq malist (cdr malist))) | |
1835 ;; We change the score file to the adaptive score file. | |
1836 (save-excursion | 2064 (save-excursion |
1837 (set-buffer gnus-summary-buffer) | 2065 (let* ((malist (gnus-copy-sequence gnus-adaptive-score-alist)) |
1838 (gnus-score-load-file | 2066 (alist malist) |
1839 (or gnus-newsgroup-adaptive-score-file | 2067 (date (current-time-string)) |
1840 (gnus-score-file-name | 2068 (data gnus-newsgroup-data) |
1841 gnus-newsgroup-name gnus-adaptive-file-suffix)))) | 2069 elem headers match) |
1842 ;; The we score away. | 2070 ;; First we transform the adaptive rule alist into something |
1843 (while data | 2071 ;; that's faster to process. |
1844 (setq elem (cdr (assq (gnus-data-mark (car data)) alist))) | 2072 (while malist |
1845 (if (or (not elem) | 2073 (setq elem (car malist)) |
1846 (gnus-data-pseudo-p (car data))) | 2074 (when (symbolp (car elem)) |
1847 () | 2075 (setcar elem (symbol-value (car elem)))) |
1848 (when (setq headers (gnus-data-header (car data))) | 2076 (setq elem (cdr elem)) |
1849 (while elem | 2077 (while elem |
1850 (setq match (funcall (caar elem) headers)) | 2078 (setcdr (car elem) |
1851 (gnus-summary-score-entry | 2079 (cons (if (eq (caar elem) 'followup) |
1852 (nth 1 (car elem)) match | 2080 "references" |
1853 (cond | 2081 (symbol-name (caar elem))) |
1854 ((numberp match) | 2082 (cdar elem))) |
1855 '=) | 2083 (setcar (car elem) |
1856 ((equal (nth 1 (car elem)) "date") | 2084 `(lambda (h) |
1857 'a) | 2085 (,(intern |
1858 (t | 2086 (concat "mail-header-" |
1859 ;; Whether we use substring or exact matches are controlled | 2087 (if (eq (caar elem) 'followup) |
1860 ;; here. | 2088 "message-id" |
1861 (if (or (not gnus-score-exact-adapt-limit) | 2089 (downcase (symbol-name (caar elem)))))) |
1862 (< (length match) gnus-score-exact-adapt-limit)) | 2090 h))) |
1863 'e | 2091 (setq elem (cdr elem))) |
1864 (if (equal (nth 1 (car elem)) "subject") | 2092 (setq malist (cdr malist))) |
1865 'f 's)))) | 2093 ;; Then we score away. |
1866 (nth 2 (car elem)) date nil t) | 2094 (while data |
1867 (setq elem (cdr elem))))) | 2095 (setq elem (cdr (assq (gnus-data-mark (car data)) alist))) |
1868 (setq data (cdr data)))))) | 2096 (if (or (not elem) |
2097 (gnus-data-pseudo-p (car data))) | |
2098 () | |
2099 (when (setq headers (gnus-data-header (car data))) | |
2100 (while elem | |
2101 (setq match (funcall (caar elem) headers)) | |
2102 (gnus-summary-score-entry | |
2103 (nth 1 (car elem)) match | |
2104 (cond | |
2105 ((numberp match) | |
2106 '=) | |
2107 ((equal (nth 1 (car elem)) "date") | |
2108 'a) | |
2109 (t | |
2110 ;; Whether we use substring or exact matches is | |
2111 ;; controlled here. | |
2112 (if (or (not gnus-score-exact-adapt-limit) | |
2113 (< (length match) gnus-score-exact-adapt-limit)) | |
2114 'e | |
2115 (if (equal (nth 1 (car elem)) "subject") | |
2116 'f 's)))) | |
2117 (nth 2 (car elem)) date nil t) | |
2118 (setq elem (cdr elem))))) | |
2119 (setq data (cdr data)))))) | |
2120 | |
2121 ;; Perform adaptive word scoring. | |
2122 (when (and (listp gnus-use-adaptive-scoring) | |
2123 (memq 'word gnus-use-adaptive-scoring)) | |
2124 (nnheader-temp-write nil | |
2125 (let* ((hashtb (gnus-make-hashtable 1000)) | |
2126 (date (gnus-day-number (current-time-string))) | |
2127 (data gnus-newsgroup-data) | |
2128 (syntab (syntax-table)) | |
2129 word d score val) | |
2130 (unwind-protect | |
2131 (progn | |
2132 (set-syntax-table gnus-adaptive-word-syntax-table) | |
2133 ;; Go through all articles. | |
2134 (while (setq d (pop data)) | |
2135 (when (and | |
2136 (not (gnus-data-pseudo-p d)) | |
2137 (setq score | |
2138 (cdr (assq | |
2139 (gnus-data-mark d) | |
2140 gnus-adaptive-word-score-alist)))) | |
2141 ;; This article has a mark that should lead to | |
2142 ;; adaptive word rules, so we insert the subject | |
2143 ;; and find all words in that string. | |
2144 (insert (mail-header-subject (gnus-data-header d))) | |
2145 (downcase-region (point-min) (point-max)) | |
2146 (goto-char (point-min)) | |
2147 (while (re-search-forward "\\b\\w+\\b" nil t) | |
2148 ;; Put the word and score into the hashtb. | |
2149 (setq val (gnus-gethash (setq word (match-string 0)) | |
2150 hashtb)) | |
2151 (gnus-sethash word (+ (or val 0) score) hashtb)) | |
2152 (erase-buffer)))) | |
2153 (set-syntax-table syntab)) | |
2154 ;; Make all the ignorable words ignored. | |
2155 (let ((ignored (append gnus-ignored-adaptive-words | |
2156 gnus-default-ignored-adaptive-words))) | |
2157 (while ignored | |
2158 (gnus-sethash (pop ignored) nil hashtb))) | |
2159 ;; Now we have all the words and scores, so we | |
2160 ;; add these rules to the ADAPT file. | |
2161 (set-buffer gnus-summary-buffer) | |
2162 (mapatoms | |
2163 (lambda (word) | |
2164 (when (symbol-value word) | |
2165 (gnus-summary-score-entry | |
2166 "subject" (symbol-name word) 'w (symbol-value word) | |
2167 date nil t))) | |
2168 hashtb)))))) | |
1869 | 2169 |
1870 (defun gnus-score-edit-done () | 2170 (defun gnus-score-edit-done () |
1871 (let ((bufnam (buffer-file-name (current-buffer))) | 2171 (let ((bufnam (buffer-file-name (current-buffer))) |
1872 (winconf gnus-prev-winconf)) | 2172 (winconf gnus-prev-winconf)) |
1873 (and winconf (set-window-configuration winconf)) | 2173 (when winconf |
2174 (set-window-configuration winconf)) | |
1874 (gnus-score-remove-from-cache bufnam) | 2175 (gnus-score-remove-from-cache bufnam) |
1875 (gnus-score-load-file bufnam))) | 2176 (gnus-score-load-file bufnam))) |
1876 | 2177 |
1877 (defun gnus-score-find-trace () | 2178 (defun gnus-score-find-trace () |
1878 "Find all score rules that applies to the current article." | 2179 "Find all score rules that applies to the current article." |
1879 (interactive) | 2180 (interactive) |
1880 (let ((gnus-newsgroup-headers | 2181 (let ((gnus-newsgroup-headers |
1881 (list (gnus-summary-article-header))) | 2182 (list (gnus-summary-article-header))) |
1882 (gnus-newsgroup-scored nil) | 2183 (gnus-newsgroup-scored nil) |
1883 (buf (current-buffer)) | |
1884 trace) | 2184 trace) |
1885 (when (get-buffer "*Gnus Scores*") | 2185 (save-excursion |
1886 (save-excursion | 2186 (nnheader-set-temp-buffer "*Score Trace*")) |
1887 (set-buffer "*Gnus Scores*") | |
1888 (erase-buffer))) | |
1889 (setq gnus-score-trace nil) | 2187 (setq gnus-score-trace nil) |
1890 (gnus-possibly-score-headers 'trace) | 2188 (gnus-possibly-score-headers 'trace) |
1891 (if (not (setq trace gnus-score-trace)) | 2189 (if (not (setq trace gnus-score-trace)) |
1892 (gnus-error 1 "No score rules apply to the current article.") | 2190 (gnus-error 1 "No score rules apply to the current article.") |
1893 (pop-to-buffer "*Gnus Scores*") | 2191 (set-buffer "*Score Trace*") |
1894 (gnus-add-current-to-buffer-list) | 2192 (gnus-add-current-to-buffer-list) |
1895 (erase-buffer) | |
1896 (while trace | 2193 (while trace |
1897 (insert (format "%S -> %s\n" (cdar trace) | 2194 (insert (format "%S -> %s\n" (cdar trace) |
1898 (file-name-nondirectory (caar trace)))) | 2195 (file-name-nondirectory (caar trace)))) |
1899 (setq trace (cdr trace))) | 2196 (setq trace (cdr trace))) |
1900 (goto-char (point-min)) | 2197 (goto-char (point-min)) |
1901 (pop-to-buffer buf)))) | 2198 (gnus-configure-windows 'score-trace)))) |
2199 | |
2200 (defun gnus-score-find-favourite-words () | |
2201 "List words used in scoring." | |
2202 (interactive) | |
2203 (let ((alists (gnus-score-load-files (gnus-all-score-files))) | |
2204 alist rule rules kill) | |
2205 ;; Go through all the score alists for this group | |
2206 ;; and find all `w' rules. | |
2207 (while (setq alist (pop alists)) | |
2208 (while (setq rule (pop alist)) | |
2209 (when (and (stringp (car rule)) | |
2210 (equal "subject" (downcase (pop rule)))) | |
2211 (while (setq kill (pop rule)) | |
2212 (when (memq (nth 3 kill) '(w W word Word)) | |
2213 (push (cons (or (nth 1 kill) | |
2214 gnus-score-interactive-default-score) | |
2215 (car kill)) | |
2216 rules)))))) | |
2217 (setq rules (sort rules (lambda (r1 r2) | |
2218 (string-lessp (cdr r1) (cdr r2))))) | |
2219 ;; Add up words that have appeared several times. | |
2220 (let ((r rules)) | |
2221 (while (cdr r) | |
2222 (if (equal (cdar r) (cdadr r)) | |
2223 (progn | |
2224 (setcar (car r) (+ (caar r) (caadr r))) | |
2225 (setcdr r (cddr r))) | |
2226 (pop r)))) | |
2227 ;; Insert the words. | |
2228 (nnheader-set-temp-buffer "*Score Words*") | |
2229 (if (not (setq rules (sort rules (lambda (r1 r2) (> (car r1) (car r2)))))) | |
2230 (gnus-error 3 "No word score rules") | |
2231 (while rules | |
2232 (insert (format "%-5d: %s\n" (caar rules) (cdar rules))) | |
2233 (pop rules)) | |
2234 (gnus-add-current-to-buffer-list) | |
2235 (goto-char (point-min)) | |
2236 (gnus-configure-windows 'score-words)))) | |
1902 | 2237 |
1903 (defun gnus-summary-rescore () | 2238 (defun gnus-summary-rescore () |
1904 "Redo the entire scoring process in the current summary." | 2239 "Redo the entire scoring process in the current summary." |
1905 (interactive) | 2240 (interactive) |
1906 (gnus-score-save) | 2241 (gnus-score-save) |
1948 (while (gnus-summary-find-subject subject) | 2283 (while (gnus-summary-find-subject subject) |
1949 (gnus-summary-raise-score score)) | 2284 (gnus-summary-raise-score score)) |
1950 (gnus-summary-next-subject 1 t))) | 2285 (gnus-summary-next-subject 1 t))) |
1951 | 2286 |
1952 (defun gnus-score-default (level) | 2287 (defun gnus-score-default (level) |
1953 (if level (prefix-numeric-value level) | 2288 (if level (prefix-numeric-value level) |
1954 gnus-score-interactive-default-score)) | 2289 gnus-score-interactive-default-score)) |
1955 | 2290 |
1956 (defun gnus-summary-raise-thread (&optional score) | 2291 (defun gnus-summary-raise-thread (&optional score) |
1957 "Raise the score of the articles in the current thread with SCORE." | 2292 "Raise the score of the articles in the current thread with SCORE." |
1958 (interactive "P") | 2293 (interactive "P") |
1964 (gnus-summary-goto-subject (car articles)) | 2299 (gnus-summary-goto-subject (car articles)) |
1965 (gnus-summary-raise-score score) | 2300 (gnus-summary-raise-score score) |
1966 (setq articles (cdr articles)))) | 2301 (setq articles (cdr articles)))) |
1967 (setq e (point))) | 2302 (setq e (point))) |
1968 (let ((gnus-summary-check-current t)) | 2303 (let ((gnus-summary-check-current t)) |
1969 (or (zerop (gnus-summary-next-subject 1 t)) | 2304 (unless (zerop (gnus-summary-next-subject 1 t)) |
1970 (goto-char e)))) | 2305 (goto-char e)))) |
1971 (gnus-summary-recenter) | 2306 (gnus-summary-recenter) |
1972 (gnus-summary-position-point) | 2307 (gnus-summary-position-point) |
1973 (gnus-set-mode-line 'summary)) | 2308 (gnus-set-mode-line 'summary)) |
1974 | 2309 |
1975 (defun gnus-summary-lower-same-subject-and-select (score) | 2310 (defun gnus-summary-lower-same-subject-and-select (score) |
1990 ;;; Finding score files. | 2325 ;;; Finding score files. |
1991 | 2326 |
1992 (defun gnus-score-score-files (group) | 2327 (defun gnus-score-score-files (group) |
1993 "Return a list of all possible score files." | 2328 "Return a list of all possible score files." |
1994 ;; Search and set any global score files. | 2329 ;; Search and set any global score files. |
1995 (and gnus-global-score-files | 2330 (when gnus-global-score-files |
1996 (or gnus-internal-global-score-files | 2331 (unless gnus-internal-global-score-files |
1997 (gnus-score-search-global-directories gnus-global-score-files))) | 2332 (gnus-score-search-global-directories gnus-global-score-files))) |
1998 ;; Fix the kill-file dir variable. | 2333 ;; Fix the kill-file dir variable. |
1999 (setq gnus-kill-files-directory | 2334 (setq gnus-kill-files-directory |
2000 (file-name-as-directory gnus-kill-files-directory)) | 2335 (file-name-as-directory gnus-kill-files-directory)) |
2001 ;; If we can't read it, there are no score files. | 2336 ;; If we can't read it, there are no score files. |
2002 (if (not (file-exists-p (expand-file-name gnus-kill-files-directory))) | 2337 (if (not (file-exists-p (expand-file-name gnus-kill-files-directory))) |
2026 (gnus-score-file-regexp))))))) | 2361 (gnus-score-file-regexp))))))) |
2027 (cdr gnus-score-file-list))) | 2362 (cdr gnus-score-file-list))) |
2028 | 2363 |
2029 (defun gnus-score-score-files-1 (dir) | 2364 (defun gnus-score-score-files-1 (dir) |
2030 "Return all possible score files under DIR." | 2365 "Return all possible score files under DIR." |
2031 (let ((files (directory-files (expand-file-name dir) t nil t)) | 2366 (let ((files (list (expand-file-name dir))) |
2032 (regexp (gnus-score-file-regexp)) | 2367 (regexp (gnus-score-file-regexp)) |
2033 out file) | 2368 (case-fold-search nil) |
2369 seen out file) | |
2034 (while (setq file (pop files)) | 2370 (while (setq file (pop files)) |
2035 (cond | 2371 (cond |
2036 ;; Ignore "." and "..". | 2372 ;; Ignore "." and "..". |
2037 ((member (file-name-nondirectory file) '("." "..")) | 2373 ((member (file-name-nondirectory file) '("." "..")) |
2038 nil) | 2374 nil) |
2039 ;; Recurse down directories. | 2375 ;; Add subtrees of directory to also be searched. |
2040 ((file-directory-p file) | 2376 ((and (file-directory-p file) |
2041 (setq out (nconc (gnus-score-score-files-1 file) out))) | 2377 (not (member (file-truename file) seen))) |
2378 (push (file-truename file) seen) | |
2379 (setq files (nconc (directory-files file t nil t) files))) | |
2042 ;; Add files to the list of score files. | 2380 ;; Add files to the list of score files. |
2043 ((string-match regexp file) | 2381 ((string-match regexp file) |
2044 (push file out)))) | 2382 (push file out)))) |
2045 (or out | 2383 (or out |
2046 ;; Return a dummy value. | 2384 ;; Return a dummy value. |
2072 (erase-buffer) | 2410 (erase-buffer) |
2073 (insert (car sfiles)) | 2411 (insert (car sfiles)) |
2074 (goto-char (point-min)) | 2412 (goto-char (point-min)) |
2075 ;; First remove the suffix itself. | 2413 ;; First remove the suffix itself. |
2076 (when (re-search-forward (concat "." score-regexp) nil t) | 2414 (when (re-search-forward (concat "." score-regexp) nil t) |
2077 (replace-match "" t t) | 2415 (replace-match "" t t) |
2078 (goto-char (point-min)) | 2416 (goto-char (point-min)) |
2079 (if (looking-at (regexp-quote kill-dir)) | 2417 (if (looking-at (regexp-quote kill-dir)) |
2080 ;; If the file name was just "SCORE", `klen' is one character | 2418 ;; If the file name was just "SCORE", `klen' is one character |
2081 ;; too much. | 2419 ;; too much. |
2082 (delete-char (min (1- (point-max)) klen)) | 2420 (delete-char (min (1- (point-max)) klen)) |
2087 (goto-char (point-min)) | 2425 (goto-char (point-min)) |
2088 (let ((regexp (concat | 2426 (let ((regexp (concat |
2089 "[/:" (if trans (char-to-string trans) "") "]"))) | 2427 "[/:" (if trans (char-to-string trans) "") "]"))) |
2090 (while (re-search-forward regexp nil t) | 2428 (while (re-search-forward regexp nil t) |
2091 (replace-match "." t t))) | 2429 (replace-match "." t t))) |
2092 ;; Cludge to get rid of "nntp+" problems. | 2430 ;; Kludge to get rid of "nntp+" problems. |
2093 (goto-char (point-min)) | 2431 (goto-char (point-min)) |
2094 (and (looking-at "nn[a-z]+\\+") | 2432 (when (looking-at "nn[a-z]+\\+") |
2095 (progn | 2433 (search-forward "+") |
2096 (search-forward "+") | 2434 (forward-char -1) |
2097 (forward-char -1) | 2435 (insert "\\") |
2098 (insert "\\"))) | 2436 (forward-char 1)) |
2099 ;; Kludge to deal with "++". | 2437 ;; Kludge to deal with "++". |
2100 (goto-char (point-min)) | 2438 (while (search-forward "+" nil t) |
2101 (while (search-forward "++" nil t) | 2439 (replace-match "\\+" t t)) |
2102 (replace-match "\\+\\+" t t)) | |
2103 ;; Translate "all" to ".*". | 2440 ;; Translate "all" to ".*". |
2104 (goto-char (point-min)) | 2441 (goto-char (point-min)) |
2105 (while (search-forward "all" nil t) | 2442 (while (search-forward "all" nil t) |
2106 (replace-match ".*" t t)) | 2443 (replace-match ".*" t t)) |
2107 (goto-char (point-min)) | 2444 (goto-char (point-min)) |
2108 ;; Deal with "not."s. | 2445 ;; Deal with "not."s. |
2109 (if (looking-at "not.") | 2446 (if (looking-at "not.") |
2110 (progn | 2447 (progn |
2111 (setq not-match t) | 2448 (setq not-match t) |
2112 (setq regexp (buffer-substring 5 (point-max)))) | 2449 (setq regexp (concat "^" (buffer-substring 5 (point-max))))) |
2113 (setq regexp (buffer-substring 1 (point-max))) | 2450 (setq regexp (concat "^" (buffer-substring 1 (point-max)))) |
2114 (setq not-match nil)) | 2451 (setq not-match nil)) |
2115 ;; Finally - if this resulting regexp matches the group name, | 2452 ;; Finally - if this resulting regexp matches the group name, |
2116 ;; we add this score file to the list of score files | 2453 ;; we add this score file to the list of score files |
2117 ;; applicable to this group. | 2454 ;; applicable to this group. |
2118 (if (or (and not-match | 2455 (when (or (and not-match |
2119 (not (string-match regexp group))) | 2456 (not (string-match regexp group))) |
2120 (and (not not-match) | 2457 (and (not not-match) |
2121 (string-match regexp group))) | 2458 (string-match regexp group))) |
2122 (setq ofiles (cons (car sfiles) ofiles)))) | 2459 (push (car sfiles) ofiles))) |
2123 (setq sfiles (cdr sfiles))) | 2460 (setq sfiles (cdr sfiles))) |
2124 (kill-buffer (current-buffer)) | 2461 (kill-buffer (current-buffer)) |
2125 ;; Slight kludge here - the last score file returned should be | 2462 ;; Slight kludge here - the last score file returned should be |
2126 ;; the local score file, whether it exists or not. This is so | 2463 ;; the local score file, whether it exists or not. This is so |
2127 ;; that any score commands the user enters will go to the right | 2464 ;; that any score commands the user enters will go to the right |
2128 ;; file, and not end up in some global score file. | 2465 ;; file, and not end up in some global score file. |
2129 (let ((localscore (gnus-score-file-name group))) | 2466 (let ((localscore (gnus-score-file-name group))) |
2130 (setq ofiles (cons localscore (delete localscore ofiles)))) | 2467 (setq ofiles (cons localscore (delete localscore ofiles)))) |
2131 (nreverse ofiles)))) | 2468 (gnus-sort-score-files (nreverse ofiles))))) |
2132 | 2469 |
2133 (defun gnus-score-find-single (group) | 2470 (defun gnus-score-find-single (group) |
2134 "Return list containing the score file for GROUP." | 2471 "Return list containing the score file for GROUP." |
2135 (list (or gnus-newsgroup-adaptive-score-file | 2472 (list (or gnus-newsgroup-adaptive-score-file |
2136 (gnus-score-file-name group gnus-adaptive-file-suffix)) | 2473 (gnus-score-file-name group gnus-adaptive-file-suffix)) |
2137 (gnus-score-file-name group))) | 2474 (gnus-score-file-name group))) |
2138 | 2475 |
2139 (defun gnus-score-find-hierarchical (group) | 2476 (defun gnus-score-find-hierarchical (group) |
2140 "Return list of score files for GROUP. | 2477 "Return list of score files for GROUP. |
2141 This includes the score file for the group and all its parents." | 2478 This includes the score file for the group and all its parents." |
2142 (let ((all (copy-sequence '(nil))) | 2479 (let* ((prefix (gnus-group-real-prefix group)) |
2143 (start 0)) | 2480 (all (list nil)) |
2481 (group (gnus-group-real-name group)) | |
2482 (start 0)) | |
2144 (while (string-match "\\." group (1+ start)) | 2483 (while (string-match "\\." group (1+ start)) |
2145 (setq start (match-beginning 0)) | 2484 (setq start (match-beginning 0)) |
2146 (setq all (cons (substring group 0 start) all))) | 2485 (push (substring group 0 start) all)) |
2147 (setq all (cons group all)) | 2486 (push group all) |
2148 (nconc | 2487 (setq all |
2149 (mapcar (lambda (newsgroup) | 2488 (nconc |
2150 (gnus-score-file-name newsgroup gnus-adaptive-file-suffix)) | 2489 (mapcar (lambda (group) |
2151 (setq all (nreverse all))) | 2490 (gnus-score-file-name group gnus-adaptive-file-suffix)) |
2152 (mapcar 'gnus-score-file-name all)))) | 2491 (setq all (nreverse all))) |
2492 (mapcar 'gnus-score-file-name all))) | |
2493 (if (equal prefix "") | |
2494 all | |
2495 (mapcar | |
2496 (lambda (file) | |
2497 (concat (file-name-directory file) prefix | |
2498 (file-name-nondirectory file))) | |
2499 all)))) | |
2500 | |
2501 (defun gnus-score-file-rank (file) | |
2502 "Return a number that says how specific score FILE is. | |
2503 Destroys the current buffer." | |
2504 (if (member file gnus-internal-global-score-files) | |
2505 0 | |
2506 (when (string-match | |
2507 (concat "^" (regexp-quote | |
2508 (expand-file-name | |
2509 (file-name-as-directory gnus-kill-files-directory)))) | |
2510 file) | |
2511 (setq file (substring file (match-end 0)))) | |
2512 (insert file) | |
2513 (goto-char (point-min)) | |
2514 (let ((beg (point)) | |
2515 elems) | |
2516 (while (re-search-forward "[./]" nil t) | |
2517 (push (buffer-substring beg (1- (point))) | |
2518 elems)) | |
2519 (erase-buffer) | |
2520 (setq elems (delete "all" elems)) | |
2521 (length elems)))) | |
2522 | |
2523 (defun gnus-sort-score-files (files) | |
2524 "Sort FILES so that the most general files come first." | |
2525 (nnheader-temp-write nil | |
2526 (let ((alist | |
2527 (mapcar | |
2528 (lambda (file) | |
2529 (cons (inline (gnus-score-file-rank file)) file)) | |
2530 files))) | |
2531 (mapcar | |
2532 (lambda (f) (cdr f)) | |
2533 (sort alist (lambda (f1 f2) (< (car f1) (car f2)))))))) | |
2153 | 2534 |
2154 (defun gnus-score-find-alist (group) | 2535 (defun gnus-score-find-alist (group) |
2155 "Return list of score files for GROUP. | 2536 "Return list of score files for GROUP. |
2156 The list is determined from the variable gnus-score-file-alist." | 2537 The list is determined from the variable gnus-score-file-alist." |
2157 (let ((alist gnus-score-file-multiple-match-alist) | 2538 (let ((alist gnus-score-file-multiple-match-alist) |
2159 ;; if this group has been seen before, return the cached entry | 2540 ;; if this group has been seen before, return the cached entry |
2160 (if (setq score-files (assoc group gnus-score-file-alist-cache)) | 2541 (if (setq score-files (assoc group gnus-score-file-alist-cache)) |
2161 (cdr score-files) ;ensures caching groups with no matches | 2542 (cdr score-files) ;ensures caching groups with no matches |
2162 ;; handle the multiple match alist | 2543 ;; handle the multiple match alist |
2163 (while alist | 2544 (while alist |
2164 (and (string-match (caar alist) group) | 2545 (when (string-match (caar alist) group) |
2165 (setq score-files | 2546 (setq score-files |
2166 (nconc score-files (copy-sequence (cdar alist))))) | 2547 (nconc score-files (copy-sequence (cdar alist))))) |
2167 (setq alist (cdr alist))) | 2548 (setq alist (cdr alist))) |
2168 (setq alist gnus-score-file-single-match-alist) | 2549 (setq alist gnus-score-file-single-match-alist) |
2169 ;; handle the single match alist | 2550 ;; handle the single match alist |
2170 (while alist | 2551 (while alist |
2171 (and (string-match (caar alist) group) | 2552 (when (string-match (caar alist) group) |
2172 ;; progn used just in case ("regexp") has no files | 2553 ;; progn used just in case ("regexp") has no files |
2173 ;; and score-files is still nil. -sj | 2554 ;; and score-files is still nil. -sj |
2174 ;; this can be construed as a "stop searching here" feature :> | 2555 ;; this can be construed as a "stop searching here" feature :> |
2175 ;; and used to simplify regexps in the single-alist | 2556 ;; and used to simplify regexps in the single-alist |
2176 (progn | 2557 (setq score-files |
2177 (setq score-files | 2558 (nconc score-files (copy-sequence (cdar alist)))) |
2178 (nconc score-files (copy-sequence (cdar alist)))) | 2559 (setq alist nil)) |
2179 (setq alist nil))) | |
2180 (setq alist (cdr alist))) | 2560 (setq alist (cdr alist))) |
2181 ;; cache the score files | 2561 ;; cache the score files |
2182 (setq gnus-score-file-alist-cache | 2562 (push (cons group score-files) gnus-score-file-alist-cache) |
2183 (cons (cons group score-files) gnus-score-file-alist-cache)) | |
2184 score-files))) | 2563 score-files))) |
2185 | 2564 |
2186 (defun gnus-possibly-score-headers (&optional trace) | 2565 (defun gnus-all-score-files (&optional group) |
2566 "Return a list of all score files for the current group." | |
2187 (let ((funcs gnus-score-find-score-files-function) | 2567 (let ((funcs gnus-score-find-score-files-function) |
2568 (group (or group gnus-newsgroup-name)) | |
2188 score-files) | 2569 score-files) |
2189 ;; Make sure funcs is a list. | 2570 ;; Make sure funcs is a list. |
2190 (and funcs | 2571 (and funcs |
2191 (not (listp funcs)) | 2572 (not (listp funcs)) |
2192 (setq funcs (list funcs))) | 2573 (setq funcs (list funcs))) |
2193 ;; Get the initial score files for this group. | 2574 ;; Get the initial score files for this group. |
2194 (when funcs | 2575 (when funcs |
2195 (setq score-files (gnus-score-find-alist gnus-newsgroup-name))) | 2576 (setq score-files (nreverse (gnus-score-find-alist group)))) |
2577 ;; Add any home adapt files. | |
2578 (let ((home (gnus-home-score-file group t))) | |
2579 (when home | |
2580 (push home score-files) | |
2581 (setq gnus-newsgroup-adaptive-score-file home))) | |
2582 ;; Check whether there is a `adapt-file' group parameter. | |
2583 (let ((param-file (gnus-group-find-parameter group 'adapt-file))) | |
2584 (when param-file | |
2585 (push param-file score-files) | |
2586 (setq gnus-newsgroup-adaptive-score-file param-file))) | |
2196 ;; Go through all the functions for finding score files (or actual | 2587 ;; Go through all the functions for finding score files (or actual |
2197 ;; scores) and add them to a list. | 2588 ;; scores) and add them to a list. |
2198 (while funcs | 2589 (while funcs |
2199 (when (gnus-functionp (car funcs)) | 2590 (when (gnus-functionp (car funcs)) |
2200 (setq score-files | 2591 (setq score-files |
2201 (nconc score-files (funcall (car funcs) gnus-newsgroup-name)))) | 2592 (nconc score-files (nreverse (funcall (car funcs) group))))) |
2202 (setq funcs (cdr funcs))) | 2593 (setq funcs (cdr funcs))) |
2594 ;; Add any home score files. | |
2595 (let ((home (gnus-home-score-file group))) | |
2596 (when home | |
2597 (push home score-files))) | |
2203 ;; Check whether there is a `score-file' group parameter. | 2598 ;; Check whether there is a `score-file' group parameter. |
2204 (let ((param-file (gnus-group-get-parameter | 2599 (let ((param-file (gnus-group-find-parameter group 'score-file))) |
2205 gnus-newsgroup-name 'score-file))) | |
2206 (when param-file | 2600 (when param-file |
2207 (push param-file score-files))) | 2601 (push param-file score-files))) |
2602 ;; Expand all files names. | |
2603 (let ((files score-files)) | |
2604 (while files | |
2605 (when (stringp (car files)) | |
2606 (setcar files (expand-file-name | |
2607 (car files) gnus-kill-files-directory))) | |
2608 (pop files))) | |
2609 (setq score-files (nreverse score-files)) | |
2610 ;; Remove any duplicate score files. | |
2611 (while (and score-files | |
2612 (member (car score-files) (cdr score-files))) | |
2613 (pop score-files)) | |
2614 (let ((files score-files)) | |
2615 (while (cdr files) | |
2616 (when (member (cadr files) (cddr files)) | |
2617 (setcdr files (cddr files))) | |
2618 (pop files))) | |
2208 ;; Do the scoring if there are any score files for this group. | 2619 ;; Do the scoring if there are any score files for this group. |
2620 score-files)) | |
2621 | |
2622 (defun gnus-possibly-score-headers (&optional trace) | |
2623 "Do scoring if scoring is required." | |
2624 (let ((score-files (gnus-all-score-files))) | |
2209 (when score-files | 2625 (when score-files |
2210 (gnus-score-headers score-files trace)))) | 2626 (gnus-score-headers score-files trace)))) |
2211 | 2627 |
2212 (defun gnus-score-file-name (newsgroup &optional suffix) | 2628 (defun gnus-score-file-name (newsgroup &optional suffix) |
2213 "Return the name of a score file for NEWSGROUP." | 2629 "Return the name of a score file for NEWSGROUP." |
2239 (while files | 2655 (while files |
2240 (if (string-match "/$" (car files)) | 2656 (if (string-match "/$" (car files)) |
2241 (setq out (nconc (directory-files | 2657 (setq out (nconc (directory-files |
2242 (car files) t | 2658 (car files) t |
2243 (concat (gnus-score-file-regexp) "$")))) | 2659 (concat (gnus-score-file-regexp) "$")))) |
2244 (setq out (cons (car files) out))) | 2660 (push (car files) out)) |
2245 (setq files (cdr files))) | 2661 (setq files (cdr files))) |
2246 (setq gnus-internal-global-score-files out))) | 2662 (setq gnus-internal-global-score-files out))) |
2247 | 2663 |
2248 (defun gnus-score-default-fold-toggle () | 2664 (defun gnus-score-default-fold-toggle () |
2249 "Toggle folding for new score file entries." | 2665 "Toggle folding for new score file entries." |
2251 (setq gnus-score-default-fold (not gnus-score-default-fold)) | 2667 (setq gnus-score-default-fold (not gnus-score-default-fold)) |
2252 (if gnus-score-default-fold | 2668 (if gnus-score-default-fold |
2253 (gnus-message 1 "New score file entries will be case insensitive.") | 2669 (gnus-message 1 "New score file entries will be case insensitive.") |
2254 (gnus-message 1 "New score file entries will be case sensitive."))) | 2670 (gnus-message 1 "New score file entries will be case sensitive."))) |
2255 | 2671 |
2672 ;;; Home score file. | |
2673 | |
2674 (defun gnus-home-score-file (group &optional adapt) | |
2675 "Return the home score file for GROUP. | |
2676 If ADAPT, return the home adaptive file instead." | |
2677 (let ((list (if adapt gnus-home-adapt-file gnus-home-score-file)) | |
2678 elem found) | |
2679 ;; Make sure we have a list. | |
2680 (unless (listp list) | |
2681 (setq list (list list))) | |
2682 ;; Go through the list and look for matches. | |
2683 (while (and (not found) | |
2684 (setq elem (pop list))) | |
2685 (setq found | |
2686 (cond | |
2687 ;; Simple string. | |
2688 ((stringp elem) | |
2689 elem) | |
2690 ;; Function. | |
2691 ((gnus-functionp elem) | |
2692 (funcall elem group)) | |
2693 ;; Regexp-file cons | |
2694 ((consp elem) | |
2695 (when (string-match (car elem) group) | |
2696 (cadr elem)))))) | |
2697 (when found | |
2698 (nnheader-concat gnus-kill-files-directory found)))) | |
2699 | |
2700 (defun gnus-hierarchial-home-score-file (group) | |
2701 "Return the score file of the top-level hierarchy of GROUP." | |
2702 (if (string-match "^[^.]+\\." group) | |
2703 (concat (match-string 0 group) gnus-score-file-suffix) | |
2704 ;; Group name without any dots. | |
2705 (concat group "." gnus-score-file-suffix))) | |
2706 | |
2707 (defun gnus-hierarchial-home-adapt-file (group) | |
2708 "Return the adapt file of the top-level hierarchy of GROUP." | |
2709 (if (string-match "^[^.]+\\." group) | |
2710 (concat (match-string 0 group) gnus-adaptive-file-suffix) | |
2711 ;; Group name without any dots. | |
2712 (concat group "." gnus-adaptive-file-suffix))) | |
2713 | |
2714 ;;; | |
2715 ;;; Score decays | |
2716 ;;; | |
2717 | |
2718 (defun gnus-decay-score (score) | |
2719 "Decay SCORE." | |
2720 (floor | |
2721 (- score | |
2722 (* (if (< score 0) 1 -1) | |
2723 (min score | |
2724 (max gnus-score-decay-constant | |
2725 (* (abs score) | |
2726 gnus-score-decay-scale))))))) | |
2727 | |
2728 (defun gnus-decay-scores (alist day) | |
2729 "Decay non-permanent scores in ALIST." | |
2730 (let ((times (- (gnus-time-to-day (current-time)) day)) | |
2731 kill entry updated score n) | |
2732 (unless (zerop times) ;Done decays today already? | |
2733 (while (setq entry (pop alist)) | |
2734 (when (stringp (car entry)) | |
2735 (setq entry (cdr entry)) | |
2736 (while (setq kill (pop entry)) | |
2737 (when (nth 2 kill) | |
2738 (setq updated t) | |
2739 (setq score (or (car kill) gnus-score-interactive-default-score) | |
2740 n times) | |
2741 (while (natnump (decf n)) | |
2742 (setq score (funcall gnus-decay-score-function score))) | |
2743 (setcar kill score)))))) | |
2744 ;; Return whether this score file needs to be saved. By Je-haysuss! | |
2745 updated)) | |
2746 | |
2256 (provide 'gnus-score) | 2747 (provide 'gnus-score) |
2257 | 2748 |
2258 ;;; gnus-score.el ends here | 2749 ;;; gnus-score.el ends here |