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, 2 months ago) by ajm
Branch: MAIN
Changes since 1.9: +3 -3 lines
Log Message:
minor change to the logging line

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
14 /**
15 * This Alert sends an IRC message.
16 *
17 * Clean shutdown could be achieved by stopping the run() method in the
18 * IRCBot inner class.
19 *
20 * @author $Author: tdb1 $
21 * @version $Id: IRC__Alerter.java,v 1.9 2001/03/04 03:34:50 tdb1 Exp $
22 */
23 public class IRC__Alerter implements PluginAlerter {
24
25 //---FINAL ATTRIBUTES---
26
27 /**
28 * The current CVS revision of this class
29 */
30 public final String REVISION = "$Revision: 1.9 $";
31
32 /**
33 * A description of this alerter
34 */
35 public final String DESC = "Sends alerts on an IRC channel";
36
37 /**
38 * The default reconnect delay in seconds
39 */
40 public final int DEFAULT_RECONNECT_DELAY = 30;
41
42 //---STATIC METHODS---
43
44 //---CONSTRUCTORS---
45
46 public IRC__Alerter() {
47
48 // connect to the IRC server
49 _ircbot = new IRCBot();
50 _ircbot.start();
51
52 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
53 }
54
55 //---PUBLIC METHODS---
56
57 public void sendAlert(Alert alert) {
58 // 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 _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
79 _ircbot.sendMsg(message);
80 _lastAlert = message;
81 }
82 }
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 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 //---ACCESSOR/MUTATOR METHODS---
123
124 //---ATTRIBUTES---
125
126 /**
127 * A reference to the IRCBot
128 */
129 private IRCBot _ircbot;
130
131 /**
132 * 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 * 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 private String _name = "IRC Alert";
151
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 // so we can stop if required
177 boolean run = true;
178 while(run) {
179 // flag so we can stop the loop
180 boolean doRead = true;
181 // connect to the IRC server
182 try {
183 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 }
205 }
206 // make sure we're disconnected
207 try {
208 disconnect();
209 } catch (IOException e) {
210 _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 }
224 try {
225 Thread.sleep(delayTime * 1000);
226 } catch (InterruptedException e) {}
227 }
228 // maybe disconnect here ? - shutdown method not implemented yet
229 //disconnect();
230 }
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 * 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 * 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 ConfigurationProxy cp = ConfigurationProxy.getInstance();
277 // setup the socket, reader and writer
278 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 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
282 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
283 //_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 // join the channel
321 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
322 _socketOut.println("JOIN "+_channel);
323 // allow alerts
324 _active = true;
325 }
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 // stop alerts
334 _active = false;
335 // send proper QUIT
336 _socketOut.println("QUIT : iscreamBot component shutting down...");
337 // close the socket
338 _socketOut.close();
339 _socketIn.close();
340 _socket.close();
341 }
342
343 /**
344 * 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 * 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 /**
473 * Just a reminder to what channel we're on...
474 * this can't be dynamic :)
475 */
476 private String _channel;
477
478 /**
479 * A reminder of our current nickname...
480 */
481 private String _nickname;
482
483 }
484
485 }