package net.sf.st0rmbot; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Hashtable; import java.util.regex.Matcher; import java.util.regex.Pattern; public class St0rmBot { private IRCConnection con = null; public String nick = "St0rmB"; public String identd = "St0rmBot"; public String name = "St0rm Bot"; public String version = "St0rm Bot Beta"; public String site = "st0rm.net"; public String address = ""; public ArrayList users = new ArrayList(); public ArrayList channels = new ArrayList(); private String modes = ""; private String opModes = ""; // Modes users can recieve for op status private String prefixes = "~!@#$%^&*+"; private String paramModes = ""; // Modes a parameter is required with private String paramSetModes = ""; // Modes a parameter is required to set but not unset @SuppressWarnings("unused") private String noParamModes = ""; // Modes no parameter is required with public User me = new User("St0rmB"); public Hashtable prefixRef = new Hashtable(); private boolean authd = false; public synchronized void connect(String host, int port) throws UnknownHostException, IOException { me = new User(nick); users.add(me); if (con != null && con.isConnected()) { quit("Duplicated CONNECT"); } con = new IRCConnection(host,port); while (!authd) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void quit(String reason) { if (con.isConnected()) { con.write("QUIT :" + reason); con.disconnect(); } } public String getModes() { return modes; } public void parseLine(String line) { String[] param; line = line.replaceAll("^:",""); if (line.contains(":")) { String[] param1 = line.split(":")[0].split("\\s+"); String param2 = line.substring(line.indexOf(":")); param = new String[param1.length +1]; System.arraycopy(param1, 0, param, 0, param1.length); param[param1.length] = param2.replaceAll("^:",""); } else { param = line.split("\\s+"); } if (param[1].matches("\\d+")) { int raw = Integer.parseInt(param[1]); /* topic */ if (raw == 332) { Channel c = getChannel(param[3]); c.topic = param[4]; } // topic info else if (raw == 333) { Channel c = getChannel(param[3]); c.topicBy = param[4]; c.topicSet = Calendar.getInstance(); c.topicSet.setTime(new Date(Long.parseLong(param[5]))); } // NAMES else if (raw == 353) { Channel c = getChannel(param[4]); for (String nick : param[5].split("\\s+")) { String rawNick = nick.replaceAll("^[" + prefixes + "]", ""); User u = addUser(rawNick,c.name); if (!rawNick.equalsIgnoreCase(nick)) { u.setPrefix(c, nick.toCharArray()[0]); } } } // Protocol else if (raw == 005) { Matcher m = Pattern.compile("PREFIX=\\(([^)]+)\\)([^ ]+)").matcher(line); if (m.find()) { opModes = m.group(1); prefixes = m.group(2); char[] modechars = opModes.toCharArray(); char[] prefixchars = prefixes.toCharArray(); for (int i = 0; i < modechars.length && i < prefixchars.length;i++) { prefixRef.put(prefixchars[i], modechars[i]); } } // CHANMODES=b,k,l,imnpstrDdcCNu m = Pattern.compile("CHANMODES=([^,]+),([^,]+),([^,]+),([^,]+)").matcher(line); if (m.find()) { paramModes = m.group(1) + m.group(2); paramSetModes = m.group(3); noParamModes = m.group(4); } } } if (param[0].equalsIgnoreCase("PING")) { write("PONG :" + param[param.length -1]); onPing(param[param.length -1]); } /* * Initial user mode setting */ else if (param[1].equalsIgnoreCase("MODE") && modes.equals("")) { modes = param[3]; } /* * Join */ else if (param[1].equalsIgnoreCase("JOIN")) { Matcher m = Pattern.compile("([^!]+)!([^@]+)@([^ ]+)").matcher(param[0]); if (!m.find()) { System.out.println("Error on JOIN regexp!"); } else { String nick = m.group(1); String identd = m.group(2); String host = m.group(3); User u = addUser(nick,param[2]); u.identd = identd; u.address = host; if (nick.equalsIgnoreCase(this.nick)) { this.address = host; } onJoin(u,getChannel(param[2])); } } /* * Part */ else if (param[1].equalsIgnoreCase("PART")) { Matcher m = Pattern.compile("([^!]+)!([^@]+)@([^ ]+)").matcher(param[0]); if (!m.find()) { System.out.println("Error on PART regexp!"); } else { String nick = m.group(1); String identd = m.group(2); String host = m.group(3); User u = addUser(nick,param[2]); u.identd = identd; u.address = host; Channel c = getChannel(param[2]); onPart(u,c); removeUser(u,c); } } /* * Message */ else if (param[1].equalsIgnoreCase("PRIVMSG")) { Matcher m = Pattern.compile("([^!]+)!([^@]+)@([^ ]+)").matcher(param[0]); if (!m.find()) { System.out.println("Error on PRIVMSG regexp!"); } else { String nick = m.group(1); String identd = m.group(2); String host = m.group(3); if (param[2].equalsIgnoreCase(me.nick)) { User u = new User(nick); users.add(u); u.identd = identd; u.address = host; onPrivMsg(u,param[3]); } else { User u = addUser(nick,param[2]); u.identd = identd; u.address = host; onChanMsg(u,getChannel(param[2]),param[3]); } } } /* * Channel modes */ else if (param[1].equalsIgnoreCase("MODE") && !param[2].equals(me.nick)) { // :aca20031!benbuzbee@NetAdmin.St0rm.Net MODE #The-Hangout +v Test Matcher match = Pattern.compile("([^!]+)!([^@]+)@([^ ]+)").matcher(param[0]); if (!match.find()) { System.out.println("Error on MODE regexp!"); return; } String nick = match.group(1); String identd = match.group(2); String host = match.group(3); User adder = addUser(nick,param[2]); adder.identd = identd; adder.address = host; // Make local modes the op modes String modes = opModes; Channel chan = getChannel(param[2]); boolean added = true; // Array of all mode characters char[] array = param[3].toCharArray(); // Create a hashtable of the modes in order from top to bottom so you know which is greater and takes precedent int i = modes.length(); Hashtable modeAccess = new Hashtable(); modeAccess.put((char)0,0); for (char c : modes.toCharArray()) { modeAccess.put(c, i); i--; } // String[] of mode parameters, null if there are no params String[] modeParams = param.length > 4 ? line.substring(line.indexOf(param[3]) + param[3].length() +1).split("\\s+") : null; i=-1; for (char c : array) { System.out.println("Now checking: " + c); if (c == '+') { added = true; } else if (c == '-') { added = false; } String modesWithParams = added ? modes + paramModes + paramSetModes : modes + paramModes; // Modes with parameters if (modesWithParams.contains(Character.toString(c))) { // If the mode has a parameter, increase i which is the pointer to the parameters System.out.println("In " + modesWithParams); i++; } if (modes.contains(Character.toString(c))) { // If the mode is a user op mode then change the prefixes likewise System.out.println("Modes " + modes + " contains " + Character.toString(c)); User target = addUser(modeParams[i],param[2]); System.out.println(modeAccess == null); if (added && modeAccess.get(getModeFromPrefix(target.getPrefix(chan))) < modeAccess.get(c)) { target.setPrefix(chan,this.getPrefixFromMode(c)); } else if (getModeFromPrefix(target.getPrefix(chan)) == c) target.setPrefix(chan,(char)0); } } } // :mobius323!fulhamrul3@Maow-1EEE3253.lns4-c12.dsl.pol.co.uk QUIT :Quit: /* * Quits */ else if (param[1].equalsIgnoreCase("QUIT")) { Matcher match = Pattern.compile("([^!]+)!([^@]+)@([^ ]+)").matcher(param[0]); if (!match.find()) { System.out.println("Error on QUIT regexp!"); return; } String nick = match.group(1); User u = getUser(nick); if (u == null) { return; } for (Channel c : u.channels) { if (c.users.contains(u)) { c.users.remove(u); } } if (users.contains(u)) { users.remove(u); } onQuit(u.nick,param[2]); } else { System.out.println("<< " + line); } } public char getModeFromPrefix(char prefix) { for (char c : prefixRef.keySet()) { if (c == prefix) { return prefixRef.get(c); } } return 0; } public char getPrefixFromMode(char mode) { for (char c : prefixRef.keySet()) { if (prefixRef.get(c) == mode) { return c; } } return 0; } protected void onJoin(User user, Channel channel) { } protected void onPing(String source) { } protected void onPart(User user, Channel channel) { } protected void onPrivMsg(User u, String message) { } protected void onChanMsg(User u, Channel c, String message) { } protected void onQuit(String nick, String message) { } protected void sendMessage(String target, String message) { write("PRIVMSG " + target + ": " + message); } protected void sendMessage(User u, String message) { sendMessage(u.nick,message); } protected void sendMessage(Channel c, String message) { sendMessage(c.name,message); } protected void setMode(String target, String mode) { write("MODE " + target + " " + mode); } private User addUser(String nick, String channel) { User u = getUser(nick); if (u == null) { u = new User(nick); } Channel c = getChannel(channel); if (c == null) { c = new Channel(channel); } if (!u.channels.contains(c)) u.channels.add(c); if (!c.users.contains(u)) c.users.add(u); if (!users.contains(u)) { users.add(u); } if (!channels.contains(c)) { channels.add(c); } return u; } private void removeUser(User u, Channel c) { if (u.channels.contains(c)) u.channels.remove(c); if (c.users.contains(u)) c.users.remove(u); if (u.channels.size() == 0 && u != me) { users.remove(u); u = null; } if (c.users.size() == 0) { channels.remove(c); c = null; } } public User getUser(String nick) { for (User u : users) { if (u.nick.equalsIgnoreCase(nick)) { return u; } } return null; } public Channel getChannel(String name) { for (Channel c : channels) { if (c.name.equalsIgnoreCase(name)) { return c; } } return null; } public void write(String line) { System.out.println(">> " + line); con.write(line); } private class IRCConnection { private Socket sock = null; private BufferedWriter bw = null; private boolean stopread = false; private String host; public IRCConnection(String host, int port) throws UnknownHostException, IOException { this.host = host; sock = new Socket(host,port); new Thread() { public synchronized void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); String line; while (!stopread) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } while ((line = br.readLine()) != null) { if (!authd) { write("NICK " + nick); write("USER " + identd + " \"" + site + "\" \"" + IRCConnection.this.host +"\" :" + name); authd = true; St0rmBot.this.notify(); } St0rmBot.this.parseLine(line); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } public boolean isConnected() { if (sock != null || sock.isConnected()) { return true; } return false; } public void disconnect() { stopread = true; if (isConnected()) { try { sock.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } sock = null; } } public void write(String line) { if (!isConnected()) { return; } try { getBw().write(line); getBw().newLine(); getBw().flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private BufferedWriter getBw() throws IOException { if (bw == null) { bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())); } return bw; } } }