aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
diff options
context:
space:
mode:
authorDr Scofield2008-11-03 17:17:57 +0000
committerDr Scofield2008-11-03 17:17:57 +0000
commitadd42f5e9b2d58a4978d4aab4440d5cc2d255a12 (patch)
tree1277fc6668ca6e34d58f7c137690f9c885106f71 /OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
parentdropping old IRCBridgeModule. (diff)
downloadopensim-SC_OLD-add42f5e9b2d58a4978d4aab4440d5cc2d255a12.zip
opensim-SC_OLD-add42f5e9b2d58a4978d4aab4440d5cc2d255a12.tar.gz
opensim-SC_OLD-add42f5e9b2d58a4978d4aab4440d5cc2d255a12.tar.bz2
opensim-SC_OLD-add42f5e9b2d58a4978d4aab4440d5cc2d255a12.tar.xz
completing move to refactored multi-channel capable IRCBridgeModule
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs843
1 files changed, 843 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..b9422f3
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
@@ -0,0 +1,843 @@
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.Timers;
30using System.Collections.Generic;
31using System.IO;
32using System.Net.Sockets;
33using System.Reflection;
34using System.Text.RegularExpressions;
35using System.Threading;
36using OpenMetaverse;
37using log4net;
38using Nini.Config;
39using OpenSim.Framework;
40using OpenSim.Region.Environment.Interfaces;
41using OpenSim.Region.Environment.Scenes;
42
43namespace OpenSim.Region.Environment.Modules.Avatar.Chat
44{
45 public class IRCConnector
46 {
47
48 #region Global (static) state
49
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 // Local constants
53
54 private static readonly Vector3 CenterOfRegion = new Vector3(128, 128, 20);
55 private static readonly char[] CS_SPACE = { ' ' };
56
57 private const int WD_INTERVAL = 1000; // base watchdog interval
58 private static int PING_PERIOD = 15; // WD intervals per PING
59 private static int ICCD_PERIOD = 10; // WD intervals between Connects
60
61 private static int _idk_ = 0; // core connector identifier
62 private static int _pdk_ = 0; // ping interval counter
63 private static int _icc_ = 0; // IRC connect counter
64
65 // List of configured connectors
66
67 private static List<IRCConnector> m_connectors = new List<IRCConnector>();
68
69 // Watchdog state
70
71 private static System.Timers.Timer m_watchdog = null;
72
73 static IRCConnector()
74 {
75 m_log.DebugFormat("[IRC-Connector]: Static initialization started");
76 m_watchdog = new System.Timers.Timer(WD_INTERVAL);
77 m_watchdog.Elapsed += new ElapsedEventHandler(WatchdogHandler);
78 m_watchdog.AutoReset = true;
79 m_watchdog.Start();
80 m_log.DebugFormat("[IRC-Connector]: Static initialization complete");
81 }
82
83 #endregion
84
85 #region Instance state
86
87 // Connector identity
88
89 internal int idn = _idk_++;
90
91 // How many regions depend upon this connection
92 // This count is updated by the ChannelState object and reflects the sum
93 // of the region clients associated with the set of associated channel
94 // state instances. That's why it cannot be managed here.
95
96 internal int depends = 0;
97
98 // Working threads
99
100 private Thread m_listener = null;
101
102 private Object msyncConnect = new Object();
103
104 internal bool m_randomizeNick = true; // add random suffix
105 internal string m_baseNick = null; // base name for randomizing
106 internal string m_nick = null; // effective nickname
107
108 public string Nick // Public property
109 {
110 get { return m_nick; }
111 set { m_nick = value; }
112 }
113
114 private bool m_enabled = false; // connector enablement
115 public bool Enabled
116 {
117 get { return m_enabled; }
118 }
119
120 private bool m_connected = false; // connection status
121 public bool Connected
122 {
123 get { return m_connected; }
124 }
125
126 private string m_ircChannel; // associated channel id
127 public string IrcChannel
128 {
129 get { return m_ircChannel; }
130 set { m_ircChannel = value; }
131 }
132
133 private uint m_port = 6667; // session port
134 public uint Port
135 {
136 get { return m_port; }
137 set { m_port = value; }
138 }
139
140 private string m_server = null; // IRC server name
141 public string Server
142 {
143 get { return m_server; }
144 set { m_server = value; }
145 }
146
147 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
148 public string User
149 {
150 get { return m_user; }
151 }
152
153 // Network interface
154
155 private TcpClient m_tcp;
156 private NetworkStream m_stream = null;
157 private StreamReader m_reader;
158 private StreamWriter m_writer;
159
160 // Channel characteristic info (if available)
161
162 internal string usermod = String.Empty;
163 internal string chanmod = String.Empty;
164 internal string version = String.Empty;
165 internal bool motd = false;
166
167 #endregion
168
169 #region connector instance management
170
171 internal IRCConnector(ChannelState cs)
172 {
173
174 // Prepare network interface
175
176 m_tcp = null;
177 m_writer = null;
178 m_reader = null;
179
180 // Setup IRC session parameters
181
182 m_server = cs.Server;
183 m_baseNick = cs.BaseNickname;
184 m_randomizeNick = cs.RandomizeNickname;
185 m_ircChannel = cs.IrcChannel;
186 m_port = (uint) cs.Port;
187 m_user = cs.User;
188
189 if (m_watchdog == null)
190 {
191 // Non-differentiating
192
193 ICCD_PERIOD = cs.ConnectDelay;
194 PING_PERIOD = cs.PingDelay;
195
196 // Smaller values are not reasonable
197
198 if (ICCD_PERIOD < 5)
199 ICCD_PERIOD = 5;
200
201 if (PING_PERIOD < 5)
202 PING_PERIOD = 5;
203
204 _icc_ = ICCD_PERIOD; // get started right away!
205
206 }
207
208 // The last line of defense
209
210 if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
211 throw new Exception("Invalid connector configuration");
212
213 // Generate an initial nickname if randomizing is enabled
214
215 if (m_randomizeNick)
216 {
217 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
218 }
219
220 // Add the newly created connector to the known connectors list
221
222 m_connectors.Add(this);
223
224 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
225
226 }
227
228 ~IRCConnector()
229 {
230 m_watchdog.Stop();
231 Close();
232 }
233
234 // Mark the connector as connectable. Harmless if already enabled.
235
236 public void Open()
237 {
238 if (!m_enabled)
239 {
240
241 m_connectors.Add(this);
242 m_enabled = true;
243
244 if (!Connected)
245 {
246 Connect();
247 }
248
249 }
250 }
251
252 // Only close the connector if the dependency count is zero.
253
254 public void Close()
255 {
256
257 m_log.InfoFormat("[IRC-Connector-{0}] Closing", idn);
258
259 lock (msyncConnect)
260 {
261
262 if ((depends == 0) && Enabled)
263 {
264
265 m_enabled = false;
266
267 if (Connected)
268 {
269 m_log.DebugFormat("[IRC-Connector-{0}] Closing interface", idn);
270
271 // Cleanup the IRC session
272
273 try
274 {
275 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
276 m_nick, m_ircChannel, m_server));
277 m_writer.Flush();
278 }
279 catch (Exception) {}
280
281
282 m_connected = false;
283
284 try { m_writer.Close(); } catch (Exception) {}
285 try { m_reader.Close(); } catch (Exception) {}
286 try { m_stream.Close(); } catch (Exception) {}
287 try { m_tcp.Close(); } catch (Exception) {}
288
289 }
290
291 m_connectors.Remove(this);
292
293 }
294 }
295
296 m_log.InfoFormat("[IRC-Connector-{0}] Closed", idn);
297
298 }
299
300 #endregion
301
302 #region session management
303
304 // Connect to the IRC server. A connector should always be connected, once enabled
305
306 public void Connect()
307 {
308
309 if (!m_enabled)
310 return;
311
312 // Delay until next WD cycle if this is too close to the last start attempt
313
314 while (_icc_ < ICCD_PERIOD)
315 return;
316
317 m_log.DebugFormat("[IRC-Connector-{0}]: Connection request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
318
319 lock (msyncConnect)
320 {
321
322 _icc_ = 0;
323
324 try
325 {
326 if (m_connected) return;
327
328 m_connected = true;
329
330 m_tcp = new TcpClient(m_server, (int)m_port);
331 m_stream = m_tcp.GetStream();
332 m_reader = new StreamReader(m_stream);
333 m_writer = new StreamWriter(m_stream);
334
335 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
336
337 m_listener = new Thread(new ThreadStart(ListenerRun));
338 m_listener.Name = "IRCConnectorListenerThread";
339 m_listener.IsBackground = true;
340 m_listener.Start();
341 ThreadTracker.Add(m_listener);
342
343 // This is the message order recommended by RFC 2812
344
345 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
346 m_writer.Flush();
347 m_writer.WriteLine(m_user);
348 m_writer.Flush();
349 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
350 m_writer.Flush();
351
352 m_log.InfoFormat("[IRC-Connector-{0}]: {1} has joined {2}", idn, m_nick, m_ircChannel);
353 m_log.InfoFormat("[IRC-Connector-{0}] Connected", idn);
354
355 }
356 catch (Exception e)
357 {
358 m_log.ErrorFormat("[IRC-Connector-{0}] cannot connect {1} to {2}:{3}: {4}",
359 idn, m_nick, m_server, m_port, e.Message);
360 m_connected = false;
361 }
362
363 }
364
365 return;
366
367 }
368
369 // Reconnect is used to force a re-cycle of the IRC connection. Should generally
370 // be a transparent event
371
372 public void Reconnect()
373 {
374
375 m_log.DebugFormat("[IRC-Connector-{0}]: Reconnect request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
376
377 // Don't do this if a Connect is in progress...
378
379 lock (msyncConnect)
380 {
381
382 if (m_connected)
383 {
384 m_log.InfoFormat("[IRC-Connector-{0}] Resetting connector", idn);
385
386 // Mark as disconnected. This will allow the listener thread
387 // to exit if still in-flight.
388
389
390 // The listener thread is not aborted - it *might* actually be
391 // the thread that is running the Reconnect! Instead just close
392 // the socket and it will disappear of its own accord, once this
393 // processing is completed.
394
395 try { m_writer.Close(); } catch (Exception) {}
396 try { m_reader.Close(); } catch (Exception) {}
397 try { m_tcp.Close(); } catch (Exception) {}
398
399 m_connected = false;
400
401 }
402
403 }
404
405 Connect();
406
407 }
408
409 #endregion
410
411 #region Outbound (to-IRC) message handlers
412
413 public void PrivMsg(string pattern, string from, string region, string msg)
414 {
415
416 m_log.DebugFormat("[IRC-Connector-{0}] PrivMsg to IRC from {1}: <{2}>", idn, from,
417 String.Format(pattern, m_ircChannel, from, region, msg));
418
419 // One message to the IRC server
420
421 try
422 {
423 m_writer.WriteLine(pattern, m_ircChannel, from, region, msg);
424 m_writer.Flush();
425 m_log.DebugFormat("[IRC-Connector-{0}]: PrivMsg from {1} in {2}: {3}", idn, from, region, msg);
426 }
427 catch (IOException)
428 {
429 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg I/O Error: disconnected from IRC server", idn);
430 Reconnect();
431 }
432 catch (Exception ex)
433 {
434 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg exception : {1}", idn, ex.Message);
435 m_log.Debug(ex);
436 }
437
438 }
439
440 public void Send(string msg)
441 {
442
443 m_log.DebugFormat("[IRC-Connector-{0}] Send to IRC : <{1}>", idn, msg);
444
445 try
446 {
447 m_writer.WriteLine(msg);
448 m_writer.Flush();
449 m_log.DebugFormat("[IRC-Connector-{0}] Sent command string: {1}", idn, msg);
450 }
451 catch (IOException)
452 {
453 m_log.ErrorFormat("[IRC-Connector-{0}] Disconnected from IRC server.(Send)", idn);
454 Reconnect();
455 }
456 catch (Exception ex)
457 {
458 m_log.ErrorFormat("[IRC-Connector-{0}] Send exception trap: {0}", idn, ex.Message);
459 m_log.Debug(ex);
460 }
461
462 }
463
464 #endregion
465
466 public void ListenerRun()
467 {
468 string inputLine;
469
470 try
471 {
472 while (m_enabled && m_connected)
473 {
474
475 if ((inputLine = m_reader.ReadLine()) == null)
476 throw new Exception("Listener input socket closed");
477
478 // m_log.Info("[IRCConnector]: " + inputLine);
479
480 if (inputLine.Contains("PRIVMSG"))
481 {
482
483 Dictionary<string, string> data = ExtractMsg(inputLine);
484
485 // Any chat ???
486 if (data != null)
487 {
488
489 OSChatMessage c = new OSChatMessage();
490 c.Message = data["msg"];
491 c.Type = ChatTypeEnum.Region;
492 c.Position = CenterOfRegion;
493 c.From = data["nick"];
494 c.Sender = null;
495 c.SenderUUID = UUID.Zero;
496
497 // Is message "\001ACTION foo bar\001"?
498 // Then change to: "/me foo bar"
499
500 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
501 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
502
503 ChannelState.OSChat(this, c, false);
504
505 }
506
507 }
508 else
509 {
510 ProcessIRCCommand(inputLine);
511 }
512 }
513 }
514 catch (Exception /*e*/)
515 {
516 // m_log.ErrorFormat("[IRC-Connector-{0}]: ListenerRun exception trap: {1}", idn, e.Message);
517 // m_log.Debug(e);
518 }
519
520 if (m_enabled) Reconnect();
521
522 }
523
524 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
525 RegexOptions.Multiline);
526
527 private Dictionary<string, string> ExtractMsg(string input)
528 {
529 //examines IRC commands and extracts any private messages
530 // which will then be reboadcast in the Sim
531
532 // m_log.InfoFormat("[IRC-Connector-{0}]: ExtractMsg: {1}", idn, input);
533
534 Dictionary<string, string> result = null;
535 MatchCollection matches = RE.Matches(input);
536
537 // Get some direct matches $1 $4 is a
538 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
539 {
540 // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count);
541 // if (matches.Count > 0)
542 // {
543 // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count);
544 // }
545 return null;
546 }
547
548 result = new Dictionary<string, string>();
549 result.Add("nick", matches[0].Groups[1].Value);
550 result.Add("user", matches[0].Groups[2].Value);
551 result.Add("channel", matches[0].Groups[3].Value);
552 result.Add("msg", matches[0].Groups[4].Value);
553
554 return result;
555 }
556
557 public void BroadcastSim(string sender, string format, params string[] args)
558 {
559 try
560 {
561 OSChatMessage c = new OSChatMessage();
562 c.From = sender;
563 c.Message = String.Format(format, args);
564 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
565 c.Position = CenterOfRegion;
566 c.Sender = null;
567 c.SenderUUID = UUID.Zero;
568
569 ChannelState.OSChat(this, c, true);
570
571 }
572 catch (Exception ex) // IRC gate should not crash Sim
573 {
574 m_log.ErrorFormat("[IRC-Connector-{0}]: BroadcastSim Exception Trap: {1}\n{2}", idn, ex.Message, ex.StackTrace);
575 }
576 }
577
578 #region IRC Command Handlers
579
580 public void ProcessIRCCommand(string command)
581 {
582
583 string[] commArgs;
584 string c_server = m_server;
585
586 string pfx = String.Empty;
587 string cmd = String.Empty;
588 string parms = String.Empty;
589
590 // ":" indicates that a prefix is present
591 // There are NEVER more than 17 real
592 // fields. A parameter that starts with
593 // ":" indicates that the remainder of the
594 // line is a single parameter value.
595
596 commArgs = command.Split(CS_SPACE,2);
597
598 if (commArgs[0].StartsWith(":"))
599 {
600 pfx = commArgs[0].Substring(1);
601 commArgs = commArgs[1].Split(CS_SPACE,2);
602 }
603
604 cmd = commArgs[0];
605 parms = commArgs[1];
606
607 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
608
609 switch (cmd)
610 {
611
612 // Messages 001-004 are always sent
613 // following signon.
614
615 case "001" : // Welcome ...
616 case "002" : // Server information
617 case "003" : // Welcome ...
618 break;
619 case "004" : // Server information
620 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
621 commArgs = parms.Split(CS_SPACE);
622 c_server = commArgs[1];
623 m_server = c_server;
624 version = commArgs[2];
625 usermod = commArgs[3];
626 chanmod = commArgs[4];
627 break;
628 case "005" : // Server information
629 break;
630 case "042" :
631 case "250" :
632 case "251" :
633 case "252" :
634 case "254" :
635 case "255" :
636 case "265" :
637 case "266" :
638 case "332" : // Subject
639 case "333" : // Subject owner (?)
640 case "353" : // Name list
641 case "366" : // End-of-Name list marker
642 case "372" : // MOTD body
643 case "375" : // MOTD start
644 m_log.InfoFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]);
645 break;
646 case "376" : // MOTD end
647 m_log.InfoFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]);
648 motd = true;
649 break;
650 case "451" : // Not registered
651 break;
652 case "433" : // Nickname in use
653 // Gen a new name
654 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
655 m_log.ErrorFormat("[IRC-Connector-{0}]: IRC SERVER reports NicknameInUse, trying {1}", idn, m_nick);
656 // Retry
657 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
658 m_writer.Flush();
659 m_writer.WriteLine(m_user);
660 m_writer.Flush();
661 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
662 m_writer.Flush();
663 break;
664 case "NOTICE" :
665 m_log.WarnFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]);
666 break;
667 case "ERROR" :
668 m_log.ErrorFormat("[IRC-Connector-{0}] {1}", idn, parms.Split(CS_SPACE,2)[1]);
669 if (parms.Contains("reconnect too fast"))
670 ICCD_PERIOD++;
671 break;
672 case "PING" :
673 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
674 m_writer.WriteLine(String.Format("PONG {0}", parms));
675 m_writer.Flush();
676 break;
677 case "PONG" :
678 break;
679 case "JOIN":
680 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
681 eventIrcJoin(pfx, cmd, parms);
682 break;
683 case "PART":
684 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
685 eventIrcPart(pfx, cmd, parms);
686 break;
687 case "MODE":
688 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
689 eventIrcMode(pfx, cmd, parms);
690 break;
691 case "NICK":
692 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
693 eventIrcNickChange(pfx, cmd, parms);
694 break;
695 case "KICK":
696 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
697 eventIrcKick(pfx, cmd, parms);
698 break;
699 case "QUIT":
700 m_log.DebugFormat("[IRC-Connector-{0}] parms = <{1}>", idn, parms);
701 eventIrcQuit(pfx, cmd, parms);
702 break;
703 default :
704 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
705 break;
706 }
707
708 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
709
710 }
711
712 public void eventIrcJoin(string prefix, string command, string parms)
713 {
714 string[] args = parms.Split(CS_SPACE,2);
715 string IrcUser = prefix.Split('!')[0];
716 string IrcChannel = args[0];
717
718 if (IrcChannel.StartsWith(":"))
719 IrcChannel = IrcChannel.Substring(1);
720
721 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCJoin {1}:{2}", idn, m_server, m_ircChannel);
722 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
723 }
724
725 public void eventIrcPart(string prefix, string command, string parms)
726 {
727 string[] args = parms.Split(CS_SPACE,2);
728 string IrcUser = prefix.Split('!')[0];
729 string IrcChannel = args[0];
730
731 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
732 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
733 }
734
735 public void eventIrcMode(string prefix, string command, string parms)
736 {
737 string[] args = parms.Split(CS_SPACE,2);
738 string UserMode = args[1];
739
740 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
741 if (UserMode.Substring(0, 1) == ":")
742 {
743 UserMode = UserMode.Remove(0, 1);
744 }
745 }
746
747 public void eventIrcNickChange(string prefix, string command, string parms)
748 {
749 string[] args = parms.Split(CS_SPACE,2);
750 string UserOldNick = prefix.Split('!')[0];
751 string UserNewNick = args[0].Remove(0, 1);
752
753 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCNickChange {1}:{2}", idn, m_server, m_ircChannel);
754 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
755 }
756
757 public void eventIrcKick(string prefix, string command, string parms)
758 {
759 string[] args = parms.Split(CS_SPACE,3);
760 string UserKicker = prefix.Split('!')[0];
761 string IrcChannel = args[0];
762 string UserKicked = args[1];
763 string KickMessage = args[2];
764
765 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
766 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
767
768 if (UserKicked == m_nick)
769 {
770 BroadcastSim(m_nick, "Hey, that was me!!!");
771 }
772
773 }
774
775 public void eventIrcQuit(string prefix, string command, string parms)
776 {
777 string IrcUser = prefix.Split('!')[0];
778 string QuitMessage = parms;
779
780 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
781 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
782 }
783
784 #endregion
785
786 #region Connector Watch Dog
787
788 // A single watch dog monitors extant connectors and makes sure that they
789 // are re-connected as necessary. If a connector IS connected, then it is
790 // pinged, but only if a PING period has elapsed.
791
792 protected static void WatchdogHandler(Object source, ElapsedEventArgs args)
793 {
794
795 // m_log.InfoFormat("[IRC-Watchdog] Status scan");
796
797 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger
798 _icc_++; // increment the inter-consecutive-connect-delay counter
799
800 foreach (IRCConnector connector in m_connectors)
801 {
802 if (connector.Enabled)
803 {
804 if (!connector.Connected)
805 {
806 try
807 {
808 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
809 connector.Connect();
810 }
811 catch (Exception e)
812 {
813 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
814 }
815 }
816 else
817 {
818 if (_pdk_ == 0)
819 {
820 try
821 {
822 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
823 connector.m_writer.Flush();
824 }
825 catch (Exception /*e*/)
826 {
827 // m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
828 // m_log.Debug(e);
829 connector.Reconnect();
830 }
831 }
832 }
833 }
834 }
835
836 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
837
838 }
839
840 #endregion
841
842 }
843}