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