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.19
Committed: Tue Mar 13 02:19:43 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.18: +5 -3 lines
Log Message:
Given all the classes that extend Thread a name using Thread.setName(). It is
only representative as far as it will tell us which class the Thread is, but
this will go some way to aiding debugging. If time permitted, more effort could
be taken to name each thread according to what it was dealing with.

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.18 2001/03/08 13:43:54 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.18 $";
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 public final String DEFAULT_LEVEL = Alert.alertLevels[0];
44
45 public final String NOT_CONFIGURED = "<NOT CONFIGURED>";
46
47 //---STATIC METHODS---
48
49 //---CONSTRUCTORS---
50
51 public IRC__Alerter() {
52
53 // connect to the IRC server
54 _ircbot = new IRCBot();
55 // set it's name and start it
56 _ircbot.setName("client.IRC__Alerter$IRCBot");
57 _ircbot.start();
58 _startTime = System.currentTimeMillis();
59
60 _logger.write(toString(), Logger.SYSINIT, "IRC Alerter started");
61 }
62
63 //---PUBLIC METHODS---
64
65 public void sendAlert(Alert alert) {
66 // only send alerts if we're active
67 if(_active) {
68 ConfigurationProxy cp = ConfigurationProxy.getInstance();
69
70 String levelName;
71 try {
72 levelName = cp.getProperty(_name, "Alerter.IRC.level");
73 } catch (PropertyNotFoundException e) {
74 levelName = DEFAULT_LEVEL;
75 _logger.write(toString(), Logger.WARNING, "Alerter.IRC.level value unavailable using default of " + levelName);
76 }
77 int level = StringUtils.getStringPos(levelName, Alert.alertLevels);
78 // only send if it's equal (or above) our level
79 if(((alert.getLevel() == 0) && (alert.getLastLevel() >= level)) || (alert.getLevel() >= level)) {
80 String alertType = Alert.alertLevels[alert.getLevel()];
81 String thresholdType = Alert.thresholdLevels[alert.getThreshold()];
82 String timeFirstSince = DateUtils.formatTime(System.currentTimeMillis() - alert.getInitialAlertTime(), "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
83 String timeFirstOccured = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(alert.getInitialAlertTime()));
84 // sort out the message
85 String message;
86 try {
87 message = cp.getProperty(_name, "Alerter.IRC.message");
88 } catch (PropertyNotFoundException e) {
89 message = NOT_CONFIGURED;
90 _logger.write(toString(), Logger.WARNING, "Alerter.IRC.message value unavailable using default of " + message);
91 }
92
93 message = StringUtils.replaceText(message, "%level%", alertType);
94 message = StringUtils.replaceText(message, "%threshold%", thresholdType);
95 message = StringUtils.replaceText(message, "%source%", alert.getSource());
96 message = StringUtils.replaceText(message, "%value%", alert.getValue());
97 message = StringUtils.replaceText(message, "%thresholdValue%", alert.getThresholdValue());
98 message = StringUtils.replaceText(message, "%attributeName%", alert.getAttributeName());
99 message = StringUtils.replaceText(message, "%timeTillNextAlert%", getTimeString(Long.parseLong(alert.getTimeTillNextAlert())));
100 message = StringUtils.replaceText(message, "%timeSinceFirstAlert%", timeFirstSince);
101 message = StringUtils.replaceText(message, "%timeOfFirstAlert%", timeFirstOccured);
102
103 // send the message
104 _logger.write(toString(), Logger.DEBUG, "Sending " + _name + " at "+ alertType + " level");
105 _ircbot.sendMsg(message);
106 _lastAlert = message;
107 _lastAlertTime = System.currentTimeMillis();
108 _alertCount ++;
109 }
110 }
111 else {
112 _ignoredCount ++;
113 }
114 }
115
116 /**
117 * Overrides the {@link java.lang.Object#toString() Object.toString()}
118 * method to provide clean logging (every class should have this).
119 *
120 * This uses the uk.ac.ukc.iscream.util.NameFormat class
121 * to format the toString()
122 *
123 * @return the name of this class and its CVS revision
124 */
125 public String toString() {
126 return FormatName.getName(
127 _name,
128 getClass().getName(),
129 REVISION);
130 }
131
132 /**
133 * return the String representation of what the filter does
134 */
135 public String getDescription(){
136 return DESC;
137 }
138
139 //---PRIVATE METHODS---
140
141 private String getTimeString(long time) {
142 String timeString = null;
143 if (time >= 60) {
144 timeString = (time / 60) + " minute(s)";
145 } else if (time >= 3600) {
146 timeString = ((time/60) / 60) + " hour(s)";
147 } else {
148 timeString = time + " second(s)";
149 }
150 return timeString;
151 }
152
153 //---ACCESSOR/MUTATOR METHODS---
154
155 //---ATTRIBUTES---
156
157 /**
158 * A reference to the IRCBot
159 */
160 private IRCBot _ircbot;
161
162 /**
163 * Are we "active"
164 */
165 private boolean _active = false;
166
167 /**
168 * The last alert that was sent
169 */
170 private String _lastAlert = "no alerts have been sent";
171
172 /**
173 * The time of the last alert
174 */
175 private long _lastAlertTime = -1;
176
177 /**
178 * Number of alerts sent
179 */
180 private int _alertCount = 0;
181
182 /**
183 * Number of alerts ignored when in "stopped" mode
184 */
185 private int _ignoredCount = 0;
186
187 /**
188 * Time of IRCBot startup
189 */
190 private long _startTime;
191
192 /**
193 * This is the friendly identifier of the
194 * component this class is running in.
195 * eg, a Filter may be called "filter1",
196 * If this class does not have an owning
197 * component, a name from the configuration
198 * can be placed here. This name could also
199 * be changed to null for utility classes.
200 */
201 private String _name = "IRC Alert";
202
203 /**
204 * This holds a reference to the
205 * system logger that is being used.
206 */
207 private Logger _logger = ReferenceManager.getInstance().getLogger();
208
209 //---STATIC ATTRIBUTES---
210
211 //---INNER CLASSES---
212
213 /**
214 * This class provides some basic IRCBot functionality. It connects
215 * to a specified server, and will remain there until told to
216 * leave. Whilst connected it can send a message or a notice to
217 * the server.
218 */
219 class IRCBot extends Thread {
220
221 public static final String DEFAULT_STARTUP_NOTICE = "i-scream ircbot starting...";
222
223 /**
224 * Main thread loop, this part of the class listens for
225 * messages from the server, and acts accordingly. At the
226 * present moment it only responds to pings.
227 */
228 public void run() {
229 // so we can stop if required
230 boolean run = true;
231 while(run) {
232 // flag so we can stop the loop
233 boolean doRead = true;
234 // get the startup notice
235 String startupNotice;
236 try {
237 startupNotice = ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.startupNotice");
238 } catch (PropertyNotFoundException e) {
239 startupNotice = DEFAULT_STARTUP_NOTICE;
240 _logger.write(this.toString(), Logger.WARNING, "Configuration error: "+e);
241 }
242 // connect to the IRC server
243 try {
244 connect();
245 sendNotice(startupNotice);
246 } catch(IOException e) {
247 doRead=false;
248 _logger.write(this.toString(), Logger.ERROR, "Error connecting: "+e);
249 }
250 while(doRead) {
251 try {
252 // read a command
253 String cmd = _socketIn.readLine();
254 // if we have a null, we've lost contact
255 if(cmd == null) {
256 throw new IOException("End of stream reached");
257 }
258 // let another method deal with the input
259 handleInput(cmd);
260 } catch (IOException e) {
261 // comms failure, maybe our link is dead.
262 _logger.write(this.toString(), Logger.ERROR, "Communication error: "+e);
263 // stop, and loop round for a reconnect.
264 doRead = false;
265 }
266 }
267 // make sure we're disconnected
268 try {
269 disconnect();
270 } catch (IOException e) {
271 _logger.write(this.toString(), Logger.ERROR, "Communication error: "+e);
272 }
273
274 // comms have failed, so wait a while and reconnect
275 int delayTime = 0;
276 try {
277 delayTime = Integer.parseInt(ConfigurationProxy.getInstance().getProperty(_name, "Alerter.IRC.reconnectDelay"));
278 } catch (NumberFormatException e) {
279 delayTime = DEFAULT_RECONNECT_DELAY;
280 _logger.write(this.toString(), Logger.WARNING, "Erronous Alerter.IRC.reconnectDelay value in configuration using default of " + delayTime + " seconds");
281 } catch (PropertyNotFoundException e) {
282 delayTime = DEFAULT_RECONNECT_DELAY;
283 _logger.write(this.toString(), Logger.WARNING, "Alerter.IRC.reconnectDelay value unavailable using default of " + delayTime + " seconds");
284 }
285 try {
286 Thread.sleep(delayTime * 1000);
287 } catch (InterruptedException e) {}
288 }
289 // maybe disconnect here ? - shutdown method not implemented yet
290 //disconnect();
291 }
292
293 /**
294 * Sends a message to the channel.
295 *
296 * @param msg The message to send
297 */
298 public void sendMsg(String msg) {
299 _socketOut.println("PRIVMSG "+_channel+" :"+msg);
300 // wait a second before returning...
301 // this ensures messages can't be sent too fast
302 try {Thread.sleep(1000);} catch (InterruptedException e) {}
303 }
304
305 /**
306 * Sends a message to the channel.
307 *
308 * @param user The user to send to
309 * @param msg The message to send
310 */
311 public void sendPrivMsg(String user, String msg) {
312 _socketOut.println("PRIVMSG "+user+" :"+msg);
313 // wait a second before returning...
314 // this ensures messages can't be sent too fast
315 try {Thread.sleep(1000);} catch (InterruptedException e) {}
316 }
317
318 /**
319 * Sends an action to the channel.
320 *
321 * @param msg the action message
322 */
323 public void sendAction(String msg) {
324 char esc = 001;
325 sendMsg(esc+"ACTION "+msg+esc);
326 // wait a second before returning...
327 // this ensures messages can't be sent too fast
328 try {Thread.sleep(1000);} catch (InterruptedException e) {}
329 }
330
331 /**
332 * Sends a notice to the channel.
333 *
334 * @param msg The notice to send
335 */
336 public void sendNotice(String msg) {
337 _socketOut.println("NOTICE "+_channel+" :"+msg);
338 // wait a second before returning...
339 // this ensures messages can't be sent too fast
340 try {Thread.sleep(1000);} catch (InterruptedException e) {}
341 }
342
343 /**
344 * Connect to the IRC server, log in, and join the channel.
345 *
346 * @throws IOException if the connection fails
347 */
348 public void connect() throws IOException {
349 ConfigurationProxy cp = ConfigurationProxy.getInstance();
350 // setup the socket, reader and writer
351 String server;
352 int port;
353 try {
354 server = cp.getProperty(_name, "Alerter.IRC.IRCServer");
355 port = Integer.parseInt(cp.getProperty(_name, "Alerter.IRC.IRCPort"));
356 } catch (PropertyNotFoundException e) {
357 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
358 throw new IOException("Can't get irc server details due to configuration error");
359 } catch (NumberFormatException e) {
360 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
361 throw new IOException("Can't get irc server details due to malformed configuration");
362 }
363 _socket = new Socket(server, port);
364 _socketIn = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
365 _socketOut = new PrintWriter(_socket.getOutputStream(), true);
366 //_socketOut.println("PASS");
367 // send USER details
368 String user, comment;
369 try {
370 user = cp.getProperty(_name, "Alerter.IRC.user");
371 comment = cp.getProperty(_name, "Alerter.IRC.comment");
372 } catch (PropertyNotFoundException e) {
373 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
374 throw new IOException("Can't get user details due to configuration error");
375 }
376 _socketOut.println("USER "+user+" 8 * :"+comment);
377 // attempt to get a nick
378 String nickList;
379 try {
380 nickList = cp.getProperty(_name, "Alerter.IRC.nickList");
381 } catch (PropertyNotFoundException e) {
382 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
383 throw new IOException("Can't get nickname due to configuration error");
384 }
385 StringTokenizer st = new StringTokenizer(nickList, ";");
386 boolean ok = false;
387 // try until we exhaust our list
388 while(!ok && st.hasMoreTokens()) {
389 String nick = st.nextToken();
390 _socketOut.println("NICK "+nick);
391 // get a "yes" or "no" response back
392 String response = "";
393 do {
394 response = _socketIn.readLine();
395 if(response==null) {
396 throw new IOException("Communication error whilst logging in");
397 }
398 } while(response.indexOf("001")==-1 && response.indexOf("433")==-1);
399 // see if it was a yes
400 if(response.indexOf("001")!=-1) {
401 // great, we're logged in !
402 ok = true;
403 // store the name we're using
404 _nickname = nick;
405 }
406 else {
407 // log we couldn't get the name
408 _logger.write(this.toString(), Logger.WARNING, "Nickname in use: "+nick);
409 }
410 }
411 if(!ok) {
412 // oh dear, we couldn't get on.
413 throw new IOException("All nicknames in use");
414 }
415 // join the channel
416 try {
417 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
418 } catch (PropertyNotFoundException e) {
419 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
420 throw new IOException("Can't get channel name due to configuration error");
421 }
422 _socketOut.println("JOIN "+_channel);
423 // allow alerts
424 _active = true;
425 }
426
427 /**
428 * Disconnect "nicely" from the IRC server.
429 *
430 * @throws IOException if the disconnection fails
431 */
432 public void disconnect() throws IOException {
433 // stop alerts
434 _active = false;
435 // send proper QUIT
436 _socketOut.println("QUIT : iscreamBot component shutting down...");
437 // close the socket
438 _socketOut.close();
439 _socketIn.close();
440 _socket.close();
441 }
442
443 /**
444 * Overrides the {@link java.lang.Object#toString() Object.toString()}
445 * method to provide clean logging (every class should have this).
446 *
447 * This uses the uk.ac.ukc.iscream.util.NameFormat class
448 * to format the toString()
449 *
450 * @return the name of this class and its CVS revision
451 */
452 public String toString() {
453 return FormatName.getName(
454 _name,
455 getClass().getName(),
456 REVISION);
457 }
458
459 /**
460 * Deals with incoming lines from the server.
461 *
462 * @param line the line to deal with
463 */
464 private void handleInput(String line) {
465 ConfigurationProxy cp = ConfigurationProxy.getInstance();
466 // if it's a PING...
467 if(line.startsWith("PING")) {
468 // ...send a PONG
469 _socketOut.println("PONG" + line.substring(4));
470 }
471 // see if it's for us
472 else if(getMsg(line).startsWith(_nickname+",") || getMsg(line).startsWith(_nickname+":") || getMsg(line).startsWith(_nickname+" ")) {
473 // setup some String's
474 String stopCommand, startCommand, timeSinceLastAlertCommand, lastAlertCommand, joinCommand;
475 String nickChangeCommand, versionCommand, helpCommand, statCommand, uptimeCommand;
476 // get the command set
477 try {
478 stopCommand = cp.getProperty(_name, "Alerter.IRC.stopCommand");
479 startCommand = cp.getProperty(_name, "Alerter.IRC.startCommand");
480 timeSinceLastAlertCommand = cp.getProperty(_name, "Alerter.IRC.timeSinceLastAlertCommand");
481 lastAlertCommand = cp.getProperty(_name, "Alerter.IRC.lastAlertCommand");
482 joinCommand = cp.getProperty(_name, "Alerter.IRC.joinCommand");
483 nickChangeCommand = cp.getProperty(_name, "Alerter.IRC.nickChangeCommand");
484 versionCommand = cp.getProperty(_name, "Alerter.IRC.versionCommand");
485 helpCommand = cp.getProperty(_name, "Alerter.IRC.helpCommand");
486 statCommand = cp.getProperty(_name, "Alerter.IRC.statCommand");
487 uptimeCommand = cp.getProperty(_name, "Alerter.IRC.uptimeCommand");
488 } catch (PropertyNotFoundException e) {
489 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
490 // lets bail from handling this line...
491 // ...it's gonna be hard without a command set!
492 return;
493 }
494
495 // we have a message for us
496 String message = getMsg(line).substring(_nickname.length());
497 if(message.indexOf(stopCommand)!=-1) {
498 _active = false;
499 sendMsg(getMsgSender(line)+", alerts have been stopped");
500 }
501 else if(message.indexOf(startCommand)!=-1) {
502 _active = true;
503 sendMsg(getMsgSender(line)+", alerts have been activated");
504 }
505 // this needs to go here if it contains the same words as the lastAlertCommand
506 else if(message.indexOf(timeSinceLastAlertCommand)!=-1) {
507 if(_lastAlertTime != -1) {
508 long uptime = (System.currentTimeMillis() - _lastAlertTime) / 1000;
509 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
510 sendMsg(getMsgSender(line)+", I last sent an alert "+uptimeText+ " ago");
511 }
512 else {
513 sendMsg(getMsgSender(line)+", I've never sent an alert!");
514 }
515 }
516 else if(message.indexOf(lastAlertCommand)!=-1) {
517 if(_lastAlertTime != -1) {
518 String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date(_lastAlertTime));
519 sendMsg(getMsgSender(line)+", last alert was at "+date+"; "+_lastAlert);
520 }
521 else {
522 sendMsg(getMsgSender(line)+", I've never sent an alert!");
523 }
524
525 }
526 else if(message.indexOf(joinCommand)!=-1) {
527 String joinCmd = joinCommand;
528 String newChan = message.substring(message.indexOf(joinCmd) + joinCmd.length() + 1);
529 int endOfChan = newChan.indexOf(" ");
530 if(endOfChan == -1) {
531 endOfChan = newChan.length();
532 }
533 newChan = newChan.substring(0, endOfChan);
534 sendMsg(getMsgSender(line)+", okay, I'm off to "+newChan);
535 _socketOut.println("PART "+_channel);
536 _socketOut.println("JOIN "+newChan);
537 _channel = newChan;
538 }
539 else if(message.indexOf(nickChangeCommand)!=-1) {
540 String nickChangeCmd = nickChangeCommand;
541 String newNick = message.substring(message.indexOf(nickChangeCmd) + nickChangeCmd.length() + 1);
542 int endOfNick = newNick.indexOf(" ");
543 if(endOfNick == -1) {
544 endOfNick = newNick.length();
545 }
546 newNick = newNick.substring(0, endOfNick);
547 sendMsg(getMsgSender(line)+", okay, changing my nickname to "+newNick);
548 _socketOut.println("NICK "+newNick);
549 _nickname = newNick;
550 }
551 else if(message.indexOf(versionCommand)!=-1) {
552 sendMsg(getMsgSender(line)+", I am version "+REVISION.substring(11, REVISION.length() -2)+" of the i-scream alerting bot");
553 }
554 else if(message.indexOf(helpCommand)!=-1) {
555 sendPrivMsg(getMsgSender(line), "Hello, I am the i-scream alerting bot version "+REVISION.substring(11, REVISION.length() -2));
556 sendPrivMsg(getMsgSender(line), "I understand the following commands;");
557 sendPrivMsg(getMsgSender(line), stopCommand);
558 sendPrivMsg(getMsgSender(line), startCommand);
559 sendPrivMsg(getMsgSender(line), lastAlertCommand);
560 sendPrivMsg(getMsgSender(line), joinCommand);
561 sendPrivMsg(getMsgSender(line), nickChangeCommand);
562 sendPrivMsg(getMsgSender(line), statCommand);
563 sendPrivMsg(getMsgSender(line), uptimeCommand);
564 sendPrivMsg(getMsgSender(line), timeSinceLastAlertCommand);
565 sendPrivMsg(getMsgSender(line), helpCommand);
566 }
567 else if(message.indexOf(statCommand)!=-1) {
568 sendMsg(getMsgSender(line)+", I have sent a total of "+_alertCount+" alerts, and ignored a total of "+_ignoredCount+"!");
569 }
570 else if(message.indexOf(uptimeCommand)!=-1) {
571 long uptime = (System.currentTimeMillis() - _startTime) / 1000;
572 String uptimeText = DateUtils.formatTime(uptime, "%DAYS% days, %HOURS% hours, %MINS% mins, and %SECS% secs");
573 sendMsg(getMsgSender(line)+", I have been running for "+uptimeText);
574 }
575 else if(message.indexOf("ping")!=-1) {
576 sendMsg("pong");
577 }
578 else if(message.indexOf("do a jibble dance")!=-1) {
579 // little joke :)
580 sendAction("jives to the funky beat shouting \"ii--screeeaaammm\"");
581 }
582 else {
583 String rejectMessage = NOT_CONFIGURED;
584 try {
585 rejectMessage = cp.getProperty(_name, "Alerter.IRC.rejectMessage");
586 } catch(PropertyNotFoundException e) {
587 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
588 }
589 sendMsg(getMsgSender(line)+", "+rejectMessage);
590 }
591 }
592 else if(line.indexOf(_nickname)!=-1 && line.indexOf(_channel)!=-1 && line.indexOf("KICK")!=-1) {
593 sendPrivMsg(getMsgSender(line), "That wasn't a nice thing to do...");
594 try {
595 _channel = cp.getProperty(_name, "Alerter.IRC.channel");
596 } catch(PropertyNotFoundException e) {
597 _logger.write(this.toString(), Logger.ERROR, "Configuration error: "+e);
598 }
599 _socketOut.println("JOIN "+_channel);
600 }
601 }
602
603 /**
604 * Strips the header from a message line
605 *
606 * @param line the line to strip
607 * @return the message from the line
608 */
609 private String getMsg(String line) {
610 String result = "";
611 if(line.indexOf("PRIVMSG")!=-1) {
612 int firstColon = line.indexOf(":");
613 if(firstColon != -1) {
614 int secondColon = line.indexOf(":", firstColon+1);
615 if(secondColon != -1) {
616 result = line.substring(secondColon+1);
617 }
618 }
619 }
620 return result;
621 }
622
623 /**
624 * Finds out the sender of the message
625 *
626 * @param line the line to look for a sender in
627 * @return the sender
628 */
629 private String getMsgSender(String line) {
630 String result = "";
631 int colon = line.indexOf(":");
632 int excl = line.indexOf("!");
633 if(colon!=-1 && excl!=-1) {
634 result = line.substring(colon+1, excl);
635 }
636 return result;
637 }
638
639 /**
640 * The socket connected to the server
641 */
642 private Socket _socket;
643
644 /**
645 * The writer
646 */
647 private PrintWriter _socketOut;
648
649 /**
650 * The reader
651 */
652 private BufferedReader _socketIn;
653
654 /**
655 * Just a reminder to what channel we're on...
656 * this can't be dynamic :)
657 */
658 private String _channel;
659
660 /**
661 * A reminder of our current nickname...
662 */
663 private String _nickname;
664
665 }
666
667 }