Java tutorial
/* irccat - a development support irc bot Copyright (C) 2006-2008 Richard Jones <rj@last.fm> 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; version 2 of the GPL only, not 3 :P 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package fm.last.irccat; import org.apache.commons.configuration.*; import org.jibble.pircbot.*; import java.net.*; import java.io.*; import java.util.List; import java.util.Map; import java.util.HashMap; public class IRCCat extends PircBot { private String nick; private String cmdScript; private String defaultChannel = null; private int maxCmdResponseLines = 26; private XMLConfiguration config; public static void main(String[] args) throws Exception { try { if (args.length == 0) { System.out.println("first param should be config file"); System.exit(-1); } XMLConfiguration c = null; try { c = new XMLConfiguration(args[0]); } catch (ConfigurationException cex) { System.err.println("Configuration error, check config file"); cex.printStackTrace(); System.exit(1); } IRCCat bot = new IRCCat(c); // listen for stuff and send it to irc: ServerSocket serverSocket = null; InetAddress inet = null; try { if (bot.getCatIP() != null) inet = InetAddress.getByName(bot.getCatIP()); } catch (UnknownHostException ex) { System.out.println("Could not resolve config cat.ip, fix your config"); ex.printStackTrace(); System.exit(2); } try { serverSocket = new ServerSocket(bot.getCatPort(), 0, inet); } catch (IOException e) { System.err.println("Could not listen on port: " + bot.getCatPort()); System.exit(1); } System.out.println("Listening on " + bot.getCatIP() + " : " + bot.getCatPort()); while (true) { try { Socket clientSocket = serverSocket.accept(); // System.out.println("Connection on catport from: " // + clientSocket.getInetAddress().toString()); CatHandler handler = new CatHandler(clientSocket, bot); handler.start(); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } public IRCCat(XMLConfiguration c) throws Exception { this.config = c; setEncoding("UTF8"); cmdScript = config.getString("script.cmdhandler"); maxCmdResponseLines = config.getInt("script.maxresponselines", 26); nick = config.getString("bot.nick"); setName(nick); setLogin(nick); setMessageDelay(config.getLong("bot.messagedelay", 1000)); setFinger(config.getString("bot.finger", "IRCCat - a development support bot, used by Last.fm")); try { // connect to server int tries = 0; while (!isConnected()) { tries++; System.out .println("Connecting to server [try " + tries + "]: " + config.getString("server.address")); connect(config.getString("server.address"), config.getInt("server.port", 6667), config.getString("server.password", "")); if (tries > 1) Thread.sleep(10000); } } catch (UnknownHostException uhe) { // we get stuck here on java.net.UnknownHostException // so just exit and let supervisor restart us System.err.println(uhe.toString()); System.err.println(uhe.getMessage()); System.exit(-1); } catch (Exception e) { System.err.println(e.toString()); System.err.println(e.getMessage()); } } public String getCmdScript() { return cmdScript; } public int getCmdMaxResponseLines() { return maxCmdResponseLines; } protected void onDisconnect() { while (!isConnected()) { try { reconnect(); } catch (Exception ex) { try { Thread.sleep(10000); } catch (InterruptedException e) { break; } } } } @SuppressWarnings("unchecked") protected void onConnect() { // join channels List<HierarchicalConfiguration> chans = config.configurationsAt("channels.channel"); for (HierarchicalConfiguration chan : chans) { System.out.println("/join #" + chan.getString("name")); joinChannel("#" + chan.getString("name") + " " + chan.getString("password", "")); // first one in the list considered default: if (defaultChannel == null) defaultChannel = "#" + chan.getString("name"); } String nickpass = config.getString("server.identify", ""); if (nickpass != "") identify(nickpass); System.out.println("Default channel: " + defaultChannel); } public int getCatPort() { return config.getInt("cat.port", 12345); } public String getCatIP() { return config.getString("cat.ip", "127.0.0.1"); } public String getDefaultChannel() { return defaultChannel; } // PM was sent to us on irc public void onPrivateMessage(String sender, String login, String hostname, String message) { handleMessage(null, sender, message); } public void changeTopic(String target, String topic) { super.setTopic(target, topic); } public void sendMsg(String t, String m) { m = mIRCify(m); super.sendMessage(t, m); } public String mIRCify(String m) { Map<String, String> colorReplacementMap = new HashMap<String, String>(); colorReplacementMap.put("NORMAL", Colors.NORMAL); colorReplacementMap.put("BOLD", Colors.BOLD); colorReplacementMap.put("UNDERLINE", Colors.UNDERLINE); colorReplacementMap.put("REVERSE", Colors.REVERSE); colorReplacementMap.put("WHITE", Colors.WHITE); colorReplacementMap.put("BLACK", Colors.BLACK); colorReplacementMap.put("DBLUE", Colors.DARK_BLUE); colorReplacementMap.put("DGREEN", Colors.DARK_GREEN); colorReplacementMap.put("RED", Colors.RED); colorReplacementMap.put("BROWN", Colors.BROWN); colorReplacementMap.put("PURPLE", Colors.PURPLE); colorReplacementMap.put("ORANGE", Colors.OLIVE); colorReplacementMap.put("YELLOW", Colors.YELLOW); colorReplacementMap.put("GREEN", Colors.GREEN); colorReplacementMap.put("TEAL", Colors.TEAL); colorReplacementMap.put("CYAN", Colors.CYAN); colorReplacementMap.put("BLUE", Colors.BLUE); colorReplacementMap.put("PINK", Colors.MAGENTA); colorReplacementMap.put("DGRAY", Colors.DARK_GRAY); colorReplacementMap.put("GRAY", Colors.LIGHT_GRAY); for (Map.Entry<String, String> e : colorReplacementMap.entrySet()) { // Support #COLOR or %COLOR // either format can be confusing, depending on context. m = m.replaceAll("%" + e.getKey(), e.getValue()); m = m.replaceAll("#" + e.getKey(), e.getValue()); } return m; } // message sent to our channel public void onMessage(String channel_, String sender, String login, String hostname, String message) { handleMessage(channel_, sender, message); } public void onPart(String _channel, String _sender, String _login, String _hostname) { if (!_sender.equals(nick)) return; // System.out.println("Exiting due to onPart()"); // System.exit(-1); } public void onQuit(String _sourceNick, String _sourceLogin, String _sourceHostname, String _reason) { if (!_sourceNick.equals(nick)) return; System.out.println("Exiting due to onQuit()"); System.exit(-1); } public void onKick(String channel_, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) { if (!recipientNick.equals(nick)) return; // we were kicked } // is this nick trusted? (are they in the default channel) private boolean isTrusted(String n) { //return true User[] users = getUsers(getDefaultChannel()); for (int j = 0; j < users.length; j++) if (n.equalsIgnoreCase(users[j].getNick())) return true; return false; } public void handleMessage(String channel_, String sender, String message) { String cmd; String respondTo = channel_ == null ? sender : channel_; if (message.startsWith(nick)) { // someone said something to us. // we don't care. return; } if (message.startsWith("!")) { if (!isTrusted(sender)) { System.out.println("UNTRUSTED (ignoring): [" + respondTo + "] <" + sender + "> " + message); return; } // irccat builtin command processing: String resp = handleBuiltInCommand(message.substring(1).trim(), sender); if (!(resp == null || resp.equals(""))) sendMessage(respondTo, resp); System.out.println("Built-in: [" + respondTo + "] <" + sender + "> " + message); return; } if (message.startsWith("?")) { // external script command. cmd = message.substring(1).trim(); } else { // just a normal message which we ignore return; } if (cmd.trim().length() < 1) return; // if a PM, you gotta be trusted. if (channel_ == null && !isTrusted(sender)) { System.out.println("UNTRUSTED (ignoring): [" + respondTo + "] <" + sender + "> " + message); return; } // now "cmd" contains the message, minus the address prefix (eg: ?) // hand off msg to thread that executes shell script System.out.println("Scripter: [" + respondTo + "] <" + sender + "> " + message); Thread t = new Scripter(sender, channel_, respondTo, cmd, this); t.run(); } /* * Basic built-in command processing allows you to instruct the bot at * runtime to join/leave channels etc */ protected String handleBuiltInCommand(String cmd, String sender) { String toks[] = cmd.split(" "); String method = toks[0]; // JOIN A CHANNEL if (method.equals("join") && toks.length >= 2) { if (toks.length == 3) joinChannel(toks[1], toks[2]); else joinChannel(toks[1]); sendMessage(toks[1], "<" + sender + "> !" + cmd); return "Joining: " + toks[1]; } return ""; } public void catTopic(String stuff, String[] recips) { for (int ci = 0; ci < recips.length; ci++) { changeTopic(recips[ci], stuff); } } public void catStuff(String stuff, String[] recips) { for (int ci = 0; ci < recips.length; ci++) { sendMsg(recips[ci], stuff); } } }