aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs3
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs860
2 files changed, 860 insertions, 3 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
index 37cf328..8216222 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
@@ -65,7 +65,6 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
65 m_scenes.Add(scene); 65 m_scenes.Add(scene);
66 scene.EventManager.OnNewClient += NewClient; 66 scene.EventManager.OnNewClient += NewClient;
67 scene.EventManager.OnChatFromWorld += SimChat; 67 scene.EventManager.OnChatFromWorld += SimChat;
68 // scene.RegisterModuleInterface<ISimChat>(this);
69 } 68 }
70 69
71 // wrap this in a try block so that defaults will work if 70 // wrap this in a try block so that defaults will work if
@@ -108,8 +107,6 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
108 public void SimChat(Object sender, ChatFromViewerArgs e) 107 public void SimChat(Object sender, ChatFromViewerArgs e)
109 { 108 {
110 ScenePresence avatar = null; 109 ScenePresence avatar = null;
111
112 //TODO: Move ForEachScenePresence and others into IScene.
113 Scene scene = (Scene) e.Scene; 110 Scene scene = (Scene) e.Scene;
114 111
115 //TODO: Remove the need for this check 112 //TODO: Remove the need for this check
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
new file mode 100644
index 0000000..0b5f1b4
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
@@ -0,0 +1,860 @@
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 libsecondlife;
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 IRCBridgeModule : IRegionModule, ISimChat
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private const int DEBUG_CHANNEL = 2147483647;
50
51 private string m_defaultzone = null;
52
53 private IRCChatModule m_irc = null;
54 private Thread m_irc_connector = null;
55
56 private string m_last_leaving_user = null;
57 private string m_last_new_user = null;
58 private List<Scene> m_scenes = new List<Scene>();
59
60 internal object m_syncInit = new object();
61 internal object m_syncLogout = new object();
62
63 #region IRegionModule Members
64
65 public void Initialise(Scene scene, IConfigSource config)
66 {
67 lock (m_syncInit)
68 {
69 if (!m_scenes.Contains(scene))
70 {
71 m_scenes.Add(scene);
72 scene.EventManager.OnNewClient += NewClient;
73 scene.EventManager.OnChatFromWorld += SimChat;
74 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
75 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
76 }
77
78 try
79 {
80 m_defaultzone = config.Configs["IRC"].GetString("fallback_region", "Sim");
81 }
82 catch (Exception)
83 {
84 }
85
86 // setup IRC Relay
87 if (m_irc == null)
88 {
89 m_irc = new IRCChatModule(config);
90 }
91 if (m_irc_connector == null)
92 {
93 m_irc_connector = new Thread(IRCConnectRun);
94 m_irc_connector.Name = "IRCConnectorThread";
95 m_irc_connector.IsBackground = true;
96 }
97 m_log.InfoFormat("[IRC] initialized for {0}, nick: {1} ", scene.RegionInfo.RegionName,
98 m_defaultzone);
99 }
100 }
101
102 public void PostInitialise()
103 {
104 if (m_irc.Enabled)
105 {
106 try
107 {
108 //m_irc.Connect(m_scenes);
109 if (m_irc_connector == null)
110 {
111 m_irc_connector = new Thread(IRCConnectRun);
112 m_irc_connector.Name = "IRCConnectorThread";
113 m_irc_connector.IsBackground = true;
114 }
115 if (!m_irc_connector.IsAlive)
116 {
117 m_irc_connector.Start();
118 ThreadTracker.Add(m_irc_connector);
119 }
120 }
121 catch (Exception)
122 {
123 }
124 }
125 }
126
127 public void Close()
128 {
129 m_irc.Close();
130 }
131
132 public string Name
133 {
134 get { return "IRCBridgeModule"; }
135 }
136
137 public bool IsSharedModule
138 {
139 get { return true; }
140 }
141
142 #endregion
143
144 #region ISimChat Members
145
146 public void SimChat(Object sender, ChatFromViewerArgs e)
147 {
148 ScenePresence avatar = null;
149 Scene scene = (Scene) e.Scene;
150
151 if (scene == null)
152 scene = m_scenes[0];
153
154 // Filled in since it's easier than rewriting right now.
155 string fromName = e.From;
156
157 if (e.Sender != null)
158 {
159 avatar = scene.GetScenePresence(e.Sender.AgentId);
160 }
161
162 if (avatar != null)
163 {
164 fromName = avatar.Firstname + " " + avatar.Lastname;
165 }
166
167 // Try to reconnect to server if not connected
168 if (m_irc.Enabled && !m_irc.Connected)
169 {
170 // In a non-blocking way. Eventually the connector will get it started
171 try
172 {
173 if (m_irc_connector == null)
174 {
175 m_irc_connector = new Thread(IRCConnectRun);
176 m_irc_connector.Name = "IRCConnectorThread";
177 m_irc_connector.IsBackground = true;
178 }
179 if (!m_irc_connector.IsAlive)
180 {
181 m_irc_connector.Start();
182 ThreadTracker.Add(m_irc_connector);
183 }
184 }
185 catch (Exception)
186 {
187 }
188 }
189
190
191 // We only want to relay stuff on channel 0
192 if (e.Channel == 0 || e.Channel == DEBUG_CHANNEL)
193 {
194 if (e.Channel == DEBUG_CHANNEL)
195 e.Type = ChatTypeEnum.DebugChannel;
196
197 // IRC stuff
198 if (e.Message.Length > 0 && e.Channel == 0)
199 {
200 if (m_irc.Connected && (avatar != null)) // this is to keep objects from talking to IRC
201 {
202 m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message);
203 }
204 }
205 }
206 }
207
208 #endregion
209
210 public void NewClient(IClientAPI client)
211 {
212 try
213 {
214 string clientName = String.Format("{0} {1}", client.FirstName, client.LastName);
215
216 client.OnChatFromViewer += SimChat;
217 client.OnLogout += ClientLoggedOut;
218 client.OnConnectionClosed += ClientLoggedOut;
219
220 if (clientName != m_last_new_user)
221 {
222 if ((m_irc.Enabled) && (m_irc.Connected))
223 {
224 m_log.DebugFormat("[IRC] {0} logging on", clientName);
225 m_irc.PrivMsg(m_irc.Nick, "Sim",
226 String.Format("notices {0} logging on", clientName));
227 }
228 m_last_new_user = clientName;
229 }
230 }
231 catch (Exception ex)
232 {
233 m_log.Error("[IRC]: NewClient exception trap:" + ex.ToString());
234 }
235 }
236
237 public void OnMakeRootAgent(ScenePresence presence)
238 {
239 try
240 {
241 if ((m_irc.Enabled) && (m_irc.Connected))
242 {
243 string regionName = presence.Scene.RegionInfo.RegionName;
244 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
245 m_log.DebugFormat("[IRC] noticing {0} in {1}", clientName, regionName);
246 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} in {1}", clientName, regionName));
247 }
248 }
249 catch (Exception ex)
250 {
251 }
252 }
253
254 public void OnMakeChildAgent(ScenePresence presence)
255 {
256 try
257 {
258 if ((m_irc.Enabled) && (m_irc.Connected))
259 {
260 string regionName = presence.Scene.RegionInfo.RegionName;
261 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
262 m_log.DebugFormat("[IRC] noticing {0} in {1}", clientName, regionName);
263 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} left {1}", clientName, regionName));
264 }
265 }
266 catch (Exception ex)
267 {
268 }
269 }
270
271
272 public void ClientLoggedOut(IClientAPI client)
273 {
274 lock (m_syncLogout)
275 {
276 try
277 {
278 if ((m_irc.Enabled) && (m_irc.Connected))
279 {
280 string clientName = String.Format("{0} {1}", client.FirstName, client.LastName);
281 // handles simple case. May not work for hundred connecting in per second.
282 // and the NewClients calles getting interleved
283 // but filters out multiple reports
284 if (clientName != m_last_leaving_user)
285 {
286 m_last_leaving_user = clientName;
287 m_irc.PrivMsg(m_irc.Nick, "Sim", String.Format("notices {0} logging out", clientName));
288 m_log.InfoFormat("[IRC]: {0} logging out", clientName);
289 }
290
291 if (m_last_new_user == clientName)
292 m_last_new_user = null;
293 }
294 }
295 catch (Exception ex)
296 {
297 m_log.Error("[IRC]: ClientLoggedOut exception trap:" + ex.ToString());
298 }
299 }
300 }
301
302 // if IRC is enabled then just keep trying using a monitor thread
303 public void IRCConnectRun()
304 {
305 while (true)
306 {
307 if ((m_irc.Enabled) && (!m_irc.Connected))
308 {
309 m_irc.Connect(m_scenes);
310 }
311 Thread.Sleep(15000);
312 }
313 }
314
315 public string FindClientRegion(string firstName, string lastName, bool ignoreChilds)
316 {
317 string sourceRegion = null;
318 foreach (Scene s in m_scenes)
319 {
320 s.ForEachScenePresence(delegate(ScenePresence presence)
321 {
322 if (ignoreChilds
323 && (presence.Firstname == firstName)
324 && (presence.Lastname == lastName))
325 {
326 sourceRegion = presence.Scene.RegionInfo.RegionName;
327 return;
328 }
329
330 if (!ignoreChilds && !presence.IsChildAgent
331 && (presence.Firstname == firstName)
332 && (presence.Lastname == lastName))
333 {
334 sourceRegion = presence.Scene.RegionInfo.RegionName;
335 return;
336 }
337 });
338 if (sourceRegion != null) return sourceRegion;
339 }
340 if (m_defaultzone == null)
341 {
342 m_defaultzone = "Sim";
343 }
344 return m_defaultzone;
345 }
346 }
347
348 internal class IRCChatModule
349 {
350 #region ErrorReplies enum
351
352 public enum ErrorReplies
353 {
354 NotRegistered = 451, // ":You have not registered"
355 NicknameInUse = 433 // "<nick> :Nickname is already in use"
356 }
357
358 #endregion
359
360 #region Replies enum
361
362 public enum Replies
363 {
364 MotdStart = 375, // ":- <server> Message of the day - "
365 Motd = 372, // ":- <text>"
366 EndOfMotd = 376 // ":End of /MOTD command"
367 }
368
369 #endregion
370
371 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
372 private Thread listener;
373
374 private string m_basenick = null;
375 private string m_channel = null;
376 private bool m_connected = false;
377 private bool m_enabled = false;
378 private List<Scene> m_last_scenes = null;
379 private string m_nick = null;
380 private uint m_port = 6668;
381 private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
382 private StreamReader m_reader;
383 private List<Scene> m_scenes = null;
384 private string m_server = null;
385
386 private NetworkStream m_stream;
387 internal object m_syncConnect = new object();
388 private TcpClient m_tcp;
389 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to irc bot";
390 private StreamWriter m_writer;
391
392 private Thread pingSender;
393
394 public IRCChatModule(IConfigSource config)
395 {
396 m_nick = "OSimBot" + Util.RandomClass.Next(1, 99);
397 m_tcp = null;
398 m_writer = null;
399 m_reader = null;
400
401 // configuration in OpenSim.ini
402 // [IRC]
403 // server = chat.freenode.net
404 // nick = OSimBot_mysim
405 // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
406 // ; username is the IRC command line sent
407 // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
408 // channel = #opensim-regions
409 // port = 6667
410 // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
411 // ;for <bot>:<user in region> :<message>
412 // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
413 // ;for <bot>:<message> - <user of region> :
414 // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
415 // ;for <bot>:<message> - from <user> :
416 // ;msgformat = "PRIVMSG {0} : {3} - from {1}"
417 // Traps I/O disconnects so it does not crash the sim
418 // Trys to reconnect if disconnected and someone says something
419 // Tells IRC server "QUIT" when doing a close (just to be nice)
420 // Default port back to 6667
421
422 try
423 {
424 m_server = config.Configs["IRC"].GetString("server");
425 m_nick = config.Configs["IRC"].GetString("nick");
426 m_basenick = m_nick;
427 m_channel = config.Configs["IRC"].GetString("channel");
428 m_port = (uint) config.Configs["IRC"].GetInt("port", (int) m_port);
429 m_user = config.Configs["IRC"].GetString("username", m_user);
430 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
431 if (m_server != null && m_nick != null && m_channel != null)
432 {
433 m_nick = m_nick + Util.RandomClass.Next(1, 99);
434 m_enabled = true;
435 }
436 }
437 catch (Exception)
438 {
439 m_log.Info("[CHAT]: No IRC config information, skipping IRC bridge configuration");
440 }
441 }
442
443 public bool Enabled
444 {
445 get { return m_enabled; }
446 }
447
448 public bool Connected
449 {
450 get { return m_connected; }
451 }
452
453 public string Nick
454 {
455 get { return m_nick; }
456 }
457
458 public bool Connect(List<Scene> scenes)
459 {
460 lock (m_syncConnect)
461 {
462 try
463 {
464 if (m_connected) return true;
465 m_scenes = scenes;
466 if (m_last_scenes == null)
467 {
468 m_last_scenes = scenes;
469 }
470
471 m_tcp = new TcpClient(m_server, (int) m_port);
472 m_log.Info("[IRC]: Connecting...");
473 m_stream = m_tcp.GetStream();
474 m_log.Info("[IRC]: Connected to " + m_server);
475 m_reader = new StreamReader(m_stream);
476 m_writer = new StreamWriter(m_stream);
477
478 pingSender = new Thread(new ThreadStart(PingRun));
479 pingSender.Name = "PingSenderThread";
480 pingSender.IsBackground = true;
481 pingSender.Start();
482 ThreadTracker.Add(pingSender);
483
484 listener = new Thread(new ThreadStart(ListenerRun));
485 listener.Name = "IRCChatModuleListenerThread";
486 listener.IsBackground = true;
487 listener.Start();
488 ThreadTracker.Add(listener);
489
490 m_writer.WriteLine(m_user);
491 m_writer.Flush();
492 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
493 m_writer.Flush();
494 m_writer.WriteLine(String.Format("JOIN {0}", m_channel));
495 m_writer.Flush();
496 m_log.Info("[IRC]: Connection fully established");
497 m_connected = true;
498 }
499 catch (Exception e)
500 {
501 Console.WriteLine(e.ToString());
502 }
503 return m_connected;
504 }
505 }
506
507 public void Reconnect()
508 {
509 m_connected = false;
510 listener.Abort();
511 pingSender.Abort();
512 m_writer.Close();
513 m_reader.Close();
514 m_tcp.Close();
515 if (m_enabled)
516 {
517 Connect(m_last_scenes);
518 }
519 }
520
521 public void PrivMsg(string from, string region, string msg)
522 {
523 // One message to the IRC server
524 try
525 {
526 m_writer.WriteLine(m_privmsgformat, m_channel, from, region, msg);
527 m_writer.Flush();
528 m_log.InfoFormat("[IRC]: PrivMsg {0} in {1}: {2}", from, region, msg);
529 }
530 catch (IOException)
531 {
532 m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)");
533 Reconnect();
534 }
535 catch (Exception ex)
536 {
537 m_log.ErrorFormat("[IRC]: PrivMsg exception trap: {0}", ex.ToString());
538 }
539 }
540
541 private Dictionary<string, string> ExtractMsg(string input)
542 {
543 //examines IRC commands and extracts any private messages
544 // which will then be reboadcast in the Sim
545
546 m_log.Info("[IRC]: ExtractMsg: " + input);
547 Dictionary<string, string> result = null;
548 //string regex = @":(?<nick>\w*)!~(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
549 string regex = @":(?<nick>\w*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
550 Regex RE = new Regex(regex, RegexOptions.Multiline);
551 MatchCollection matches = RE.Matches(input);
552 // Get some direct matches $1 $4 is a
553 if ((matches.Count == 1) && (matches[0].Groups.Count == 5))
554 {
555 result = new Dictionary<string, string>();
556 result.Add("nick", matches[0].Groups[1].Value);
557 result.Add("user", matches[0].Groups[2].Value);
558 result.Add("channel", matches[0].Groups[3].Value);
559 result.Add("msg", matches[0].Groups[4].Value);
560 }
561 else
562 {
563 m_log.Info("[IRC]: Number of matches: " + matches.Count);
564 if (matches.Count > 0)
565 {
566 m_log.Info("[IRC]: Number of groups: " + matches[0].Groups.Count);
567 }
568 }
569 return result;
570 }
571
572 public void PingRun()
573 {
574 // IRC keep alive thread
575 // send PING ever 15 seconds
576 while (true)
577 {
578 try
579 {
580 if (m_connected == true)
581 {
582 m_writer.WriteLine(String.Format("PING :{0}", m_server));
583 m_writer.Flush();
584 Thread.Sleep(15000);
585 }
586 }
587 catch (IOException)
588 {
589 m_log.Error("[IRC]: Disconnected from IRC server.(PingRun)");
590 Reconnect();
591 }
592 catch (Exception ex)
593 {
594 m_log.ErrorFormat("[IRC]: PingRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
595 }
596 }
597 }
598
599 public void ListenerRun()
600 {
601 string inputLine;
602 LLVector3 pos = new LLVector3(128, 128, 20);
603 while (true)
604 {
605 try
606 {
607 while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null))
608 {
609 // Console.WriteLine(inputLine);
610 if (inputLine.Contains(m_channel))
611 {
612 Dictionary<string, string> data = ExtractMsg(inputLine);
613 // Any chat ???
614 if (data != null)
615 {
616 foreach (Scene m_scene in m_scenes)
617 {
618 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
619 {
620 if (!avatar.IsChildAgent)
621 {
622 avatar.ControllingClient.SendChatMessage(
623 Helpers.StringToField(data["msg"]),
624 1, // 255,
625 pos, data["nick"],
626 LLUUID.Zero,(byte)ChatSourceType.Agent,(byte)ChatAudibleLevel.Fully);
627 }
628 });
629 }
630 }
631 else
632 {
633 // Was an command from the IRC server
634 ProcessIRCCommand(inputLine);
635 }
636 }
637 else
638 {
639 // Was an command from the IRC server
640 ProcessIRCCommand(inputLine);
641 }
642 Thread.Sleep(150);
643 }
644 }
645 catch (IOException)
646 {
647 m_log.Error("[IRC]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
648 Reconnect();
649 }
650 catch (Exception ex)
651 {
652 m_log.ErrorFormat("[IRC]: ListenerRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
653 }
654 }
655 }
656
657 public void BroadcastSim(string sender, string format, params string[] args)
658 {
659 LLVector3 pos = new LLVector3(128, 128, 20);
660 try
661 {
662 foreach (Scene m_scene in m_scenes)
663 {
664 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
665 {
666 if (!avatar.IsChildAgent)
667 {
668 avatar.ControllingClient.SendChatMessage(
669 Helpers.StringToField(String.Format(format, args)),
670 1, //255,
671 pos, sender, LLUUID.Zero,
672 (byte)ChatSourceType.Object,
673 (byte)ChatAudibleLevel.Fully);
674 }
675 });
676 }
677 }
678 catch (Exception ex) // IRC gate should not crash Sim
679 {
680 m_log.ErrorFormat("[IRC]: BroadcastSim Exception Trap: {0}\n{1}", ex.ToString(), ex.StackTrace);
681 }
682 }
683
684 public void ProcessIRCCommand(string command)
685 {
686 //m_log.Info("[IRC]: ProcessIRCCommand:" + command);
687
688 string[] commArgs = new string[command.Split(' ').Length];
689 string c_server = m_server;
690
691 commArgs = command.Split(' ');
692 if (commArgs[0].Substring(0, 1) == ":")
693 {
694 commArgs[0] = commArgs[0].Remove(0, 1);
695 }
696
697 if (commArgs[1] == "002")
698 {
699 // fetch the correct servername
700 // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
701 // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
702
703 c_server = (commArgs[6].Split('['))[0];
704 m_server = c_server;
705 }
706
707 if (commArgs[0] == "ERROR")
708 {
709 m_log.ErrorFormat("[IRC]: IRC SERVER ERROR: {0}", command);
710 }
711
712 if (commArgs[0] == "PING")
713 {
714 string p_reply = "";
715
716 for (int i = 1; i < commArgs.Length; i++)
717 {
718 p_reply += commArgs[i] + " ";
719 }
720
721 m_writer.WriteLine(String.Format("PONG {0}", p_reply));
722 m_writer.Flush();
723 }
724 else if (commArgs[0] == c_server)
725 {
726 // server message
727 try
728 {
729 Int32 commandCode = Int32.Parse(commArgs[1]);
730 switch (commandCode)
731 {
732 case (int) ErrorReplies.NicknameInUse:
733 // Gen a new name
734 m_nick = m_basenick + Util.RandomClass.Next(1, 99);
735 m_log.ErrorFormat("[IRC]: IRC SERVER reports NicknameInUse, trying {0}", m_nick);
736 // Retry
737 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
738 m_writer.Flush();
739 m_writer.WriteLine(String.Format("JOIN {0}", m_channel));
740 m_writer.Flush();
741 break;
742 case (int) ErrorReplies.NotRegistered:
743 break;
744 case (int) Replies.EndOfMotd:
745 break;
746 }
747 }
748 catch (Exception)
749 {
750 }
751 }
752 else
753 {
754 // Normal message
755 string commAct = commArgs[1];
756 switch (commAct)
757 {
758 case "JOIN":
759 eventIrcJoin(commArgs);
760 break;
761 case "PART":
762 eventIrcPart(commArgs);
763 break;
764 case "MODE":
765 eventIrcMode(commArgs);
766 break;
767 case "NICK":
768 eventIrcNickChange(commArgs);
769 break;
770 case "KICK":
771 eventIrcKick(commArgs);
772 break;
773 case "QUIT":
774 eventIrcQuit(commArgs);
775 break;
776 case "PONG":
777 break; // that's nice
778 }
779 }
780 }
781
782 public void eventIrcJoin(string[] commArgs)
783 {
784 string IrcChannel = commArgs[2];
785 string IrcUser = commArgs[0].Split('!')[0];
786 BroadcastSim(m_nick, "{0} is joining {1}", IrcUser, IrcChannel);
787 }
788
789 public void eventIrcPart(string[] commArgs)
790 {
791 string IrcChannel = commArgs[2];
792 string IrcUser = commArgs[0].Split('!')[0];
793 BroadcastSim(m_nick, "{0} is parting {1}", IrcUser, IrcChannel);
794 }
795
796 public void eventIrcMode(string[] commArgs)
797 {
798 string IrcChannel = commArgs[2];
799 string IrcUser = commArgs[0].Split('!')[0];
800 string UserMode = "";
801 for (int i = 3; i < commArgs.Length; i++)
802 {
803 UserMode += commArgs[i] + " ";
804 }
805
806 if (UserMode.Substring(0, 1) == ":")
807 {
808 UserMode = UserMode.Remove(0, 1);
809 }
810 }
811
812 public void eventIrcNickChange(string[] commArgs)
813 {
814 string UserOldNick = commArgs[0].Split('!')[0];
815 string UserNewNick = commArgs[2].Remove(0, 1);
816 BroadcastSim(m_nick, "{0} changed their nick to {1}", UserOldNick, UserNewNick);
817 }
818
819 public void eventIrcKick(string[] commArgs)
820 {
821 string UserKicker = commArgs[0].Split('!')[0];
822 string UserKicked = commArgs[3];
823 string IrcChannel = commArgs[2];
824 string KickMessage = "";
825 for (int i = 4; i < commArgs.Length; i++)
826 {
827 KickMessage += commArgs[i] + " ";
828 }
829 BroadcastSim(m_nick, "{0} kicked {1} on {2} saying {3}", UserKicker, UserKicked, IrcChannel, KickMessage);
830 if (UserKicked == m_nick)
831 {
832 BroadcastSim(m_nick, "Hey, that was me!!!");
833 }
834 }
835
836 public void eventIrcQuit(string[] commArgs)
837 {
838 string IrcUser = commArgs[0].Split('!')[0];
839 string QuitMessage = "";
840
841 for (int i = 2; i < commArgs.Length; i++)
842 {
843 QuitMessage += commArgs[i] + " ";
844 }
845 BroadcastSim(m_nick, "{0} quits saying {1}", IrcUser, QuitMessage);
846 }
847
848 public void Close()
849 {
850 m_connected = false;
851 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole with {2} closing", m_nick, m_channel, m_server));
852 m_writer.Flush();
853 listener.Abort();
854 pingSender.Abort();
855 m_writer.Close();
856 m_reader.Close();
857 m_tcp.Close();
858 }
859 }
860} \ No newline at end of file