3 ;; Copyright (C) 1997 Noah S. Friedman
4 ;; Copyright (C) 1997, 1998 Per Persson
6 ;; Author: Noah Friedman <friedman@prep.ai.mit.edu>
7 ;; Maintainer: pp@sno.pp.se
8 ;; Keywords: zenirc, extensions, oink
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program; if not, you can either send email to this
23 ;; program's maintainer or write to: The Free Software Foundation,
24 ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
28 ;; Use this package to define "triggers" regexps.
29 ;; For example, you can define a function /time and specify a regexp that
30 ;; sends the current time whenever someone asks "what time is it?":
32 ;; (zenirc-trigger-register "time" 'current-time-string "what time is it\\?")
34 ;; You can also use the /trigger command in the *zenirc* buffer:
36 ;; /trigger set time "what time is it\\?" current-time-string
38 ;; People have defined more interesting triggers such as horoscopes, zippy
46 (defvar zenirc-trigger-table nil)
47 (defvar zenirc-command-trigger-hook '(zenirc-command-trigger))
49 ;; Changing this to NOTICE will generally avoid loops from other clients
50 ;; that also load this. But that's less fun.
51 (defconst zenirc-trigger-response-type "PRIVMSG")
53 (defun zenirc-trigger-register (name response &optional regexp pass-string)
54 "Define a trigger named NAME, that runs RESPONSE when REGEXP is seen,
55 passing the matched-string if PASS-STRING is true.
56 When a string mathcing REGEXP is detected in a zenirc buffer, the function
57 RESPONSE is called with no arguments by default, or with the matched string
58 if PASS-STRING is non-nil. That function should return a string
59 which is to be sent to the originator of the message matching REGEXP.
60 It may instead return a list of strings, in which case each string is
61 sent as a separate message.
63 NAME can be used as a key for changing, deleting, activating, and
64 deactivating the trigger via /trigger subcommands."
65 (zenirc-trigger-make-command name response)
67 (zenirc-trigger-set-trigger name regexp response pass-string)))
69 ;;; Users shouldn't generally need to make use of anything below here.
71 (defun zenirc-trigger-make-command (name response)
72 (let* ((symname (format "zenirc-command-%s" name))
73 (cmdsym (intern symname))
74 (cmdhook (intern (concat symname "-hook"))))
75 (zenirc-add-hook cmdhook cmdsym)
77 (` (lambda (proc victim)
78 (zenirc-trigger-send-fn-result proc victim '(, response)))))))
80 (defun zenirc-trigger-set-trigger (name regexp response &optional pass-string)
82 (setq name (intern name)))
83 (let ((elt (assq name zenirc-trigger-table)))
85 (setcar (nthcdr 1 elt) t)
86 (setcar (nthcdr 2 elt) regexp)
87 (setcar (nthcdr 3 elt) response)
88 (setcar (nthcdr 4 elt) pass-string))
90 (setq zenirc-trigger-table
91 (cons (list name t regexp response pass-string)
92 zenirc-trigger-table))))))
94 ;; Returns nil if the named trigger doesn't exist, t otherwise.
95 (defun zenirc-trigger-activate (name state)
96 (and (stringp name) (setq name (intern name)))
97 (let ((elt (assq name zenirc-trigger-table)))
99 (setcar (nthcdr 1 elt) state)
103 (defun zenirc-trigger-enable (name)
104 (zenirc-trigger-activate name t))
106 (defun zenirc-trigger-disable (name)
107 (zenirc-trigger-activate name nil))
110 (defun zenirc-server-PRIVMSG-trigger (proc parsedmsg)
112 (let ((case-fold-search t)
113 (trigger-table zenirc-trigger-table)
116 (cond ((nth 1 (car trigger-table))
117 (setq regexp (nth 2 (car trigger-table)))
119 (string-match regexp (aref parsedmsg 3))
120 (let ((victim (zenirc-trigger-parse-sender parsedmsg))
121 (msg (zenirc-trigger-response
122 (nth 3 (car trigger-table))
123 (and (nth 4 (car trigger-table))
124 (match-string 0 (aref parsedmsg 3))))))
125 (zenirc-trigger-send-response proc victim msg)))))
126 (setq trigger-table (cdr trigger-table))))))
128 (defun zenirc-trigger-parse-sender (parsedmsg)
129 (let ((from (aref parsedmsg 2)))
130 (cond ((zenirc-names-equal-p from zenirc-nick)
131 (zenirc-extract-nick (aref parsedmsg 1)))
134 (defun zenirc-trigger-response (fn msg)
135 (cond ((stringp fn) fn)
140 (defun zenirc-trigger-send-fn-result (proc victim fn &optional msg)
141 (setq victim (cdr victim))
142 (cond ((or (null victim)
144 (setq victim zenirc-current-victim)))
145 (zenirc-trigger-send-response proc victim (zenirc-trigger-response fn msg)))
147 (defun zenirc-trigger-send-response (proc victim msg)
149 (zenirc-message proc 'trigger-sent victim msg)
150 (process-send-string proc (concat zenirc-trigger-response-type
151 " " victim " :" msg "\n")))
154 (zenirc-message proc 'trigger-sent victim (car msg))
155 (process-send-string proc
156 (concat zenirc-trigger-response-type
157 " " victim " :" (car msg) "\n"))
158 (setq msg (cdr msg))))))
161 ;; Parser for /trigger command. This figures out the trigger subcommand
162 ;; and calls the appropriate routine to handle it.
163 ;; The function dispatched should be named "zenirc-trigger-do-FOO-command",
164 ;; where FOO is one of `list', `set', `enable', `disable', etc.
165 ;; With no arguments, lists available subcommands.
166 (defun zenirc-command-trigger (proc parsedcmd)
167 (let* ((cmd (zenirc-parse-firstword (cdr parsedcmd)))
168 (fn (intern-soft (concat "zenirc-trigger-do-" (car cmd) "-command"))))
169 (cond ((and fn (fboundp fn))
170 (funcall fn proc cmd))
172 (zenirc-message proc 'trigger-subcommands
174 (zenirc-trigger-subcommand-list)
177 (zenirc-message proc 'trigger-command-undefined (car cmd))))))
179 ;; Returns a list of defined subcommands to /trigger.
180 (defun zenirc-trigger-subcommand-list ()
182 (let* ((prefix "zenirc-trigger-do-")
184 (re (concat suffix "$")))
185 (sort (mapcar (function (lambda (s)
186 (substring s (length prefix)
187 (- (length suffix)))))
188 (all-completions prefix obarray
191 (string-match re (symbol-name s))))))
194 (defun zenirc-trigger-do-list-command (proc args)
195 (let ((table zenirc-trigger-table))
196 (zenirc-message proc 'trigger-list-head)
197 (zenirc-message proc 'trigger-list-line)
199 (zenirc-message proc 'trigger-list-item
202 (prin1-to-string (nth 2 (car table)))
203 (prin1-to-string (nth 3 (car table))))
204 (setq table (cdr table)))
205 (zenirc-message proc 'trigger-list-end)))
207 (defun zenirc-trigger-do-set-command (proc args)
208 (let* ((parsed1 (zenirc-parse-firstword (cdr args)))
210 (parsed2 (read-from-string (cdr parsed1)))
211 (regexp (car parsed2))
212 (fn (car (read-from-string (substring (cdr parsed1)
214 (zenirc-trigger-register name fn regexp)
215 (zenirc-message proc 'trigger-enable name)))
217 (defun zenirc-trigger-do-delete-command (proc args)
218 (let ((names (zenirc-parse-words (cdr args)))
223 ;; If intern-soft returns nil, assq will return nil.
224 (setq elt (assq (intern-soft (car names)) zenirc-trigger-table))
226 (setq unknown (cons (car names) unknown))
227 (setq zenirc-trigger-table (delq elt zenirc-trigger-table))
228 (setq known (cons (car names) known)))
229 (setq names (cdr names)))
231 (zenirc-message proc 'trigger-deleted (nreverse known)))
233 (zenirc-message proc trigger-undefined (nreverse unknown)))))
235 (defun zenirc-trigger-do-enable-command (proc args)
236 (zenirc-trigger-do-activation proc (cdr args) t))
238 (defun zenirc-trigger-do-disable-command (proc args)
239 (zenirc-trigger-do-activation proc (cdr args) nil))
241 (defun zenirc-trigger-do-activation (proc args state)
242 (let ((msg (if state 'trigger-enable 'trigger-disable))
243 (names (zenirc-parse-words args))
247 (if (zenirc-trigger-activate (car names) state)
248 (setq known (cons (car names) known))
249 (setq unknown (cons (car names) unknown)))
250 (setq names (cdr names)))
252 (zenirc-message proc msg (nreverse known)))
254 (zenirc-message proc trigger-undefined (nreverse unknown)))))
257 (provide 'zenirc-trigger)
259 (zenirc-lang-define-catalog 'english
260 '((trigger-sent . "[trigger] Sent to %s: %s")
261 (trigger-enable . "[info] Triggers enabled: %s")
262 (trigger-disable . "[info] Triggers disabled: %s")
263 (trigger-deleted . "[info] Triggers deleted: %s")
264 (trigger-undefined . "[info] Undefined triggers: %s")
265 (trigger-list-head . "[trigger] Name On? Regexp Function")
266 (trigger-list-line . "[trigger] ---- --- ------ --------")
267 (trigger-list-item . "[trigger] %-10s %-3s %-15s %s")
268 (trigger-list-end . "[trigger] End of list.")
269 (trigger-subcommands . "[info] Trigger subcommands: %s")
270 (trigger-command-undefined . "[info] undefined trigger command: %s")))
272 (zenirc-add-hook 'zenirc-server-PRIVMSG-hook
273 'zenirc-server-PRIVMSG-trigger 'append)
275 ;;; zenirc-trigger.el ends here