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.10
Committed: Sun Mar 4 04:43:29 2001 UTC (23 years, 3 months ago) by ajm
Branch: MAIN
Changes since 1.9: +3 -3 lines
Log Message:
minor change to the logging line

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