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
(Generate patch)

Comparing projects/cms/source/server/uk/org/iscream/cms/server/client/alerters/IRC__Alerter.java (file contents):
Revision 1.30.2.1 by tdb, Mon Feb 4 00:14:13 2002 UTC vs.
Revision 1.32 by tdb, Sat May 18 18:16:00 2002 UTC

# Line 1 | Line 1
1 + /*
2 + * i-scream central monitoring system
3 + * Copyright (C) 2000-2002 i-scream
4 + *
5 + * This program is free software; you can redistribute it and/or
6 + * modify it under the terms of the GNU General Public License
7 + * as published by the Free Software Foundation; either version 2
8 + * of the License, or (at your option) any later version.
9 + *
10 + * This program is distributed in the hope that it will be useful,
11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 + * GNU General Public License for more details.
14 + *
15 + * You should have received a copy of the GNU General Public License
16 + * along with this program; if not, write to the Free Software
17 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 + */
19 +
20   //---PACKAGE DECLARATION---
21   package uk.org.iscream.cms.server.client.alerters;
22  
# Line 43 | Line 62 | public class IRC__Alerter extends AlerterSkeleton {
62          super();
63          // construct and initialise the bot
64          _ircbot = new IRCBot();
65 <        //_ircbot.setVerbose(true);
65 >        _ircbot.setVerbose(false);
66          Thread ircThread = new Thread(_ircbot);
67          // set it's name and start it
68          ircThread.setName("client.IRC__Alerter$IRCBot");
# Line 77 | Line 96 | public class IRC__Alerter extends AlerterSkeleton {
96          if(_active) {          
97              // send the message
98              _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
99 <            _ircbot.sendMsg(message);
99 >            _ircbot.sendMessage(message);
100              // count sent alerts
101              _alertCount++;
102          } else {
# Line 195 | Line 214 | public class IRC__Alerter extends AlerterSkeleton {
214           */
215          public final int DEFAULT_RECONNECT_DELAY = 30;
216          
217 +        /**
218 +         * Attempt to kick-start the IRCBot into action. Will
219 +         * keep calling init() until it doesn't throw an
220 +         * an IOException (which will only be thrown if there
221 +         * is an error initialising). After a successful call
222 +         * to init() the method finishes.
223 +         */
224          public void run() {
225              while(true) {
226                  try {
# Line 203 | Line 229 | public class IRC__Alerter extends AlerterSkeleton {
229                  }
230                  catch (IOException e) {
231                      _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
232 +                    // wait for a while, defined in the config
233                      reconnectSleep();
234                  }
235              }
209            //System.out.println("falling out!");
236          }
237          
238 <        public void init() throws IOException {
238 >        /**
239 >         * Connects the bot to an irc server and joins a channel,
240 >         * using details supplied from the i-scream configuration
241 >         * system. If this method completes without an exception
242 >         * one can presume the bot is ready for use.
243 >         *
244 >         * @throws IOException if there is any problem initialising
245 >         */
246 >        private void init() throws IOException {
247              _logger.write(this.toString(), Logger.DEBUG, "Initialising IRCBot...");
248 +            
249 +            // get a hook on the configuration system
250              ConfigurationProxy cp = ConfigurationProxy.getInstance();
251 +            
252 +            // get hold of the server details
253              String server;
254              int port;
255              try {
# Line 224 | Line 262 | public class IRC__Alerter extends AlerterSkeleton {
262                  _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
263                  throw new IOException("Can't get irc server details due to malformed configuration");
264              }
265 <            String user, comment;
265 >            
266 >            // get hold of the user details and nickname list
267 >            String user, nickList;
268              try {
269                  user = cp.getProperty(_name, "Alerter.IRC.user");
270 <                comment = cp.getProperty(_name, "Alerter.IRC.comment");
270 >                nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
271              } catch (PropertyNotFoundException e) {
272                  _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
273 <                throw new IOException("Can't get user details due to configuration error");
273 >                throw new IOException("Can't get user/nickname details due to configuration error");
274              }
275 <            this.setLogin(user);
276 <            this.setVersion(comment);
277 <            this.setFinger(comment); // ?
278 <            String nickList;
275 >            
276 >            // get hold of comment and finger information
277 >            //  -- we're not too fussed if these aren't set
278 >            String comment = "Alerter.IRC.comment is undefined";
279 >            String finger = "Alerter.IRC.finger is undefined";
280              try {
281 <                nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
281 >                comment = cp.getProperty(_name, "Alerter.IRC.comment");
282 >                finger = cp.getProperty(_name, "Alerter.IRC.finger");
283              } catch (PropertyNotFoundException e) {
284 <                _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
243 <                throw new IOException("Can't get nickname due to configuration error");
284 >                _logger.write(this.toString(), Logger.WARNING, "Configuration warning, using default: "+e);
285              }
286 +            
287 +            // put these details into the bot
288 +            this.setLogin(user);
289 +            this.setVersion("[" + getRevision() + "] " + comment);
290 +            this.setFinger(finger);
291 +            
292 +            // attempt to connect, trying each nickname
293 +            // in turn until sucessfully connected
294              StringTokenizer st = new StringTokenizer(nickList, ";");
295              boolean ok = false;
296              while(!ok && st.hasMoreTokens()) {
297                  String nick = st.nextToken();
298                  try {
299 +                    // try to connect with a nickname
300                      _logger.write(this.toString(), Logger.DEBUG, "Trying nick: "+nick);
301                      this.setName(nick);
302                      this.connect(server, port);
303 <                    // must be ok if we get here
303 >                    // at this point we know the nickname was accepted
304                      _nickname = nick;
305                      ok = true;
306                  }
# Line 264 | Line 314 | public class IRC__Alerter extends AlerterSkeleton {
314                  }
315                  catch(NickAlreadyInUseException e) {
316                      _logger.write(this.toString(), Logger.ERROR, "Nickname "+nick+" is already in use: "+e);
317 <                    // just carry on around while loop
317 >                    // don't do anything, instead just loop round
318 >                    // and try the next nickname in the list
319                  }
320              }
321              if(!ok) {
322 <                // oh dear, we couldn't get on.
322 >                // must have tried all the nicknames, best bail out
323                  _logger.write(this.toString(), Logger.ERROR, "All nicknames already in use");
324                  throw new IOException("All nicknames already in use");
325              }
326 +            
327 +            // get hold of the channel details, and attempt
328 +            // to join the specified channel
329              try {
330                  _channel = cp.getProperty(_name, "Alerter.IRC.channel");
331                  this.joinChannel(_channel);
# Line 280 | Line 334 | public class IRC__Alerter extends AlerterSkeleton {
334                  throw new IOException("Can't get channel name due to configuration error");
335              }
336              
337 +            // get hold of the startup notice, and send
338 +            // it if it's defined
339              String startupNotice;
340              try {
341                  startupNotice = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice");
# Line 288 | Line 344 | public class IRC__Alerter extends AlerterSkeleton {
344                  _logger.write(this.toString(), Logger.DEBUG, "Startup notice not defined, so not sending: "+e);
345              }
346              
347 <            // we should set this when all is ready!
347 >            // at this point initialisation is complete, so
348 >            // we can return and set this flag to allow alerts
349              _active = true;
293            //System.out.println("leaving init");
350          }
351          
352 <        public void sendMsg(String msg) {
353 <            sendMessage(_channel, msg);
352 >        /**
353 >         * Send a message to the current channel.
354 >         *
355 >         * @param message The message to send
356 >         */
357 >        private void sendMessage(String message) {
358 >            sendMessage(_channel, message);
359          }
360          
361 +        /**
362 +         * If we get disconnected this method will be
363 +         * called, so we must take action. We'll simply
364 +         * keep trying to reinitialise, and thus
365 +         * reconnect to the server.
366 +         */
367          public void onDisconnect() {
368 +            // stop alerts being sent for now
369              _active = false;
370              while(true) {
371 +                // wait for a while, defined in the config
372                  reconnectSleep();
373                  try {
374                      init();
# Line 309 | Line 378 | public class IRC__Alerter extends AlerterSkeleton {
378                      _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
379                  }
380              }
312            //System.out.println("falling out of disconnect!");
381          }
382          
383 +        /**
384 +         * If we receive a message this method will
385 +         * be called. We'll check if the message is
386 +         * for us, and call handleInput if it is.
387 +         *
388 +         * @param channel The channel the message came from
389 +         * @param sender The sender of the message
390 +         * @param login The login of the sender
391 +         * @param hostname The hostname of the sender
392 +         * @param message The message sent
393 +         */
394          public void onMessage(String channel, String sender, String login, String hostname, String message) {
395 <            if(isForMe(message)) {
396 <                String response = handleInput(message);
397 <                if(response != null) {
398 <                    sendMessage(channel, response);
320 <                }
395 >            String trimmedMessage = isForMe(message);
396 >            // if trimmedMessage is null, it's not for us
397 >            if(trimmedMessage != null) {
398 >                handleInput(trimmedMessage, channel);
399              }
400          }
401          
402 +        /**
403 +         * If we receive a private message this method
404 +         * will be called. No need to check if it's for
405 +         * us -- it has to be if it's a private message.
406 +         *
407 +         * @param sender The sender of the message
408 +         * @param login The login of the sender
409 +         * @param hostname The hostname of the sender
410 +         * @param message The message sent
411 +         */
412          public void onPrivateMessage(String sender, String login, String hostname, String message) {
413 <            String response = handleInput(message);
326 <            if(response != null) {
327 <                sendMessage(sender, response);
328 <            }
413 >            handleInput(message, sender);
414          }
415          
416 +        /**
417 +         * If we receive a nick change message, this
418 +         * method gets called. We don't care about
419 +         * other users changing their nick, so we only
420 +         * take notice if our nick changes. If it does
421 +         * we need to change our internal nickname
422 +         * state.
423 +         *
424 +         * @param oldNick the old nickname
425 +         * @param login the login of the nick changer
426 +         * @param hostname the hostname of the nick changer
427 +         * @param newNick the new nickname
428 +         */
429          public void onNickChange(String oldNick, String login, String hostname, String newNick) {
430              if(oldNick.equals(_nickname)) {
431                  _nickname = newNick;
432 +                // tell the underlying pircbot that our nick has changed too :)
433 +                setName(newNick);
434              }
435          }
436          
437 <        private String handleInput(String message) {
438 <            //return "yup, gotcha!";
437 >        /**
438 >         * If we receive a kick message this method
439 >         * gets called. We only take notice if it's
440 >         * us getting kicked, and then we'll rejoin
441 >         * the channel after a short wait.
442 >         *
443 >         * @param channel the channel the kick happened on
444 >         * @param kickerNick the person who performed the kick
445 >         * @param kickerLogin the login of the person who performed the kick
446 >         * @param kickerHostname the hostname of the person who performed the kick
447 >         * @param recipientNick the nickname of the person being kicked
448 >         * @param reason the reason for the kick
449 >         */
450 >        public void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
451 >            if(recipientNick.equals(_nickname) && channel.equals(_channel)) {
452 >                // remind the person it's not very nice :)
453 >                sendMessage(kickerNick, "That wasn't a nice thing to do...");
454 >                // get hold of the channel details, in case they've changed
455 >                try {
456 >                    _channel = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.channel");
457 >                } catch(PropertyNotFoundException e) {
458 >                    _logger.write(this.toString(), Logger.ERROR, "Can't get channel name due to configuration error: "+e);
459 >                }
460 >                // wait for a while, defined in the config
461 >                reconnectSleep();
462 >                // we'll try and rejoin the channel regardless
463 >                // otherwise we might end up doing nothing!
464 >                joinChannel(_channel);
465 >            }
466 >        }
467 >        
468 >        /**
469 >         * This method handles input directed to us, and
470 >         * responds accordingly if required.
471 >         *
472 >         * @param message the message from someone
473 >         * @param source where the message came from, so we know where to send the response
474 >         */
475 >        private void handleInput(String message, String source) {
476 >            // get hold of the configuration system
477              ConfigurationProxy cp = ConfigurationProxy.getInstance();
478              // setup some String's
479              String stopCommand, startCommand, timeSinceLastAlertCommand, lastAlertCommand, joinCommand;
480              String nickChangeCommand, versionCommand, helpCommand, statCommand, uptimeCommand;
481 <            // get the command set
481 >            // get the command set from the configuration
482              try {
483                  stopCommand = cp.getProperty(_name, "Alerter.IRC.stopCommand");
484                  startCommand = cp.getProperty(_name, "Alerter.IRC.startCommand");
# Line 356 | Line 494 | public class IRC__Alerter extends AlerterSkeleton {
494                  _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
495                  // lets bail from handling this line...
496                  // ...it's gonna be hard without a command set!
497 <                return null;
497 >                return;
498              }
499              
500 <            if(message.indexOf(stopCommand)!=-1) {
500 >            if(message.equalsIgnoreCase(stopCommand)) {
501                  _active = false;
502 <                return "alerts have been stopped";
502 >                sendMessage(source, "alerts have been stopped");
503              }
504 <            else if(message.indexOf(startCommand)!=-1) {
504 >            else if(message.equalsIgnoreCase(startCommand)) {
505                  _active = true;
506 <                return "alerts have been activated";
506 >                sendMessage(source, "alerts have been activated");
507              }
508 <            // this needs to go here if it contains the same words as the lastAlertCommand
509 <            else if(message.indexOf(timeSinceLastAlertCommand)!=-1) {
508 >            // this needs to go before lastAlertCommand if it contains
509 >            // the same words as the lastAlertCommand.
510 >            else if(message.equalsIgnoreCase(timeSinceLastAlertCommand)) {
511                  if(_lastAlertTime != -1) {
512                      long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
513                      String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
514 <                    return "I last sent an alert "+uptimeText+ " ago";
514 >                    sendMessage(source, "I last sent an alert "+uptimeText+ " ago");
515                  }
516                  else {
517 <                    return "I've never sent an alert!";
517 >                    sendMessage(source, "I've never sent an alert!");
518                  }
519              }
520 <            else if(message.indexOf(lastAlertCommand)!=-1) {
520 >            else if(message.equalsIgnoreCase(lastAlertCommand)) {
521                  if(_lastAlertTime != -1) {
522                      String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
523 <                    return "last alert was at "+date+"; "+_lastAlert;
523 >                    sendMessage(source, "last alert was at "+date+"; "+_lastAlert);
524                  }
525                  else {
526 <                    return "I've never sent an alert!";
526 >                    sendMessage(source, "I've never sent an alert!");
527                  }
528                  
529              }
530 <            else if(message.indexOf(joinCommand)!=-1) {
530 >            else if(message.toLowerCase().startsWith(joinCommand.toLowerCase())) {
531                  String joinCmd = joinCommand;
532                  String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
533                  int endOfChan = newChan.indexOf(" ");
# Line 397 | Line 536 | public class IRC__Alerter extends AlerterSkeleton {
536                  }
537                  newChan = newChan.substring(0, endOfChan);
538                  if(newChan.equals(_channel)) {
539 <                    return "I'm already on "+newChan+"!";
539 >                    sendMessage(source, "I'm already on "+newChan+"!");
540                  } else {
541                      partChannel(_channel);
542                      joinChannel(newChan);
543                      _channel = newChan;
405                    return null; // ???
544                  }
545              }
546 <            else if(message.indexOf(nickChangeCommand)!=-1) {
546 >            else if(message.toLowerCase().startsWith(nickChangeCommand.toLowerCase())) {
547                  String nickChangeCmd = nickChangeCommand;
548                  String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
549                  int endOfNick = newNick.indexOf(" ");
# Line 414 | Line 552 | public class IRC__Alerter extends AlerterSkeleton {
552                  }
553                  newNick = newNick.substring(0, endOfNick);
554                  changeNick(newNick);
417                // should we check this worked?
418                //_nickname = newNick;
419                return null; // ???
555              }
556 <            else if(message.indexOf(versionCommand)!=-1) {
557 <                return "I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot";
556 >            else if(message.equalsIgnoreCase(versionCommand)) {
557 >                sendMessage(source, "I am version " + getRevision() + " of the i-scream alerting bot");
558              }
559 <            else if(message.indexOf(helpCommand)!=-1) {
560 <                return "this will return some help text soon";
561 <                /*
562 <                sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
563 <                sendPrivMsg(getMsgSender(line), "I understand the following commands;");
564 <                sendPrivMsg(getMsgSender(line), stopCommand);
565 <                sendPrivMsg(getMsgSender(line), startCommand);
566 <                sendPrivMsg(getMsgSender(line), lastAlertCommand);
567 <                sendPrivMsg(getMsgSender(line), joinCommand);
568 <                sendPrivMsg(getMsgSender(line), nickChangeCommand);
569 <                sendPrivMsg(getMsgSender(line), statCommand);
570 <                sendPrivMsg(getMsgSender(line), uptimeCommand);
436 <                sendPrivMsg(getMsgSender(line), timeSinceLastAlertCommand);
437 <                sendPrivMsg(getMsgSender(line), helpCommand);
438 <                */
559 >            else if(message.equalsIgnoreCase(helpCommand)) {
560 >                sendMessage(source, "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
561 >                sendMessage(source, "I understand the following commands;");
562 >                sendMessage(source, stopCommand);
563 >                sendMessage(source, startCommand);
564 >                sendMessage(source, lastAlertCommand);
565 >                sendMessage(source, joinCommand);
566 >                sendMessage(source, nickChangeCommand);
567 >                sendMessage(source, statCommand);
568 >                sendMessage(source, uptimeCommand);
569 >                sendMessage(source, timeSinceLastAlertCommand);
570 >                sendMessage(source, helpCommand);
571              }
572 <            else if(message.indexOf(statCommand)!=-1) {
573 <                return "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!";
572 >            else if(message.equalsIgnoreCase(statCommand)) {
573 >                sendMessage(source, "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!");
574              }
575 <            else if(message.indexOf(uptimeCommand)!=-1) {
575 >            else if(message.equalsIgnoreCase(uptimeCommand)) {
576                  long uptime = (System.currentTimeMillis() - _startTime) / 1000;
577                  String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
578 <                return "I have been running for "+uptimeText;
578 >                sendMessage(source, "I have been running for "+uptimeText);
579              }
580 <            else if(message.indexOf("ping")!=-1) {
581 <                return "pong";
580 >            else if(message.equalsIgnoreCase("ping")) {
581 >                sendMessage(source, "pong");
582              }
583 <            else if(message.indexOf("do a jibble dance")!=-1) {
583 >            else if(message.equalsIgnoreCase("do a jibble dance")) {
584                  // little joke :)
585 <                return "jives to the funky beat shouting \"ii--screeeaaammm\"";
585 >                sendAction(source, "jives to the funky beat shouting \"ii--screeeaaammm\"");
586              }
455            
587              else {
588                  String rejectMessage = NOT_CONFIGURED;
589                  try {
# Line 460 | Line 591 | public class IRC__Alerter extends AlerterSkeleton {
591                  } catch(PropertyNotFoundException e) {
592                      _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
593                  }
594 <                return rejectMessage;
594 >                sendMessage(source, rejectMessage);
595              }
596          }
597          
598 <        private boolean isForMe(String message) {
599 <            // change this!
598 >        /**
599 >         * Quick method to check if the message appears
600 >         * to be directed at us. We simply check to see
601 >         * if it starts with our nick in some fashion.
602 >         * This will return null if the message is not
603 >         * for us - thus allowing this method to perform
604 >         * two tasks at once.
605 >         *
606 >         * @param message the message to check
607 >         * @return the message (with our nick removed), or null if it's not for us.
608 >         */
609 >        private String isForMe(String message) {
610 >            // change to lower case to remove
611 >            // case ambiguities
612              String nick = _nickname.toLowerCase();
613              String msg = message.toLowerCase();
614              if(msg.startsWith(nick + ", ") ||
615                 msg.startsWith(nick + ": ") ||
616                 msg.startsWith(nick + " ")) {
617 <                return true;
617 >                // NOTE that the 1 here is hardcoded to be the length
618 >                // of the above 'extra' character (eg , or :)
619 >                return message.substring(nick.length()+1).trim();
620              }
621              else {
622 <                return false;
622 >                return null;
623              }
624          }
625          
626 +        /**
627 +         * Sleep for a configurable amount of time and
628 +         * then return. This is used when reconnecting
629 +         * to the server or a channel.
630 +         */
631          private void reconnectSleep() {
632              int delayTime = 0;
633              try {
# Line 493 | Line 643 | public class IRC__Alerter extends AlerterSkeleton {
643              try {
644                  Thread.sleep(delayTime * 1000);
645              } catch (InterruptedException e) {}
646 +        }
647 +        
648 +        /**
649 +         * Returns the revision of the bot.
650 +         *
651 +         * @return the revision of this bot
652 +         */
653 +        private String getRevision() {
654 +            return REVISION.substring(11, REVISION.length()-2);
655          }
656          
657          /**

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines