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.14
Committed: Mon Mar 5 12:09:28 2001 UTC (23 years, 2 months ago) by ajm
Branch: MAIN
Changes since 1.13: +3 -3 lines
Log Message:
Now responds to OK messages even if that isn't the level its monitoring.

Maybe not ideal just yet though, it should only get OK's if its level has been passed, but not sure how to do that yet.

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: tdb1 $
22 * @version $Id: IRC__Alerter.java,v 1.13 2001/03/05 01:38:01 tdb1 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.13 $";
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.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 }