summaryrefslogtreecommitdiff
path: root/elisp/erbot/erbot.el
diff options
context:
space:
mode:
Diffstat (limited to 'elisp/erbot/erbot.el')
-rw-r--r--elisp/erbot/erbot.el961
1 files changed, 961 insertions, 0 deletions
diff --git a/elisp/erbot/erbot.el b/elisp/erbot/erbot.el
new file mode 100644
index 0000000..9769dbf
--- /dev/null
+++ b/elisp/erbot/erbot.el
@@ -0,0 +1,961 @@
+;;; erbot.el --- Another robot for ERC.
+;; Time-stamp: <2009-09-26 22:28:50 fledermaus>
+;; Emacs Lisp Archive entry
+;; Filename: erbot.el
+;; Package: erbot
+;; Authors: David Edmunston (dme@dme.org)
+;; Modified by: D. Goel <deego@gnufans.org>, V Dasmohapatra <vivek@etla.org>
+;; Version: 0.0
+;; URL: http://www.emacswiki.org/cgi-bin/wiki.pl?ErBot
+;; Maintainer: Deepak Goel <deego@gnufans.org>
+
+
+(defvar erbot-home-page
+ "http://www.emacswiki.org/cgi-bin/wiki.pl?ErBot/")
+
+;; Version:
+;; Keywords: ERC, IRC, chat, robot, bot
+
+;; Copyright (C) 2002 Deepak Goel, FSF
+
+;; 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 3 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.
+
+
+
+
+;; See also:
+;; erc-robot.el from which this was derived...
+
+
+
+
+;; See http://www.emacswiki.org/cgi-bin/wiki/ErBot
+
+;; OLD DOCS:
+;; Thanks for erbot's/erbot's behavior and their data go to a lot
+;; of people on #emacs, like:
+;; kensanata (Alex Schroeder)
+;; resolve (Damien Elmes)
+;; bpt (Brian P. Templeton)
+;; forcer (Jorgen "forcer" Schaefer)
+;; and many others
+
+;; and also to bot(s):
+;; apt on debian, for english syntax examples.
+
+;; Thanks for code go to:
+;; David Edmonsdon (who wrote erc-robot.el which is what this started
+;; out from).
+;; Nick Hober (who wrote google.el)
+
+
+
+
+
+
+;;; David E's Commentary:
+
+;; erbot is a derivative of David's erc-robot.el --- that code was
+;; copied over on 2002-09-02 into erbot.el. Erbot seeks to make the
+;; bot similar to apt on #debian.. viz: English style.. yet allowing
+;; access to commands via the "cmd" command. Erbot shall seek to
+;; save all its information periodically, and publicly...
+
+
+;; Erc-robot 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 "erbot")
+
+
+;; 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 "erbot-commands".
+;; XXX better description of the functions.
+;; An example might be:
+
+;; (setq erbot-commands
+;; '(
+;; ("cmds" t (lambda (args)
+;; (concat "commands available: "
+;; (mapconcat
+;; (lambda (e)
+;; (car e))
+;; erbot-commands " "))))
+;; ("hello" t (lambda (args) "hello to you too !"))
+;; ("zippy" t (lambda (args) (erc-replace-regexp-in-string "\n" " " (yow))))
+;; ("music" t (lambda (args) (concat "now playing: "
+;; (let ((track (dme:now-playing)))
+;; (if track
+;; track
+;; "nothing.")))))
+;; ("echo" t (lambda (args) args))
+;; ; only i'm allowed to talk to my doctor !
+;; ("doctor" nil erc-doctor)
+;; ("version" t (lambda (args) (erc-version)))
+;; ))
+
+
+; 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)
+
+(defvar erbot-paranoid-p t
+ " Meant as a CATCHALL for security. Setting this variable to non-nil
+should disable most features. When non-nil, all potentially funny
+functions are disabled. We think these functions are safe, but we
+disable them in any case. We also disable all functions that we can
+that may potentially freeze the bot or severly slow it down upon
+receiving weird requests.
+
+
+t by default. No enablings like erbot-setf-p, etc. will work
+unless this is non-nil. If this is non-nil, erbot is paranoid, it will
+not allow apply, setf, funcall, sregex, etc. even if the corresponding
+variables are turned on.
+
+NOTE: Making this variable nil and later non-nil in the middle of a
+running emacs session will NOT make your bot completely paranoid. You
+need to have this function non-nil BEFORE you load erbot. See, for
+example, how we define fs-kbd.
+")
+
+
+
+
+(defun erbot-commentary ()
+ "Provides electric help regarding variable `erbot-commentary'."
+ (interactive)
+ (with-electric-help
+ '(lambda () (insert erbot-commentary) nil) "*doc*"))
+
+;;; History:
+
+;;; Bugs:
+
+;;; New features:
+(defvar erbot-new-features
+ "Help..."
+)
+
+(defun erbot-new-features ()
+ "Provides electric help regarding variable `erbot-new-features'."
+ (interactive)
+ (with-electric-help
+ '(lambda () (insert erbot-new-features) nil) "*doc*"))
+
+;;; TO DO:
+(defvar erbot-todo
+ "Current shortcomings:"
+
+)
+
+(defun erbot-todo ()
+ "Provides electric help regarding variable `erbot-todo'."
+ (interactive)
+ (with-electric-help
+ '(lambda () (insert erbot-todo) nil) "*doc*"))
+
+(defvar erbot-version "0.0")
+
+;;==========================================
+;;; Code:
+(require 'cl)
+
+(defcustom erbot-before-load-hooks nil "" :group 'erbot)
+(defcustom erbot-after-load-hooks nil "" :group 'erbot)
+
+
+
+(defcustom erbot-ignore-nicks '("^apt[0-9]?$" "bot" "google" "serv")
+ "A list of REGEXPS.
+Nicks matching these regexps will be ignored by the bot, viz. not
+generate replies.
+
+I would suggest including atleast bot, google and serv here to prevent
+infinite chat loops with other bots. :)
+"
+:type '(repeat regexp)
+:group 'erbot)
+
+(defcustom erbot-use-whitelist nil "Use a whitelist for accessing the bot.
+Any request from another source will be ignored. If a source is present in whitelist
+and in `erbot-ignore-nicks' it is ignored"
+:type 'boolean
+:group 'erbot)
+
+(defcustom erbot-whitelist-nicks nil
+"List of the entries that have access to the bot. Used only when `erbot-use-whitelist' is non-nil"
+:type '(repeat regexp)
+:group 'erbot)
+
+(defcustom erbot-ignore-userinfos "" "list of regex's" :group 'erbot)
+(run-hooks 'erbot-before-load-hooks)
+
+
+(defgroup erbot nil
+ "The group erbot"
+ :group 'applications)
+
+(defcustom erbot-nick "fsbot"
+"Changing this in the middle of things
+may have unspecified and unpleasant results..."
+:group 'erbot)
+
+(defvar erbot-end-user-nick "dummy-nick"
+ "just a temporary variable..")
+
+(defvar erbot-end-user-nick-latest "dummy-end-user-nick-latest"
+ "just a temporary variable..")
+
+
+
+
+
+(defcustom erbot-servers-channels
+ '(("irc.openprojects.net"
+ ("#testopn"
+ ))
+ (".gnome.org"
+ ("#testgnome")
+ ;; optional but:
+ 6667
+ ))
+ "Servers and channels ..."
+ :group 'erbot)
+
+
+
+; (defalias 'erc-replace-regexp-in-string 'replace-regexp-in-string))
+
+
+(defface erbot-face '((t (:foreground "yellow")))
+ "Face used for your robot's output."
+ :group 'erc-faces)
+
+(defcustom erbot-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))
+ )
+
+
+
+(defcustom erbot-erbmsg-p nil
+ "When true, erball.el loads the erbmsg module by default ")
+
+
+(defcustom erbot-notify-p t
+ "Set it to t if you want RSS notification
+for your erbot.
+
+Note that even if it is t, we will internally setq it to nil temporarily during
+the inner workings of the bot. ")
+
+;; The next part suggested by forcer, See
+;; http://www.kollektiv-hamburg.de/~forcer/erbot-notify.txt, which is
+;; also copied here:
+
+;; erbot should include the following function lists, which are
+;; called on these events with the specified arguments:
+
+;; erbot-notify-add-functions
+;; arguments: nick channel term entry-num entry
+
+(defvar erbot-notify-add-functions nil
+ "Functions to call when an erbot add takes place. Each of these is
+called with the arguments arguments: nick channel term entry-num
+entry")
+
+;; erbot-notify-forget-functions
+;; arguments: nick channel term entry-num entry
+;; If entry-num is 'all, entry is a list of entries
+
+
+;; SPECS CHANGED!
+(defvar erbot-notify-forget-functions nil
+ "Functions to call when an erbot forget takes place. Each of these
+is called with the arguments arguments: nick channel term entry-num
+entry remaining-entries. If entry-num is 'all, entry is a list of
+entries")
+
+;; erbot-notify-move-functions
+;; arguments: nick channel old-term new-term
+
+(defvar erbot-notify-move-functions nil
+ "Functions to call when an erbot move operation takes place. Each
+of these is called with the arguments arguments: nick channel old-term
+new-term ")
+
+;; erbot-notify-rearrange-functions
+;; arguments: nick channel term from-num from-entry to-num
+;; entries
+
+(defvar erbot-notify-rearrange-functions nil
+ "Functions to call when an erbot rearrange operation takes place. Each
+of these is called with the arguments arguments: nick channel term
+from-num from-entry to-num entries. Entries refers to the rearranged
+entries. ")
+
+
+;; erbot-notify-substitute-functions
+;; arguments: nick channel term entry-num old-entry new-entry
+(defvar erbot-notify-substitute-functions nil
+ "Functions to call when an erbot substitute operation takes place.
+Each of these is called with the arguments arguments: nick channel
+term entry-num old-entry new-entry")
+
+;;; 2005-08-31 T10:56:27-0400 (Wednesday) D. Goel
+(defvar erbot-nickserv-p nil
+ "When t, erbot will load the appropriate erc modules and will try to
+auto-identify to nickserv.
+
+If using this, we recommend these settings at the *BEGINNING* of your
+bot's .emacs:
+
+ (setq erbot-nickserv-p t)
+ (setq erc-prompt-for-nickserv-password nil)
+
+ (setq erc-nickserv-passwords
+ '((freenode ((\"mybot\" . \"mypassword\")))))
+
+See this page for more details:
+http://www.emacswiki.org/cgi-bin/wiki?ErcNickserv
+")
+
+(when erbot-nickserv-p
+ (require 'erc-nickserv nil t) ;; old erc
+ (require 'erc-services nil t) ;; erc from emacs22
+ (erc-nickserv-mode 1)
+ )
+
+
+
+
+;; erbot-notify-merge-functions
+;; arguments: nick channel old-term new-term new-entries
+;; NOW CHANGED SPEC!
+(defvar erbot-notify-merge-functions nil
+ "Functions to call when an erbot merge operation takes place.
+Each of these is called with the arguments arguments: nick channel
+from-term to-term from-entries to-entries final-entries")
+
+
+
+; This function is used by the example above.
+(defun erbot-doctor (args)
+ "Glue the doctor into the ERC robot."
+ (let* ((thisbuf (current-buffer))
+ (dbuf (concat "*doctor: " (buffer-name thisbuf) "*"))
+ (docbuf (get-buffer dbuf))
+ outpoint
+ res)
+ (if (not docbuf)
+ (progn
+ (set-buffer (get-buffer-create dbuf))
+ (make-doctor-variables)
+ (set-buffer thisbuf)
+ (setq docbuf (get-buffer dbuf))
+ (bury-buffer docbuf)))
+ (save-excursion
+ (set-buffer docbuf)
+ (goto-char (point-max))
+ (insert args)
+ (goto-char (point-max))
+ (setq outpoint (point))
+ (doctor-ret-or-read 1)
+ (doctor-ret-or-read 1)
+ (goto-char outpoint)
+ (re-search-forward "^.")
+ (setq outpoint (- (point) 1))
+ (re-search-forward "^$")
+ (erc-replace-regexp-in-string
+ "\n" " " (buffer-substring outpoint (point)))
+ )))
+
+
+
+(defun erbot-dunnet (arg)
+ "Glue the dunnet into the ERC robot."
+ (save-excursion
+ (let ((freshp nil)
+ outpoint res ans
+ (pre "")
+ full
+ )
+ (when (or (not (boundp 'dun-dead)) dun-dead
+ (not (get-buffer "*dungeon*"))
+ )
+ (setq freshp t)
+ (setq dun-dead nil))
+ (when freshp (dunnet))
+ (set-buffer "*dungeon*")
+ (goto-char (point-max))
+ (when (string-match "save" arg)
+ (setq arg "save ~/pub/dunnet/dunnet.game")
+ (setq pre "Will save to ~/pub/dunnet/dunnet.game"))
+ (cond
+ ((string-match "^.?more" arg)
+ (setq ans (fsi-more)))
+ (t
+ (unless freshp (insert arg))
+ (goto-char (point-max))
+ (setq outpoint (if freshp (point-min) (point)))
+ (unless freshp (dun-parse 1))
+ (setq ans
+ (buffer-substring-no-properties
+ outpoint (- (point-max) 1)))
+ (when (equal arg "quit")
+ (when (kill-buffer "*dungeon*")))))
+ (setq full (concat pre ans))
+ (when
+ (string-match
+ "I don't understand that"
+ full)
+ (setq
+ full
+ (concat
+ full
+ " I am in dunnet mode. For regular fsbot, type , (dunnet-mode)")))
+ full)))
+
+(defvar erbot-quiet-p nil
+ "When non-nil, the erbot only listens, never replies")
+(defun erbot-quiet ()
+ (interactive)
+ (setq erbot-quiet-p
+ (not erbot-quiet-p))
+ (message "set to %S" erbot-quiet-p))
+
+(defvar erbot-quiet-target-p-function nil
+ "A function. The function should take up to 3 arguments, TARGET
+\(channel) , nick and msg. If it returns non-nil, then erbot will
+listen and do everything but never reply back.")
+
+
+(defvar erbot-on-new-erc-p nil
+ "Whether we use erc >1.660 with new erc-backend.
+The value should not be set but is auto-guessed within
+`erbot-install'.")
+
+
+;; A very very main function..
+(defun erbot-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,
+command - the specific command,
+args - arguments to the command (optional).
+
+For newer erc, see `erbot-on-new-erc-p' and read the specs of
+the new erc-backend functions."
+ (set-buffer (process-buffer proc))
+ (let* (
+ (erbn-buffer (erc-server-buffer))
+ (sspec (cond (erbot-on-new-erc-p
+ (erc-response.sender parsed))
+ (t (aref parsed 1))))
+ (userinfo (erc-parse-user sspec))
+ (nick (erbutils-remove-text-properties-maybe (nth 0 userinfo)))
+ ;; bind fs-nick in a let.. so that changes to fs-nick are
+ ;; independent and do not affect each other.. when it is
+ ;; parsing too many messages once..
+ (fs-nick nick)
+ (erbn-nick fs-nick)
+ (cmdargs (and erbot-on-new-erc-p
+ (erc-response.command-args parsed)))
+ (tgta
+ (erbutils-remove-text-properties-maybe
+ (cond (cmdargs
+ (nth 0 cmdargs))
+ (t (aref parsed 2)))))
+ (tgt (if (equalp tgta (or (erc-current-nick) erbot-nick))
+ nick
+ tgta))
+ (erbn-tgt tgt)
+ (fs-tgt tgt)
+ (msg
+ (erbutils-remove-text-properties-maybe
+ (erc-response.contents parsed)))
+ (erbot-end-user-nick nick)
+ (csys (if (fboundp 'erc-coding-system-for-target)
+ (erc-coding-system-for-target tgt)
+ 'utf-8))
+ (code-in (if (consp csys) (cdr csys) csys))
+ (code-out (if (consp csys) (car csys) csys))
+ )
+ ;; changing the structure here..
+ ;; also changing erbot-command to erbot-reply..
+ ;; from now on, erend-main will take care of what to reply..
+ ;; erbot-reply will simply take the reply and reply that...
+ ;; should not be setq.. else other invocations may change it..
+ ;;(setq erbot-end-user-nick nick)
+
+ (setq erbot-end-user-nick-latest erbot-end-user-nick)
+ ;;(setq fs-tgt tgt)
+ ;;(setq erbn-tgt tgt)
+
+ ;;(setq fs-nick nick)
+ ;;(setq erbn-nick nick)
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; make sure we decode the raw text we received...
+ (unless (multibyte-string-p msg)
+ (setq msg (decode-coding-string msg code-in)))
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ (let ((msgg
+ (erbeng-main msg proc nick tgt nil userinfo)))
+ ;; erbot-reply needs a correct buffer...
+ (set-buffer (process-buffer proc))
+
+ (cond
+ (erbot-quiet-p nil)
+ ((and erbot-quiet-target-p-function
+ (funcall erbot-quiet-target-p-function tgt nick msg))
+ nil)
+ (t (erbot-reply
+ msgg
+ proc erbn-nick erbn-tgt msg nil
+ )))
+
+ ))
+ nil)
+
+
+(defun erbot-frob-with-init-string (reply)
+ (cond
+ ((or (not (stringp reply)) (string= erbot-init-string "")) reply)
+ (t
+ (with-temp-buffer
+ (insert reply)
+ (goto-char (point-min))
+ (while (re-search-forward "\n" nil t)
+ (replace-match
+ (concat "\n" erbot-init-string) nil t))
+ (concat erbot-init-string (erbutils-buffer-string))))))
+
+(defvar erbot-init-string ""
+ "The basic init string.. should be concated to ALL lines of
+replies... right at last.. the values it will hold will look like /msg
+foo, and will be set by fs-parse-english, when that function
+determines it appropriate..
+Currently: we do not use it, since we have found a better way to do
+those things..
+
+")
+
+;; this one is probably never used any more... just to make sure,
+;; introduced an error command..
+;(defun erbot-local (str)
+; "Funnel text typed by the local user to the local robot. See
+;\"erbot-remote\" for details of the command format."
+; (error "foo")
+; (erbot-command erc-process (erc-current-nick) (buffer-name) str t))
+
+(defcustom erbot-reply-p t
+ "when nil, don't reply")
+
+(defun erbot-toggle-reply ()
+ (interactive)
+ (setq erbot-reply-p (not erbot-reply-p))
+ (message "erbot-reply-p set to %S" erbot-reply-p)
+ )
+(defun erbot-reply (main-reply proc from tgt msg locally-generated)
+ "Robot worker. Should do nothing when main-reply is nil or 'noreply
+or \"noreply\"
+
+"
+ (unless (stringp main-reply)
+ (setq main-reply (format "%S" main-reply)))
+ (let (
+ linen
+ (me (or (erc-current-nick) erbot-nick))
+ ;;(if (and erbot-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 erbot-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 (concat from ": " main-reply))
+ ;; my frobbing of reply..
+ (reply
+ (erbot-frob-with-init-string main-reply))
+
+
+ (rep-buffer (erc-get-buffer tgt proc)))
+ ;;(if permitted
+ ;; (if l
+ ;; (funcall function args)
+ ;;(concat "unknown command: " cmd
+ ;; ": try \"cmds\""))
+ ;; (concat "no access to command \"" cmd
+ ;; "\" for " from ".")))))
+ (erc-log reply)
+
+
+ (unless
+ (or
+ (null erbot-reply-p)
+ (equal main-reply 'noreply)
+ (equal main-reply "noreply"))
+ ;; now we are actually gonna reply.
+ (save-excursion
+ (setq reply (fs-limit-lines reply))
+ (if rep-buffer (set-buffer rep-buffer)
+ ;;; this alternative reply somehow never gets sent out..
+ ;;(setq reply (concat "msg " from " "
+ ;; "No private msgs.. try #testopn"))
+ ;;(set-buffer (erc-get-buffer tgt proc))
+ (progn
+ (ding t)
+ (message "WTF? no rep-buffer? "))
+ )
+
+ (let* ((inhibit-read-only t)
+ (lines (split-string reply "[\n\r]+"))
+ (multiline-p (< 1 (length lines)))
+ p)
+ (mapc
+ (lambda (line)
+ (when (and line
+ (not (erbot-safe-p line)))
+ (setq line (erbot-safe-make line)))
+ (goto-char (point-max))
+ (setq p (re-search-backward (erc-prompt)))
+ ;;(insert (erc-format-timestamp) "<" me "> ")
+ (insert ;;(erc-format-timestamp)
+ "<" me "> ")
+ (erc-put-text-property 0 (length line) 'face
+ 'erbot-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))
+ (setq linen (concat line "\n"))
+ ;; fledermaus: I used to force the encoding here, but I now
+ ;; think that's the wrong thing to do. Hopefully if the data-path
+ ;; through erc->fsbot->erc is clean, erc will do the right thing
+ ;; to outbound data.
+ (erc-process-input-line linen nil multiline-p))
+ lines))))))
+
+
+(defcustom erbot-setf-p nil
+ "If you want your bot to allow setf, set this symbol to non-nil at
+the beginning of your .emacs")
+
+
+(defcustom erbot-setf-symbols
+ '(caar cadr car cdar cddr cdr eighth elt
+ first fourth
+ ninth nth
+ nthcdr
+ second
+ seventh sixth
+ subseq substring
+ tenth third)
+"Safe symbols for setf...")
+
+
+;;;###autoload
+(defun erbot-install ()
+ "Run this function AFTER loading all the files..."
+ (interactive)
+ (setq erbot-on-new-erc-p
+ (and (boundp 'erc-server-PRIVMSG-functions)
+ (featurep 'erc-backend)))
+ (cond (erbot-on-new-erc-p
+ (add-hook 'erc-server-PRIVMSG-functions 'erbot-remote t)
+ ;; Do we need this local command thing...?
+ ;;(add-hook 'erc-send-completed-hook 'erbot-local t)
+ (add-hook 'erc-server-001-functions
+ 'erbot-autojoin-channels))
+ (t
+ (add-hook 'erc-server-PRIVMSG-hook 'erbot-remote t)
+ ;; Do we need this local command thing...?
+ ;;(add-hook 'erc-send-completed-hook 'erbot-local t)
+ (add-hook 'erc-server-001-hook
+ 'erbot-autojoin-channels))
+ )
+ (erbot-install-symbols)
+ (when (and erbot-setf-p (not erbot-paranoid-p))
+ (erbot-install-setf))
+ ;; A running bot should have these nil, else userfunctions will not
+ ;; function right:
+ (setq eval-expression-print-length nil)
+ (setq eval-expression-print-level nil)
+ (setq print-length nil)
+ (setq print-level nil)
+ )
+
+
+
+(defun erbot-install-setf ()
+ (interactive)
+ (defalias 'fs-setf 'setf)
+ (require 'cl)
+ (let*
+ (
+ ;; all possible symbols
+ ;;(syms
+ ;;(apropos-internal "" (lambda (a) (get a 'setf-method))))
+ (syms erbot-setf-symbols)
+ (fssyms
+ (mapcar
+ (lambda (a) (intern (format "fs-%s" a)))
+ syms))
+ (fsisyms
+ (mapcar
+ (lambda (a) (intern (format "fsi-%s" a)))
+ syms)))
+ (mapcar*
+ (lambda (a b c)
+ (let ((foo (get a 'setf-method)))
+ (when (fboundp b) (put b 'setf-method foo))
+ (when (fboundp c) (put c 'setf-method foo))))
+ syms fssyms fsisyms)))
+
+
+
+
+(defun erbot-install-symbols ()
+ "By now, you should have loaded all pertinent erbot files... If you
+add any new functions, don't forget to run (erbot-install) AFTER
+that.."
+ (interactive)
+ (let ((ss (fsi-command-list-readonly)))
+ (dolist (s ss)
+
+ (if (symbolp s)
+ (let ((f-s (erbutils-concat-symbols 'fs- s))
+ (fi-s (erbutils-concat-symbols 'fsi- s)))
+
+ (defalias f-s fi-s)
+ (put f-s 'readonly t))
+ (message "Ignoring fsi->fs for %s" s)))))
+
+
+
+
+;;;###autoload
+(defun erbot-autojoin-channels (server nick)
+ ;;(interactive)
+ (dolist (l erbot-servers-channels)
+ (when (string-match (car l) (process-name server))
+ (dolist (chan (cadr l))
+ (erc-send-command (concat "join " chan))))))
+
+
+
+(defun erbot-get-servers ()
+ (mapcar '(lambda (arg) (list (car arg) (caddr arg)))
+ erbot-servers-channels))
+
+
+;;;###autoload
+(defun erbot-alive-p ()
+ "Is atleast one connection still alive?"
+ ;;(require 'cl-extra)
+ (some
+ 'identity
+ (mapcar
+ (lambda (buf)
+ (save-excursion
+ (set-buffer buf)
+ (erc-process-alive)))
+ (erc-buffer-list))))
+
+(defvar erbot-reconnection-attempts nil)
+
+;;;###autoload
+(defun erbot-keep-alive (&rest args)
+ "Periodically check if atleast one connection is still alive. If
+not, try to reconnect. "
+ (require 'idledo)
+ (idledo-add-periodic-action-crude
+ '(unless (erbot-alive-p)
+ (add-to-list 'erbot-reconnection-attempts
+ (message "Erbot trying to reconnect at %s"
+ (format-time-string
+ "%Y%m%d-%H%M-%S")))
+ (ignore-errors (apply 'erbot-join-servers args)))))
+
+;;;###autoload
+(defun erbot-join-servers (&optional server port nick
+ user-full-name
+ not-connect-arg passwd)
+ "Try to never join if already joined..."
+ (interactive)
+ (require 'erc)
+ (if (null server)
+ (mapcar
+ '(lambda (arg)
+ (erbot-join-servers
+ (car arg) (cadr arg) nick user-full-name not-connect-arg passwd)
+ (sit-for 1)
+ )
+
+ ;; get the list of servers
+ (erbot-get-servers)
+
+ )
+ (progn
+ ;;(if (null server)
+ ;; (setq server erc-server))
+ ;; 2002-08-21 T11:22:35-0400 (Wednesday) D. Goel
+ (setq erc-current-server-my server)
+ (if (null port)
+ (setq port
+ (if (fboundp 'erc-compute-port)
+ (erc-compute-port)
+ erc-port)))
+ (setq nick (or erbot-nick (erc-compute-nick nick)))
+ (let* (
+ (foo 'bar)
+ (version nil)
+ ;(nick
+ ; (if (erc-already-logged-in server port nick)
+ ;; (read-from-minibuffer
+ ;; (erc-format-message 'nick-in-use ?n nick)
+ ;; nick
+ ;; nil nil 'erc-nick-history-list)
+ ;; nick)))
+ )
+ (if (and passwd (string= "" passwd))
+ (setq passwd nil))
+ ;; (while (erc-already-logged-in server port nick)
+ ;; (setq nick (read-from-minibuffer
+ ;; (erc-format-message 'nick-in-use ?n nick)
+ ;; nick
+ ;; nil nil 'erc-nick-history-list)))
+
+ (run-hook-with-args 'erc-before-connect server port nick)
+ (if (string-match "\\(\\<[[:digit:]]+.[[:digit:]]+\\>\\)"
+ erc-version-string)
+ (setq version (string-to-number
+ (match-string 1 erc-version-string)))
+ (setq version 0))
+
+ (unless (erc-already-logged-in server port nick)
+ (if (<= 5.0 version)
+ (erc :server server
+ :port port
+ :nick nick
+ :password passwd
+ :full-name user-full-name)
+ (erc
+ server port nick user-full-name (not not-connect-arg) passwd) ))
+ ))))
+
+
+(defun erbot-safe-make (line)
+ (let* ((ans line)
+ (rlist (string-to-list line)))
+ (when (string-match "^/" line)
+ (unless (string-match "^/me " line)
+ (setq ans (concat " " line))))
+ (when (member-if (lambda (a)
+ (and (< a 32)
+ (not (= a 9))))
+ rlist)
+ (setq ans "<control characters>"))
+ (when (string-match "[\n\r]" line)
+ (setq ans " <newlines> "))
+ ans))
+
+
+
+
+
+(defun erbot-safe-p (reply)
+ "Determine whether a reply is safe. Any newlines are simply
+reported as unsafe.
+
+If this functions deems a reply as unsafe, you should not send it to
+ERC but call `erbot-safe-make' first. "
+ (and
+ (not (string-match "[\n\r]" reply))
+ ;; err on the side of caution. Demand that the 1st char. be VERY
+ ;; safe.
+ (or
+ (string-match "^[0-9a-zA-Z]" reply)
+ ;;(not (string-match "^/" reply)) -- this is bad.. since, control
+ ;;characters are bad... beginnning ^A for example, will send CTCP requests..
+
+ ;; Allow /me commands.. but only when the rest of the text has no
+ ;; control characters..
+ (equal 0 (string-match "^/me " reply)))
+ ;; And there be no control characters whatsoever anywhere.
+ (erbot-safe-nocontrol-p reply)))
+
+(defun erbot-safe-nocontrol-p (reply)
+ (let ((rlist (string-to-list reply)))
+ (not (member-if (lambda (a) (< a 32)) rlist))))
+
+
+
+
+
+
+(defun erbot-dunnet-install ()
+ "Defines some dunnet specific aliases. "
+ (interactive)
+ (require 'dunnet)
+ (defalias 'dun-read-line 'fs-botread)
+ ;;(defalias 'dun-mprinc
+ ;;'fs-dun-mprinc))
+ )
+
+
+(defmacro erbot-working (&rest args)
+ `(let ((erbbdb-save-p nil)
+ (erbot-notify-p nil))
+ ,@args))
+
+
+
+(provide 'erbot)
+(run-hooks 'erbot-after-load-hooks)
+
+
+
+;;; erbot.el ends here