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