comparison lisp/gnus/gnus-kill.el @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents ec9a17fef872
children 0d2f883870bc
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
1 ;;; gnus-kill.el --- kill commands for Gnus 1 ;;; gnus-kill.el --- kill commands 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: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> 4 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
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-art) 30 (eval-when-compile (require 'cl))
31 (require 'gnus-range) 31
32 32 (defvar gnus-kill-file-mode-hook nil
33 (defcustom gnus-kill-file-mode-hook nil 33 "*A hook for Gnus kill file mode.")
34 "Hook for Gnus kill file mode." 34
35 :group 'gnus-score-kill 35 (defvar gnus-kill-expiry-days 7
36 :type 'hook) 36 "*Number of days before expiring unused kill file entries.")
37 37
38 (defcustom gnus-kill-expiry-days 7 38 (defvar gnus-kill-save-kill-file nil
39 "*Number of days before expiring unused kill file entries." 39 "*If non-nil, will save kill files after processing them.")
40 :group 'gnus-score-kill 40
41 :group 'gnus-score-expire 41 (defvar gnus-winconf-kill-file nil)
42 :type 'integer)
43
44 (defcustom gnus-kill-save-kill-file nil
45 "*If non-nil, will save kill files after processing them."
46 :group 'gnus-score-kill
47 :type 'boolean)
48
49 (defcustom gnus-winconf-kill-file nil
50 "What does this do, Lars?"
51 :group 'gnus-score-kill
52 :type 'sexp)
53
54 (defcustom gnus-kill-killed t
55 "*If non-nil, Gnus will apply kill files to already killed articles.
56 If it is nil, Gnus will never apply kill files to articles that have
57 already been through the scoring process, which might very well save lots
58 of time."
59 :group 'gnus-score-kill
60 :type 'boolean)
61 42
62 43
63 44
64 (defmacro gnus-raise (field expression level) 45 (defmacro gnus-raise (field expression level)
65 `(gnus-kill ,field ,expression 46 `(gnus-kill ,field ,expression
74 ;;; 55 ;;;
75 56
76 (defvar gnus-kill-file-mode-map nil) 57 (defvar gnus-kill-file-mode-map nil)
77 58
78 (unless gnus-kill-file-mode-map 59 (unless gnus-kill-file-mode-map
79 (gnus-define-keymap (setq gnus-kill-file-mode-map 60 (gnus-define-keymap
80 (copy-keymap emacs-lisp-mode-map)) 61 (setq gnus-kill-file-mode-map (copy-keymap emacs-lisp-mode-map))
81 "\C-c\C-k\C-s" gnus-kill-file-kill-by-subject 62 "\C-c\C-k\C-s" gnus-kill-file-kill-by-subject
82 "\C-c\C-k\C-a" gnus-kill-file-kill-by-author 63 "\C-c\C-k\C-a" gnus-kill-file-kill-by-author
83 "\C-c\C-k\C-t" gnus-kill-file-kill-by-thread 64 "\C-c\C-k\C-t" gnus-kill-file-kill-by-thread
84 "\C-c\C-k\C-x" gnus-kill-file-kill-by-xref 65 "\C-c\C-k\C-x" gnus-kill-file-kill-by-xref
85 "\C-c\C-a" gnus-kill-file-apply-buffer 66 "\C-c\C-a" gnus-kill-file-apply-buffer
86 "\C-c\C-e" gnus-kill-file-apply-last-sexp 67 "\C-c\C-e" gnus-kill-file-apply-last-sexp
87 "\C-c\C-c" gnus-kill-file-exit)) 68 "\C-c\C-c" gnus-kill-file-exit))
88 69
89 (defun gnus-kill-file-mode () 70 (defun gnus-kill-file-mode ()
90 "Major mode for editing kill files. 71 "Major mode for editing kill files.
91 72
92 If you are using this mode - you probably shouldn't. Kill files 73 If you are using this mode - you probably shouldn't. Kill files
110 purpose is not so easy because the internal working of Gnus must be 91 purpose is not so easy because the internal working of Gnus must be
111 well-known. For this reason, Gnus provides a general function which 92 well-known. For this reason, Gnus provides a general function which
112 does this easily for non-Lisp programmers. 93 does this easily for non-Lisp programmers.
113 94
114 The `gnus-kill' function executes commands available in Summary Mode 95 The `gnus-kill' function executes commands available in Summary Mode
115 by their key sequences. `gnus-kill' should be called with FIELD, 96 by their key sequences. `gnus-kill' should be called with FIELD,
116 REGEXP and optional COMMAND and ALL. FIELD is a string representing 97 REGEXP and optional COMMAND and ALL. FIELD is a string representing
117 the header field or an empty string. If FIELD is an empty string, the 98 the header field or an empty string. If FIELD is an empty string, the
118 entire article body is searched for. REGEXP is a string which is 99 entire article body is searched for. REGEXP is a string which is
119 compared with FIELD value. COMMAND is a string representing a valid 100 compared with FIELD value. COMMAND is a string representing a valid
120 key sequence in Summary mode or Lisp expression. COMMAND defaults to 101 key sequence in Summary mode or Lisp expression. COMMAND defaults to
121 '(gnus-summary-mark-as-read nil \"X\"). Make sure that COMMAND is 102 '(gnus-summary-mark-as-read nil \"X\"). Make sure that COMMAND is
122 executed in the Summary buffer. If the second optional argument ALL 103 executed in the Summary buffer. If the second optional argument ALL
123 is non-nil, the COMMAND is applied to articles which are already 104 is non-nil, the COMMAND is applied to articles which are already
124 marked as read or unread. Articles which are marked are skipped over 105 marked as read or unread. Articles which are marked are skipped over
125 by default. 106 by default.
197 ;; Enter kill file entry. 178 ;; Enter kill file entry.
198 ;; FIELD: String containing the name of the header field to kill. 179 ;; FIELD: String containing the name of the header field to kill.
199 ;; REGEXP: The string to kill. 180 ;; REGEXP: The string to kill.
200 (save-excursion 181 (save-excursion
201 (let (string) 182 (let (string)
202 (unless (eq major-mode 'gnus-kill-file-mode) 183 (or (eq major-mode 'gnus-kill-file-mode)
203 (gnus-kill-set-kill-buffer)) 184 (gnus-kill-set-kill-buffer))
204 (unless dont-move 185 (unless dont-move
205 (goto-char (point-max))) 186 (goto-char (point-max)))
206 (insert (setq string (format "(gnus-kill %S %S)\n" field regexp))) 187 (insert (setq string (format "(gnus-kill %S %S)\n" field regexp)))
207 (gnus-kill-file-apply-string string)))) 188 (gnus-kill-file-apply-string string))))
208 189
209 (defun gnus-kill-file-kill-by-subject () 190 (defun gnus-kill-file-kill-by-subject ()
210 "Kill by subject." 191 "Kill by subject."
211 (interactive) 192 (interactive)
212 (gnus-kill-file-enter-kill 193 (gnus-kill-file-enter-kill
213 "Subject" 194 "Subject"
214 (if (vectorp gnus-current-headers) 195 (if (vectorp gnus-current-headers)
215 (regexp-quote 196 (regexp-quote
216 (gnus-simplify-subject (mail-header-subject gnus-current-headers))) 197 (gnus-simplify-subject (mail-header-subject gnus-current-headers)))
217 "") 198 "") t))
218 t)) 199
219
220 (defun gnus-kill-file-kill-by-author () 200 (defun gnus-kill-file-kill-by-author ()
221 "Kill by author." 201 "Kill by author."
222 (interactive) 202 (interactive)
223 (gnus-kill-file-enter-kill 203 (gnus-kill-file-enter-kill
224 "From" 204 "From"
225 (if (vectorp gnus-current-headers) 205 (if (vectorp gnus-current-headers)
226 (regexp-quote (mail-header-from gnus-current-headers)) 206 (regexp-quote (mail-header-from gnus-current-headers))
227 "") t)) 207 "") t))
228 208
229 (defun gnus-kill-file-kill-by-thread () 209 (defun gnus-kill-file-kill-by-thread ()
230 "Kill by author." 210 "Kill by author."
231 (interactive) 211 (interactive)
232 (gnus-kill-file-enter-kill 212 (gnus-kill-file-enter-kill
233 "References" 213 "References"
234 (if (vectorp gnus-current-headers) 214 (if (vectorp gnus-current-headers)
235 (regexp-quote (mail-header-id gnus-current-headers)) 215 (regexp-quote (mail-header-id gnus-current-headers))
236 ""))) 216 "")))
237 217
238 (defun gnus-kill-file-kill-by-xref () 218 (defun gnus-kill-file-kill-by-xref ()
239 "Kill by Xref." 219 "Kill by Xref."
240 (interactive) 220 (interactive)
241 (let ((xref (and (vectorp gnus-current-headers) 221 (let ((xref (and (vectorp gnus-current-headers)
242 (mail-header-xref gnus-current-headers))) 222 (mail-header-xref gnus-current-headers)))
243 (start 0) 223 (start 0)
244 group) 224 group)
245 (if xref 225 (if xref
246 (while (string-match " \\([^ \t]+\\):" xref start) 226 (while (string-match " \\([^ \t]+\\):" xref start)
247 (setq start (match-end 0)) 227 (setq start (match-end 0))
248 (when (not (string= 228 (if (not (string=
249 (setq group 229 (setq group
250 (substring xref (match-beginning 1) (match-end 1))) 230 (substring xref (match-beginning 1) (match-end 1)))
251 gnus-newsgroup-name)) 231 gnus-newsgroup-name))
252 (gnus-kill-file-enter-kill 232 (gnus-kill-file-enter-kill
253 "Xref" (concat " " (regexp-quote group) ":") t))) 233 "Xref" (concat " " (regexp-quote group) ":") t)))
254 (gnus-kill-file-enter-kill "Xref" "" t)))) 234 (gnus-kill-file-enter-kill "Xref" "" t))))
255 235
256 (defun gnus-kill-file-raise-followups-to-author (level) 236 (defun gnus-kill-file-raise-followups-to-author (level)
257 "Raise score for all followups to the current author." 237 "Raise score for all followups to the current author."
258 (interactive "p") 238 (interactive "p")
262 (gnus-kill-set-kill-buffer) 242 (gnus-kill-set-kill-buffer)
263 (goto-char (point-min)) 243 (goto-char (point-min))
264 (setq name (read-string (concat "Add " level 244 (setq name (read-string (concat "Add " level
265 " to followup articles to: ") 245 " to followup articles to: ")
266 (regexp-quote name))) 246 (regexp-quote name)))
267 (setq 247 (setq
268 string 248 string
269 (format 249 (format
270 "(gnus-kill %S %S '(gnus-summary-temporarily-raise-by-thread %S))\n" 250 "(gnus-kill %S %S '(gnus-summary-temporarily-raise-by-thread %S))\n"
271 "From" name level)) 251 "From" name level))
272 (insert string) 252 (insert string)
273 (gnus-kill-file-apply-string string)) 253 (gnus-kill-file-apply-string string))
274 (gnus-message 254 (gnus-message
275 6 "Added temporary score file entry for followups to %s." name))) 255 6 "Added temporary score file entry for followups to %s." name)))
276 256
277 (defun gnus-kill-file-apply-buffer () 257 (defun gnus-kill-file-apply-buffer ()
278 "Apply current buffer to current newsgroup." 258 "Apply current buffer to current newsgroup."
279 (interactive) 259 (interactive)
311 "Save a kill file, then return to the previous buffer." 291 "Save a kill file, then return to the previous buffer."
312 (interactive) 292 (interactive)
313 (save-buffer) 293 (save-buffer)
314 (let ((killbuf (current-buffer))) 294 (let ((killbuf (current-buffer)))
315 ;; We don't want to return to article buffer. 295 ;; We don't want to return to article buffer.
316 (when (get-buffer gnus-article-buffer) 296 (and (get-buffer gnus-article-buffer)
317 (bury-buffer gnus-article-buffer)) 297 (bury-buffer gnus-article-buffer))
318 ;; Delete the KILL file windows. 298 ;; Delete the KILL file windows.
319 (delete-windows-on killbuf) 299 (delete-windows-on killbuf)
320 ;; Restore last window configuration if available. 300 ;; Restore last window configuration if available.
321 (when gnus-winconf-kill-file 301 (and gnus-winconf-kill-file
322 (set-window-configuration gnus-winconf-kill-file)) 302 (set-window-configuration gnus-winconf-kill-file))
323 (setq gnus-winconf-kill-file nil) 303 (setq gnus-winconf-kill-file nil)
324 ;; Kill the KILL file buffer. Suggested by tale@pawl.rpi.edu. 304 ;; Kill the KILL file buffer. Suggested by tale@pawl.rpi.edu.
325 (kill-buffer killbuf))) 305 (kill-buffer killbuf)))
326 306
327 ;; For kill files 307 ;; For kill files
352 332
353 (defun gnus-apply-kill-file-unless-scored () 333 (defun gnus-apply-kill-file-unless-scored ()
354 "Apply .KILL file, unless a .SCORE file for the same newsgroup exists." 334 "Apply .KILL file, unless a .SCORE file for the same newsgroup exists."
355 (cond ((file-exists-p (gnus-score-file-name gnus-newsgroup-name)) 335 (cond ((file-exists-p (gnus-score-file-name gnus-newsgroup-name))
356 ;; Ignores global KILL. 336 ;; Ignores global KILL.
357 (when (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)) 337 (if (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name))
358 (gnus-message 3 "Note: Ignoring %s.KILL; preferring .SCORE" 338 (gnus-message 3 "Note: Ignoring %s.KILL; preferring .SCORE"
359 gnus-newsgroup-name)) 339 gnus-newsgroup-name))
360 0) 340 0)
361 ((or (file-exists-p (gnus-newsgroup-kill-file nil)) 341 ((or (file-exists-p (gnus-newsgroup-kill-file nil))
362 (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name))) 342 (file-exists-p (gnus-newsgroup-kill-file gnus-newsgroup-name)))
363 (gnus-apply-kill-file-internal)) 343 (gnus-apply-kill-file-internal))
364 (t 344 (t
373 (gnus-summary-inhibit-highlight t) 353 (gnus-summary-inhibit-highlight t)
374 beg) 354 beg)
375 (setq gnus-newsgroup-kill-headers nil) 355 (setq gnus-newsgroup-kill-headers nil)
376 ;; If there are any previously scored articles, we remove these 356 ;; If there are any previously scored articles, we remove these
377 ;; from the `gnus-newsgroup-headers' list that the score functions 357 ;; from the `gnus-newsgroup-headers' list that the score functions
378 ;; will see. This is probably pretty wasteful when it comes to 358 ;; will see. This is probably pretty wasteful when it comes to
379 ;; conses, but is, I think, faster than having to assq in every 359 ;; conses, but is, I think, faster than having to assq in every
380 ;; single score function. 360 ;; single score function.
381 (let ((files kill-files)) 361 (let ((files kill-files))
382 (while files 362 (while files
383 (if (file-exists-p (car files)) 363 (if (file-exists-p (car files))
385 (if gnus-kill-killed 365 (if gnus-kill-killed
386 (setq gnus-newsgroup-kill-headers 366 (setq gnus-newsgroup-kill-headers
387 (mapcar (lambda (header) (mail-header-number header)) 367 (mapcar (lambda (header) (mail-header-number header))
388 headers)) 368 headers))
389 (while headers 369 (while headers
390 (unless (gnus-member-of-range 370 (or (gnus-member-of-range
391 (mail-header-number (car headers)) 371 (mail-header-number (car headers))
392 gnus-newsgroup-killed) 372 gnus-newsgroup-killed)
393 (push (mail-header-number (car headers)) 373 (setq gnus-newsgroup-kill-headers
394 gnus-newsgroup-kill-headers)) 374 (cons (mail-header-number (car headers))
375 gnus-newsgroup-kill-headers)))
395 (setq headers (cdr headers)))) 376 (setq headers (cdr headers))))
396 (setq files nil)) 377 (setq files nil))
397 (setq files (cdr files))))) 378 (setq files (cdr files)))))
398 (if (not gnus-newsgroup-kill-headers) 379 (if (not gnus-newsgroup-kill-headers)
399 () 380 ()
405 (gnus-message 6 "Processing kill file %s..." (car kill-files)) 386 (gnus-message 6 "Processing kill file %s..." (car kill-files))
406 (find-file (car kill-files)) 387 (find-file (car kill-files))
407 (gnus-add-current-to-buffer-list) 388 (gnus-add-current-to-buffer-list)
408 (goto-char (point-min)) 389 (goto-char (point-min))
409 390
410 (if (consp (ignore-errors (read (current-buffer)))) 391 (if (consp (condition-case nil (read (current-buffer))
392 (error nil)))
411 (gnus-kill-parse-gnus-kill-file) 393 (gnus-kill-parse-gnus-kill-file)
412 (gnus-kill-parse-rn-kill-file)) 394 (gnus-kill-parse-rn-kill-file))
413 395
414 (gnus-message 396 (gnus-message
415 6 "Processing kill file %s...done" (car kill-files))) 397 6 "Processing kill file %s...done" (car kill-files)))
416 (setq kill-files (cdr kill-files))))) 398 (setq kill-files (cdr kill-files)))))
417 399
418 (gnus-set-mode-line 'summary) 400 (gnus-set-mode-line 'summary)
419 401
437 419
438 (defun gnus-kill-parse-gnus-kill-file () 420 (defun gnus-kill-parse-gnus-kill-file ()
439 (goto-char (point-min)) 421 (goto-char (point-min))
440 (gnus-kill-file-mode) 422 (gnus-kill-file-mode)
441 (let (beg form) 423 (let (beg form)
442 (while (progn 424 (while (progn
443 (setq beg (point)) 425 (setq beg (point))
444 (setq form (ignore-errors (read (current-buffer))))) 426 (setq form (condition-case () (read (current-buffer))
445 (unless (listp form) 427 (error nil))))
446 (error "Illegal kill entry (possibly rn kill file?): %s" form)) 428 (or (listp form)
429 (error "Illegal kill entry (possibly rn kill file?): %s" form))
447 (if (or (eq (car form) 'gnus-kill) 430 (if (or (eq (car form) 'gnus-kill)
448 (eq (car form) 'gnus-raise) 431 (eq (car form) 'gnus-raise)
449 (eq (car form) 'gnus-lower)) 432 (eq (car form) 'gnus-lower))
450 (progn 433 (progn
451 (delete-region beg (point)) 434 (delete-region beg (point))
452 (insert (or (eval form) ""))) 435 (insert (or (eval form) "")))
453 (save-excursion 436 (save-excursion
454 (set-buffer gnus-summary-buffer) 437 (set-buffer gnus-summary-buffer)
455 (ignore-errors (eval form))))) 438 (condition-case () (eval form) (error nil)))))
456 (and (buffer-modified-p) 439 (and (buffer-modified-p)
457 gnus-kill-save-kill-file 440 gnus-kill-save-kill-file
458 (save-buffer)) 441 (save-buffer))
459 (set-buffer-modified-p nil))) 442 (set-buffer-modified-p nil)))
460 443
461 ;; Parse an rn killfile. 444 ;; Parse an rn killfile.
479 ?s)) 462 ?s))
480 (setq commands (buffer-substring (match-beginning 3) (match-end 3))) 463 (setq commands (buffer-substring (match-beginning 3) (match-end 3)))
481 464
482 ;; The "f:+" command marks everything *but* the matches as read, 465 ;; The "f:+" command marks everything *but* the matches as read,
483 ;; so we simply first match everything as read, and then unmark 466 ;; so we simply first match everything as read, and then unmark
484 ;; PATTERN later. 467 ;; PATTERN later.
485 (when (string-match "\\+" commands) 468 (and (string-match "\\+" commands)
486 (gnus-kill "from" ".") 469 (progn
487 (setq commands "m")) 470 (gnus-kill "from" ".")
488 471 (setq commands "m")))
489 (gnus-kill 472
473 (gnus-kill
490 (or (cdr (assq modifier mod-to-header)) "subject") 474 (or (cdr (assq modifier mod-to-header)) "subject")
491 pattern 475 pattern
492 (if (string-match "m" commands) 476 (if (string-match "m" commands)
493 '(gnus-summary-mark-as-unread nil " ") 477 '(gnus-summary-mark-as-unread nil " ")
494 '(gnus-summary-mark-as-read nil "X")) 478 '(gnus-summary-mark-as-read nil "X"))
495 nil t)) 479 nil t))
496 (forward-line 1)))) 480 (forward-line 1))))
497 481
498 ;; Kill changes and new format by suggested by JWZ and Sudish Joseph 482 ;; Kill changes and new format by suggested by JWZ and Sudish Joseph
499 ;; <joseph@cis.ohio-state.edu>. 483 ;; <joseph@cis.ohio-state.edu>.
500 (defun gnus-kill (field regexp &optional exe-command all silent) 484 (defun gnus-kill (field regexp &optional exe-command all silent)
501 "If FIELD of an article matches REGEXP, execute COMMAND. 485 "If FIELD of an article matches REGEXP, execute COMMAND.
502 Optional 1st argument COMMAND is default to 486 Optional 1st argument COMMAND is default to
503 (gnus-summary-mark-as-read nil \"X\"). 487 (gnus-summary-mark-as-read nil \"X\").
504 If optional 2nd argument ALL is non-nil, articles marked are also applied to. 488 If optional 2nd argument ALL is non-nil, articles marked are also applied to.
507 ;; We don't want to change current point nor window configuration. 491 ;; We don't want to change current point nor window configuration.
508 (let ((old-buffer (current-buffer))) 492 (let ((old-buffer (current-buffer)))
509 (save-excursion 493 (save-excursion
510 (save-window-excursion 494 (save-window-excursion
511 ;; Selected window must be summary buffer to execute keyboard 495 ;; Selected window must be summary buffer to execute keyboard
512 ;; macros correctly. See command_loop_1. 496 ;; macros correctly. See command_loop_1.
513 (switch-to-buffer gnus-summary-buffer 'norecord) 497 (switch-to-buffer gnus-summary-buffer 'norecord)
514 (goto-char (point-min)) ;From the beginning. 498 (goto-char (point-min)) ;From the beginning.
515 (let ((kill-list regexp) 499 (let ((kill-list regexp)
516 (date (current-time-string)) 500 (date (current-time-string))
517 (command (or exe-command '(gnus-summary-mark-as-read 501 (command (or exe-command '(gnus-summary-mark-as-read
518 nil gnus-kill-file-mark))) 502 nil gnus-kill-file-mark)))
519 kill kdate prev) 503 kill kdate prev)
520 (if (listp kill-list) 504 (if (listp kill-list)
521 ;; It is a list. 505 ;; It is a list.
522 (if (not (consp (cdr kill-list))) 506 (if (not (consp (cdr kill-list)))
523 ;; It's on the form (regexp . date). 507 ;; It's on the form (regexp . date).
524 (if (zerop (gnus-execute field (car kill-list) 508 (if (zerop (gnus-execute field (car kill-list)
525 command nil (not all))) 509 command nil (not all)))
526 (when (> (gnus-days-between date (cdr kill-list)) 510 (if (> (gnus-days-between date (cdr kill-list))
527 gnus-kill-expiry-days) 511 gnus-kill-expiry-days)
528 (setq regexp nil)) 512 (setq regexp nil))
529 (setcdr kill-list date)) 513 (setcdr kill-list date))
530 (while (setq kill (car kill-list)) 514 (while (setq kill (car kill-list))
531 (if (consp kill) 515 (if (consp kill)
532 ;; It's a temporary kill. 516 ;; It's a temporary kill.
533 (progn 517 (progn
534 (setq kdate (cdr kill)) 518 (setq kdate (cdr kill))
535 (if (zerop (gnus-execute 519 (if (zerop (gnus-execute
536 field (car kill) command nil (not all))) 520 field (car kill) command nil (not all)))
537 (when (> (gnus-days-between date kdate) 521 (if (> (gnus-days-between date kdate)
538 gnus-kill-expiry-days) 522 gnus-kill-expiry-days)
539 ;; Time limit has been exceeded, so we 523 ;; Time limit has been exceeded, so we
540 ;; remove the match. 524 ;; remove the match.
541 (if prev 525 (if prev
542 (setcdr prev (cdr kill-list)) 526 (setcdr prev (cdr kill-list))
543 (setq regexp (cdr regexp)))) 527 (setq regexp (cdr regexp))))
544 ;; Successful kill. Set the date to today. 528 ;; Successful kill. Set the date to today.
545 (setcdr kill date))) 529 (setcdr kill date)))
546 ;; It's a permanent kill. 530 ;; It's a permanent kill.
547 (gnus-execute field kill command nil (not all))) 531 (gnus-execute field kill command nil (not all)))
548 (setq prev kill-list) 532 (setq prev kill-list)
549 (setq kill-list (cdr kill-list)))) 533 (setq kill-list (cdr kill-list))))
550 (gnus-execute field kill-list command nil (not all)))))) 534 (gnus-execute field kill-list command nil (not all))))))
551 (switch-to-buffer old-buffer) 535 (switch-to-buffer old-buffer)
552 (when (and (eq major-mode 'gnus-kill-file-mode) regexp (not silent)) 536 (if (and (eq major-mode 'gnus-kill-file-mode) regexp (not silent))
553 (gnus-pp-gnus-kill 537 (gnus-pp-gnus-kill
554 (nconc (list 'gnus-kill field 538 (nconc (list 'gnus-kill field
555 (if (consp regexp) (list 'quote regexp) regexp)) 539 (if (consp regexp) (list 'quote regexp) regexp))
556 (when (or exe-command all) 540 (if (or exe-command all) (list (list 'quote exe-command)))
557 (list (list 'quote exe-command))) 541 (if all (list t) nil))))))
558 (if all (list t) nil))))))
559 542
560 (defun gnus-pp-gnus-kill (object) 543 (defun gnus-pp-gnus-kill (object)
561 (if (or (not (consp (nth 2 object))) 544 (if (or (not (consp (nth 2 object)))
562 (not (consp (cdr (nth 2 object)))) 545 (not (consp (cdr (nth 2 object))))
563 (and (eq 'quote (car (nth 2 object))) 546 (and (eq 'quote (car (nth 2 object)))
564 (not (consp (cdadr (nth 2 object)))))) 547 (not (consp (cdadr (nth 2 object))))))
565 (concat "\n" (gnus-prin1-to-string object)) 548 (concat "\n" (prin1-to-string object))
566 (save-excursion 549 (save-excursion
567 (set-buffer (get-buffer-create "*Gnus PP*")) 550 (set-buffer (get-buffer-create "*Gnus PP*"))
568 (buffer-disable-undo (current-buffer)) 551 (buffer-disable-undo (current-buffer))
569 (erase-buffer) 552 (erase-buffer)
570 (insert (format "\n(%S %S\n '(" (nth 0 object) (nth 1 object))) 553 (insert (format "\n(%S %S\n '(" (nth 0 object) (nth 1 object)))
571 (let ((klist (cadr (nth 2 object))) 554 (let ((klist (cadr (nth 2 object)))
572 (first t)) 555 (first t))
573 (while klist 556 (while klist
574 (insert (if first (progn (setq first nil) "") "\n ") 557 (insert (if first (progn (setq first nil) "") "\n ")
575 (gnus-prin1-to-string (car klist))) 558 (prin1-to-string (car klist)))
576 (setq klist (cdr klist)))) 559 (setq klist (cdr klist))))
577 (insert ")") 560 (insert ")")
578 (and (nth 3 object) 561 (and (nth 3 object)
579 (insert "\n " 562 (insert "\n "
580 (if (and (consp (nth 3 object)) 563 (if (and (consp (nth 3 object))
581 (not (eq 'quote (car (nth 3 object))))) 564 (not (eq 'quote (car (nth 3 object)))))
582 "'" "") 565 "'" "")
583 (gnus-prin1-to-string (nth 3 object)))) 566 (prin1-to-string (nth 3 object))))
584 (when (nth 4 object) 567 (and (nth 4 object)
585 (insert "\n t")) 568 (insert "\n t"))
586 (insert ")") 569 (insert ")")
587 (prog1 570 (prog1
588 (buffer-substring (point-min) (point-max)) 571 (buffer-substring (point-min) (point-max))
589 (kill-buffer (current-buffer)))))) 572 (kill-buffer (current-buffer))))))
590 573
598 (let (value) 581 (let (value)
599 (and header 582 (and header
600 (progn 583 (progn
601 (setq value (funcall function header)) 584 (setq value (funcall function header))
602 ;; Number (Lines:) or symbol must be converted to string. 585 ;; Number (Lines:) or symbol must be converted to string.
603 (unless (stringp value) 586 (or (stringp value)
604 (setq value (gnus-prin1-to-string value))) 587 (setq value (prin1-to-string value)))
605 (setq did-kill (string-match regexp value))) 588 (setq did-kill (string-match regexp value)))
606 (cond ((stringp form) ;Keyboard macro. 589 (cond ((stringp form) ;Keyboard macro.
607 (execute-kbd-macro form)) 590 (execute-kbd-macro form))
608 ((gnus-functionp form) 591 ((gnus-functionp form)
609 (funcall form)) 592 (funcall form))
610 (t 593 (t
611 (eval form))))) 594 (eval form)))))
612 ;; Search article body. 595 ;; Search article body.
613 (let ((gnus-current-article nil) ;Save article pointer. 596 (let ((gnus-current-article nil) ;Save article pointer.
614 (gnus-last-article nil) 597 (gnus-last-article nil)
615 (gnus-break-pages nil) ;No need to break pages. 598 (gnus-break-pages nil) ;No need to break pages.
616 (gnus-mark-article-hook nil)) ;Inhibit marking as read. 599 (gnus-mark-article-hook nil)) ;Inhibit marking as read.
617 (gnus-message 600 (gnus-message
618 6 "Searching for article: %d..." (mail-header-number header)) 601 6 "Searching for article: %d..." (mail-header-number header))
619 (gnus-article-setup-buffer) 602 (gnus-article-setup-buffer)
620 (gnus-article-prepare (mail-header-number header) t) 603 (gnus-article-prepare (mail-header-number header) t)
621 (when (save-excursion 604 (if (save-excursion
622 (set-buffer gnus-article-buffer) 605 (set-buffer gnus-article-buffer)
623 (goto-char (point-min)) 606 (goto-char (point-min))
624 (setq did-kill (re-search-forward regexp nil t))) 607 (setq did-kill (re-search-forward regexp nil t)))
625 (cond ((stringp form) ;Keyboard macro. 608 (if (stringp form) ;Keyboard macro.
626 (execute-kbd-macro form)) 609 (execute-kbd-macro form)
627 ((gnus-functionp form) 610 (eval form))))))
628 (funcall form))
629 (t
630 (eval form)))))))
631 did-kill))) 611 did-kill)))
632 612
633 (defun gnus-execute (field regexp form &optional backward unread) 613 (defun gnus-execute (field regexp form &optional backward ignore-marked)
634 "If FIELD of article header matches REGEXP, execute lisp FORM (or a string). 614 "If FIELD of article header matches REGEXP, execute lisp FORM (or a string).
635 If FIELD is an empty string (or nil), entire article body is searched for. 615 If FIELD is an empty string (or nil), entire article body is searched for.
636 If optional 1st argument BACKWARD is non-nil, do backward instead. 616 If optional 1st argument BACKWARD is non-nil, do backward instead.
637 If optional 2nd argument UNREAD is non-nil, articles which are 617 If optional 2nd argument IGNORE-MARKED is non-nil, articles which are
638 marked as read or ticked are ignored." 618 marked as read or ticked are ignored."
639 (save-excursion 619 (save-excursion
640 (let ((killed-no 0) 620 (let ((killed-no 0)
641 function article header) 621 function article header)
642 (cond 622 (cond
643 ;; Search body. 623 ;; Search body.
644 ((or (null field) 624 ((or (null field)
645 (string-equal field "")) 625 (string-equal field ""))
646 (setq function nil)) 626 (setq function nil))
647 ;; Get access function of header field. 627 ;; Get access function of header field.
648 ((fboundp 628 ((fboundp
649 (setq function 629 (setq function
650 (intern-soft 630 (intern-soft
651 (concat "mail-header-" (downcase field))))) 631 (concat "mail-header-" (downcase field)))))
652 (setq function `(lambda (h) (,function h)))) 632 (setq function `(lambda (h) (,function h))))
653 ;; Signal error. 633 ;; Signal error.
654 (t 634 (t
655 (error "Unknown header field: \"%s\"" field))) 635 (error "Unknown header field: \"%s\"" field)))
657 (while (or 637 (while (or
658 ;; First article. 638 ;; First article.
659 (and (not article) 639 (and (not article)
660 (setq article (gnus-summary-article-number))) 640 (setq article (gnus-summary-article-number)))
661 ;; Find later articles. 641 ;; Find later articles.
662 (setq article 642 (setq article
663 (gnus-summary-search-forward unread nil backward))) 643 (gnus-summary-search-forward
644 (not ignore-marked) nil backward)))
664 (and (or (null gnus-newsgroup-kill-headers) 645 (and (or (null gnus-newsgroup-kill-headers)
665 (memq article gnus-newsgroup-kill-headers)) 646 (memq article gnus-newsgroup-kill-headers))
666 (vectorp (setq header (gnus-summary-article-header article))) 647 (vectorp (setq header (gnus-summary-article-header article)))
667 (gnus-execute-1 function regexp form header) 648 (gnus-execute-1 function regexp form header)
668 (setq killed-no (1+ killed-no)))) 649 (setq killed-no (1+ killed-no))))
669 ;; Return the number of killed articles. 650 ;; Return the number of killed articles.
670 killed-no))) 651 killed-no)))
671 652
672 ;;;###autoload
673 (defalias 'gnus-batch-kill 'gnus-batch-score)
674 ;;;###autoload
675 (defun gnus-batch-score ()
676 "Run batched scoring.
677 Usage: emacs -batch -l gnus -f gnus-batch-score <newsgroups> ...
678 Newsgroups is a list of strings in Bnews format. If you want to score
679 the comp hierarchy, you'd say \"comp.all\". If you would not like to
680 score the alt hierarchy, you'd say \"!alt.all\"."
681 (interactive)
682 (let* ((gnus-newsrc-options-n
683 (gnus-newsrc-parse-options
684 (concat "options -n "
685 (mapconcat 'identity command-line-args-left " "))))
686 (gnus-expert-user t)
687 (nnmail-spool-file nil)
688 (gnus-use-dribble-file nil)
689 (gnus-batch-mode t)
690 group newsrc entry
691 ;; Disable verbose message.
692 gnus-novice-user gnus-large-newsgroup
693 gnus-options-subscribe gnus-auto-subscribed-groups
694 gnus-options-not-subscribe)
695 ;; Eat all arguments.
696 (setq command-line-args-left nil)
697 (gnus-slave)
698 ;; Apply kills to specified newsgroups in command line arguments.
699 (setq newsrc (cdr gnus-newsrc-alist))
700 (while (setq group (car (pop newsrc)))
701 (setq entry (gnus-gethash group gnus-newsrc-hashtb))
702 (when (and (<= (gnus-info-level (car newsrc)) gnus-level-subscribed)
703 (and (car entry)
704 (or (eq (car entry) t)
705 (not (zerop (car entry)))))
706 ;;(eq (gnus-matches-options-n group) 'subscribe)
707 )
708 (gnus-summary-read-group group nil t nil t)
709 (when (eq (current-buffer) (get-buffer gnus-summary-buffer))
710 (gnus-summary-exit))))
711 ;; Exit Emacs.
712 (switch-to-buffer gnus-group-buffer)
713 (gnus-group-save-newsrc)))
714
715 (provide 'gnus-kill) 653 (provide 'gnus-kill)
716 654
717 ;;; gnus-kill.el ends here 655 ;;; gnus-kill.el ends here