* gnus-agent.el (directory-files-and-attributes): Move all the way
[gnus] / lisp / gnus-score.el
1 ;;; gnus-score.el --- scoring code for Gnus
2
3 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4 ;;   2004, 2005, 2006 Free Software Foundation, Inc.
5
6 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
7 ;;      Lars Magne Ingebrigtsen <larsi@gnus.org>
8 ;; Keywords: news
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28
29 ;;; Code:
30
31 (eval-when-compile (require 'cl))
32
33 (require 'gnus)
34 (require 'gnus-sum)
35 (require 'gnus-range)
36 (require 'gnus-win)
37 (require 'message)
38 (require 'score-mode)
39
40 (defcustom gnus-global-score-files nil
41   "List of global score files and directories.
42 Set this variable if you want to use people's score files.  One entry
43 for each score file or each score file directory.  Gnus will decide
44 by itself what score files are applicable to which group.
45
46 Say you want to use the single score file
47 \"/ftp.gnus.org@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all
48 score files in the \"/ftp.some-where:/pub/score\" directory.
49
50  (setq gnus-global-score-files
51        '(\"/ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE\"
52          \"/ftp.some-where:/pub/score\"))"
53   :group 'gnus-score-files
54   :type '(repeat file))
55
56 (defcustom gnus-score-file-single-match-alist nil
57   "Alist mapping regexps to lists of score files.
58 Each element of this alist should be of the form
59         (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
60
61 If the name of a group is matched by REGEXP, the corresponding scorefiles
62 will be used for that group.
63 The first match found is used, subsequent matching entries are ignored (to
64 use multiple matches, see `gnus-score-file-multiple-match-alist').
65
66 These score files are loaded in addition to any files returned by
67 `gnus-score-find-score-files-function'."
68   :group 'gnus-score-files
69   :type '(repeat (cons regexp (repeat file))))
70
71 (defcustom gnus-score-file-multiple-match-alist nil
72   "Alist mapping regexps to lists of score files.
73 Each element of this alist should be of the form
74         (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
75
76 If the name of a group is matched by REGEXP, the corresponding scorefiles
77 will be used for that group.
78 If multiple REGEXPs match a group, the score files corresponding to each
79 match will be used (for only one match to be used, see
80 `gnus-score-file-single-match-alist').
81
82 These score files are loaded in addition to any files returned by
83 `gnus-score-find-score-files-function'."
84   :group 'gnus-score-files
85   :type '(repeat (cons regexp (repeat file))))
86
87 (defcustom gnus-score-file-suffix "SCORE"
88   "Suffix of the score files."
89   :group 'gnus-score-files
90   :type 'string)
91
92 (defcustom gnus-adaptive-file-suffix "ADAPT"
93   "Suffix of the adaptive score files."
94   :group 'gnus-score-files
95   :group 'gnus-score-adapt
96   :type 'string)
97
98 (defcustom gnus-score-find-score-files-function 'gnus-score-find-bnews
99   "Function used to find score files.
100 The function will be called with the group name as the argument, and
101 should return a list of score files to apply to that group.  The score
102 files do not actually have to exist.
103
104 Predefined values are:
105
106 `gnus-score-find-single': Only apply the group's own score file.
107 `gnus-score-find-hierarchical': Also apply score files from parent groups.
108 `gnus-score-find-bnews': Apply score files whose names matches.
109
110 See the documentation to these functions for more information.
111
112 This variable can also be a list of functions to be called.  Each
113 function is given the group name as argument and should either return
114 a list of score files, or a list of score alists.
115
116 If functions other than these pre-defined functions are used,
117 the `a' symbolic prefix to the score commands will always use
118 \"all.SCORE\"."
119   :group 'gnus-score-files
120   :type '(radio (function-item gnus-score-find-single)
121                 (function-item gnus-score-find-hierarchical)
122                 (function-item gnus-score-find-bnews)
123                 (repeat :tag "List of functions"
124                         (choice (function :tag "Other" :value 'ignore)
125                                 (function-item gnus-score-find-single)
126                                 (function-item gnus-score-find-hierarchical)
127                                 (function-item gnus-score-find-bnews)))
128                 (function :tag "Other" :value 'ignore)))
129
130 (defcustom gnus-score-interactive-default-score 1000
131   "*Scoring commands will raise/lower the score with this number as the default."
132   :group 'gnus-score-default
133   :type 'integer)
134
135 (defcustom gnus-score-expiry-days 7
136   "*Number of days before unused score file entries are expired.
137 If this variable is nil, no score file entries will be expired."
138   :group 'gnus-score-expire
139   :type '(choice (const :tag "never" nil)
140                  number))
141
142 (defcustom gnus-update-score-entry-dates t
143   "*If non-nil, update matching score entry dates.
144 If this variable is nil, then score entries that provide matches
145 will be expired along with non-matching score entries."
146   :group 'gnus-score-expire
147   :type 'boolean)
148
149 (defcustom gnus-decay-scores nil
150   "*If non-nil, decay non-permanent scores.
151
152 If it is a regexp, only decay score files matching regexp."
153   :group 'gnus-score-decay
154   :type `(choice (const :tag "never" nil)
155                  (const :tag "always" t)
156                  (const :tag "adaptive score files"
157                         ,(concat "\\." gnus-adaptive-file-suffix "\\'"))
158                  (regexp)))
159
160 (defcustom gnus-decay-score-function 'gnus-decay-score
161   "*Function called to decay a score.
162 It is called with one parameter -- the score to be decayed."
163   :group 'gnus-score-decay
164   :type '(radio (function-item gnus-decay-score)
165                 (function :tag "Other")))
166
167 (defcustom gnus-score-decay-constant 3
168   "*Decay all \"small\" scores with this amount."
169   :group 'gnus-score-decay
170   :type 'integer)
171
172 (defcustom gnus-score-decay-scale .05
173   "*Decay all \"big\" scores with this factor."
174   :group 'gnus-score-decay
175   :type 'number)
176
177 (defcustom gnus-home-score-file nil
178   "Variable to control where interactive score entries are to go.
179 It can be:
180
181  * A string
182    This file will be used as the home score file.
183
184  * A function
185    The result of this function will be used as the home score file.
186    The function will be passed the name of the group as its
187    parameter.
188
189  * A list
190    The elements in this list can be:
191
192    * `(regexp file-name ...)'
193      If the `regexp' matches the group name, the first `file-name'
194      will be used as the home score file.  (Multiple filenames are
195      allowed so that one may use gnus-score-file-single-match-alist to
196      set this variable.)
197
198    * A function.
199      If the function returns non-nil, the result will be used
200      as the home score file.  The function will be passed the
201      name of the group as its parameter.
202
203    * A string.  Use the string as the home score file.
204
205    The list will be traversed from the beginning towards the end looking
206    for matches."
207   :group 'gnus-score-files
208   :type '(choice string
209                  (repeat (choice string
210                                  (cons regexp (repeat file))
211                                  (function :value fun)))
212                  (function-item gnus-hierarchial-home-score-file)
213                  (function-item gnus-current-home-score-file)
214                  (function :value fun)))
215
216 (defcustom gnus-home-adapt-file nil
217   "Variable to control where new adaptive score entries are to go.
218 This variable allows the same syntax as `gnus-home-score-file'."
219   :group 'gnus-score-adapt
220   :group 'gnus-score-files
221   :type '(choice string
222                  (repeat (choice string
223                                  (cons regexp (repeat file))
224                                  (function :value fun)))
225                  (function :value fun)))
226
227 (defcustom gnus-default-adaptive-score-alist
228   `((gnus-kill-file-mark)
229     (gnus-unread-mark)
230     (gnus-read-mark
231      (from , (+ 2 gnus-score-decay-constant))
232      (subject , (+ 27 gnus-score-decay-constant)))
233     (gnus-catchup-mark
234      (subject , (+ -7 (* -1 gnus-score-decay-constant))))
235     (gnus-killed-mark
236      (from , (- -1 gnus-score-decay-constant))
237      (subject , (+ -17 (* -1 gnus-score-decay-constant))))
238     (gnus-del-mark
239      (from , (- -1 gnus-score-decay-constant))
240      (subject , (+ -12 (* -1 gnus-score-decay-constant)))))
241   "Alist of marks and scores.
242 If you use score decays, you might want to set values higher than
243 `gnus-score-decay-constant'."
244   :group 'gnus-score-adapt
245   :type '(repeat (cons (symbol :tag "Mark")
246                        (repeat (list (choice :tag "Header"
247                                              (const from)
248                                              (const subject)
249                                              (symbol :tag "other"))
250                                      (integer :tag "Score"))))))
251
252 (defcustom gnus-adaptive-word-length-limit nil
253   "*Words of a length lesser than this limit will be ignored when doing adaptive scoring."
254   :version "22.1"
255   :group 'gnus-score-adapt
256   :type '(radio (const :format "Unlimited " nil)
257                 (integer :format "Maximum length: %v")))
258
259 (defcustom gnus-ignored-adaptive-words nil
260   "List of words to be ignored when doing adaptive word scoring."
261   :group 'gnus-score-adapt
262   :type '(repeat string))
263
264 (defcustom gnus-default-ignored-adaptive-words