17493
|
1 ;;; gnus-cus.el --- customization commands for Gnus
|
|
2 ;;
|
|
3 ;; Copyright (C) 1996 Free Software Foundation, Inc.
|
|
4
|
|
5 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
|
|
6 ;; Keywords: news
|
|
7
|
|
8 ;; This file is part of GNU Emacs.
|
|
9
|
|
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
11 ;; it under the terms of the GNU General Public License as published by
|
|
12 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
13 ;; any later version.
|
|
14
|
|
15 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18 ;; GNU General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
|
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
23 ;; Boston, MA 02111-1307, USA.
|
|
24
|
|
25 ;;; Commentary:
|
|
26
|
|
27 ;;; Code:
|
|
28
|
|
29 (require 'wid-edit)
|
|
30 (require 'gnus-score)
|
|
31
|
|
32 ;;; Widgets:
|
|
33
|
|
34 ;; There should be special validation for this.
|
|
35 (define-widget 'gnus-email-address 'string
|
|
36 "An email address")
|
|
37
|
|
38 (defun gnus-custom-mode ()
|
|
39 "Major mode for editing Gnus customization buffers.
|
|
40
|
|
41 The following commands are available:
|
|
42
|
|
43 \\[widget-forward] Move to next button or editable field.
|
|
44 \\[widget-backward] Move to previous button or editable field.
|
|
45 \\[widget-button-click] Activate button under the mouse pointer.
|
|
46 \\[widget-button-press] Activate button under point.
|
|
47
|
|
48 Entry to this mode calls the value of `gnus-custom-mode-hook'
|
|
49 if that value is non-nil."
|
|
50 (kill-all-local-variables)
|
|
51 (setq major-mode 'gnus-custom-mode
|
|
52 mode-name "Gnus Customize")
|
|
53 (use-local-map widget-keymap)
|
|
54 (run-hooks 'gnus-custom-mode-hook))
|
|
55
|
|
56 ;;; Group Customization:
|
|
57
|
|
58 (defconst gnus-group-parameters
|
|
59 '((to-address (gnus-email-address :tag "To Address") "\
|
|
60 This will be used when doing followups and posts.
|
|
61
|
|
62 This is primarily useful in mail groups that represent closed
|
|
63 mailing lists--mailing lists where it's expected that everybody that
|
|
64 writes to the mailing list is subscribed to it. Since using this
|
|
65 parameter ensures that the mail only goes to the mailing list itself,
|
|
66 it means that members won't receive two copies of your followups.
|
|
67
|
|
68 Using `to-address' will actually work whether the group is foreign or
|
|
69 not. Let's say there's a group on the server that is called
|
|
70 `fa.4ad-l'. This is a real newsgroup, but the server has gotten the
|
|
71 articles from a mail-to-news gateway. Posting directly to this group
|
|
72 is therefore impossible--you have to send mail to the mailing list
|
|
73 address instead.")
|
|
74
|
|
75 (to-list (gnus-email-address :tag "To List") "\
|
|
76 This address will be used when doing a `a' in the group.
|
|
77
|
|
78 It is totally ignored when doing a followup--except that if it is
|
|
79 present in a news group, you'll get mail group semantics when doing
|
|
80 `f'.")
|
|
81
|
|
82 (broken-reply-to (const :tag "Broken Reply To" t) "\
|
|
83 Ignore `Reply-To' headers in this group.
|
|
84
|
|
85 That can be useful if you're reading a mailing list group where the
|
|
86 listserv has inserted `Reply-To' headers that point back to the
|
|
87 listserv itself. This is broken behavior. So there!")
|
|
88
|
|
89 (to-group (string :tag "To Group") "\
|
|
90 All posts will be send to the specified group.")
|
|
91
|
|
92 (gcc-self (choice :tag "GCC"
|
|
93 :value t
|
|
94 (const t)
|
|
95 (const none)
|
|
96 (string :format "%v" :hide-front-space t)) "\
|
|
97 Specify default value for GCC header.
|
|
98
|
|
99 If this symbol is present in the group parameter list and set to `t',
|
|
100 new composed messages will be `Gcc''d to the current group. If it is
|
|
101 present and set to `none', no `Gcc:' header will be generated, if it
|
|
102 is present and a string, this string will be inserted literally as a
|
|
103 `gcc' header (this symbol takes precedence over any default `Gcc'
|
|
104 rules as described later).")
|
|
105
|
|
106 (auto-expire (const :tag "Automatic Expire" t) "\
|
|
107 All articles that are read will be marked as expirable.")
|
|
108
|
|
109 (total-expire (const :tag "Total Expire" t) "\
|
|
110 All read articles will be put through the expiry process
|
|
111
|
|
112 This happens even if they are not marked as expirable.
|
|
113 Use with caution.")
|
|
114
|
|
115 (expiry-wait (choice :tag "Expire Wait"
|
|
116 :value never
|
|
117 (const never)
|
|
118 (const immediate)
|
|
119 (number :hide-front-space t
|
|
120 :format "%v")) "\
|
|
121 When to expire.
|
|
122
|
|
123 Overrides any `nnmail-expiry-wait' and `nnmail-expiry-wait-function'
|
|
124 when expiring expirable messages. The value can either be a number of
|
|
125 days (not necessarily an integer) or the symbols `never' or
|
|
126 `immediate'.")
|
|
127
|
|
128 (score-file (file :tag "Score File") "\
|
|
129 Make the specified file into the current score file.
|
|
130 This means that all score commands you issue will end up in this file.")
|
|
131
|
|
132 (adapt-file (file :tag "Adapt File") "\
|
|
133 Make the specified file into the current adaptive file.
|
|
134 All adaptive score entries will be put into this file.")
|
|
135
|
|
136 (admin-address (gnus-email-address :tag "Admin Address") "\
|
|
137 Administration address for a mailing list.
|
|
138
|
|
139 When unsubscribing to a mailing list you should never send the
|
|
140 unsubscription notice to the mailing list itself. Instead, you'd
|
|
141 send messages to the administrative address. This parameter allows
|
|
142 you to put the admin address somewhere convenient.")
|
|
143
|
|
144 (display (choice :tag "Display"
|
|
145 :value default
|
|
146 (const all)
|
|
147 (const default)) "\
|
|
148 Which articles to display on entering the group.
|
|
149
|
|
150 `all'
|
|
151 Display all articles, both read and unread.
|
|
152
|
|
153 `default'
|
|
154 Display the default visible articles, which normally includes
|
|
155 unread and ticked articles.")
|
|
156
|
|
157 (comment (string :tag "Comment") "\
|
|
158 An arbitrary comment on the group."))
|
|
159 "Alist of valid group parameters.
|
|
160
|
|
161 Each entry has the form (NAME TYPE DOC), where NAME is the parameter
|
|
162 itself (a symbol), TYPE is the parameters type (a sexp widget), and
|
|
163 DOC is a documentation string for the parameter.")
|
|
164
|
|
165 (defvar gnus-custom-params)
|
|
166 (defvar gnus-custom-method)
|
|
167 (defvar gnus-custom-group)
|
|
168
|
|
169 (defun gnus-group-customize (group &optional part)
|
|
170 "Edit the group on the current line."
|
|
171 (interactive (list (gnus-group-group-name)))
|
|
172 (let ((part (or part 'info))
|
|
173 info
|
|
174 (types (mapcar (lambda (entry)
|
|
175 `(cons :format "%v%h\n"
|
|
176 :doc ,(nth 2 entry)
|
|
177 (const :format "" ,(nth 0 entry))
|
|
178 ,(nth 1 entry)))
|
|
179 gnus-group-parameters)))
|
|
180 (unless group
|
|
181 (error "No group on current line"))
|
|
182 (unless (setq info (gnus-get-info group))
|
|
183 (error "Killed group; can't be edited"))
|
|
184 ;; Ready.
|
|
185 (kill-buffer (get-buffer-create "*Gnus Customize*"))
|
|
186 (switch-to-buffer (get-buffer-create "*Gnus Customize*"))
|
|
187 (gnus-custom-mode)
|
|
188 (make-local-variable 'gnus-custom-group)
|
|
189 (setq gnus-custom-group group)
|
|
190 (widget-insert "Customize the ")
|
|
191 (widget-create 'info-link
|
|
192 :help-echo "Push me to learn more."
|
|
193 :tag "group parameters"
|
|
194 "(gnus)Group Parameters")
|
|
195 (widget-insert " for <")
|
|
196 (widget-insert group)
|
|
197 (widget-insert "> and press ")
|
|
198 (widget-create 'push-button
|
|
199 :tag "done"
|
|
200 :help-echo "Push me when done customizing."
|
|
201 :action 'gnus-group-customize-done)
|
|
202 (widget-insert ".\n\n")
|
|
203 (make-local-variable 'gnus-custom-params)
|
|
204 (setq gnus-custom-params
|
|
205 (widget-create 'group
|
|
206 :value (gnus-info-params info)
|
|
207 `(set :inline t
|
|
208 :greedy t
|
|
209 :tag "Parameters"
|
|
210 :format "%t:\n%h%v"
|
|
211 :doc "\
|
|
212 These special paramerters are recognized by Gnus.
|
|
213 Check the [ ] for the parameters you want to apply to this group, then
|
|
214 edit the value to suit your taste."
|
|
215 ,@types)
|
|
216 '(repeat :inline t
|
|
217 :tag "Variables"
|
|
218 :format "%t:\n%h%v%i\n\n"
|
|
219 :doc "\
|
|
220 Set variables local to the group you are entering.
|
|
221
|
|
222 If you want to turn threading off in `news.answers', you could put
|
|
223 `(gnus-show-threads nil)' in the group parameters of that group.
|
|
224 `gnus-show-threads' will be made into a local variable in the summary
|
|
225 buffer you enter, and the form `nil' will be `eval'ed there.
|
|
226
|
|
227 This can also be used as a group-specific hook function, if you'd
|
|
228 like. If you want to hear a beep when you enter a group, you could
|
|
229 put something like `(dummy-variable (ding))' in the parameters of that
|
|
230 group. `dummy-variable' will be set to the result of the `(ding)'
|
|
231 form, but who cares?"
|
|
232 (group :value (nil nil)
|
|
233 (symbol :tag "Variable")
|
|
234 (sexp :tag
|
|
235 "Value")))
|
|
236
|
|
237 '(repeat :inline t
|
|
238 :tag "Unknown entries"
|
|
239 sexp)))
|
|
240 (widget-insert "\n\nYou can also edit the ")
|
|
241 (widget-create 'info-link
|
|
242 :tag "select method"
|
|
243 :help-echo "Push me to learn more about select methods."
|
|
244 "(gnus)Select Methods")
|
|
245 (widget-insert " for the group.\n")
|
|
246 (setq gnus-custom-method
|
|
247 (widget-create 'sexp
|
|
248 :tag "Method"
|
|
249 :value (gnus-info-method info)))
|
|
250 (use-local-map widget-keymap)
|
|
251 (widget-setup)))
|
|
252
|
|
253 (defun gnus-group-customize-done (&rest ignore)
|
|
254 "Apply changes and bury the buffer."
|
|
255 (interactive)
|
|
256 (gnus-group-edit-group-done 'params gnus-custom-group
|
|
257 (widget-value gnus-custom-params))
|
|
258 (gnus-group-edit-group-done 'method gnus-custom-group
|
|
259 (widget-value gnus-custom-method))
|
|
260 (bury-buffer))
|
|
261
|
|
262 ;;; Score Customization:
|
|
263
|
|
264 (defconst gnus-score-parameters
|
|
265 '((mark (number :tag "Mark") "\
|
|
266 The value of this entry should be a number.
|
|
267 Any articles with a score lower than this number will be marked as read.")
|
|
268
|
|
269 (expunge (number :tag "Expunge") "\
|
|
270 The value of this entry should be a number.
|
|
271 Any articles with a score lower than this number will be removed from
|
|
272 the summary buffer.")
|
|
273
|
|
274 (mark-and-expunge (number :tag "Mark-and-expunge") "\
|
|
275 The value of this entry should be a number.
|
|
276 Any articles with a score lower than this number will be marked as
|
|
277 read and removed from the summary buffer.")
|
|
278
|
|
279 (thread-mark-and-expunge (number :tag "Thread-mark-and-expunge") "\
|
|
280 The value of this entry should be a number.
|
|
281 All articles that belong to a thread that has a total score below this
|
|
282 number will be marked as read and removed from the summary buffer.
|
|
283 `gnus-thread-score-function' says how to compute the total score
|
|
284 for a thread.")
|
|
285
|
|
286 (files (repeat :tag "Files" file) "\
|
|
287 The value of this entry should be any number of file names.
|
|
288 These files are assumed to be score files as well, and will be loaded
|
|
289 the same way this one was.")
|
|
290
|
|
291 (exclude-files (repeat :tag "Exclude-files" file) "\
|
|
292 The clue of this entry should be any number of files.
|
|
293 These files will not be loaded, even though they would normally be so,
|
|
294 for some reason or other.")
|
|
295
|
|
296 (eval (sexp :tag "Eval" :value nil) "\
|
|
297 The value of this entry will be `eval'el.
|
|
298 This element will be ignored when handling global score files.")
|
|
299
|
|
300 (read-only (boolean :tag "Read-only" :value t) "\
|
|
301 Read-only score files will not be updated or saved.
|
|
302 Global score files should feature this atom.")
|
|
303
|
|
304 (orphan (number :tag "Orphan") "\
|
|
305 The value of this entry should be a number.
|
|
306 Articles that do not have parents will get this number added to their
|
|
307 scores. Imagine you follow some high-volume newsgroup, like
|
|
308 `comp.lang.c'. Most likely you will only follow a few of the threads,
|
|
309 also want to see any new threads.
|
|
310
|
|
311 You can do this with the following two score file entries:
|
|
312
|
|
313 (orphan -500)
|
|
314 (mark-and-expunge -100)
|
|
315
|
|
316 When you enter the group the first time, you will only see the new
|
|
317 threads. You then raise the score of the threads that you find
|
|
318 interesting (with `I T' or `I S'), and ignore (`C y') the rest.
|
|
319 Next time you enter the group, you will see new articles in the
|
|
320 interesting threads, plus any new threads.
|
|
321
|
|
322 I.e.---the orphan score atom is for high-volume groups where there
|
|
323 exist a few interesting threads which can't be found automatically
|
|
324 by ordinary scoring rules.")
|
|
325
|
|
326 (adapt (choice :tag "Adapt"
|
|
327 (const t)
|
|
328 (const ignore)
|
|
329 (sexp :format "%v"
|
|
330 :hide-front-space t)) "\
|
|
331 This entry controls the adaptive scoring.
|
|
332 If it is `t', the default adaptive scoring rules will be used. If it
|
|
333 is `ignore', no adaptive scoring will be performed on this group. If
|
|
334 it is a list, this list will be used as the adaptive scoring rules.
|
|
335 If it isn't present, or is something other than `t' or `ignore', the
|
|
336 default adaptive scoring rules will be used. If you want to use
|
|
337 adaptive scoring on most groups, you'd set `gnus-use-adaptive-scoring'
|
|
338 to `t', and insert an `(adapt ignore)' in the groups where you do not
|
|
339 want adaptive scoring. If you only want adaptive scoring in a few
|
|
340 groups, you'd set `gnus-use-adaptive-scoring' to `nil', and insert
|
|
341 `(adapt t)' in the score files of the groups where you want it.")
|
|
342
|
|
343 (adapt-file (file :tag "Adapt-file") "\
|
|
344 All adaptive score entries will go to the file named by this entry.
|
|
345 It will also be applied when entering the group. This atom might
|
|
346 be handy if you want to adapt on several groups at once, using the
|
|
347 same adaptive file for a number of groups.")
|
|
348
|
|
349 (local (repeat :tag "Local"
|
|
350 (group :value (nil nil)
|
|
351 (symbol :tag "Variable")
|
|
352 (sexp :tag "Value"))) "\
|
|
353 The value of this entry should be a list of `(VAR VALUE)' pairs.
|
|
354 Each VAR will be made buffer-local to the current summary buffer,
|
|
355 and set to the value specified. This is a convenient, if somewhat
|
|
356 strange, way of setting variables in some groups if you don't like
|
|
357 hooks much.")
|
|
358 (touched (sexp :format "Touched\n") "Internal variable."))
|
|
359 "Alist of valid symbolic score parameters.
|
|
360
|
|
361 Each entry has the form (NAME TYPE DOC), where NAME is the parameter
|
|
362 itself (a symbol), TYPE is the parameters type (a sexp widget), and DOC is a
|
|
363 documentation string for the parameter.")
|
|
364
|
|
365 (define-widget 'gnus-score-string 'group
|
|
366 "Edit score entries for string-valued headers."
|
|
367 :convert-widget 'gnus-score-string-convert)
|
|
368
|
|
369 (defun gnus-score-string-convert (widget)
|
|
370 ;; Set args appropriately.
|
|
371 (let* ((tag (widget-get widget :tag))
|
|
372 (item `(const :format "" :value ,(downcase tag)))
|
|
373 (match '(string :tag "Match"))
|
|
374 (score '(choice :tag "Score"
|
|
375 (const :tag "default" nil)
|
|
376 (integer :format "%v"
|
|
377 :hide-front-space t)))
|
|
378 (expire '(choice :tag "Expire"
|
|
379 (const :tag "off" nil)
|
|
380 (integer :format "%v"
|
|
381 :hide-front-space t)))
|
|
382 (type '(choice :tag "Type"
|
|
383 :value s
|
|
384 ;; I should really create a forgiving :match
|
|
385 ;; function for each type below, that only
|
|
386 ;; looked at the first letter.
|
|
387 (const :tag "Regexp" r)
|
|
388 (const :tag "Regexp (fixed case)" R)
|
|
389 (const :tag "Substring" s)
|
|
390 (const :tag "Substring (fixed case)" S)
|
|
391 (const :tag "Exact" e)
|
|
392 (const :tag "Exact (fixed case)" E)
|
|
393 (const :tag "Word" w)
|
|
394 (const :tag "Word (fixed case)" W)
|
|
395 (const :tag "default" nil)))
|
|
396 (group `(group ,match ,score ,expire ,type))
|
|
397 (doc (concat (or (widget-get widget :doc)
|
|
398 (concat "Change score based on the " tag
|
|
399 " header.\n"))
|
|
400 "
|
|
401 You can have an arbitrary number of score entries for this header,
|
|
402 each score entry has four elements:
|
|
403
|
|
404 1. The \"match element\". This should be the string to look for in the
|
|
405 header.
|
|
406
|
|
407 2. The \"score element\". This number should be an integer in the
|
|
408 neginf to posinf interval. This number is added to the score
|
|
409 of the article if the match is successful. If this element is
|
|
410 not present, the `gnus-score-interactive-default-score' number
|
|
411 will be used instead. This is 1000 by default.
|
|
412
|
|
413 3. The \"date element\". This date says when the last time this score
|
|
414 entry matched, which provides a mechanism for expiring the
|
|
415 score entries. It this element is not present, the score
|
|
416 entry is permanent. The date is represented by the number of
|
|
417 days since December 31, 1 ce.
|
|
418
|
|
419 4. The \"type element\". This element specifies what function should
|
|
420 be used to see whether this score entry matches the article.
|
|
421
|
|
422 There are the regexp, as well as substring types, and exact match,
|
|
423 and word match types. If this element is not present, Gnus will
|
|
424 assume that substring matching should be used. There is case
|
|
425 sensitive variants of all match types.")))
|
|
426 (widget-put widget :args `(,item
|
|
427 (repeat :inline t
|
|
428 :indent 0
|
|
429 :tag ,tag
|
|
430 :doc ,doc
|
|
431 :format "%t:\n%h%v%i\n\n"
|
|
432 (choice :format "%v"
|
|
433 :value ("" nil nil s)
|
|
434 ,group
|
|
435 sexp)))))
|
|
436 widget)
|
|
437
|
|
438 (define-widget 'gnus-score-integer 'group
|
|
439 "Edit score entries for integer-valued headers."
|
|
440 :convert-widget 'gnus-score-integer-convert)
|
|
441
|
|
442 (defun gnus-score-integer-convert (widget)
|
|
443 ;; Set args appropriately.
|
|
444 (let* ((tag (widget-get widget :tag))
|
|
445 (item `(const :format "" :value ,(downcase tag)))
|
|
446 (match '(integer :tag "Match"))
|
|
447 (score '(choice :tag "Score"
|
|
448 (const :tag "default" nil)
|
|
449 (integer :format "%v"
|
|
450 :hide-front-space t)))
|
|
451 (expire '(choice :tag "Expire"
|
|
452 (const :tag "off" nil)
|
|
453 (integer :format "%v"
|
|
454 :hide-front-space t)))
|
|
455 (type '(choice :tag "Type"
|
|
456 :value <
|
|
457 (const <)
|
|
458 (const >)
|
|
459 (const =)
|
|
460 (const >=)
|
|
461 (const <=)))
|
|
462 (group `(group ,match ,score ,expire ,type))
|
|
463 (doc (concat (or (widget-get widget :doc)
|
|
464 (concat "Change score based on the " tag
|
|
465 " header.")))))
|
|
466 (widget-put widget :args `(,item
|
|
467 (repeat :inline t
|
|
468 :indent 0
|
|
469 :tag ,tag
|
|
470 :doc ,doc
|
|
471 :format "%t:\n%h%v%i\n\n"
|
|
472 ,group))))
|
|
473 widget)
|
|
474
|
|
475 (define-widget 'gnus-score-date 'group
|
|
476 "Edit score entries for date-valued headers."
|
|
477 :convert-widget 'gnus-score-date-convert)
|
|
478
|
|
479 (defun gnus-score-date-convert (widget)
|
|
480 ;; Set args appropriately.
|
|
481 (let* ((tag (widget-get widget :tag))
|
|
482 (item `(const :format "" :value ,(downcase tag)))
|
|
483 (match '(string :tag "Match"))
|
|
484 (score '(choice :tag "Score"
|
|
485 (const :tag "default" nil)
|
|
486 (integer :format "%v"
|
|
487 :hide-front-space t)))
|
|
488 (expire '(choice :tag "Expire"
|
|
489 (const :tag "off" nil)
|
|
490 (integer :format "%v"
|
|
491 :hide-front-space t)))
|
|
492 (type '(choice :tag "Type"
|
|
493 :value regexp
|
|
494 (const regexp)
|
|
495 (const before)
|
|
496 (const at)
|
|
497 (const after)))
|
|
498 (group `(group ,match ,score ,expire ,type))
|
|
499 (doc (concat (or (widget-get widget :doc)
|
|
500 (concat "Change score based on the " tag
|
|
501 " header."))
|
|
502 "
|
|
503 For the Date header we have three kinda silly match types: `before',
|
|
504 `at' and `after'. I can't really imagine this ever being useful, but,
|
|
505 like, it would feel kinda silly not to provide this function. Just in
|
|
506 case. You never know. Better safe than sorry. Once burnt, twice
|
|
507 shy. Don't judge a book by its cover. Never not have sex on a first
|
|
508 date. (I have been told that at least one person, and I quote,
|
|
509 \"found this function indispensable\", however.)
|
|
510
|
|
511 A more useful match type is `regexp'. With it, you can match the date
|
|
512 string using a regular expression. The date is normalized to ISO8601
|
|
513 compact format first---`YYYYMMDDTHHMMSS'. If you want to match all
|
|
514 articles that have been posted on April 1st in every year, you could
|
|
515 use `....0401.........' as a match string, for instance. (Note that
|
|
516 the date is kept in its original time zone, so this will match
|
|
517 articles that were posted when it was April 1st where the article was
|
|
518 posted from. Time zones are such wholesome fun for the whole family,
|
|
519 eh?")))
|
|
520 (widget-put widget :args `(,item
|
|
521 (repeat :inline t
|
|
522 :indent 0
|
|
523 :tag ,tag
|
|
524 :doc ,doc
|
|
525 :format "%t:\n%h%v%i\n\n"
|
|
526 ,group))))
|
|
527 widget)
|
|
528
|
|
529 (defvar gnus-custom-scores)
|
|
530 (defvar gnus-custom-score-alist)
|
|
531
|
|
532 (defun gnus-score-customize (file)
|
|
533 "Customize score file FILE."
|
|
534 (interactive (list gnus-current-score-file))
|
|
535 (let ((scores (gnus-score-load file))
|
|
536 (types (mapcar (lambda (entry)
|
|
537 `(group :format "%v%h\n"
|
|
538 :doc ,(nth 2 entry)
|
|
539 (const :format "" ,(nth 0 entry))
|
|
540 ,(nth 1 entry)))
|
|
541 gnus-score-parameters)))
|
|
542 ;; Ready.
|
|
543 (kill-buffer (get-buffer-create "*Gnus Customize*"))
|
|
544 (switch-to-buffer (get-buffer-create "*Gnus Customize*"))
|
|
545 (gnus-custom-mode)
|
|
546 (make-local-variable 'gnus-custom-score-alist)
|
|
547 (setq gnus-custom-score-alist scores)
|
|
548 (widget-insert "Customize the ")
|
|
549 (widget-create 'info-link
|
|
550 :help-echo "Push me to learn more."
|
|
551 :tag "score entries"
|
|
552 "(gnus)Score File Format")
|
|
553 (widget-insert " for\n\t")
|
|
554 (widget-insert file)
|
|
555 (widget-insert "\nand press ")
|
|
556 (widget-create 'push-button
|
|
557 :tag "done"
|
|
558 :help-echo "Push me when done customizing."
|
|
559 :action 'gnus-score-customize-done)
|
|
560 (widget-insert ".\n
|
|
561 Check the [ ] for the entries you want to apply to this score file, then
|
|
562 edit the value to suit your taste. Don't forget to mark the checkbox,
|
|
563 if you do all your changes will be lost. ")
|
|
564 (widget-create 'push-button
|
|
565 :action (lambda (&rest ignore)
|
|
566 (require 'gnus-audio)
|
|
567 (gnus-audio-play "Evil_Laugh.au"))
|
|
568 "Bhahahah!")
|
|
569 (widget-insert "\n\n")
|
|
570 (make-local-variable 'gnus-custom-scores)
|
|
571 (setq gnus-custom-scores
|
|
572 (widget-create 'group
|
|
573 :value scores
|
|
574 `(checklist :inline t
|
|
575 :greedy t
|
|
576 (gnus-score-string :tag "From")
|
|
577 (gnus-score-string :tag "Subject")
|
|
578 (gnus-score-string :tag "References")
|
|
579 (gnus-score-string :tag "Xref")
|
|
580 (gnus-score-string :tag "Message-ID")
|
|
581 (gnus-score-integer :tag "Lines")
|
|
582 (gnus-score-integer :tag "Chars")
|
|
583 (gnus-score-date :tag "Date")
|
|
584 (gnus-score-string :tag "Head"
|
|
585 :doc "\
|
|
586 Match all headers in the article.
|
|
587
|
|
588 Using one of `Head', `Body', `All' will slow down scoring considerable.
|
|
589 ")
|
|
590 (gnus-score-string :tag "Body"
|
|
591 :doc "\
|
|
592 Match the body sans header of the article.
|
|
593
|
|
594 Using one of `Head', `Body', `All' will slow down scoring considerable.
|
|
595 ")
|
|
596 (gnus-score-string :tag "All"
|
|
597 :doc "\
|
|
598 Match the entire article, including both headers and body.
|
|
599
|
|
600 Using one of `Head', `Body', `All' will slow down scoring
|
|
601 considerable.
|
|
602 ")
|
|
603 (gnus-score-string :tag
|
|
604 "Followup"
|
|
605 :doc "\
|
|
606 Score all followups to the specified authors.
|
|
607
|
|
608 This entry is somewhat special, in that it will match the `From:'
|
|
609 header, and affect the score of not only the matching articles, but
|
|
610 also all followups to the matching articles. This allows you
|
|
611 e.g. increase the score of followups to your own articles, or decrease
|
|
612 the score of followups to the articles of some known trouble-maker.
|
|
613 ")
|
|
614 (gnus-score-string :tag "Thread"
|
|
615 :doc "\
|
|
616 Add a score entry on all articles that are part of a thread.
|
|
617
|
|
618 This match key works along the same lines as the `Followup' match key.
|
|
619 If you say that you want to score on a (sub-)thread that is started by
|
|
620 an article with a `Message-ID' X, then you add a `thread' match. This
|
|
621 will add a new `thread' match for each article that has X in its
|
|
622 `References' header. (These new `thread' matches will use the
|
|
623 `Message-ID's of these matching articles.) This will ensure that you
|
|
624 can raise/lower the score of an entire thread, even though some
|
|
625 articles in the thread may not have complete `References' headers.
|
|
626 Note that using this may lead to undeterministic scores of the
|
|
627 articles in the thread.
|
|
628 ")
|
|
629 ,@types)
|
|
630 '(repeat :inline t
|
|
631 :tag "Unknown entries"
|
|
632 sexp)))
|
|
633 (use-local-map widget-keymap)
|
|
634 (widget-setup)))
|
|
635
|
|
636 (defun gnus-score-customize-done (&rest ignore)
|
|
637 "Reset the score alist with the present value."
|
|
638 (let ((alist gnus-custom-score-alist)
|
|
639 (value (widget-value gnus-custom-scores)))
|
|
640 (setcar alist (car value))
|
|
641 (setcdr alist (cdr value))
|
|
642 (gnus-score-set 'touched '(t) alist))
|
|
643 (bury-buffer))
|
|
644
|
|
645 ;;; The End:
|
|
646
|
|
647 (provide 'gnus-cus)
|
|
648
|
|
649 ;;; gnus-cus.el ends here
|
|
650
|