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.12
Committed: Sun Mar 4 05:37:15 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.11: +7 -4 lines
Log Message:
Added a version command.

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.11 2001/03/04 05:26:00 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.11 $";
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() >= 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 }
259
260 /**
261 * Sends a message to the channel.
262 *
263 * @param user The user to send to
264 * @param msg The message to send
265 */
266 public void sendPrivMsg(String user, String msg) {
267 _socketOut.println("PRIVMSG "+user+" :"+msg);
268 }
269
270 /**
271 * Sends an action to the channel.
272 *
273 * @param msg the action message
274 */
275 public void sendAction(String msg) {
276 char esc = 001;
277 sendMsg(esc+"ACTION "+msg+esc);
278 }
279
280 /**
281 * Sends a notice to the channel.
282 *
283 * @param msg The notice to send
284 */
285 public void sendNotice(String msg) {
286 _socketOut.println("NOTICE "+_channel+" :"+msg);
287 }
288
289 /**
290 * Connect to the IRC server, log in, and join the channel.
291 *
292 * @throws IOException if the connection fails
293 */
294 public void connect() throws IOException {
295 ConfigurationProxy cp = ConfigurationProxy.getInstance();
296 // setup the socket, reader and writer
297 String server = cp.getProperty(_name, "Alerter.IRC.IRCServer");
298 int port = Integer.parseInt(cp.getProperty(_name, "Alerter.IRC.IRCPort"));
299 _socket = new Socket(server, port);
300 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
301 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
302 //_socketOut.println("PASS");
303 // send USER details
304 String user = cp.getProperty(_name, "Alerter.IRC.user");
305 String comment = cp.getProperty(_name, "Alerter.IRC.comment");
306 _socketOut.println("USER "+user+" 8 * :"+comment);
307 // attempt to get a nick
308 String nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
309 StringTokenizer st = new StringTokenizer(nickList, ";");
310 boolean ok = false;
311 // try until we exhaust our list
312 while(!ok && st.hasMoreTokens()) {
313 String nick = st.nextToken();
314 _socketOut.println("NICK "+nick);
315 // get a "yes" or "no" response back
316 String response = "";
317 do {
318 response = _socketIn.readLine();
319 if(response==null) {
320 throw new IOException("Communication error whilst logging in");
321 }
322 } while(response.indexOf("001")==-1 && response.indexOf("433")==-1);
323 // see if it was a yes
324 if(response.indexOf("001")!=-1) {
325 // great, we're logged in !
326 ok = true;
327 // store the name we're using
328 _nickname = nick;
329 }
330 else {
331 // log we couldn't get the name
332 _logger.write(this.toString(), Logger.WARNING, "Nickname in use: "+nick);
333 }
334 }
335 if(!ok) {
336 // oh dear, we couldn't get on.
337 throw new IOException("All nicknames in use");
338 }
339 // join the channel
340 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
341 _socketOut.println("JOIN "+_channel);
342 // allow alerts
343 _active = true;
344 }
345
346 /**
347 * Disconnect "nicely" from the IRC server.
348 *
349 * @throws IOException if the disconnection fails
350 */
351 public void disconnect() throws IOException {
352 // stop alerts
353 _active = false;
354 // send proper QUIT
355 _socketOut.println("QUIT : iscreamBot component shutting down...");
356 // close the socket
357 _socketOut.close();
358 _socketIn.close();
359 _socket.close();
360 }
361
362 /**
363 * Overrides the {@link java.lang.Object#toString() Object.toString()}
364 * method to provide clean logging (every class should have this).
365 *
366 * This uses the uk.ac.ukc.iscream.util.NameFormat class
367 * to format the toString()
368 *
369 * @return the name of this class and its CVS revision
370 */
371 public String toString() {
372 return FormatName.getName(
373 _name,
374 getClass().getName(),
375 REVISION);
376 }
377
378 /**
379 * Deals with incoming lines from the server.
380 *
381 * @param line the line to deal with
382 */
383 private void handleInput(String line) {
384 ConfigurationProxy cp = ConfigurationProxy.getInstance();
385 // if it's a PING...
386 if(line.startsWith("PING")) {
387 // ...send a PONG
388 _socketOut.println("PONG" + line.substring(4));
389 }
390 // see if it's for us
391 else if(getMsg(line).startsWith(_nickname+",")
392 || getMsg(line).startsWith(_nickname+":")
393 || getMsg(line).startsWith(_nickname+" ")) {
394 // we have a message for us
395 String message = getMsg(line).substring(_nickname.length());
396 if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.stopCommand"))!=-1) {
397 _active = false;
398 sendMsg(getMsgSender(line)+", alerts have been stopped");
399 }
400 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.startCommand"))!=-1) {
401 _active = true;
402 sendMsg(getMsgSender(line)+", alerts have been activated");
403 }
404 // this needs to go here if it contains the same words as the lastAlertCommand
405 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand"))!=-1) {
406 if(_lastAlertTime != -1) {
407 long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
408 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
409 sendMsg(getMsgSender(line)+", I last sent an alert "+uptimeText+ " ago");
410 }
411 else {
412 sendMsg(getMsgSender(line)+", I've never sent an alert!");
413 }
414 }
415 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.lastAlertCommand"))!=-1) {
416 if(_lastAlertTime != -1) {
417 String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
418 sendMsg(getMsgSender(line)+", last alert was at "+date+"; "+_lastAlert);
419 }
420 else {
421 sendMsg(getMsgSender(line)+", I've never sent an alert!");
422 }
423
424 }
425 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.joinCommand"))!=-1) {
426 String joinCmd = cp.getProperty(_name, "Alerter.IRC.joinCommand");
427 String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
428 int endOfChan = newChan.indexOf(" ");
429 if(endOfChan == -1) {
430 endOfChan = newChan.length();
431 }
432 newChan = newChan.substring(0, endOfChan);
433 sendMsg(getMsgSender(line)+", okay, I'm off to "+newChan);
434 _socketOut.println("PART "+_channel);
435 _socketOut.println("JOIN "+newChan);
436 _channel = newChan;
437 }
438 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.nickChangeCommand"))!=-1) {
439 String nickChangeCmd = cp.getProperty(_name, "Alerter.IRC.nickChangeCommand");
440 String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
441 int endOfNick = newNick.indexOf(" ");
442 if(endOfNick == -1) {
443 endOfNick = newNick.length();
444 }
445 newNick = newNick.substring(0, endOfNick);
446 sendMsg(getMsgSender(line)+", okay, changing my nickname to "+newNick);
447 _socketOut.println("NICK "+newNick);
448 _nickname = newNick;
449 }
450 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.versionCommand"))!=-1) {
451 sendMsg(getMsgSender(line)+", I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot");
452 }
453 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.helpCommand"))!=-1) {
454 sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
455 sendPrivMsg(getMsgSender(line), "I understand the following commands;");
456 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.stopCommand"));
457 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.startCommand"));
458 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.lastAlertCommand"));
459 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.joinCommand"));
460 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.nickChangeCommand"));
461 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.statCommand"));
462 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.uptimeCommand"));
463 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand"));
464 sendPrivMsg(getMsgSender(line), cp.getProperty(_name, "Alerter.IRC.helpCommand"));
465 }
466 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.statCommand"))!=-1) {
467 sendMsg(getMsgSender(line)+", I have sent a total of "+_alertCount+" alerts!");
468 }
469 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.uptimeCommand"))!=-1) {
470 long uptime = (System.currentTimeMillis() - _startTime) / 1000;
471 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
472 sendMsg(getMsgSender(line)+", I have been running for "+uptimeText);
473 }
474 else if(message.indexOf("do a jibble dance")!=-1) {
475 // little joke :)
476 sendAction("jives to the funky beat shouting \"ii--screeeaaammm\"");
477 }
478 else {
479 sendMsg(getMsgSender(line)+", "+cp.getProperty(_name, "Alerter.IRC.rejectMessage"));
480 }
481 }
482 else if(line.indexOf(_nickname)!=-1 && line.indexOf(_channel)!=-1 && line.indexOf("KICK")!=-1) {
483 sendPrivMsg(getMsgSender(line), "That wasn't a nice thing to do...");
484 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
485 _socketOut.println("JOIN "+_channel);
486 }
487 }
488
489 /**
490 * Strips the header from a message line
491 *
492 * @param line the line to strip
493 * @return the message from the line
494 */
495 private String getMsg(String line) {
496 String result = "";
497 if(line.indexOf("PRIVMSG")!=-1) {
498 int firstColon = line.indexOf(":");
499 if(firstColon != -1) {
500 int secondColon = line.indexOf(":", firstColon+1);
501 if(secondColon != -1) {
502 result = line.substring(secondColon+1);
503 }
504 }
505 }
506 return result;
507 }
508
509 /**
510 * Finds out the sender of the message
511 *
512 * @param line the line to look for a sender in
513 * @return the sender
514 */
515 private String getMsgSender(String line) {
516 String result = "";
517 int colon = line.indexOf(":");
518 int excl = line.indexOf("!");
519 if(colon!=-1 && excl!=-1) {
520 result = line.substring(colon+1, excl);
521 }
522 return result;
523 }
524
525 /**
526 * The socket connected to the server
527 */
528 private Socket _socket;
529
530 /**
531 * The writer
532 */
533 private PrintWriter _socketOut;
534
535 /**
536 * The reader
537 */
538 private BufferedReader _socketIn;
539
540 /**
541 * Just a reminder to what channel we're on...
542 * this can't be dynamic :)
543 */
544 private String _channel;
545
546 /**
547 * A reminder of our current nickname...
548 */
549 private String _nickname;
550
551 }
552
553 }