aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
diff options
context:
space:
mode:
authorDr Scofield2008-05-23 16:07:47 +0000
committerDr Scofield2008-05-23 16:07:47 +0000
commit09188d5d10e279583c0e6074d38a1ac99abb7e43 (patch)
treef2bfcd205cac6657d219d9b20086d362915bf51d /OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
parent*Refactor of the LandManagementModule that allows OpenSim to run without it (diff)
downloadopensim-SC-09188d5d10e279583c0e6074d38a1ac99abb7e43.zip
opensim-SC-09188d5d10e279583c0e6074d38a1ac99abb7e43.tar.gz
opensim-SC-09188d5d10e279583c0e6074d38a1ac99abb7e43.tar.bz2
opensim-SC-09188d5d10e279583c0e6074d38a1ac99abb7e43.tar.xz
IRCBridgeModule (and ChatModule before the refactoring) didn't succeed in
finding out which region a new avatar was logging in to; the same problem occurred when the client/avatar logged out. the reason was mani-fold: - Scene.AddNewClient(...) would call SubscribeToClientEvents(client) which would subscribe to all client events and then call TriggerOnNewClient(...) BEFORE the ScenePresence object had even been created and added. i've moved the TriggerOnNewClient() call to the end of Scene.AddNewClient() - Scene.AddNewClient(...) is called with child == true; a later call to ScenePresence.MakeRootAgent() will turn child to false. When OnNewClient is triggered, child is still true, causing IRCBridgeModule's FindClientRegion to ignore the ScenePresence of the new avatar. i've changed IRCBridgeModule to still use OnNewClient and also OnLogout and OnConnectionClosed but only to signal that the avatar has logged on (logged off respectively). to track whether an avatar has actually entered a region i've added EventManager.OnMakeRootAgent (complementing OnMakeChildAgent). also, i've cleaned up the internal IRCModule code a bit. currently it still uses IClientAPI.SendChatMessage() which replicates the code in ChatModule, that needs to be changed to use TriggerOnChatFromWorld().
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs860
1 files changed, 860 insertions, 0 deletions
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