SiteMap Search ElispArea HowTo Glossary RecentChanges News Problems Suggestions

erc-robot.el

Last major edit (later minor edits)

Summary: Source code for ErcRobot.

No diff available.

Download

;;; erc-robot.el --- A robot for ERC.

;; Author: David Edmondson (dme@dme.org)
;; Maintainer: David Edmondson (dme@dme.org)
;; Version: $Revision$
;; Keywords: ERC, IRC, chat, robot, bot

;; Copyright (C) 2002 David Edmondson.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;; Commentary:

;; This code implements a simple robot for ERC.

;; Installation:

;; The robot uses hooks to gain access to ERC.  The following need to
;; be executed after ERC has loaded:

;;     (load-library "erc-robot")
;;     (add-hook 'erc-server-PRIVMSG-functions 'erc-robot-remote t)
;;     (add-hook 'erc-send-completed-hook 'erc-robot-local t)

;; It is particularly important that the remote robot function is added
;; to the tail of the PRIVMSG hook.

;; Robot commands are declared using the list "erc-robot-commands".
;; TODO: better description of the functions.
;; An example might be:

;; (setq erc-robot-commands
;;       '(
;; 	("cmds" t (lambda (args)
;; 		  (concat "commands available: "
;; 			  (mapconcat
;; 			   (lambda (e)
;; 			     (car e))
;; 			   erc-robot-commands " "))))
;; 	("hello" t (lambda (args) "hello to you too !"))
;; 	("zippy" t (lambda (args) (erc-replace-regexp-in-string "\n" " " (yow))))
;; 	("echo" t (lambda (args) args))
;;	; only i'm allowed to talk to my doctor !
;; 	("version" t (lambda (args) (erc-version)))
;;       ))

(require 'erc)
(require 'erc-stamp)

; compatability
(if (featurep 'xemacs)
    (defun erc-replace-regexp-in-string
      (regexp rep string &optional fixedcase literal subexp start)
      (replace-in-string string regexp rep literal))
  (defalias 'erc-replace-regexp-in-string 'replace-regexp-in-string))


(defface erc-robot-face '((t (:foreground "darkslateblue")))
  "Face used for your robot's output."
  :group 'erc-faces)

(defcustom erc-robot-commands nil
  "A list of robot commands and the functions which implement them."
  :group 'erc
  :type '(repeat (list string (choice (const nil) (const t) string) function))
  )

(defun erc-robot-remote (proc parsed)
  "Implements a simple robot for erc.  Messages to the robot are of the form:
\"nick: !command args\", where:
nick	- the nickname of the user who is the target of the command, i.e. the
	  person running the robot,
command	- the specific command,
args	- arguments to the command (optional)."
  (let* ((sspec (aref parsed 1))
         (nick (substring (nth 0 (erc-parse-user sspec)) 1))
         (tgt (car (aref parsed 4)))
         (msg (aref parsed 5)))
    (erc-robot-command proc nick tgt msg nil))
  nil)

(defun erc-robot-local (str)
  "Funnel text typed by the local user to the local robot.  See
\"erc-robot-remote\" for details of the command format."
  (erc-robot-command erc-process (erc-current-nick) (buffer-name) str t))

(defun erc-robot-command (proc from tgt msg locally-generated)
  "Robot worker."
  (let ((me (erc-current-nick)))
    (if (and erc-robot-commands
	     (string-match (concat "^" (regexp-quote me)
				   ": !\\([^ ]+\\) ?\\(.*\\)") msg))
					; this is a robot command to me.
	(let* ((cmd (substring msg (match-beginning 1) (match-end 1)))
	       (args (substring msg (match-beginning 2)))
	       (l (assoc cmd erc-robot-commands))
	       (allowed-users (nth 1 l))
	       (function (nth 2 l))
	       (permitted (or (eq t allowed-users)
			      (and (eq nil allowed-users) locally-generated)
			      (and (stringp allowed-users)
				   (string-match allowed-users
						 (regexp-quote from)))))
	       (reply
		(if permitted
		    (if l
			(funcall function args)
		      (concat "unknown command: " cmd
			      ": try \"cmds\""))
		  (concat "no access to command \"" cmd
			  "\" for " from ".")))
;; dme: this version allows you to cause the robot to do things, for
;;	example you can try "dme: !echo /kick fred", and it will send
;;	to the server "/kick fred", rather than "joe: /kick fred".
;; 	       (full-reply (if (string-match "^/" reply)
;; 			       reply
;; 			     (concat from ": " reply))))
	       (full-reply (concat from ": " reply)))
	  (erc-log (substring-no-properties full-reply))
	  (save-excursion
	    (set-buffer (erc-get-buffer tgt proc))
	    (let* ((inhibit-read-only t)
		   (lines (split-string full-reply "\n"))
		   (multiline-p (< 1 (length lines)))
		   p)
	      (mapc
	       (lambda (line)
		 (goto-char (point-max))
		 (setq p (re-search-backward (erc-prompt)))
		 (insert (erc-format-timestamp (current-time)
					       erc-timestamp-format)
			 "<" me "> ")
		 (erc-put-text-property 0 (length line) 'face
					'erc-robot-face line)
		 (insert line "\n")
		 (save-excursion
		   (save-match-data
		     (save-restriction
		       (narrow-to-region p (point))
		       (run-hook-with-args 'erc-send-modify-hook)
		       (run-hook-with-args 'erc-send-post-hook))))
		 (set-marker (process-mark erc-process) (point))
		 (set-marker erc-insert-marker (point))
		 (goto-char (point-max))

		 (erc-process-input-line (concat line "\n") t multiline-p))
	       lines)))))))

(provide 'erc-robot)