ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/client/alerters/IRC__Alerter.java
Revision: 1.30.2.5
Committed: Tue Feb 5 22:39:29 2002 UTC (22 years, 3 months ago) by tdb
Branch: SERVER_PIRCBOT
Changes since 1.30.2.4: +13 -4 lines
Log Message:
Thought it'd be nice if VERSION returned the revision of the code.

File Contents

# User Rev Content
1 tdb 1.1 //---PACKAGE DECLARATION---
2 tdb 1.29 package uk.org.iscream.cms.server.client.alerters;
3 tdb 1.1
4     //---IMPORTS---
5 tdb 1.29 import uk.org.iscream.cms.server.client.*;
6     import uk.org.iscream.cms.server.core.*;
7     import uk.org.iscream.cms.server.util.*;
8     import uk.org.iscream.cms.server.componentmanager.*;
9 tdb 1.1 import java.io.*;
10     import java.net.*;
11 tdb 1.9 import java.util.*;
12 ajm 1.25 import java.text.DateFormat;
13 tdb 1.30.2.1 import org.jibble.pircbot.*;
14 tdb 1.1
15     /**
16     * This Alert sends an IRC message.
17     *
18 tdb 1.9 * Clean shutdown could be achieved by stopping the run() method in the
19     * IRCBot inner class.
20     *
21 tdb 1.30.2.1 * @author $Author: tdb $
22 tdb 1.30.2.5 * @version $Id: IRC__Alerter.java,v 1.30.2.4 2002/02/05 21:40:03 tdb Exp $
23 tdb 1.1 */
24 ajm 1.25 public class IRC__Alerter extends AlerterSkeleton {
25 tdb 1.1
26     //---FINAL ATTRIBUTES---
27    
28     /**
29     * The current CVS revision of this class
30     */
31 tdb 1.30.2.5 public final String REVISION = "$Revision: 1.30.2.4 $";
32 tdb 1.1
33 tdb 1.9 /**
34     * A description of this alerter
35     */
36 tdb 1.1 public final String DESC = "Sends alerts on an IRC channel";
37    
38     //---STATIC METHODS---
39    
40     //---CONSTRUCTORS---
41 tdb 1.30.2.1
42 tdb 1.1 public IRC__Alerter() {
43 ajm 1.25 super();
44 tdb 1.30.2.1 // construct and initialise the bot
45 tdb 1.9 _ircbot = new IRCBot();
46 tdb 1.30.2.3 _ircbot.setVerbose(false);
47 tdb 1.30.2.1 Thread ircThread = new Thread(_ircbot);
48 tdb 1.19 // set it's name and start it
49 tdb 1.30.2.1 ircThread.setName("client.IRC__Alerter$IRCBot");
50     ircThread.start();
51     // log our start time
52 tdb 1.11 _startTime = System.currentTimeMillis();
53 tdb 1.5 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
54 tdb 1.1 }
55    
56     //---PUBLIC METHODS---
57    
58 ajm 1.25 /**
59     * Implements the abstract method from the skeleton class.
60     * This method will attempt to send an alert
61     * message over the IRC channel.
62     *
63     * @param alert the alert to send
64     */
65 tdb 1.1 public void sendAlert(Alert alert) {
66 tdb 1.27 // sort out the message
67     String alertType = Alert.alertLevels[alert.getLevel()];
68     String message;
69     try {
70     message = _cp.getProperty(_name, "Alerter.IRC.message");
71     } catch (PropertyNotFoundException e) {
72     message = NOT_CONFIGURED;
73     _logger.write(toString(), Logger.WARNING, "Alerter.IRC.message value unavailable using default of " + message);
74     }
75     message = processAlertMessage(message, alert);
76 tdb 1.9 // only send alerts if we're active
77 tdb 1.27 if(_active) {
78 ajm 1.25 // send the message
79     _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
80 tdb 1.30.2.3 _ircbot.sendMessage(message);
81 tdb 1.26 // count sent alerts
82     _alertCount++;
83 ajm 1.25 } else {
84 tdb 1.26 // don't send, but keep a count that we ignored it
85     _ignoredCount++;
86 tdb 1.18 }
87 tdb 1.26 // we'll always store the "last alert", regardless
88     // of whether we actually display it or not
89     _lastAlert = message;
90     _lastAlertTime = System.currentTimeMillis();
91 tdb 1.1 }
92    
93     /**
94     * Overrides the {@link java.lang.Object#toString() Object.toString()}
95     * method to provide clean logging (every class should have this).
96     *
97 tdb 1.29 * This uses the uk.org.iscream.cms.server.util.NameFormat class
98 tdb 1.1 * to format the toString()
99     *
100     * @return the name of this class and its CVS revision
101     */
102     public String toString() {
103     return FormatName.getName(
104     _name,
105     getClass().getName(),
106     REVISION);
107     }
108    
109 ajm 1.25 /**
110     * Return the String representation of what the alerter does
111     *
112     * @return the description
113 tdb 1.1 */
114     public String getDescription(){
115     return DESC;
116     }
117    
118     //---PRIVATE METHODS---
119 ajm 1.8
120 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
121 tdb 1.28
122     /**
123     * Returns the "friendly" name of this class. This
124     * is simply an accessor for _name, required due to
125     * inheritance issues with extending AlerterSkeleton.
126     *
127     * @return the friendly name
128     */
129     protected String getFName() {
130     return _name;
131     }
132 tdb 1.1
133     //---ATTRIBUTES---
134    
135 tdb 1.7 /**
136     * A reference to the IRCBot
137     */
138 tdb 1.1 private IRCBot _ircbot;
139    
140     /**
141 tdb 1.9 * Are we "active"
142     */
143     private boolean _active = false;
144    
145     /**
146     * The last alert that was sent
147     */
148     private String _lastAlert = "no alerts have been sent";
149    
150     /**
151 tdb 1.11 * The time of the last alert
152     */
153     private long _lastAlertTime = -1;
154    
155     /**
156     * Number of alerts sent
157     */
158 tdb 1.18 private int _alertCount = 0;
159    
160     /**
161     * Number of alerts ignored when in "stopped" mode
162     */
163     private int _ignoredCount = 0;
164 tdb 1.11
165     /**
166     * Time of IRCBot startup
167     */
168     private long _startTime;
169    
170     /**
171 tdb 1.30.2.1 * This holds a reference to the
172     * system logger that is being used.
173     */
174     protected Logger _logger = ReferenceManager.getInstance().getLogger();
175    
176     /**
177 tdb 1.1 * This is the friendly identifier of the
178     * component this class is running in.
179     * eg, a Filter may be called "filter1",
180     * If this class does not have an owning
181     * component, a name from the configuration
182     * can be placed here. This name could also
183     * be changed to null for utility classes.
184     */
185 ajm 1.25 private String _name = "IRC";
186 tdb 1.1
187     //---STATIC ATTRIBUTES---
188    
189     //---INNER CLASSES---
190    
191 tdb 1.30.2.1 class IRCBot extends PircBot implements Runnable {
192 tdb 1.16
193 tdb 1.1 /**
194 tdb 1.30.2.1 * The default reconnect delay in seconds
195 tdb 1.1 */
196 tdb 1.30.2.1 public final int DEFAULT_RECONNECT_DELAY = 30;
197    
198 tdb 1.30.2.3 /**
199     * Attempt to kick-start the IRCBot into action. Will
200     * keep calling init() until it doesn't throw an
201     * an IOException (which will only be thrown if there
202     * is an error initialising). After a successful call
203     * to init() the method finishes.
204     */
205 tdb 1.1 public void run() {
206 tdb 1.30.2.1 while(true) {
207 tdb 1.1 try {
208 tdb 1.30.2.1 init();
209     break;
210 tdb 1.9 }
211 tdb 1.30.2.1 catch (IOException e) {
212     _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
213 tdb 1.30.2.3 // wait for a while, defined in the config
214 tdb 1.30.2.1 reconnectSleep();
215 tdb 1.9 }
216 tdb 1.1 }
217 tdb 1.9 }
218    
219 tdb 1.30.2.3 /**
220     * Connects the bot to an irc server and joins a channel,
221     * using details supplied from the i-scream configuration
222     * system. If this method completes without an exception
223     * one can presume the bot is ready for use.
224     *
225     * @throws IOException if there is any problem initialising
226     */
227 tdb 1.30.2.4 private void init() throws IOException {
228 tdb 1.30.2.1 _logger.write(this.toString(), Logger.DEBUG, "Initialising IRCBot...");
229 tdb 1.30.2.3
230     // get a hook on the configuration system
231 tdb 1.7 ConfigurationProxy cp = ConfigurationProxy.getInstance();
232 tdb 1.30.2.3
233     // get hold of the server details
234 tdb 1.16 String server;
235     int port;
236     try {
237     server = cp.getProperty(_name, "Alerter.IRC.IRCServer");
238     port = Integer.parseInt(cp.getProperty(_name, "Alerter.IRC.IRCPort"));
239     } catch (PropertyNotFoundException e) {
240     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
241     throw new IOException("Can't get irc server details due to configuration error");
242     } catch (NumberFormatException e) {
243     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
244     throw new IOException("Can't get irc server details due to malformed configuration");
245     }
246 tdb 1.30.2.3
247     // get hold of the user details and nickname list
248 tdb 1.30.2.4 String user, nickList;
249 tdb 1.16 try {
250     user = cp.getProperty(_name, "Alerter.IRC.user");
251 tdb 1.30.2.3 nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
252 tdb 1.16 } catch (PropertyNotFoundException e) {
253     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
254 tdb 1.30.2.3 throw new IOException("Can't get user/nickname details due to configuration error");
255 tdb 1.16 }
256 tdb 1.30.2.3
257 tdb 1.30.2.4 // get hold of comment and finger information
258     // -- we're not too fussed if these aren't set
259     String comment = "Alerter.IRC.comment is undefined";
260     String finger = "Alerter.IRC.finger is undefined";
261     try {
262     comment = cp.getProperty(_name, "Alerter.IRC.comment");
263     finger = cp.getProperty(_name, "Alerter.IRC.finger");
264     } catch (PropertyNotFoundException e) {
265     _logger.write(this.toString(), Logger.WARNING, "Configuration warning, using default: "+e);
266     }
267    
268 tdb 1.30.2.3 // put these details into the bot
269 tdb 1.30.2.1 this.setLogin(user);
270 tdb 1.30.2.5 this.setVersion("[" + getRevision() + "] " + comment);
271 tdb 1.30.2.3 this.setFinger(finger);
272    
273     // attempt to connect, trying each nickname
274     // in turn until sucessfully connected
275 tdb 1.9 StringTokenizer st = new StringTokenizer(nickList, ";");
276     boolean ok = false;
277     while(!ok && st.hasMoreTokens()) {
278     String nick = st.nextToken();
279 tdb 1.30.2.1 try {
280 tdb 1.30.2.3 // try to connect with a nickname
281 tdb 1.30.2.1 _logger.write(this.toString(), Logger.DEBUG, "Trying nick: "+nick);
282     this.setName(nick);
283     this.connect(server, port);
284 tdb 1.30.2.3 // at this point we know the nickname was accepted
285 tdb 1.9 _nickname = nick;
286 tdb 1.30.2.1 ok = true;
287 tdb 1.9 }
288 tdb 1.30.2.1 catch(IOException e) {
289     _logger.write(this.toString(), Logger.ERROR, "IO error when connecting to server: "+e);
290     throw new IOException("IO error when connecting to server");
291     }
292     catch(IrcException e) {
293     _logger.write(this.toString(), Logger.ERROR, "IRC error when connecting to server: "+e);
294     throw new IOException("IRC error when connecting to server");
295     }
296     catch(NickAlreadyInUseException e) {
297     _logger.write(this.toString(), Logger.ERROR, "Nickname "+nick+" is already in use: "+e);
298 tdb 1.30.2.3 // don't do anything, instead just loop round
299     // and try the next nickname in the list
300 tdb 1.9 }
301     }
302     if(!ok) {
303 tdb 1.30.2.3 // must have tried all the nicknames, best bail out
304 tdb 1.30.2.1 _logger.write(this.toString(), Logger.ERROR, "All nicknames already in use");
305     throw new IOException("All nicknames already in use");
306 tdb 1.9 }
307 tdb 1.30.2.3
308     // get hold of the channel details, and attempt
309     // to join the specified channel
310 tdb 1.16 try {
311     _channel = cp.getProperty(_name, "Alerter.IRC.channel");
312 tdb 1.30.2.1 this.joinChannel(_channel);
313 tdb 1.16 } catch (PropertyNotFoundException e) {
314     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
315     throw new IOException("Can't get channel name due to configuration error");
316     }
317 tdb 1.30.2.1
318 tdb 1.30.2.3 // get hold of the startup notice, and send
319     // it if it's defined
320 tdb 1.30.2.1 String startupNotice;
321     try {
322     startupNotice = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice");
323     sendNotice(_channel, startupNotice);
324     } catch (PropertyNotFoundException e) {
325     _logger.write(this.toString(), Logger.DEBUG, "Startup notice not defined, so not sending: "+e);
326     }
327    
328 tdb 1.30.2.3 // at this point initialisation is complete, so
329     // we can return and set this flag to allow alerts
330 tdb 1.9 _active = true;
331 tdb 1.1 }
332    
333 tdb 1.30.2.3 /**
334     * Send a message to the current channel.
335     *
336     * @param message The message to send
337     */
338 tdb 1.30.2.4 private void sendMessage(String message) {
339 tdb 1.30.2.3 sendMessage(_channel, message);
340 tdb 1.9 }
341    
342 tdb 1.30.2.3 /**
343     * If we get disconnected this method will be
344     * called, so we must take action. We'll simply
345     * keep trying to reinitialise, and thus
346     * reconnect to the server.
347     */
348 tdb 1.30.2.1 public void onDisconnect() {
349 tdb 1.30.2.3 // stop alerts being sent for now
350 tdb 1.30.2.1 _active = false;
351     while(true) {
352 tdb 1.30.2.3 // wait for a while, defined in the config
353 tdb 1.30.2.1 reconnectSleep();
354 tdb 1.16 try {
355 tdb 1.30.2.1 init();
356     break;
357 tdb 1.16 }
358 tdb 1.30.2.1 catch (IOException e) {
359     _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
360 tdb 1.11 }
361 tdb 1.30.2.1 }
362     }
363    
364 tdb 1.30.2.3 /**
365     * If we receive a message this method will
366     * be called. We'll check if the message is
367     * for us, and call handleInput if it is.
368     *
369     * @param channel The channel the message came from
370     * @param sender The sender of the message
371     * @param login The login of the sender
372     * @param hostname The hostname of the sender
373     * @param message The message sent
374     */
375 tdb 1.30.2.1 public void onMessage(String channel, String sender, String login, String hostname, String message) {
376 tdb 1.30.2.4 String trimmedMessage = isForMe(message);
377     // if trimmedMessage is null, it's not for us
378     if(trimmedMessage != null) {
379     handleInput(trimmedMessage, channel);
380 tdb 1.30.2.1 }
381     }
382    
383 tdb 1.30.2.3 /**
384     * If we receive a private message this method
385     * will be called. No need to check if it's for
386     * us -- it has to be if it's a private message.
387     *
388     * @param sender The sender of the message
389     * @param login The login of the sender
390     * @param hostname The hostname of the sender
391     * @param message The message sent
392     */
393 tdb 1.30.2.1 public void onPrivateMessage(String sender, String login, String hostname, String message) {
394 tdb 1.30.2.2 handleInput(message, sender);
395 tdb 1.30.2.1 }
396    
397 tdb 1.30.2.3 /**
398     * If we receive a nick change message, this
399     * method gets called. We don't care about
400     * other users changing their nick, so we only
401     * take notice if our nick changes. If it does
402     * we need to change our internal nickname
403     * state.
404     *
405     * @param oldNick the old nickname
406     * @param login the login of the nick changer
407     * @param hostname the hostname of the nick changer
408     * @param newNick the new nickname
409     */
410 tdb 1.30.2.1 public void onNickChange(String oldNick, String login, String hostname, String newNick) {
411     if(oldNick.equals(_nickname)) {
412     _nickname = newNick;
413     }
414     }
415    
416 tdb 1.30.2.3 /**
417     * If we receive a kick message this method
418     * gets called. We only take notice if it's
419     * us getting kicked, and then we'll rejoin
420     * the channel after a short wait.
421     *
422     * @param channel the channel the kick happened on
423     * @param kickerNick the person who performed the kick
424     * @param kickerLogin the login of the person who performed the kick
425     * @param kickerHostname the hostname of the person who performed the kick
426     * @param recipientNick the nickname of the person being kicked
427     * @param reason the reason for the kick
428     */
429 tdb 1.30.2.2 public void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
430     if(recipientNick.equals(_nickname) && channel.equals(_channel)) {
431 tdb 1.30.2.3 // remind the person it's not very nice :)
432 tdb 1.30.2.2 sendMessage(kickerNick, "That wasn't a nice thing to do...");
433 tdb 1.30.2.3 // get hold of the channel details, in case they've changed
434 tdb 1.30.2.2 try {
435     _channel = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.channel");
436     } catch(PropertyNotFoundException e) {
437 tdb 1.30.2.3 _logger.write(this.toString(), Logger.ERROR, "Can't get channel name due to configuration error: "+e);
438 tdb 1.30.2.2 }
439 tdb 1.30.2.3 // wait for a while, defined in the config
440     reconnectSleep();
441     // we'll try and rejoin the channel regardless
442     // otherwise we might end up doing nothing!
443 tdb 1.30.2.2 joinChannel(_channel);
444     }
445     }
446    
447 tdb 1.30.2.3 /**
448     * This method handles input directed to us, and
449     * responds accordingly if required.
450     *
451     * nb. matching user input is quite bad right now,
452     * and should be improved one day.
453     *
454     * @param message the message from someone
455     * @param source where the message came from, so we know where to send the response
456     */
457 tdb 1.30.2.2 private void handleInput(String message, String source) {
458 tdb 1.30.2.3 // get hold of the configuration system
459 tdb 1.30.2.1 ConfigurationProxy cp = ConfigurationProxy.getInstance();
460     // setup some String's
461     String stopCommand, startCommand, timeSinceLastAlertCommand, lastAlertCommand, joinCommand;
462     String nickChangeCommand, versionCommand, helpCommand, statCommand, uptimeCommand;
463 tdb 1.30.2.3 // get the command set from the configuration
464 tdb 1.30.2.1 try {
465     stopCommand = cp.getProperty(_name, "Alerter.IRC.stopCommand");
466     startCommand = cp.getProperty(_name, "Alerter.IRC.startCommand");
467     timeSinceLastAlertCommand = cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand");
468     lastAlertCommand = cp.getProperty(_name, "Alerter.IRC.lastAlertCommand");
469     joinCommand = cp.getProperty(_name, "Alerter.IRC.joinCommand");
470     nickChangeCommand = cp.getProperty(_name, "Alerter.IRC.nickChangeCommand");
471     versionCommand = cp.getProperty(_name, "Alerter.IRC.versionCommand");
472     helpCommand = cp.getProperty(_name, "Alerter.IRC.helpCommand");
473     statCommand = cp.getProperty(_name, "Alerter.IRC.statCommand");
474     uptimeCommand = cp.getProperty(_name, "Alerter.IRC.uptimeCommand");
475     } catch (PropertyNotFoundException e) {
476     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
477     // lets bail from handling this line...
478     // ...it's gonna be hard without a command set!
479 tdb 1.30.2.2 return;
480 tdb 1.30.2.1 }
481    
482 tdb 1.30.2.3 // see if the message matches (loosely!) any
483     // of our known commands
484 tdb 1.30.2.4 if(message.equalsIgnoreCase(stopCommand)) {
485 tdb 1.30.2.1 _active = false;
486 tdb 1.30.2.2 sendMessage(source, "alerts have been stopped");
487 tdb 1.30.2.1 }
488 tdb 1.30.2.4 else if(message.equalsIgnoreCase(startCommand)) {
489 tdb 1.30.2.1 _active = true;
490 tdb 1.30.2.2 sendMessage(source, "alerts have been activated");
491 tdb 1.30.2.1 }
492 tdb 1.30.2.3 // this needs to go before lastAlertCommand if it contains
493     // the same words as the lastAlertCommand.
494 tdb 1.30.2.4 else if(message.equalsIgnoreCase(timeSinceLastAlertCommand)) {
495 tdb 1.30.2.1 if(_lastAlertTime != -1) {
496     long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
497 tdb 1.11 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
498 tdb 1.30.2.2 sendMessage(source, "I last sent an alert "+uptimeText+ " ago");
499 tdb 1.18 }
500 tdb 1.30.2.1 else {
501 tdb 1.30.2.2 sendMessage(source, "I've never sent an alert!");
502 tdb 1.9 }
503 tdb 1.30.2.1 }
504 tdb 1.30.2.4 else if(message.equalsIgnoreCase(lastAlertCommand)) {
505 tdb 1.30.2.1 if(_lastAlertTime != -1) {
506     String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
507 tdb 1.30.2.2 sendMessage(source, "last alert was at "+date+"; "+_lastAlert);
508 tdb 1.9 }
509     else {
510 tdb 1.30.2.2 sendMessage(source, "I've never sent an alert!");
511 tdb 1.9 }
512 tdb 1.30.2.1
513 tdb 1.9 }
514 tdb 1.30.2.4 else if(message.equalsIgnoreCase(joinCommand)) {
515 tdb 1.30.2.1 String joinCmd = joinCommand;
516     String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
517     int endOfChan = newChan.indexOf(" ");
518     if(endOfChan == -1) {
519     endOfChan = newChan.length();
520     }
521     newChan = newChan.substring(0, endOfChan);
522     if(newChan.equals(_channel)) {
523 tdb 1.30.2.2 sendMessage(source, "I'm already on "+newChan+"!");
524 tdb 1.30.2.1 } else {
525     partChannel(_channel);
526     joinChannel(newChan);
527     _channel = newChan;
528     }
529     }
530 tdb 1.30.2.4 else if(message.equalsIgnoreCase(nickChangeCommand)) {
531 tdb 1.30.2.1 String nickChangeCmd = nickChangeCommand;
532     String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
533     int endOfNick = newNick.indexOf(" ");
534     if(endOfNick == -1) {
535     endOfNick = newNick.length();
536     }
537     newNick = newNick.substring(0, endOfNick);
538     changeNick(newNick);
539     }
540 tdb 1.30.2.4 else if(message.equalsIgnoreCase(versionCommand)) {
541 tdb 1.30.2.5 sendMessage(source, "I am version " + getRevision() + " of the i-scream alerting bot");
542 tdb 1.30.2.1 }
543 tdb 1.30.2.4 else if(message.equalsIgnoreCase(helpCommand)) {
544 tdb 1.30.2.2 sendMessage(source, "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
545     sendMessage(source, "I understand the following commands;");
546     sendMessage(source, stopCommand);
547     sendMessage(source, startCommand);
548     sendMessage(source, lastAlertCommand);
549     sendMessage(source, joinCommand);
550     sendMessage(source, nickChangeCommand);
551     sendMessage(source, statCommand);
552     sendMessage(source, uptimeCommand);
553     sendMessage(source, timeSinceLastAlertCommand);
554     sendMessage(source, helpCommand);
555 tdb 1.30.2.1 }
556 tdb 1.30.2.4 else if(message.equalsIgnoreCase(statCommand)) {
557 tdb 1.30.2.2 sendMessage(source, "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!");
558 tdb 1.30.2.1 }
559 tdb 1.30.2.4 else if(message.equalsIgnoreCase(uptimeCommand)) {
560 tdb 1.30.2.1 long uptime = (System.currentTimeMillis() - _startTime) / 1000;
561     String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
562 tdb 1.30.2.2 sendMessage(source, "I have been running for "+uptimeText);
563 tdb 1.30.2.1 }
564 tdb 1.30.2.4 else if(message.equalsIgnoreCase("ping")) {
565 tdb 1.30.2.2 sendMessage(source, "pong");
566 tdb 1.30.2.1 }
567 tdb 1.30.2.4 else if(message.equalsIgnoreCase("do a jibble dance")) {
568 tdb 1.30.2.1 // little joke :)
569 tdb 1.30.2.2 sendAction(source, "jives to the funky beat shouting \"ii--screeeaaammm\"");
570 tdb 1.30.2.1 }
571     else {
572     String rejectMessage = NOT_CONFIGURED;
573 tdb 1.16 try {
574 tdb 1.30.2.1 rejectMessage = cp.getProperty(_name, "Alerter.IRC.rejectMessage");
575 tdb 1.16 } catch(PropertyNotFoundException e) {
576     _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
577     }
578 tdb 1.30.2.2 sendMessage(source, rejectMessage);
579 tdb 1.9 }
580     }
581    
582 tdb 1.30.2.3 /**
583     * Quick method to check if the message appears
584     * to be directed at us. We simply check to see
585     * if it starts with our nick in some fashion.
586 tdb 1.30.2.4 * This will return null if the message is not
587     * for us - thus allowing this method to perform
588     * two tasks at once.
589 tdb 1.30.2.3 *
590     * @param message the message to check
591 tdb 1.30.2.4 * @return the message (with our nick removed), or null if it's not for us.
592 tdb 1.30.2.3 */
593 tdb 1.30.2.4 private String isForMe(String message) {
594     // change to lower case to remove
595     // case ambiguities
596 tdb 1.30.2.1 String nick = _nickname.toLowerCase();
597     String msg = message.toLowerCase();
598     if(msg.startsWith(nick + ", ") ||
599     msg.startsWith(nick + ": ") ||
600     msg.startsWith(nick + " ")) {
601 tdb 1.30.2.4 // NOTE that the 1 here is hardcoded to be the length
602     // of the above 'extra' character (eg , or :)
603     return message.substring(nick.length()+1).trim();
604 tdb 1.30.2.1 }
605     else {
606 tdb 1.30.2.4 return null;
607 tdb 1.9 }
608     }
609    
610 tdb 1.30.2.3 /**
611     * Sleep for a configurable amount of time and
612     * then return. This is used when reconnecting
613     * to the server or a channel.
614     */
615 tdb 1.30.2.1 private void reconnectSleep() {
616     int delayTime = 0;
617     try {
618     delayTime = Integer.parseInt(ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.reconnectDelay"));
619     } catch (NumberFormatException e) {
620     delayTime = DEFAULT_RECONNECT_DELAY;
621     _logger.write(this.toString(), Logger.WARNING, "Erronous Alerter.IRC.reconnectDelay value in configuration using default of " + delayTime + " seconds");
622     } catch (PropertyNotFoundException e) {
623     delayTime = DEFAULT_RECONNECT_DELAY;
624     _logger.write(this.toString(), Logger.WARNING, "Alerter.IRC.reconnectDelay value unavailable using default of " + delayTime + " seconds");
625 tdb 1.9 }
626 tdb 1.30.2.1 _logger.write(this.toString(), Logger.ERROR, "Waiting "+delayTime+" seconds for reconnect...");
627     try {
628     Thread.sleep(delayTime * 1000);
629     } catch (InterruptedException e) {}
630 tdb 1.30.2.5 }
631    
632     /**
633     * Returns the revision of the bot.
634     *
635     * @return the revision of this bot
636     */
637     private String getRevision() {
638     return REVISION.substring(11, REVISION.length()-2);
639 tdb 1.9 }
640    
641     /**
642 tdb 1.30.2.1 * Overrides the {@link java.lang.Object#toString() Object.toString()}
643     * method to provide clean logging (every class should have this).
644     *
645     * This uses the uk.org.iscream.cms.server.util.NameFormat class
646     * to format the toString()
647     *
648     * @return the name of this class and its CVS revision
649 tdb 1.1 */
650 tdb 1.30.2.1 public String toString() {
651     return FormatName.getName(
652     _name,
653     getClass().getName(),
654     REVISION);
655     }
656 tdb 1.1
657 tdb 1.7 /**
658     * Just a reminder to what channel we're on...
659     * this can't be dynamic :)
660     */
661     private String _channel;
662 tdb 1.9
663     /**
664     * A reminder of our current nickname...
665     */
666     private String _nickname;
667    
668 tdb 1.1 }
669    
670     }