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