aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
diff options
context:
space:
mode:
authorDr Scofield2008-10-20 17:31:54 +0000
committerDr Scofield2008-10-20 17:31:54 +0000
commit72a388a7b6dfba8f93ffc5c5c45db4c44bb46480 (patch)
treedb9ab06f6820806d8c2b3fc32029383971e955b7 /OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
parentMantis #2438 (diff)
downloadopensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.zip
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.gz
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.bz2
opensim-SC_OLD-72a388a7b6dfba8f93ffc5c5c45db4c44bb46480.tar.xz
cleaning up IRCBridgeModule to allow for configuration from in-world,
chat relaying via private channels, and old IRCBridgeModule behaviour. also cleaning up IRCBridgeModule's OpenSim.ini configuration variable names (still supporting "old" variable names). refactored IRCChatModule into IRCConnector and incorporating watchdog from IRCBridgeModule into IRCConnector. enabling ChatModule to be used as a super-class and utilizing it in ConciergeModule.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs710
1 files changed, 710 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
new file mode 100644
index 0000000..0eb303c
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
@@ -0,0 +1,710 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net.Sockets;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using OpenMetaverse;
36using log4net;
37using Nini.Config;
38using OpenSim.Framework;
39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes;
41
42namespace OpenSim.Region.Environment.Modules.Avatar.Chat
43{
44 public class IRCConnector
45 {
46 #region ErrorReplies enum
47
48 public enum ErrorReplies
49 {
50 NotRegistered = 451, // ":You have not registered"
51 NicknameInUse = 433 // "<nick> :Nickname is already in use"
52 }
53
54 #endregion
55
56 #region Replies enum
57
58 public enum Replies
59 {
60 MotdStart = 375, // ":- <server> Message of the day - "
61 Motd = 372, // ":- <text>"
62 EndOfMotd = 376 // ":End of /MOTD command"
63 }
64
65 #endregion
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 private Thread m_listener = null;
70 private Thread m_watchdog = null;
71 private Thread m_pinger = null;
72
73 private bool m_randomizeNick = true;
74
75 public string m_baseNick = null;
76 private string m_nick = null;
77 public string Nick
78 {
79 get { return m_baseNick; }
80 set { m_baseNick = value; }
81 }
82
83 private bool m_enabled = false;
84 public bool Enabled
85 {
86 get { return m_enabled; }
87 }
88
89 private bool m_connected = false;
90 public bool Connected
91 {
92 get { return m_connected; }
93 }
94
95 private string m_ircChannel;
96 public string IrcChannel
97 {
98 get { return m_ircChannel; }
99
100 set { m_ircChannel = value; }
101 }
102
103 private bool m_relayPrivateChannels = false;
104 public bool RelayPrivateChannels
105 {
106 get { return m_relayPrivateChannels; }
107 set { m_relayPrivateChannels = value; }
108 }
109
110 private int m_relayChannel = 0;
111 public int RelayChannel
112 {
113 get { return m_relayChannel; }
114 set { m_relayChannel = value; }
115 }
116
117 private bool m_clientReporting = true;
118 public bool ClientReporting
119 {
120 get { return m_clientReporting; }
121 set { m_clientReporting = value; }
122 }
123
124 private uint m_port = 6667;
125 public uint Port
126 {
127 get { return m_port; }
128 set { m_port = value; }
129 }
130
131 private string m_server = null;
132 public string Server
133 {
134 get { return m_server; }
135 set { m_server = value; }
136 }
137
138 public string m_accessPassword = "badkitty";
139
140 private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
141 private StreamReader m_reader;
142 private List<Scene> m_scenes = new List<Scene>();
143
144 private NetworkStream m_stream = null;
145 internal object m_syncConnect = new object();
146 private TcpClient m_tcp;
147 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
148 private StreamWriter m_writer;
149
150
151 public IRCConnector(IConfigSource config)
152 {
153 m_tcp = null;
154 m_writer = null;
155 m_reader = null;
156
157 // configuration in OpenSim.ini
158 // [IRC]
159 // server = chat.freenode.net
160 // nick = OSimBot_mysim
161 // nicknum = true
162 // ;nicknum set to true appends a 2 digit random number to the nick
163 // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
164 // ; username is the IRC command line sent
165 // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
166 // channel = #opensim-regions
167 // port = 6667
168 // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
169 // ;for <bot>:<user in region> :<message>
170 // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
171 // ;for <bot>:<message> - <user of region> :
172 // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
173 // ;for <bot>:<message> - from <user> :
174 // ;msgformat = "PRIVMSG {0} : {3} - from {1}"
175 // Traps I/O disconnects so it does not crash the sim
176 // Trys to reconnect if disconnected and someone says something
177 // Tells IRC server "QUIT" when doing a close (just to be nice)
178 // Default port back to 6667
179
180 try
181 {
182 m_server = config.Configs["IRC"].GetString("server");
183 m_baseNick = config.Configs["IRC"].GetString("nick", "OSimBot");
184
185 m_randomizeNick = config.Configs["IRC"].GetBoolean("randomize_nick", m_randomizeNick);
186 m_randomizeNick = config.Configs["IRC"].GetBoolean("nicknum", m_randomizeNick); // compat
187 m_ircChannel = config.Configs["IRC"].GetString("channel");
188 m_port = (uint)config.Configs["IRC"].GetInt("port", (int)m_port);
189 m_user = config.Configs["IRC"].GetString("username", m_user);
190 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
191 // m_commandChannel = config.Configs["IRC"].GetInt("commandchannel", m_commandChannel);
192
193 // m_verbosity = config.Configs["IRC"].GetInt("verbosity", m_verbosity);
194 m_clientReporting = config.Configs["IRC"].GetInt("verbosity", 2) > 0;
195 m_clientReporting = config.Configs["IRC"].GetBoolean("report_clients", m_clientReporting);
196
197 // m_messageOutChannel = config.Configs["IRC"].GetInt("outchannel", m_messageOutChannel);
198 // m_messageInChannel = config.Configs["IRC"].GetInt("inchannel", m_messageInChannel);
199 m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("relay_private_channels", m_relayPrivateChannels);
200 m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("useworldcomm", m_relayPrivateChannels); //compat
201 m_relayChannel = config.Configs["IRC"].GetInt("relay_private_channel_in", m_relayChannel);
202 m_relayChannel = config.Configs["IRC"].GetInt("inchannel", m_relayChannel);
203 m_accessPassword = config.Configs["IRC"].GetString("access_password",m_accessPassword);
204 // m_useWorldComm = config.Configs["IRC"].GetBoolean("useworldcomm", m_useWorldComm);
205
206 if (m_server != null && m_baseNick != null && m_ircChannel != null)
207 {
208 if (m_randomizeNick)
209 {
210 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
211 }
212 m_enabled = true;
213 }
214 }
215 catch (Exception ex)
216 {
217 m_log.Error("[IRCConnector]: Incomplete IRC configuration, skipping IRC bridge configuration");
218 m_log.DebugFormat("[IRCConnector] Incomplete IRC configuration: {0}", ex.ToString());
219 }
220
221 if (null == m_watchdog)
222 {
223 m_watchdog = new Thread(WatchdogRun);
224 m_watchdog.Name = "IRCWatchdog";
225 m_watchdog.IsBackground = true;
226 }
227 }
228
229 public void Start()
230 {
231 if (!m_watchdog.IsAlive)
232 {
233 m_watchdog.Start();
234 ThreadTracker.Add(m_watchdog);
235 }
236 }
237
238 public void AddScene(Scene scene)
239 {
240 lock(m_syncConnect) m_scenes.Add(scene);
241 }
242
243 public bool Connect()
244 {
245 lock (m_syncConnect)
246 {
247 try
248 {
249 if (m_connected) return true;
250
251 m_tcp = new TcpClient(m_server, (int)m_port);
252 m_stream = m_tcp.GetStream();
253 m_reader = new StreamReader(m_stream);
254 m_writer = new StreamWriter(m_stream);
255
256 m_log.DebugFormat("[IRCConnector]: Connected to {0}:{1}", m_server, m_port);
257
258 m_pinger = new Thread(new ThreadStart(PingRun));
259 m_pinger.Name = "PingSenderThread";
260 m_pinger.IsBackground = true;
261 m_pinger.Start();
262 ThreadTracker.Add(m_pinger);
263
264 m_listener = new Thread(new ThreadStart(ListenerRun));
265 m_listener.Name = "IRCConnectorListenerThread";
266 m_listener.IsBackground = true;
267 m_listener.Start();
268 ThreadTracker.Add(m_listener);
269
270 m_writer.WriteLine(m_user);
271 m_writer.Flush();
272 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
273 m_writer.Flush();
274 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
275 m_writer.Flush();
276 m_log.Info("[IRCConnector]: Connection fully established");
277 m_connected = true;
278 }
279 catch (Exception e)
280 {
281 m_log.ErrorFormat("[IRCConnector] cannot connect to {0}:{1}: {2}",
282 m_server, m_port, e.Message);
283 }
284 m_log.Debug("[IRCConnector] Connected");
285 return m_connected;
286 }
287 }
288
289 public void Reconnect()
290 {
291 m_connected = false;
292 try
293 {
294 m_listener.Abort();
295 m_pinger.Abort();
296
297 m_writer.Close();
298 m_reader.Close();
299
300 m_tcp.Close();
301 }
302 catch (Exception)
303 {
304 }
305
306 if (m_enabled)
307 {
308 Connect();
309 }
310 }
311
312 public void PrivMsg(string from, string region, string msg)
313 {
314 m_log.DebugFormat("[IRCConnector] Sending message to IRC from {0}: {1}", from, msg);
315
316 // One message to the IRC server
317 try
318 {
319 m_writer.WriteLine(m_privmsgformat, m_ircChannel, from, region, msg);
320 m_writer.Flush();
321 m_log.InfoFormat("[IRCConnector]: PrivMsg {0} in {1}: {2}", from, region, msg);
322 }
323 catch (IOException)
324 {
325 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)");
326 Reconnect();
327 }
328 catch (Exception ex)
329 {
330 m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString());
331 }
332 }
333
334 public void Send(string msg)
335 {
336 try
337 {
338 m_writer.WriteLine(msg);
339 m_writer.Flush();
340 m_log.Info("IRC: Sent command string: " + msg);
341 }
342 catch (IOException)
343 {
344 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)");
345 Reconnect();
346 }
347 catch (Exception ex)
348 {
349 m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString());
350 }
351
352 }
353
354
355 private Dictionary<string, string> ExtractMsg(string input)
356 {
357 //examines IRC commands and extracts any private messages
358 // which will then be reboadcast in the Sim
359
360 m_log.Info("[IRCConnector]: ExtractMsg: " + input);
361 Dictionary<string, string> result = null;
362 string regex = @":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
363 Regex RE = new Regex(regex, RegexOptions.Multiline);
364 MatchCollection matches = RE.Matches(input);
365
366 // Get some direct matches $1 $4 is a
367 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
368 {
369 // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count);
370 // if (matches.Count > 0)
371 // {
372 // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count);
373 // }
374 return null;
375 }
376
377 result = new Dictionary<string, string>();
378 result.Add("nick", matches[0].Groups[1].Value);
379 result.Add("user", matches[0].Groups[2].Value);
380 result.Add("channel", matches[0].Groups[3].Value);
381 result.Add("msg", matches[0].Groups[4].Value);
382
383 return result;
384 }
385
386 public void PingRun()
387 {
388 // IRC keep alive thread
389 // send PING ever 15 seconds
390 while (m_enabled)
391 {
392 try
393 {
394 if (m_connected == true)
395 {
396 m_writer.WriteLine(String.Format("PING :{0}", m_server));
397 m_writer.Flush();
398 Thread.Sleep(15000);
399 }
400 }
401 catch (IOException)
402 {
403 if (m_enabled)
404 {
405 m_log.Error("[IRCConnector]: Disconnected from IRC server.(PingRun)");
406 Reconnect();
407 }
408 }
409 catch (Exception ex)
410 {
411 m_log.ErrorFormat("[IRCConnector]: PingRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
412 }
413 }
414 }
415
416 static private Vector3 pos = new Vector3(128, 128, 20);
417 public void ListenerRun()
418 {
419 string inputLine;
420
421 while (m_enabled)
422 {
423 try
424 {
425 while ((m_connected) && ((inputLine = m_reader.ReadLine()) != null))
426 {
427 // m_log.Info("[IRCConnector]: " + inputLine);
428
429 if (inputLine.Contains(m_ircChannel))
430 {
431 Dictionary<string, string> data = ExtractMsg(inputLine);
432 // Any chat ???
433 if (data != null)
434 {
435 OSChatMessage c = new OSChatMessage();
436 c.Message = data["msg"];
437 c.Type = ChatTypeEnum.Region;
438 c.Position = pos;
439 c.Channel = m_relayPrivateChannels ? m_relayChannel : 0;
440 c.From = data["nick"];
441 c.Sender = null;
442 c.SenderUUID = UUID.Zero;
443
444 // is message "\001ACTION foo
445 // bar\001"? -> "/me foo bar"
446 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
447 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
448
449 m_log.DebugFormat("[IRCConnector] ListenerRun from: {0}, {1}", c.From, c.Message);
450
451 foreach (Scene scene in m_scenes)
452 {
453 c.Scene = scene;
454 scene.EventManager.TriggerOnChatBroadcast(this, c);
455 }
456 }
457
458 Thread.Sleep(150);
459 continue;
460 }
461
462 ProcessIRCCommand(inputLine);
463 Thread.Sleep(150);
464 }
465 }
466 catch (IOException)
467 {
468 if (m_enabled)
469 {
470 m_log.Error("[IRCConnector]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
471 Reconnect();
472 }
473 }
474 catch (Exception ex)
475 {
476 m_log.ErrorFormat("[IRCConnector]: ListenerRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
477 }
478 }
479 }
480
481 public void BroadcastSim(string sender, string format, params string[] args)
482 {
483 try
484 {
485 OSChatMessage c = new OSChatMessage();
486 c.From = sender;
487 c.Message = String.Format(format, args);
488 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
489 c.Channel = m_relayPrivateChannels ? m_relayChannel : 0;
490 c.Position = new Vector3(128, 128, 20);
491 c.Sender = null;
492 c.SenderUUID = UUID.Zero;
493
494 m_log.DebugFormat("[IRCConnector] BroadcastSim from {0}: {1}", c.From, c.Message);
495
496 foreach (Scene scene in m_scenes)
497 {
498 c.Scene = scene;
499 scene.EventManager.TriggerOnChatBroadcast(this, c);
500 // // m_scene.EventManager.TriggerOnChatFromWorld(this, c);
501 // IWorldComm wComm = m_scene.RequestModuleInterface<IWorldComm>();
502 // wComm.DeliverMessage(ChatTypeEnum.Region, m_messageInChannel, sender, UUID.Zero, c.Message);
503 // //IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
504 // //wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
505
506 }
507 }
508 catch (Exception ex) // IRC gate should not crash Sim
509 {
510 m_log.ErrorFormat("[IRCConnector]: BroadcastSim Exception Trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
511 }
512 }
513
514 public void ProcessIRCCommand(string command)
515 {
516 // m_log.Debug("[IRCConnector]: ProcessIRCCommand:" + command);
517
518 string[] commArgs = new string[command.Split(' ').Length];
519 string c_server = m_server;
520
521 commArgs = command.Split(' ');
522 if (commArgs[0].Substring(0, 1) == ":")
523 {
524 commArgs[0] = commArgs[0].Remove(0, 1);
525 }
526
527 if (commArgs[1] == "002")
528 {
529 // fetch the correct servername
530 // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
531 // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
532
533 c_server = (commArgs[6].Split('['))[0];
534 m_server = c_server;
535 }
536
537 if (commArgs[0] == "ERROR")
538 {
539 m_log.ErrorFormat("[IRCConnector]: IRC SERVER ERROR: {0}", command);
540 }
541
542 if (commArgs[0] == "PING")
543 {
544 string p_reply = "";
545
546 for (int i = 1; i < commArgs.Length; i++)
547 {
548 p_reply += commArgs[i] + " ";
549 }
550
551 m_writer.WriteLine(String.Format("PONG {0}", p_reply));
552 m_writer.Flush();
553 }
554 else if (commArgs[0] == c_server)
555 {
556 // server message
557 try
558 {
559 Int32 commandCode = Int32.Parse(commArgs[1]);
560 switch (commandCode)
561 {
562 case (int)ErrorReplies.NicknameInUse:
563 // Gen a new name
564 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
565 m_log.ErrorFormat("[IRCConnector]: IRC SERVER reports NicknameInUse, trying {0}", m_nick);
566 // Retry
567 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
568 m_writer.Flush();
569 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
570 m_writer.Flush();
571 break;
572 case (int)ErrorReplies.NotRegistered:
573 break;
574 case (int)Replies.EndOfMotd:
575 break;
576 }
577 }
578 catch (Exception)
579 {
580 }
581 }
582 else
583 {
584 // Normal message
585 string commAct = commArgs[1];
586 switch (commAct)
587 {
588 case "JOIN":
589 eventIrcJoin(commArgs);
590 break;
591 case "PART":
592 eventIrcPart(commArgs);
593 break;
594 case "MODE":
595 eventIrcMode(commArgs);
596 break;
597 case "NICK":
598 eventIrcNickChange(commArgs);
599 break;
600 case "KICK":
601 eventIrcKick(commArgs);
602 break;
603 case "QUIT":
604 eventIrcQuit(commArgs);
605 break;
606 case "PONG":
607 break; // that's nice
608 }
609 }
610 }
611
612 public void eventIrcJoin(string[] commArgs)
613 {
614 string IrcChannel = commArgs[2];
615 if (IrcChannel.StartsWith(":"))
616 IrcChannel = IrcChannel.Substring(1);
617 string IrcUser = commArgs[0].Split('!')[0];
618 if (m_clientReporting)
619 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
620 }
621
622 public void eventIrcPart(string[] commArgs)
623 {
624 string IrcChannel = commArgs[2];
625 string IrcUser = commArgs[0].Split('!')[0];
626 if (m_clientReporting)
627 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
628 }
629
630 public void eventIrcMode(string[] commArgs)
631 {
632 string UserMode = "";
633 for (int i = 3; i < commArgs.Length; i++)
634 {
635 UserMode += commArgs[i] + " ";
636 }
637
638 if (UserMode.Substring(0, 1) == ":")
639 {
640 UserMode = UserMode.Remove(0, 1);
641 }
642 }
643
644 public void eventIrcNickChange(string[] commArgs)
645 {
646 string UserOldNick = commArgs[0].Split('!')[0];
647 string UserNewNick = commArgs[2].Remove(0, 1);
648 if (m_clientReporting)
649 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
650 }
651
652 public void eventIrcKick(string[] commArgs)
653 {
654 string UserKicker = commArgs[0].Split('!')[0];
655 string UserKicked = commArgs[3];
656 string IrcChannel = commArgs[2];
657 string KickMessage = "";
658 for (int i = 4; i < commArgs.Length; i++)
659 {
660 KickMessage += commArgs[i] + " ";
661 }
662 if (m_clientReporting)
663 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
664 if (UserKicked == m_nick)
665 {
666 BroadcastSim(m_nick, "Hey, that was me!!!");
667 }
668 }
669
670 public void eventIrcQuit(string[] commArgs)
671 {
672 string IrcUser = commArgs[0].Split('!')[0];
673 string QuitMessage = "";
674
675 for (int i = 2; i < commArgs.Length; i++)
676 {
677 QuitMessage += commArgs[i] + " ";
678 }
679 if (m_clientReporting)
680 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
681 }
682
683 public void Close()
684 {
685 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
686 m_nick, m_ircChannel, m_server));
687 m_writer.Flush();
688
689 m_connected = false;
690 m_enabled = false;
691
692 //listener.Abort();
693 //pingSender.Abort();
694
695 m_writer.Close();
696 m_reader.Close();
697 m_stream.Close();
698 m_tcp.Close();
699 }
700
701 protected void WatchdogRun()
702 {
703 while (m_enabled)
704 {
705 if (!m_connected) Connect();
706 Thread.Sleep(15000);
707 }
708 }
709 }
710} \ No newline at end of file