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.2
Committed: Mon Feb 4 23:14:38 2002 UTC (22 years, 3 months ago) by tdb
Branch: SERVER_PIRCBOT
Changes since 1.30.2.1: +61 -54 lines
Log Message:
Some tweaks and additions. Should now have the functionality that the old
version had. Still some bugs to iron out relating to pircbot though. Also
need to tidy up and javadoc.

File Contents

# Content
1 //---PACKAGE DECLARATION---
2 package uk.org.iscream.cms.server.client.alerters;
3
4 //---IMPORTS---
5 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 import java.io.*;
10 import java.net.*;
11 import java.util.*;
12 import java.text.DateFormat;
13 import org.jibble.pircbot.*;
14
15 /**
16 * This Alert sends an IRC message.
17 *
18 * Clean shutdown could be achieved by stopping the run() method in the
19 * IRCBot inner class.
20 *
21 * @author $Author: tdb $
22 * @version $Id: IRC__Alerter.java,v 1.30.2.1 2002/02/04 00:14:13 tdb Exp $
23 */
24 public class IRC__Alerter extends AlerterSkeleton {
25
26 //---FINAL ATTRIBUTES---
27
28 /**
29 * The current CVS revision of this class
30 */
31 public final String REVISION = "$Revision: 1.30.2.1 $";
32
33 /**
34 * A description of this alerter
35 */
36 public final String DESC = "Sends alerts on an IRC channel";
37
38 //---STATIC METHODS---
39
40 //---CONSTRUCTORS---
41
42 public IRC__Alerter() {
43 super();
44 // construct and initialise the bot
45 _ircbot = new IRCBot();
46 //_ircbot.setVerbose(true);
47 Thread ircThread = new Thread(_ircbot);
48 // set it's name and start it
49 ircThread.setName("client.IRC__Alerter$IRCBot");
50 ircThread.start();
51 // log our start time
52 _startTime = System.currentTimeMillis();
53 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
54 }
55
56 //---PUBLIC METHODS---
57
58 /**
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 public void sendAlert(Alert alert) {
66 // 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 // only send alerts if we're active
77 if(_active) {
78 // send the message
79 _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
80 _ircbot.sendMsg(message);
81 // count sent alerts
82 _alertCount++;
83 } else {
84 // don't send, but keep a count that we ignored it
85 _ignoredCount++;
86 }
87 // 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 }
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 * This uses the uk.org.iscream.cms.server.util.NameFormat class
98 * 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 /**
110 * Return the String representation of what the alerter does
111 *
112 * @return the description
113 */
114 public String getDescription(){
115 return DESC;
116 }
117
118 //---PRIVATE METHODS---
119
120 //---ACCESSOR/MUTATOR METHODS---
121
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
133 //---ATTRIBUTES---
134
135 /**
136 * A reference to the IRCBot
137 */
138 private IRCBot _ircbot;
139
140 /**
141 * 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 * The time of the last alert
152 */
153 private long _lastAlertTime = -1;
154
155 /**
156 * Number of alerts sent
157 */
158 private int _alertCount = 0;
159
160 /**
161 * Number of alerts ignored when in "stopped" mode
162 */
163 private int _ignoredCount = 0;
164
165 /**
166 * Time of IRCBot startup
167 */
168 private long _startTime;
169
170 /**
171 * This holds a reference to the
172 * system logger that is being used.
173 */
174 protected Logger _logger = ReferenceManager.getInstance().getLogger();
175
176 /**
177 * 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 private String _name = "IRC";
186
187 //---STATIC ATTRIBUTES---
188
189 //---INNER CLASSES---
190
191 class IRCBot extends PircBot implements Runnable {
192
193 /**
194 * The default reconnect delay in seconds
195 */
196 public final int DEFAULT_RECONNECT_DELAY = 30;
197
198 public void run() {
199 while(true) {
200 try {
201 init();
202 break;
203 }
204 catch (IOException e) {
205 _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
206 reconnectSleep();
207 }
208 }
209 //System.out.println("falling out!");
210 }
211
212 public void init() throws IOException {
213 _logger.write(this.toString(), Logger.DEBUG, "Initialising IRCBot...");
214 ConfigurationProxy cp = ConfigurationProxy.getInstance();
215 String server;
216 int port;
217 try {
218 server = cp.getProperty(_name, "Alerter.IRC.IRCServer");
219 port = Integer.parseInt(cp.getProperty(_name, "Alerter.IRC.IRCPort"));
220 } catch (PropertyNotFoundException e) {
221 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
222 throw new IOException("Can't get irc server details due to configuration error");
223 } catch (NumberFormatException e) {
224 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
225 throw new IOException("Can't get irc server details due to malformed configuration");
226 }
227 String user, comment;
228 try {
229 user = cp.getProperty(_name, "Alerter.IRC.user");
230 comment = cp.getProperty(_name, "Alerter.IRC.comment");
231 } catch (PropertyNotFoundException e) {
232 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
233 throw new IOException("Can't get user details due to configuration error");
234 }
235 this.setLogin(user);
236 this.setVersion(comment);
237 this.setFinger(comment); // ?
238 String nickList;
239 try {
240 nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
241 } catch (PropertyNotFoundException e) {
242 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
243 throw new IOException("Can't get nickname due to configuration error");
244 }
245 StringTokenizer st = new StringTokenizer(nickList, ";");
246 boolean ok = false;
247 while(!ok && st.hasMoreTokens()) {
248 String nick = st.nextToken();
249 try {
250 _logger.write(this.toString(), Logger.DEBUG, "Trying nick: "+nick);
251 this.setName(nick);
252 this.connect(server, port);
253 // must be ok if we get here
254 _nickname = nick;
255 ok = true;
256 }
257 catch(IOException e) {
258 _logger.write(this.toString(), Logger.ERROR, "IO error when connecting to server: "+e);
259 throw new IOException("IO error when connecting to server");
260 }
261 catch(IrcException e) {
262 _logger.write(this.toString(), Logger.ERROR, "IRC error when connecting to server: "+e);
263 throw new IOException("IRC error when connecting to server");
264 }
265 catch(NickAlreadyInUseException e) {
266 _logger.write(this.toString(), Logger.ERROR, "Nickname "+nick+" is already in use: "+e);
267 // just carry on around while loop
268 }
269 }
270 if(!ok) {
271 // oh dear, we couldn't get on.
272 _logger.write(this.toString(), Logger.ERROR, "All nicknames already in use");
273 throw new IOException("All nicknames already in use");
274 }
275 try {
276 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
277 this.joinChannel(_channel);
278 } catch (PropertyNotFoundException e) {
279 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
280 throw new IOException("Can't get channel name due to configuration error");
281 }
282
283 String startupNotice;
284 try {
285 startupNotice = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice");
286 sendNotice(_channel, startupNotice);
287 } catch (PropertyNotFoundException e) {
288 _logger.write(this.toString(), Logger.DEBUG, "Startup notice not defined, so not sending: "+e);
289 }
290
291 // we should set this when all is ready!
292 _active = true;
293 //System.out.println("leaving init");
294 }
295
296 public void sendMsg(String msg) {
297 sendMessage(_channel, msg);
298 }
299
300 public void onDisconnect() {
301 _active = false;
302 while(true) {
303 reconnectSleep();
304 try {
305 init();
306 break;
307 }
308 catch (IOException e) {
309 _logger.write(this.toString(), Logger.ERROR, "Error initialising IRCBot: "+e);
310 }
311 }
312 //System.out.println("falling out of disconnect!");
313 }
314
315 public void onMessage(String channel, String sender, String login, String hostname, String message) {
316 if(isForMe(message)) {
317 handleInput(message, channel);
318 }
319 }
320
321 public void onPrivateMessage(String sender, String login, String hostname, String message) {
322 handleInput(message, sender);
323 }
324
325 public void onNickChange(String oldNick, String login, String hostname, String newNick) {
326 if(oldNick.equals(_nickname)) {
327 _nickname = newNick;
328 }
329 }
330
331 public void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
332 if(recipientNick.equals(_nickname) && channel.equals(_channel)) {
333 sendMessage(kickerNick, "That wasn't a nice thing to do...");
334 try {
335 _channel = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.channel");
336 } catch(PropertyNotFoundException e) {
337 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
338 }
339 // should this be in the try?
340 joinChannel(_channel);
341 }
342 }
343
344 private void handleInput(String message, String source) {
345 System.out.println("message: "+message);
346 System.out.println("from: "+source);
347 ConfigurationProxy cp = ConfigurationProxy.getInstance();
348 // setup some String's
349 String stopCommand, startCommand, timeSinceLastAlertCommand, lastAlertCommand, joinCommand;
350 String nickChangeCommand, versionCommand, helpCommand, statCommand, uptimeCommand;
351 // get the command set
352 try {
353 stopCommand = cp.getProperty(_name, "Alerter.IRC.stopCommand");
354 startCommand = cp.getProperty(_name, "Alerter.IRC.startCommand");
355 timeSinceLastAlertCommand = cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand");
356 lastAlertCommand = cp.getProperty(_name, "Alerter.IRC.lastAlertCommand");
357 joinCommand = cp.getProperty(_name, "Alerter.IRC.joinCommand");
358 nickChangeCommand = cp.getProperty(_name, "Alerter.IRC.nickChangeCommand");
359 versionCommand = cp.getProperty(_name, "Alerter.IRC.versionCommand");
360 helpCommand = cp.getProperty(_name, "Alerter.IRC.helpCommand");
361 statCommand = cp.getProperty(_name, "Alerter.IRC.statCommand");
362 uptimeCommand = cp.getProperty(_name, "Alerter.IRC.uptimeCommand");
363 } catch (PropertyNotFoundException e) {
364 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
365 // lets bail from handling this line...
366 // ...it's gonna be hard without a command set!
367 return;
368 }
369
370 if(message.indexOf(stopCommand) != -1) {
371 _active = false;
372 sendMessage(source, "alerts have been stopped");
373 }
374 else if(message.indexOf(startCommand) != -1) {
375 _active = true;
376 sendMessage(source, "alerts have been activated");
377 }
378 // this needs to go here if it contains the same words as the lastAlertCommand
379 else if(message.indexOf(timeSinceLastAlertCommand) != -1) {
380 if(_lastAlertTime != -1) {
381 long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
382 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
383 sendMessage(source, "I last sent an alert "+uptimeText+ " ago");
384 }
385 else {
386 sendMessage(source, "I've never sent an alert!");
387 }
388 }
389 else if(message.indexOf(lastAlertCommand) != -1) {
390 if(_lastAlertTime != -1) {
391 String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
392 sendMessage(source, "last alert was at "+date+"; "+_lastAlert);
393 }
394 else {
395 sendMessage(source, "I've never sent an alert!");
396 }
397
398 }
399 else if(message.indexOf(joinCommand) != -1) {
400 String joinCmd = joinCommand;
401 String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
402 int endOfChan = newChan.indexOf(" ");
403 if(endOfChan == -1) {
404 endOfChan = newChan.length();
405 }
406 newChan = newChan.substring(0, endOfChan);
407 if(newChan.equals(_channel)) {
408 sendMessage(source, "I'm already on "+newChan+"!");
409 } else {
410 partChannel(_channel);
411 joinChannel(newChan);
412 _channel = newChan;
413 //return null; // ???
414 }
415 }
416 else if(message.indexOf(nickChangeCommand) != -1) {
417 String nickChangeCmd = nickChangeCommand;
418 String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
419 int endOfNick = newNick.indexOf(" ");
420 if(endOfNick == -1) {
421 endOfNick = newNick.length();
422 }
423 newNick = newNick.substring(0, endOfNick);
424 changeNick(newNick);
425 // should we check this worked?
426 //_nickname = newNick;
427 //return null; // ???
428 }
429 else if(message.indexOf(versionCommand) != -1) {
430 sendMessage(source, "I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot");
431 }
432 else if(message.indexOf(helpCommand) != -1) {
433 //System.out.println("--starting help");
434 sendMessage(source, "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
435 sendMessage(source, "I understand the following commands;");
436 sendMessage(source, stopCommand);
437 sendMessage(source, startCommand);
438 sendMessage(source, lastAlertCommand);
439 sendMessage(source, joinCommand);
440 sendMessage(source, nickChangeCommand);
441 sendMessage(source, statCommand);
442 sendMessage(source, uptimeCommand);
443 sendMessage(source, timeSinceLastAlertCommand);
444 sendMessage(source, helpCommand);
445 //System.out.println("--ending help");
446 }
447 else if(message.indexOf(statCommand) != -1) {
448 sendMessage(source, "I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!");
449 }
450 else if(message.indexOf(uptimeCommand) != -1) {
451 long uptime = (System.currentTimeMillis() - _startTime) / 1000;
452 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
453 sendMessage(source, "I have been running for "+uptimeText);
454 }
455 else if(message.indexOf("ping") != -1) {
456 sendMessage(source, "pong");
457 }
458 else if(message.indexOf("do a jibble dance") != -1) {
459 // little joke :)
460 sendAction(source, "jives to the funky beat shouting \"ii--screeeaaammm\"");
461 }
462
463 else {
464 String rejectMessage = NOT_CONFIGURED;
465 try {
466 rejectMessage = cp.getProperty(_name, "Alerter.IRC.rejectMessage");
467 } catch(PropertyNotFoundException e) {
468 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
469 }
470 sendMessage(source, rejectMessage);
471 }
472 }
473
474 private boolean isForMe(String message) {
475 // change this!
476 String nick = _nickname.toLowerCase();
477 String msg = message.toLowerCase();
478 if(msg.startsWith(nick + ", ") ||
479 msg.startsWith(nick + ": ") ||
480 msg.startsWith(nick + " ")) {
481 return true;
482 }
483 else {
484 return false;
485 }
486 }
487
488 private void reconnectSleep() {
489 int delayTime = 0;
490 try {
491 delayTime = Integer.parseInt(ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.reconnectDelay"));
492 } catch (NumberFormatException e) {
493 delayTime = DEFAULT_RECONNECT_DELAY;
494 _logger.write(this.toString(), Logger.WARNING, "Erronous Alerter.IRC.reconnectDelay value in configuration using default of " + delayTime + " seconds");
495 } catch (PropertyNotFoundException e) {
496 delayTime = DEFAULT_RECONNECT_DELAY;
497 _logger.write(this.toString(), Logger.WARNING, "Alerter.IRC.reconnectDelay value unavailable using default of " + delayTime + " seconds");
498 }
499 _logger.write(this.toString(), Logger.ERROR, "Waiting "+delayTime+" seconds for reconnect...");
500 try {
501 Thread.sleep(delayTime * 1000);
502 } catch (InterruptedException e) {}
503 }
504
505 /**
506 * Overrides the {@link java.lang.Object#toString() Object.toString()}
507 * method to provide clean logging (every class should have this).
508 *
509 * This uses the uk.org.iscream.cms.server.util.NameFormat class
510 * to format the toString()
511 *
512 * @return the name of this class and its CVS revision
513 */
514 public String toString() {
515 return FormatName.getName(
516 _name,
517 getClass().getName(),
518 REVISION);
519 }
520
521 /**
522 * Just a reminder to what channel we're on...
523 * this can't be dynamic :)
524 */
525 private String _channel;
526
527 /**
528 * A reminder of our current nickname...
529 */
530 private String _nickname;
531
532 }
533
534 }