< Day Day Up > |
Hack 56 Find Out When People Are on the Network
People aren't always connected to IRC 24/7. Find out when they are. If you're looking for a particular person on IRC, you can tell if she's around by seeing if she's in any of your channels. But what if she's connected to the network but not in any of your channels? Most people resort to a simple /whois nickname at this stage. If the user is on the network, then you will be told what public channels she is in, how long she has been connected, and so on. If she doesn't appear to be in any public channels, you can still send a private message directly to that user. This is all rather inefficient if you plan to do it regularly, so the ISON command was implemented and detailed in the IRC RFC. This provides a quick and efficient way of finding out whether a given nickname is on IRC. At the protocol level, the ISON command takes a list of nicknames as its only parameter, for example: ISON Jibbler golbeck pasky raelity DeadEd There is no limit to the number of nicknames that can be included in the argument, but as with all IRC messages, you cannot exceed the 512-character line-length limit, which includes the return and newline characters at the end. The server will generate a 303 numeric reply (referred to as RPL_ISON in the IRC RFC), which lists the subset of nicknames that are connected to the network. In this case, everyone except "raelity" was connected, so he is omitted from the returned list: :kornbluth.freenode.net 303 Jibbler :Jibbler golbeck pasky DeadEd This is the best method of finding out who is on a server, as the request is handled locally by the server you are connected to—there is no need for it to get any information from any other servers in the network. 8.7.1 The CodeWith this knowledge of the ISON command, it's easy to write a bot that keeps track of your friends on IRC. All it needs to do is store a set of nicknames to look for and send the ISON command periodically. The nicknames will be stored in a HashSet, which ensures that no duplicates are stored. Extra nicknames can be added to the bot using the addNick method. The onServerResponse method is overridden to catch the RPL_ISON reply and work out which users are newcomers to the network. Save the following as IsonBot.java: import org.jibble.pircbot.*; import java.util.*; public class IsonBot extends PircBot { // Stores the nicknames that were on the server when we last checked. private HashSet onServer = new HashSet( ); // Stores the nicknames that we are looking for. private HashSet nicks = new HashSet( ); public IsonBot(String name) { setName(name); } public synchronized void addNick(String nick) { nicks.add(nick.toLowerCase( )); } public HashSet getNicks( ) { return nicks; } public synchronized void onServerResponse(int code, String response) { if (code == RPL_ISON) { // Get the list of nicknames returned by the server. String nicks = response.substring(response.indexOf(':') + 1); String[] tokens = nicks.split("\\s+"); HashSet newOnServer = new HashSet( ); for (int i = 0; i < tokens.length; i++) { String nick = tokens[i]; String key = nick.toLowerCase( ); newOnServer.add(key); if (!onServer.contains(key)) { // If the user wasn't already on, let us know. System.out.println(nick + " is on the server."); } } // Update the set of users who are currently on the network. onServer = newOnServer; } } } The bot thus far handles ISON replies perfectly and prints out a message each time someone new appears in the reply. A separate thread will be used to perform the task of sending the ISON request every minute. The PircBot class lets you send raw commands to the server with its sendRawLine method, which appends the return and newline characters to the line on your behalf. Save the following as IsonThread.java : import java.util.*; public class IsonThread extends Thread { IsonBot bot; public IsonThread(IsonBot bot) { this.bot = bot; // Let the program to exit if this is the only thread still running. setDaemon(true); } public void run( ) { boolean running = true; while (running) { // Build up the contents of the ISON command. String command = "ISON"; synchronized (bot) { HashSet nicks = bot.getNicks( ); Iterator it = nicks.iterator( ); while (it.hasNext( )) { String nick = (String) it.next( ); // Append each nickname to the argument list. command += " " + nick; } } bot.sendRawLine(command); // Wait for 60 seconds before sending the next request. delay(60); } } // Delay for the given number of seconds. private void delay (int seconds) { try { Thread.sleep(1000 * (long) seconds); } catch (InterruptedException e) { // Do nothing. } } } The main method has to instantiate the bot, add some nicknames to its search set, and tell the bot to connect to an IRC server. After it has connected, you can then start up the IsonThread so it can send a request every minute. Save the following as IsonBotMain.java: public class IsonBotMain { public static void main(String[] args) throws Exception { IsonBot bot = new IsonBot("IsonBot"); // Add any set of nicknames you want... bot.addNick("Jibbler"); bot.addNick("golbeck"); bot.addNick("pasky"); bot.addNick("raelity"); bot.addNick("DeadEd"); bot.setVerbose(false); bot.connect("irc.freenode.net"); // Start the IsonThread. IsonThread thread = new IsonThread(bot); thread.start( ); } } 8.7.2 Running the HackC:\java\IsonBot> javac -classpath .;pircbot.jar *.java Run the bot like this: C:\java\IsonBot> java -classpath .;pircbot.jar IsonBotMain 8.7.3 The ResultsWhen the bot receives its first reply to an ISON query, it will let you know straightaway who is connected to the network, for example: Jibbler is on the server. golbeck is on the server. pasky is on the server. DeadEd is on the server. If one of these users disconnects from the network, he or she will be removed from the onServer HashSet the next time an ISON is performed. If the user eventually comes back to the network, the bot will announce his or her reappearance in a similar way, for example: Jibbler is on the server. Adding ISON functionality to the TellBot [Hack #50] would allow it to deliver messages to other users even if they don't join the same channels as TellBot. |
< Day Day Up > |