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