home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / gnus / gnus-logic.el.z / gnus-logic.el
Encoding:
Text File  |  1998-05-21  |  7.5 KB  |  230 lines

  1. ;;; gnus-logic.el --- advanced scoring code for Gnus
  2. ;; Copyright (C) 1996,97 Free Software Foundation, Inc.
  3.  
  4. ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
  5. ;; Keywords: news
  6.  
  7. ;; This file is part of GNU Emacs.
  8.  
  9. ;; GNU Emacs is free software; you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation; either version 2, or (at your option)
  12. ;; any later version.
  13.  
  14. ;; GNU Emacs is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;; GNU General Public License for more details.
  18.  
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  21. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  22. ;; Boston, MA 02111-1307, USA.
  23.  
  24. ;;; Commentary:
  25.  
  26. ;;; Code:
  27.  
  28. (eval-when-compile (require 'cl))
  29.  
  30. (require 'gnus)
  31. (require 'gnus-score)
  32. (require 'gnus-util)
  33.  
  34. ;;; Internal variables.
  35.  
  36. (defvar gnus-advanced-headers nil)
  37.  
  38. ;; To avoid having 8-bit characters in the source file.
  39. (defvar gnus-advanced-not (intern (format "%c" 172)))
  40.  
  41. (defconst gnus-advanced-index
  42.   ;; Name to index alist.
  43.   '(("number" 0 gnus-advanced-integer)
  44.     ("subject" 1 gnus-advanced-string)
  45.     ("from" 2 gnus-advanced-string)
  46.     ("date" 3 gnus-advanced-date)
  47.     ("message-id" 4 gnus-advanced-string)
  48.     ("references" 5 gnus-advanced-string)
  49.     ("chars" 6 gnus-advanced-integer)
  50.     ("lines" 7 gnus-advanced-integer)
  51.     ("xref" 8 gnus-advanced-string)
  52.     ("head" nil gnus-advanced-body)
  53.     ("body" nil gnus-advanced-body)
  54.     ("all" nil gnus-advanced-body)))
  55.  
  56. (eval-and-compile
  57.   (autoload 'parse-time-string "parse-time"))
  58.  
  59. (defun gnus-score-advanced (rule &optional trace)
  60.   "Apply advanced scoring RULE to all the articles in the current group."
  61.   (let ((headers gnus-newsgroup-headers)
  62.     gnus-advanced-headers score)
  63.     (while (setq gnus-advanced-headers (pop headers))
  64.       (when (gnus-advanced-score-rule (car rule))
  65.     ;; This rule was successful, so we add the score to
  66.     ;; this article.
  67.     (if (setq score (assq (mail-header-number gnus-advanced-headers)
  68.                   gnus-newsgroup-scored))
  69.         (setcdr score
  70.             (+ (cdr score)
  71.                (or (nth 1 rule)
  72.                gnus-score-interactive-default-score)))
  73.       (push (cons (mail-header-number gnus-advanced-headers)
  74.               (or (nth 1 rule)
  75.               gnus-score-interactive-default-score))
  76.         gnus-newsgroup-scored)
  77.       (when trace
  78.         (push (cons "A file" rule)
  79.           gnus-score-trace)))))))
  80.  
  81. (defun gnus-advanced-score-rule (rule)
  82.   "Apply RULE to `gnus-advanced-headers'."
  83.   (let ((type (car rule)))
  84.     (cond
  85.      ;; "And" rule.
  86.      ((or (eq type '&) (eq type 'and))
  87.       (pop rule)
  88.       (if (not rule)
  89.       t                ; Empty rule is true.
  90.     (while (and rule
  91.             (gnus-advanced-score-rule (car rule)))
  92.       (pop rule))
  93.     ;; If all the rules were true, then `rule' should be nil.
  94.     (not rule)))
  95.      ;; "Or" rule.
  96.      ((or (eq type '|) (eq type 'or))
  97.       (pop rule)
  98.       (if (not rule)
  99.       nil
  100.     (while (and rule
  101.             (not (gnus-advanced-score-rule (car rule))))
  102.       (pop rule))
  103.     ;; If one of the rules returned true, then `rule' should be non-nil.
  104.     rule))
  105.      ;; "Not" rule.
  106.      ((or (eq type '!) (eq type 'not) (eq type gnus-advanced-not))
  107.       (not (gnus-advanced-score-rule (nth 1 rule))))
  108.      ;; This is a `1-'-type redirection rule.
  109.      ((and (symbolp type)
  110.        (string-match "^[0-9]+-$\\|^\\^+$" (symbol-name type)))
  111.       (let ((gnus-advanced-headers
  112.          (gnus-parent-headers
  113.           gnus-advanced-headers
  114.           (if (string-match "^\\([0-9]+\\)-$" (symbol-name type))
  115.           ;; 1- type redirection.
  116.           (string-to-number
  117.            (substring (symbol-name type)
  118.                   (match-beginning 0) (match-end 0)))
  119.         ;; ^^^ type redirection.
  120.         (length (symbol-name type))))))
  121.     (when gnus-advanced-headers
  122.       (gnus-advanced-score-rule (nth 1 rule)))))
  123.      ;; Plain scoring rule.
  124.      ((stringp type)
  125.       (gnus-advanced-score-article rule))
  126.      ;; Bug-out time!
  127.      (t
  128.       (error "Unknown advanced score type: %s" rule)))))
  129.  
  130. (defun gnus-advanced-score-article (rule)
  131.   ;; `rule' is a semi-normal score rule, so we find out
  132.   ;; what function that's supposed to do the actual
  133.   ;; processing.
  134.   (let* ((header (car rule))
  135.      (func (assoc (downcase header) gnus-advanced-index)))
  136.     (if (not func)
  137.     (error "No such header: %s" rule)
  138.       ;; Call the score function.
  139.       (funcall (caddr func) (or (cadr func) header)
  140.            (cadr rule) (caddr rule)))))
  141.  
  142. (defun gnus-advanced-string (index match type)
  143.   "See whether string MATCH of TYPE matches `gnus-advanced-headers' in INDEX."
  144.   (let* ((type (or type 's))
  145.      (case-fold-search (not (eq (downcase (symbol-name type))
  146.                     (symbol-name type))))
  147.      (header (aref gnus-advanced-headers index)))
  148.     (cond
  149.      ((memq type '(r R regexp Regexp))
  150.       (string-match match header))
  151.      ((memq type '(s S string String))
  152.       (string-match (regexp-quote match) header))
  153.      ((memq type '(e E exact Exact))
  154.       (string= match header))
  155.      ((memq type '(f F fuzzy Fuzzy))
  156.       (string-match (regexp-quote (gnus-simplify-subject-fuzzy match))
  157.             header))
  158.      (t
  159.       (error "No such string match type: %s" type)))))
  160.  
  161. (defun gnus-advanced-integer (index match type)
  162.   (if (not (memq type '(< > <= >= =)))
  163.       (error "No such integer score type: %s" type)
  164.     (funcall type match (or (aref gnus-advanced-headers index) 0))))
  165.  
  166. (defun gnus-advanced-date (index match type)
  167.   (let ((date (encode-time (parse-time-string
  168.                 (aref gnus-advanced-headers index))))
  169.     (match (encode-time (parse-time-string match))))
  170.     (cond
  171.      ((eq type 'at)
  172.       (equal date match))
  173.      ((eq type 'before)
  174.       (gnus-time-less match date))
  175.      ((eq type 'after)
  176.       (gnus-time-less date match))
  177.      (t
  178.       (error "No such date score type: %s" type)))))
  179.  
  180. (defun gnus-advanced-body (header match type)
  181.   (when (string= header "all")
  182.     (setq header "article"))
  183.   (save-excursion
  184.     (set-buffer nntp-server-buffer)
  185.     (let* ((request-func (cond ((string= "head" header)
  186.                 'gnus-request-head)
  187.                    ((string= "body" header)
  188.                 'gnus-request-body)
  189.                    (t 'gnus-request-article)))
  190.        ofunc article)
  191.       ;; Not all backends support partial fetching.  In that case,
  192.       ;; we just fetch the entire article.
  193.       (unless (gnus-check-backend-function
  194.            (intern (concat "request-" header))
  195.            gnus-newsgroup-name)
  196.     (setq ofunc request-func)
  197.     (setq request-func 'gnus-request-article))
  198.       (setq article (mail-header-number gnus-advanced-headers))
  199.       (gnus-message 7 "Scoring article %s..." article)
  200.       (when (funcall request-func article gnus-newsgroup-name)
  201.     (goto-char (point-min))
  202.     ;; If just parts of the article is to be searched and the
  203.     ;; backend didn't support partial fetching, we just narrow
  204.     ;; to the relevant parts.
  205.     (when ofunc
  206.       (if (eq ofunc 'gnus-request-head)
  207.           (narrow-to-region
  208.            (point)
  209.            (or (search-forward "\n\n" nil t) (point-max)))
  210.         (narrow-to-region
  211.          (or (search-forward "\n\n" nil t) (point))
  212.          (point-max))))
  213.     (let* ((case-fold-search (not (eq (downcase (symbol-name type))
  214.                       (symbol-name type))))
  215.            (search-func
  216.         (cond ((memq type '(r R regexp Regexp))
  217.                're-search-forward)
  218.               ((memq type '(s S string String))
  219.                'search-forward)
  220.               (t
  221.                (error "Illegal match type: %s" type)))))
  222.       (goto-char (point-min))
  223.       (prog1
  224.           (funcall search-func match nil t)
  225.         (widen)))))))
  226.  
  227. (provide 'gnus-logic)
  228.  
  229. ;;; gnus-logic.el ends here.
  230.