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.30.2.5 by tdb, Tue Feb 5 22:39:29 2002 UTC

# Line 43 | Line 43 | public class IRC__Alerter extends AlerterSkeleton {
43          super();
44          // construct and initialise the bot
45          _ircbot = new IRCBot();
46 <        //_ircbot.setVerbose(true);
46 >        _ircbot.setVerbose(false);
47          Thread ircThread = new Thread(_ircbot);
48          // set it's name and start it
49          ircThread.setName("client.IRC__Alerter$IRCBot");
# Line 77 | Line 77 | public class IRC__Alerter extends AlerterSkeleton {
77          if(_active) {          
78              // send the message
79              _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
80 <            _ircbot.sendMsg(message);
80 >            _ircbot.sendMessage(message);
81              // count sent alerts
82              _alertCount++;
83          } else {
# Line 195 | Line 195 | public class IRC__Alerter extends AlerterSkeleton {
195           */
196          public final int DEFAULT_RECONNECT_DELAY = 30;
197          
198 +        /**
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          public void run() {
206              while(true) {
207                  try {
# Line 203 | Line 210 | public class IRC__Alerter extends AlerterSkeleton {
210                  }
211                  catch (IOException e) {
212                      _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
213 +                    // wait for a while, defined in the config
214                      reconnectSleep();
215                  }
216              }
209            //System.out.println("falling out!");
217          }
218          
219 <        public void init() throws IOException {
219 >        /**
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 >        private void init() throws IOException {
228              _logger.write(this.toString(), Logger.DEBUG, "Initialising IRCBot...");
229 +            
230 +            // get a hook on the configuration system
231              ConfigurationProxy cp = ConfigurationProxy.getInstance();
232 +            
233 +            // get hold of the server details
234              String server;
235              int port;
236              try {
# Line 224 | Line 243 | public class IRC__Alerter extends AlerterSkeleton {
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 <            String user, comment;
246 >            
247 >            // get hold of the user details and nickname list
248 >            String user, nickList;
249              try {
250                  user = cp.getProperty(_name, "Alerter.IRC.user");
251 <                comment = cp.getProperty(_name, "Alerter.IRC.comment");
251 >                nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
252              } catch (PropertyNotFoundException e) {
253                  _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
254 <                throw new IOException("Can't get user details due to configuration error");
254 >                throw new IOException("Can't get user/nickname details due to configuration error");
255              }
256 <            this.setLogin(user);
257 <            this.setVersion(comment);
258 <            this.setFinger(comment); // ?
259 <            String nickList;
256 >            
257 >            // 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 <                nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
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.ERROR, "Configuration error: "+e);
243 <                throw new IOException("Can't get nickname due to configuration error");
265 >                _logger.write(this.toString(), Logger.WARNING, "Configuration warning, using default: "+e);
266              }
267 +            
268 +            // put these details into the bot
269 +            this.setLogin(user);
270 +            this.setVersion("[" + getRevision() + "] " + comment);
271 +            this.setFinger(finger);
272 +            
273 +            // attempt to connect, trying each nickname
274 +            // in turn until sucessfully connected
275              StringTokenizer st = new StringTokenizer(nickList, ";");
276              boolean ok = false;
277              while(!ok && st.hasMoreTokens()) {
278                  String nick = st.nextToken();
279                  try {
280 +                    // try to connect with a nickname
281                      _logger.write(this.toString(), Logger.DEBUG, "Trying nick: "+nick);
282                      this.setName(nick);
283                      this.connect(server, port);
284 <                    // must be ok if we get here
284 >                    // at this point we know the nickname was accepted
285                      _nickname = nick;
286                      ok = true;
287                  }
# Line 264 | Line 295 | public class IRC__Alerter extends AlerterSkeleton {
295                  }
296                  catch(NickAlreadyInUseException e) {
297                      _logger.write(this.toString(), Logger.ERROR, "Nickname "+nick+" is already in use: "+e);
298 <                    // just carry on around while loop
298 >                    // don't do anything, instead just loop round
299 >                    // and try the next nickname in the list
300                  }
301              }
302              if(!ok) {
303 <                // oh dear, we couldn't get on.
303 >                // must have tried all the nicknames, best bail out
304                  _logger.write(this.toString(), Logger.ERROR, "All nicknames already in use");
305                  throw new IOException("All nicknames already in use");
306              }
307 +            
308 +            // get hold of the channel details, and attempt
309 +            // to join the specified channel
310              try {
311                  _channel = cp.getProperty(_name, "Alerter.IRC.channel");
312                  this.joinChannel(_channel);
# Line 280 | Line 315 | public class IRC__Alerter extends AlerterSkeleton {
315                  throw new IOException("Can't get channel name due to configuration error");
316              }
317              
318 +            // get hold of the startup notice, and send
319 +            // it if it's defined
320              String startupNotice;
321              try {
322                  startupNotice = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice");
# Line 288 | Line 325 | public class IRC__Alerter extends AlerterSkeleton {
325                  _logger.write(this.toString(), Logger.DEBUG, "Startup notice not defined, so not sending: "+e);
326              }
327              
328 <            // we should set this when all is ready!
328 >            // at this point initialisation is complete, so
329 >            // we can return and set this flag to allow alerts
330              _active = true;
293            //System.out.println("leaving init");
331          }
332          
333 <        public void sendMsg(String msg) {
334 <            sendMessage(_channel, msg);
333 >        /**
334 >         * Send a message to the current channel.
335 >         *
336 >         * @param message The message to send
337 >         */
338 >        private void sendMessage(String message) {
339 >            sendMessage(_channel, message);
340          }
341          
342 +        /**
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          public void onDisconnect() {
349 +            // stop alerts being sent for now
350              _active = false;
351              while(true) {
352 +                // wait for a while, defined in the config
353                  reconnectSleep();
354                  try {
355                      init();
# Line 309 | Line 359 | public class IRC__Alerter extends AlerterSkeleton {
359                      _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
360                  }
361              }
312            //System.out.println("falling out of disconnect!");
362          }
363          
364 +        /**
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          public void onMessage(String channel, String sender, String login, String hostname, String message) {
376 <            if(isForMe(message)) {
377 <                String response = handleInput(message);
378 <                if(response != null) {
379 <                    sendMessage(channel, response);
320 <                }
376 >            String trimmedMessage = isForMe(message);
377 >            // if trimmedMessage is null, it's not for us
378 >            if(trimmedMessage != null) {
379 >                handleInput(trimmedMessage, channel);
380              }
381          }
382          
383 +        /**
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          public void onPrivateMessage(String sender, String login, String hostname, String message) {
394 <            String response = handleInput(message);
326 <            if(response != null) {
327 <                sendMessage(sender, response);
328 <            }
394 >            handleInput(message, sender);
395          }
396          
397 +        /**
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          public void onNickChange(String oldNick, String login, String hostname, String newNick) {
411              if(oldNick.equals(_nickname)) {
412                  _nickname = newNick;
413              }
414          }
415          
416 <        private String handleInput(String message) {
417 <            //return "yup, gotcha!";
416 >        /**
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 >        public void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
430 >            if(recipientNick.equals(_nickname) && channel.equals(_channel)) {
431 >                // remind the person it's not very nice :)
432 >                sendMessage(kickerNick, "That wasn't a nice thing to do...");
433 >                // get hold of the channel details, in case they've changed
434 >                try {
435 >                    _channel = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.channel");
436 >                } catch(PropertyNotFoundException e) {
437 >                    _logger.write(this.toString(), Logger.ERROR, "Can't get channel name due to configuration error: "+e);
438 >                }
439 >                // 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 >                joinChannel(_channel);
444 >            }
445 >        }
446 >        
447 >        /**
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 >        private void handleInput(String message, String source) {
458 >            // get hold of the configuration system
459              ConfigurationProxy cp = ConfigurationProxy.getInstance();
460              // setup some String's
461              String stopCommand, startCommand, timeSinceLastAlertCommand, lastAlertCommand, joinCommand;
462              String nickChangeCommand, versionCommand, helpCommand, statCommand, uptimeCommand;
463 <            // get the command set
463 >            // get the command set from the configuration
464              try {
465                  stopCommand = cp.getProperty(_name, "Alerter.IRC.stopCommand");
466                  startCommand = cp.getProperty(_name, "Alerter.IRC.startCommand");
# Line 356 | Line 476 | public class IRC__Alerter extends AlerterSkeleton {
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 <                return null;
479 >                return;
480              }
481              
482 <            if(message.indexOf(stopCommand)!=-1) {
482 >            // see if the message matches (loosely!) any
483 >            // of our known commands
484 >            if(message.equalsIgnoreCase(stopCommand)) {
485                  _active = false;
486 <                return "alerts have been stopped";
486 >                sendMessage(source, "alerts have been stopped");
487              }
488 <            else if(message.indexOf(startCommand)!=-1) {
488 >            else if(message.equalsIgnoreCase(startCommand)) {
489                  _active = true;
490 <                return "alerts have been activated";
490 >                sendMessage(source, "alerts have been activated");
491              }
492 <            // this needs to go here if it contains the same words as the lastAlertCommand
493 <            else if(message.indexOf(timeSinceLastAlertCommand)!=-1) {
492 >            // this needs to go before lastAlertCommand if it contains
493 >            // the same words as the lastAlertCommand.
494 >            else if(message.equalsIgnoreCase(timeSinceLastAlertCommand)) {
495                  if(_lastAlertTime != -1) {
496                      long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
497                      String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
498 <                    return "I last sent an alert "+uptimeText+ " ago";
498 >                    sendMessage(source, "I last sent an alert "+uptimeText+ " ago");
499                  }
500                  else {
501 <                    return "I've never sent an alert!";
501 >                    sendMessage(source, "I've never sent an alert!");
502                  }
503              }
504 <            else if(message.indexOf(lastAlertCommand)!=-1) {
504 >            else if(message.equalsIgnoreCase(lastAlertCommand)) {
505                  if(_lastAlertTime != -1) {
506                      String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
507 <                    return "last alert was at "+date+"; "+_lastAlert;
507 >                    sendMessage(source, "last alert was at "+date+"; "+_lastAlert);
508                  }
509                  else {
510 <                    return "I've never sent an alert!";
510 >                    sendMessage(source, "I've never sent an alert!");
511                  }
512                  
513              }
514 <            else if(message.indexOf(joinCommand)!=-1) {
514 >            else if(message.equalsIgnoreCase(joinCommand)) {
515                  String joinCmd = joinCommand;
516                  String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
517                  int endOfChan = newChan.indexOf(" ");
# Line 397 | Line 520 | public class IRC__Alerter extends AlerterSkeleton {
520                  }
521                  newChan = newChan.substring(0, endOfChan);
522                  if(newChan.equals(_channel)) {
523 <                    return "I'm already on "+newChan+"!";
523 >                    sendMessage(source, "I'm already on "+newChan+"!");
524                  } else {
525                      partChannel(_channel);
526                      joinChannel(newChan);
527                      _channel = newChan;
405                    return null; // ???
528                  }
529              }
530 <            else if(message.indexOf(nickChangeCommand)!=-1) {
530 >            else if(message.equalsIgnoreCase(nickChangeCommand)) {
531                  String nickChangeCmd = nickChangeCommand;
532                  String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
533                  int endOfNick = newNick.indexOf(" ");
# Line 414 | Line 536 | public class IRC__Alerter extends AlerterSkeleton {
536                  }
537                  newNick = newNick.substring(0, endOfNick);
538                  changeNick(newNick);
417                // should we check this worked?
418                //_nickname = newNick;
419                return null; // ???
539              }
540 <            else if(message.indexOf(versionCommand)!=-1) {
541 <                return "I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot";
540 >            else if(message.equalsIgnoreCase(versionCommand)) {
541 >                sendMessage(source, "I am version " + getRevision() + " of the i-scream alerting bot");
542              }
543 <            else if(message.indexOf(helpCommand)!=-1) {
544 <                return "this will return some help text soon";
545 <                /*
546 <                sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
547 <                sendPrivMsg(getMsgSender(line), "I understand the following commands;");
548 <                sendPrivMsg(getMsgSender(line), stopCommand);
549 <                sendPrivMsg(getMsgSender(line), startCommand);
550 <                sendPrivMsg(getMsgSender(line), lastAlertCommand);
551 <                sendPrivMsg(getMsgSender(line), joinCommand);
552 <                sendPrivMsg(getMsgSender(line), nickChangeCommand);
553 <                sendPrivMsg(getMsgSender(line), statCommand);
554 <                sendPrivMsg(getMsgSender(line), uptimeCommand);
436 <                sendPrivMsg(getMsgSender(line), timeSinceLastAlertCommand);
437 <                sendPrivMsg(getMsgSender(line), helpCommand);
438 <                */
543 >            else if(message.equalsIgnoreCase(helpCommand)) {
544 >                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              }
556 <            else if(message.indexOf(statCommand)!=-1) {
557 <                return "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!";
556 >            else if(message.equalsIgnoreCase(statCommand)) {
557 >                sendMessage(source, "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!");
558              }
559 <            else if(message.indexOf(uptimeCommand)!=-1) {
559 >            else if(message.equalsIgnoreCase(uptimeCommand)) {
560                  long uptime = (System.currentTimeMillis() - _startTime) / 1000;
561                  String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
562 <                return "I have been running for "+uptimeText;
562 >                sendMessage(source, "I have been running for "+uptimeText);
563              }
564 <            else if(message.indexOf("ping")!=-1) {
565 <                return "pong";
564 >            else if(message.equalsIgnoreCase("ping")) {
565 >                sendMessage(source, "pong");
566              }
567 <            else if(message.indexOf("do a jibble dance")!=-1) {
567 >            else if(message.equalsIgnoreCase("do a jibble dance")) {
568                  // little joke :)
569 <                return "jives to the funky beat shouting \"ii--screeeaaammm\"";
569 >                sendAction(source, "jives to the funky beat shouting \"ii--screeeaaammm\"");
570              }
455            
571              else {
572                  String rejectMessage = NOT_CONFIGURED;
573                  try {
# Line 460 | Line 575 | public class IRC__Alerter extends AlerterSkeleton {
575                  } catch(PropertyNotFoundException e) {
576                      _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
577                  }
578 <                return rejectMessage;
578 >                sendMessage(source, rejectMessage);
579              }
580          }
581          
582 <        private boolean isForMe(String message) {
583 <            // change this!
582 >        /**
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 >         * This will return null if the message is not
587 >         * for us - thus allowing this method to perform
588 >         * two tasks at once.
589 >         *
590 >         * @param message the message to check
591 >         * @return the message (with our nick removed), or null if it's not for us.
592 >         */
593 >        private String isForMe(String message) {
594 >            // change to lower case to remove
595 >            // case ambiguities
596              String nick = _nickname.toLowerCase();
597              String msg = message.toLowerCase();
598              if(msg.startsWith(nick + ", ") ||
599                 msg.startsWith(nick + ": ") ||
600                 msg.startsWith(nick + " ")) {
601 <                return true;
601 >                // 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              }
605              else {
606 <                return false;
606 >                return null;
607              }
608          }
609          
610 +        /**
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          private void reconnectSleep() {
616              int delayTime = 0;
617              try {
# Line 493 | Line 627 | public class IRC__Alerter extends AlerterSkeleton {
627              try {
628                  Thread.sleep(delayTime * 1000);
629              } catch (InterruptedException e) {}
630 +        }
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          }
640          
641          /**

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines