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

# User Rev Content
1 tdb 1.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 tdb 1.9 import java.util.*;
13 tdb 1.11 import java.text.*;
14 tdb 1.1
15     /**
16     * This Alert sends an IRC message.
17     *
18 tdb 1.9 * Clean shutdown could be achieved by stopping the run() method in the
19     * IRCBot inner class.
20     *
21 ajm 1.15 * @author $Author: ajm4 $
22     * @version $Id: IRC__Alerter.java,v 1.14 2001/03/05 12:09:28 ajm4 Exp $
23 tdb 1.1 */
24     public class IRC__Alerter implements PluginAlerter {
25    
26     //---FINAL ATTRIBUTES---
27    
28     /**
29     * The current CVS revision of this class
30     */
31 ajm 1.15 public final String REVISION = "$Revision: 1.14 $";
32 tdb 1.1
33 tdb 1.9 /**
34     * A description of this alerter
35     */
36 tdb 1.1 public final String DESC = "Sends alerts on an IRC channel";
37    
38 tdb 1.9 /**
39     * The default reconnect delay in seconds
40     */
41     public final int DEFAULT_RECONNECT_DELAY = 30;
42    
43 tdb 1.1 //---STATIC METHODS---
44    
45     //---CONSTRUCTORS---
46    
47     public IRC__Alerter() {
48 tdb 1.7
49 tdb 1.1 // connect to the IRC server
50 tdb 1.9 _ircbot = new IRCBot();
51     _ircbot.start();
52 tdb 1.11 _startTime = System.currentTimeMillis();
53 tdb 1.4
54 tdb 1.5 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
55 tdb 1.1 }
56    
57     //---PUBLIC METHODS---
58    
59     public void sendAlert(Alert alert) {
60 tdb 1.9 // 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 ajm 1.15 if(((alert.getLevel() == 0) && (alert.getLastLevel() >= level)) || (alert.getLevel() >= level)) {
67 tdb 1.9 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 ajm 1.10 _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
81 tdb 1.9 _ircbot.sendMsg(message);
82     _lastAlert = message;
83 tdb 1.11 _lastAlertTime = System.currentTimeMillis();
84     _alertCount ++;
85 tdb 1.9 }
86 tdb 1.1 }
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 ajm 1.8 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 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
127    
128     //---ATTRIBUTES---
129    
130 tdb 1.7 /**
131     * A reference to the IRCBot
132     */
133 tdb 1.1 private IRCBot _ircbot;
134    
135     /**
136 tdb 1.9 * 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 tdb 1.11 * 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 tdb 1.1 * 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 ajm 1.8 private String _name = "IRC Alert";
170 tdb 1.1
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 tdb 1.9 // so we can stop if required
196 tdb 1.1 boolean run = true;
197     while(run) {
198 tdb 1.9 // flag so we can stop the loop
199     boolean doRead = true;
200     // connect to the IRC server
201 tdb 1.1 try {
202 tdb 1.9 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 tdb 1.1 }
224 tdb 1.9 }
225     // make sure we're disconnected
226     try {
227     disconnect();
228 tdb 1.1 } catch (IOException e) {
229 tdb 1.9 _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 tdb 1.1 }
243 tdb 1.9 try {
244     Thread.sleep(delayTime * 1000);
245     } catch (InterruptedException e) {}
246 tdb 1.1 }
247 tdb 1.9 // maybe disconnect here ? - shutdown method not implemented yet
248     //disconnect();
249 tdb 1.1 }
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 tdb 1.13 // wait a second before returning...
259     // this ensures messages can't be sent too fast
260     try {Thread.sleep(1000);} catch (InterruptedException e) {}
261 tdb 1.1 }
262    
263     /**
264 tdb 1.9 * 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 tdb 1.13 // wait a second before returning...
272     // this ensures messages can't be sent too fast
273     try {Thread.sleep(1000);} catch (InterruptedException e) {}
274 tdb 1.9 }
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 tdb 1.13 // wait a second before returning...
285     // this ensures messages can't be sent too fast
286     try {Thread.sleep(1000);} catch (InterruptedException e) {}
287 tdb 1.9 }
288    
289     /**
290 tdb 1.1 * 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 tdb 1.13 // wait a second before returning...
297     // this ensures messages can't be sent too fast
298     try {Thread.sleep(1000);} catch (InterruptedException e) {}
299 tdb 1.1 }
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 tdb 1.7 ConfigurationProxy cp = ConfigurationProxy.getInstance();
308 tdb 1.1 // setup the socket, reader and writer
309 tdb 1.7 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 tdb 1.1 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
313     _socketOut = new PrintWriter(_socket.getOutputStream(), true);
314 tdb 1.9 //_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 tdb 1.1 // join the channel
352 tdb 1.7 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
353 tdb 1.1 _socketOut.println("JOIN "+_channel);
354 tdb 1.9 // allow alerts
355     _active = true;
356 tdb 1.1 }
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 tdb 1.9 // stop alerts
365     _active = false;
366 tdb 1.6 // send proper QUIT
367 tdb 1.1 _socketOut.println("QUIT : iscreamBot component shutting down...");
368     // close the socket
369     _socketOut.close();
370     _socketIn.close();
371     _socket.close();
372     }
373 tdb 1.7
374 tdb 1.1 /**
375 tdb 1.9 * 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 tdb 1.11 else if(getMsg(line).startsWith(_nickname+",")
404     || getMsg(line).startsWith(_nickname+":")
405     || getMsg(line).startsWith(_nickname+" ")) {
406 tdb 1.9 // 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 tdb 1.11 // 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 tdb 1.9 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.lastAlertCommand"))!=-1) {
428 tdb 1.11 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 tdb 1.9 }
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 tdb 1.11 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 tdb 1.12 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 tdb 1.9 else if(message.indexOf(cp.getProperty(_name, "Alerter.IRC.helpCommand"))!=-1) {
466 tdb 1.12 sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
467 tdb 1.9 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 tdb 1.11 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 tdb 1.9 }
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 tdb 1.1 * 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 tdb 1.7 /**
553     * Just a reminder to what channel we're on...
554     * this can't be dynamic :)
555     */
556     private String _channel;
557 tdb 1.9
558     /**
559     * A reminder of our current nickname...
560     */
561     private String _nickname;
562    
563 tdb 1.1 }
564    
565     }