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.15
Committed: Mon Mar 5 12:45:51 2001 UTC (23 years, 2 months ago) by ajm
Branch: MAIN
Changes since 1.14: +4 -4 lines
Log Message:
Now shows OK alerts if the previous alert exceeded the alerters level

File Contents

# Content
1 //---PACKAGE DECLARATION---
2 package uk.ac.ukc.iscream.client.alerters;
3
4 //---IMPORTS---
5 import uk.ac.ukc.iscream.client.*;
6 import uk.ac.ukc.iscream.core.*;
7 import uk.ac.ukc.iscream.util.*;
8 import uk.ac.ukc.iscream.componentmanager.*;
9
10 import java.io.*;
11 import java.net.*;
12 import java.util.*;
13 import java.text.*;
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: ajm4 $
22 * @version $Id: IRC__Alerter.java,v 1.14 2001/03/05 12:09:28 ajm4 Exp $
23 */
24 public class IRC__Alerter implements PluginAlerter {
25
26 //---FINAL ATTRIBUTES---
27
28 /**
29 * The current CVS revision of this class
30 */
31 public final String REVISION = "$Revision: 1.14 $";
32
33 /**
34 * A description of this alerter
35 */
36 public final String DESC = "Sends alerts on an IRC channel";
37
38 /**
39 * The default reconnect delay in seconds
40 */
41 public final int DEFAULT_RECONNECT_DELAY = 30;
42
43 //---STATIC METHODS---
44
45 //---CONSTRUCTORS---
46
47 public IRC__Alerter() {
48
49 // connect to the IRC server
50 _ircbot = new IRCBot();
51 _ircbot.start();
52 _startTime = System.currentTimeMillis();
53
54 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
55 }
56
57 //---PUBLIC METHODS---
58
59 public void sendAlert(Alert alert) {
60 // only send alerts if we're active
61 if(_active) {
62 ConfigurationProxy cp = ConfigurationProxy.getInstance();
63 String levelName = cp.getProperty(_name, "Alerter.IRC.level");
64 int level = StringUtils.getStringPos(levelName, Alert.alertLevels);
65 // only send if it's equal (or above) our level
66 if(((alert.getLevel() == 0) && (alert.getLastLevel() >= level)) || (alert.getLevel() >= level)) {
67 String alertType = Alert.alertLevels[alert.getLevel()];
68 String thresholdType = Alert.thresholdLevels[alert.getThreshold()];
69 // sort out the message
70 String message = cp.getProperty(_name, "Alerter.IRC.message");
71 message = StringUtils.replaceText(message, "%level%", alertType);
72 message = StringUtils.replaceText(message, "%threshold%", thresholdType);
73 message = StringUtils.replaceText(message, "%source%", alert.getSource());
74 message = StringUtils.replaceText(message, "%value%", alert.getValue());
75 message = StringUtils.replaceText(message, "%thresholdValue%", alert.getThresholdValue());
76 message = StringUtils.replaceText(message, "%attributeName%", alert.getAttributeName());
77 message = StringUtils.replaceText(message, "%timeTillNextAlert%", getTimeString(Long.parseLong(alert.getTimeTillNextAlert())));
78
79 // send the message
80 _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
81 _ircbot.sendMsg(message);
82 _lastAlert = message;
83 _lastAlertTime = System.currentTimeMillis();
84 _alertCount ++;
85 }
86 }
87 }
88
89 /**
90 * Overrides the {@link java.lang.Object#toString() Object.toString()}
91 * method to provide clean logging (every class should have this).
92 *
93 * This uses the uk.ac.ukc.iscream.util.NameFormat class
94 * to format the toString()
95 *
96 * @return the name of this class and its CVS revision
97 */
98 public String toString() {
99 return FormatName.getName(
100 _name,
101 getClass().getName(),
102 REVISION);
103 }
104
105 /**
106 * return the String representation of what the filter does
107 */
108 public String getDescription(){
109 return DESC;
110 }
111
112 //---PRIVATE METHODS---
113
114 private String getTimeString(long time) {
115 String timeString = null;
116 if (time >= 60) {
117 timeString = (time / 60) + " minute(s)";
118 } else if (time >= 3600) {
119 timeString = ((time/60) / 60) + " hour(s)";
120 } else {
121 timeString = time + " second(s)";
122 }
123 return timeString;
124 }
125
126 //---ACCESSOR/MUTATOR METHODS---
127
128 //---ATTRIBUTES---
129
130 /**
131 * A reference to the IRCBot
132 */
133 private IRCBot _ircbot;
134
135 /**
136 * Are we "active"
137 */
138 private boolean _active = false;
139
140 /**
141 * The last alert that was sent
142 */
143 private String _lastAlert = "no alerts have been sent";
144
145 /**
146 * The time of the last alert
147 */
148 private long _lastAlertTime = -1;
149
150 /**
151 * Number of alerts sent
152 */
153 private long _alertCount = 0;
154
155 /**
156 * Time of IRCBot startup
157 */
158 private long _startTime;
159
160 /**
161 * This is the friendly identifier of the
162 * component this class is running in.
163 * eg, a Filter may be called "filter1",
164 * If this class does not have an owning
165 * component, a name from the configuration
166 * can be placed here. This name could also
167 * be changed to null for utility classes.
168 */
169 private String _name = "IRC Alert";
170
171 /**
172 * This holds a reference to the
173 * system logger that is being used.
174 */
175 private Logger _logger = ReferenceManager.getInstance().getLogger();
176
177 //---STATIC ATTRIBUTES---
178
179 //---INNER CLASSES---
180
181 /**
182 * This class provides some basic IRCBot functionality. It connects
183 * to a specified server, and will remain there until told to
184 * leave. Whilst connected it can send a message or a notice to
185 * the server.
186 */
187 class IRCBot extends Thread {
188
189 /**
190 * Main thread loop, this part of the class listens for
191 * messages from the server, and acts accordingly. At the
192 * present moment it only responds to pings.
193 */
194 public void run() {
195 // so we can stop if required
196 boolean run = true;
197 while(run) {
198 // flag so we can stop the loop
199 boolean doRead = true;
200 // connect to the IRC server
201 try {
202 connect();
203 sendNotice(ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice"));
204 } catch(IOException e) {
205 doRead=false;
206 _logger.write(this.toString(), Logger.ERROR, "Error connecting: "+e);
207 }
208 while(doRead) {
209 try {
210 // read a command
211 String cmd = _socketIn.readLine();
212 // if we have a null, we've lost contact
213 if(cmd == null) {
214 throw new IOException("End of stream reached");
215 }
216 // let another method deal with the input
217 handleInput(cmd);
218 } catch (IOException e) {
219 // comms failure, maybe our link is dead.
220 _logger.write(this.toString(), Logger.ERROR, "Communication error: "+e);
221 // stop, and loop round for a reconnect.
222 doRead = false;
223 }
224 }
225 // make sure we're disconnected
226 try {
227 disconnect();
228 } catch (IOException e) {
229 _logger.write(this.toString(), Logger.ERROR, "Communication error: "+e);
230 }
231
232 // comms have failed, so wait a while and reconnect
233 int delayTime = 0;
234 try {
235 delayTime = Integer.parseInt(ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.reconnectDelay"));
236 } catch (NumberFormatException e) {
237 delayTime = DEFAULT_RECONNECT_DELAY;
238 _logger.write(this.toString(), Logger.WARNING, "Erronous Alerter.IRC.reconnectDelay value in configuration using default of " + delayTime + " seconds");
239 } catch (org.omg.CORBA.MARSHAL e2) {
240 delayTime = DEFAULT_RECONNECT_DELAY;
241 _logger.write(this.toString(), Logger.WARNING, "Alerter.IRC.reconnectDelay value unavailable using default of " + delayTime + " seconds");
242 }
243 try {
244 Thread.sleep(delayTime * 1000);
245 } catch (InterruptedException e) {}
246 }
247 // maybe disconnect here ? - shutdown method not implemented yet
248 //disconnect();
249 }
250
251 /**
252 * Sends a message to the channel.
253 *
254 * @param msg The message to send
255 */
256 public void sendMsg(String msg) {
257 _socketOut.println("PRIVMSG "+_channel+" :"+msg);
258 // wait a second before returning...
259 // this ensures messages can't be sent too fast
260 try {Thread.sleep(1000);} catch (InterruptedException e) {}
261 }
262
263 /**
264 * Sends a message to the channel.
265 *
266 * @param user The user to send to
267 * @param msg The message to send
268 */
269 public void sendPrivMsg(String user, String msg) {
270 _socketOut.println("PRIVMSG "+user+" :"+msg);
271 // wait a second before returning...
272 // this ensures messages can't be sent too fast
273 try {Thread.sleep(1000);} catch (InterruptedException e) {}
274 }
275
276 /**
277 * Sends an action to the channel.
278 *
279 * @param msg the action message
280 */
281 public void sendAction(String msg) {
282 char esc = 001;
283 sendMsg(esc+"ACTION "+msg+esc);
284 // wait a second before returning...
285 // this ensures messages can't be sent too fast
286 try {Thread.sleep(1000);} catch (InterruptedException e) {}
287 }
288
289 /**
290 * Sends a notice to the channel.
291 *
292 * @param msg The notice to send
293 */
294 public void sendNotice(String msg) {
295 _socketOut.println("NOTICE "+_channel+" :"+msg);
296 // wait a second before returning...
297 // this ensures messages can't be sent too fast
298 try {Thread.sleep(1000);} catch (InterruptedException e) {}
299 }
300
301 /**
302 * Connect to the IRC server, log in, and join the channel.
303 *
304 * @throws IOException if the connection fails
305 */
306 public void connect() throws IOException {
307 ConfigurationProxy cp = ConfigurationProxy.getInstance();
308 // setup the socket, reader and writer
309 String server = cp.getProperty(_name, "Alerter.IRC.IRCServer");
310 int port = Integer.parseInt(cp.getProperty(_name, "Alerter.IRC.IRCPort"));
311 _socket = new Socket(server, port);
312 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
313 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
314 //_socketOut.println("PASS");
315 // send USER details
316 String user = cp.getProperty(_name, "Alerter.IRC.user");
317 String comment = cp.getProperty(_name, "Alerter.IRC.comment");
318 _socketOut.println("USER "+user+" 8 * :"+comment);
319 // attempt to get a nick
320 String nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
321 StringTokenizer st = new StringTokenizer(nickList, ";");
322 boolean ok = false;
323 // try until we exhaust our list
324 while(!ok && st.hasMoreTokens()) {
325 String nick = st.nextToken();
326 _socketOut.println("NICK "+nick);
327 // get a "yes" or "no" response back
328 String response = "";
329 do {
330 response = _socketIn.readLine();
331 if(response==null) {
332 throw new IOException("Communication error whilst logging in");
333 }
334 } while(response.indexOf("001")==-1 && response.indexOf("433")==-1);
335 // see if it was a yes
336 if(response.indexOf("001")!=-1) {
337 // great, we're logged in !
338 ok = true;
339 // store the name we're using
340 _nickname = nick;
341 }
342 else {
343 // log we couldn't get the name
344 _logger.write(this.toString(), Logger.WARNING, "Nickname in use: "+nick);
345 }
346 }
347 if(!ok) {
348 // oh dear, we couldn't get on.
349 throw new IOException("All nicknames in use");
350 }
351 // join the channel
352 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
353 _socketOut.println("JOIN "+_channel);
354 // allow alerts
355 _active = true;
356 }
357
358 /**
359 * Disconnect "nicely" from the IRC server.
360 *
361 * @throws IOException if the disconnection fails
362 */
363 public void disconnect() throws IOException {
364 // stop alerts
365 _active = false;
366 // send proper QUIT
367 _socketOut.println("QUIT : iscreamBot component shutting down...");
368 // close the socket
369 _socketOut.close();
370 _socketIn.close();
371 _socket.close();
372 }
373
374 /**
375 * Overrides the {@link java.lang.Object#toString() Object.toString()}
376 * method to provide clean logging (every class should have this).
377 *
378 * This uses the uk.ac.ukc.iscream.util.NameFormat class
379 * to format the toString()
380 *
381 * @return the name of this class and its CVS revision
382 */
383 public String toString() {
384 return FormatName.getName(
385 _name,
386 getClass().getName(),
387 REVISION);
388 }
389
390 /**
391 * Deals with incoming lines from the server.
392 *
393 * @param line the line to deal with
394 */
395 private void handleInput(String line) {
396 ConfigurationProxy cp = ConfigurationProxy.getInstance();
397 // if it's a PING...
398 if(line.startsWith("PING")) {
399 // ...send a PONG
400 _socketOut.println("PONG" + line.substring(4));
401 }
402 // see if it's for us
403 else if(getMsg(line).startsWith(_nickname+",")
404 || getMsg(line).startsWith(_nickname+":")
405 || getMsg(line).startsWith(_nickname+" ")) {
406 // we have a message for us
407 String message = getMsg(line).substring(_nickname.length());
408 if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.stopCommand"))!=-1) {
409 _active = false;
410 sendMsg(getMsgSender(line)+", alerts have been stopped");
411 }
412 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.startCommand"))!=-1) {
413 _active = true;
414 sendMsg(getMsgSender(line)+", alerts have been activated");
415 }
416 // this needs to go here if it contains the same words as the lastAlertCommand
417 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand"))!=-1) {
418 if(_lastAlertTime != -1) {
419 long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
420 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
421 sendMsg(getMsgSender(line)+", I last sent an alert "+uptimeText+ " ago");
422 }
423 else {
424 sendMsg(getMsgSender(line)+", I've never sent an alert!");
425 }
426 }
427 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.lastAlertCommand"))!=-1) {
428 if(_lastAlertTime != -1) {
429 String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
430 sendMsg(getMsgSender(line)+", last alert was at "+date+"; "+_lastAlert);
431 }
432 else {
433 sendMsg(getMsgSender(line)+", I've never sent an alert!");
434 }
435
436 }
437 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.joinCommand"))!=-1) {
438 String joinCmd = cp.getProperty(_name, "Alerter.IRC.joinCommand");
439 String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
440 int endOfChan = newChan.indexOf(" ");
441 if(endOfChan == -1) {
442 endOfChan = newChan.length();
443 }
444 newChan = newChan.substring(0, endOfChan);
445 sendMsg(getMsgSender(line)+", okay, I'm off to "+newChan);
446 _socketOut.println("PART "+_channel);
447 _socketOut.println("JOIN "+newChan);
448 _channel = newChan;
449 }
450 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.nickChangeCommand"))!=-1) {
451 String nickChangeCmd = cp.getProperty(_name, "Alerter.IRC.nickChangeCommand");
452 String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
453 int endOfNick = newNick.indexOf(" ");
454 if(endOfNick == -1) {
455 endOfNick = newNick.length();
456 }
457 newNick = newNick.substring(0, endOfNick);
458 sendMsg(getMsgSender(line)+", okay, changing my nickname to "+newNick);
459 _socketOut.println("NICK "+newNick);
460 _nickname = newNick;
461 }
462 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.versionCommand"))!=-1) {
463 sendMsg(getMsgSender(line)+", I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot");
464 }
465 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.helpCommand"))!=-1) {
466 sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
467 sendPrivMsg(getMsgSender(line), "I understand the following commands;");
468 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.stopCommand"));
469 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.startCommand"));
470 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.lastAlertCommand"));
471 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.joinCommand"));
472 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.nickChangeCommand"));
473 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.statCommand"));
474 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.uptimeCommand"));
475 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand"));
476 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.helpCommand"));
477 }
478 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.statCommand"))!=-1) {
479 sendMsg(getMsgSender(line)+", I have sent a total of "+_alertCount+" alerts!");
480 }
481 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.uptimeCommand"))!=-1) {
482 long uptime = (System.currentTimeMillis() - _startTime) / 1000;
483 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
484 sendMsg(getMsgSender(line)+", I have been running for "+uptimeText);
485 }
486 else if(message.indexOf("do a jibble dance")!=-1) {
487 // little joke :)
488 sendAction("jives to the funky beat shouting \"ii--screeeaaammm\"");
489 }
490 else {
491 sendMsg(getMsgSender(line)+", "+cp.getProperty(_name, "Alerter.IRC.rejectMessage"));
492 }
493 }
494 else if(line.indexOf(_nickname)!=-1 && line.indexOf(_channel)!=-1 && line.indexOf("KICK")!=-1) {
495 sendPrivMsg(getMsgSender(line), "That wasn't a nice thing to do...");
496 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
497 _socketOut.println("JOIN "+_channel);
498 }
499 }
500
501 /**
502 * Strips the header from a message line
503 *
504 * @param line the line to strip
505 * @return the message from the line
506 */
507 private String getMsg(String line) {
508 String result = "";
509 if(line.indexOf("PRIVMSG")!=-1) {
510 int firstColon = line.indexOf(":");
511 if(firstColon != -1) {
512 int secondColon = line.indexOf(":", firstColon+1);
513 if(secondColon != -1) {
514 result = line.substring(secondColon+1);
515 }
516 }
517 }
518 return result;
519 }
520
521 /**
522 * Finds out the sender of the message
523 *
524 * @param line the line to look for a sender in
525 * @return the sender
526 */
527 private String getMsgSender(String line) {
528 String result = "";
529 int colon = line.indexOf(":");
530 int excl = line.indexOf("!");
531 if(colon!=-1 && excl!=-1) {
532 result = line.substring(colon+1, excl);
533 }
534 return result;
535 }
536
537 /**
538 * The socket connected to the server
539 */
540 private Socket _socket;
541
542 /**
543 * The writer
544 */
545 private PrintWriter _socketOut;
546
547 /**
548 * The reader
549 */
550 private BufferedReader _socketIn;
551
552 /**
553 * Just a reminder to what channel we're on...
554 * this can't be dynamic :)
555 */
556 private String _channel;
557
558 /**
559 * A reminder of our current nickname...
560 */
561 private String _nickname;
562
563 }
564
565 }