/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is JSIRC Sample bot. * * The Initial Developer of the Original Code is * New Dimensions Consulting, Inc. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Robert Ginda, rginda@ndcico.com, original author * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ var LIB_PATH = "../lib/"; bot = new Object(); bot.ownerPatterns = new Array(); bot.personality = new Object(); bot.personality.hooks = new Array(); bot.prefix = "!js "; function loadDeps() { load(LIB_PATH + "utils.js"); load(LIB_PATH + "events.js"); load(LIB_PATH + "connection.js"); load(LIB_PATH + "http.js"); load(LIB_PATH + "dcc.js"); load(LIB_PATH + "irc.js"); load(LIB_PATH + "irc-debug.js"); load(LIB_PATH + "message-manager.js"); bot.messageManager = new MessageManager(); if (!connection_init(LIB_PATH)) return false; return true; } // FIXME: Find somewhere better for these guys. // function toUnicode(msg, charsetOrView) { if (!msg) return msg; var charset; if (typeof charsetOrView == "string") charset = charsetOrView; else return msg; return bot.messageManager.toUnicode(msg, charset); } function fromUnicode(msg, charsetOrView) { if (!msg) return msg; var charset; if (typeof charsetOrView == "string") charset = charsetOrView; else return msg; return bot.messageManager.fromUnicode(msg, charset); } // FIXME: END // function initStatic() { if (jsenv.HAS_RHINO) gc = java.lang.System.gc; CIRCNetwork.prototype.INITIAL_NICK = "jsbot"; CIRCNetwork.prototype.INITIAL_NAME = "XPJSBot"; CIRCNetwork.prototype.INITIAL_DESC = "XPCOM Javascript bot"; CIRCNetwork.prototype.INITIAL_CHANNEL = "#jsbot"; CIRCNetwork.prototype.stayingPower = true; CIRCNetwork.prototype.on433 = my_433; CIRCChannel.prototype.onPrivmsg = my_chan_privmsg; CIRCUser.prototype.onDCCChat = my_user_dccchat; CIRCDCCChat.prototype.onRawData = my_dccchat_rawdata; } /* * One time initilization stuff */ function init(obj) { obj.eventPump = new CEventPump(100); obj.networks = new Object(); obj.networks["hybridnet"] = new CIRCNetwork("hybridnet", [{name: "irc.ssc.net", port: 6667}], obj.eventPump); obj.networks["moznet"] = new CIRCNetwork("moznet", [{name: "irc.mozilla.org", port: 6667}], obj.eventPump); obj.networks["efnet"] = new CIRCNetwork ("efnet", [{name: "irc.mcs.net", port: 6667}, {name: "irc.cs.cmu.edu", port: 6667}], obj.eventPump); obj.primNet = obj.networks["efnet"]; } /* * Kick off the mainloop for the first time */ function go() { if (!loadDeps()) return false; // The utils.js formatException relies on localization, we can't. Fix: formatException = function formatException(ex) { if (isinstance(ex, Error) || ((typeof ex == "object") && ("filename" in ex))) { return [ex.name, ex.message, ex.fileName, ex.lineNumber].join(", "); } return String(ex); }; initStatic(); init(bot); if (DEBUG) { /* hook all events EXCEPT server.poll and *.event-end types * (the 4th param inverts the match) */ bot.eventPump.addHook([{type: "poll", set: /^(server|dcc-chat)$/}, {type: "event-end"}], event_tracer, "event-tracer", true /* negate */); } if (typeof initPersonality == "function") initPersonality(); bot.primNet.connect(); rego(); return true; } /* * If you didn't compile libjs with JS_HAS_ERROR_EXCEPTIONS, any error the * bot encounters will exit the mainloop and drop you back to a shell ("js>") * prompt. You can continue the mainloop by executing this function. */ function rego() { /* mainloop */ while (bot.eventPump.queue.length > 0) { bot.eventPump.stepEvents(); if (typeof gc == "function") { if ((typeof bot.lastGc == "undefined") || (Number(new Date()) - bot.lastGc > 60000)) { gc(); bot.lastGc = Number(new Date()); } } } dd("No events to process."); return true; } function addOwner(pattern) { bot.ownerPatterns.push(pattern); } function userIsOwner(user) { if (!user.host) { /* we havn't got any information on this user yet. They havn't spoken * yet, and we havn't /whoi's them yet. Say no for now, but do the * /whois so we'll know for sure next time. */ if (user.TYPE == "IRCChanUser") user.parent.parent.sendData("WHOIS " + user.unicodeName + "\n"); else user.parent.sendData("WHOIS " + user.unicodeName + "\n"); return false; } var userString = user.unicodeName + "!" + user.name + "@" + user.host; dd("userIsOwner: checking userString `" + userString + "' against:"); for (var p in bot.ownerPatterns) { if (userString.search(bot.ownerPatterns[p]) != -1) { dd(String(bot.ownerPatterns[p]) + " passed."); return true; } else { dd(String(bot.ownerPatterns[p]) + " fails."); } } return false; } function psn_isAddressedToMe(e) { if (!e.server) return false; if ((e.type.search(/privmsg|ctcp-action/)) || (e.set != "channel")) return false; var msg = e.decodeParam(2); if (msg.indexOf(bot.prefix) == 0) return false; /* dd ("-*- checking to see if message '" + msg + "' is addressed to me."); */ var regex = new RegExp("^\\s*" + e.server.me.unicodeName + "\\W+(.*)", "i"); var ary = msg.match(regex); //dd ("address match: " + ary); if (ary != null) { e.statement = ary[1]; return true; } //XXXgijs: Shouldn't this be in mingus.js? bot.personality.dp.addPhrase(msg); return false; } function psn_onAddressedMsg(e) { bot.eventPump.onHook(e, bot.personality.hooks); return false; } bot.personality.addHook = function psn_addhook(pattern, f, name, neg, enabled) { if (pattern instanceof RegExp) pattern = {statement: pattern}; return bot.eventPump.addHook(pattern, f, name, neg, enabled, bot.personality.hooks); } function bot_eval(e, script) { try { var v = eval(script); } catch (ex) { e.replyTo.say(e.user.unicodeName + ": " + String(ex)); return false; } if (typeof v != "undefined") { if (v != null) v = String(v); else v = "null"; var rsp = e.user.unicodeName + ", your result is,"; if (v.indexOf("\n") != -1) rsp += "\n"; else rsp += " "; e.replyTo.say(rsp + v); } } /* * The following my_* are attached to their proper objects in the init() * function. This is because the CIRC* objects are not defined at load time * (they get defined when loadDeps() loads the irc library) and so connecting * them here would cause an error. */ /* * What to do when a privmsg is received on a channel */ function my_chan_privmsg(e) { var user = e.user; var msg = e.decodeParam(2); if ((msg.indexOf(bot.prefix) == 0) && userIsOwner(user)) { /* if last char is a continuation character, then... */ if (msg[msg.length - 1] == "\\") { user.accumulatedScript = msg.substring(bot.prefix.length, msg.length - 1); return false; // prevent other hooks from processing this... } else { return bot_eval(e, msg.substring(bot.prefix.length, msg.length)); } } else if ((typeof(user.accumulatedScript) != "undefined") && userIsOwner(user)) /* if we were accumulating a message, add here, * and finish if not ends with '\'. */ { var lastLine = (msg[msg.length - 1] != "\\"); var line = msg.substring(0, msg.length - (lastLine ? 0 : 1)); user.accumulatedScript += line; if (lastLine) { var script = user.accumulatedScript; delete user.accumulatedScript; return bot_eval(e, script); } } } /* * What to do when a dcc chat request reaches a user object */ function my_user_dccchat(e) { if (!e.user.canDCC) { e.user.notice("\01DCC REJECT CHAT chat\01"); return false; } var c = new CIRCDCCChat(bot.eventPump); if (!c.connect(e.user.host, e.port)) { e.user.notice("\01DCC REJECT CHAT chat\01"); return false; } return true; } /* * What to do when our requested nickname is in use */ function my_433(e) { if (e.params[2] != CIRCNetwork.prototype.INITIAL_NICK) { /* server didn't like the last nick we tried, probably too long. * not much more we can do, bail out. */ e.server.disconnect(); } CIRCNetwork.prototype.INITIAL_NICK += "_"; e.server.sendData("nick " + CIRCNetwork.prototype.INITIAL_NICK + "\n"); } /* * What to do when raw data is received on a dcc chat connection */ function my_dccchat_rawdata(e) { try { var v = eval(e.data); } catch (ex) { this.say(String(ex)); return false; } if (typeof v != "undefined") { if (v != null) v = String(v); else v = "null"; this.say(v); } } /* * Wrapper around CHTTPDoc to make is simpler to use */ function loadHTTP(host, path, onComplete) { var htdoc = new CHTTPDoc(host, path); htdoc.onComplete = onComplete; htdoc.get(bot.eventPump); return htdoc; }