diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs new file mode 100644 index 0000000..0eb303c --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs | |||
@@ -0,0 +1,710 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net.Sockets; | ||
32 | using System.Reflection; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using System.Threading; | ||
35 | using OpenMetaverse; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Environment.Interfaces; | ||
40 | using OpenSim.Region.Environment.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.Environment.Modules.Avatar.Chat | ||
43 | { | ||
44 | public class IRCConnector | ||
45 | { | ||
46 | #region ErrorReplies enum | ||
47 | |||
48 | public enum ErrorReplies | ||
49 | { | ||
50 | NotRegistered = 451, // ":You have not registered" | ||
51 | NicknameInUse = 433 // "<nick> :Nickname is already in use" | ||
52 | } | ||
53 | |||
54 | #endregion | ||
55 | |||
56 | #region Replies enum | ||
57 | |||
58 | public enum Replies | ||
59 | { | ||
60 | MotdStart = 375, // ":- <server> Message of the day - " | ||
61 | Motd = 372, // ":- <text>" | ||
62 | EndOfMotd = 376 // ":End of /MOTD command" | ||
63 | } | ||
64 | |||
65 | #endregion | ||
66 | |||
67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
68 | |||
69 | private Thread m_listener = null; | ||
70 | private Thread m_watchdog = null; | ||
71 | private Thread m_pinger = null; | ||
72 | |||
73 | private bool m_randomizeNick = true; | ||
74 | |||
75 | public string m_baseNick = null; | ||
76 | private string m_nick = null; | ||
77 | public string Nick | ||
78 | { | ||
79 | get { return m_baseNick; } | ||
80 | set { m_baseNick = value; } | ||
81 | } | ||
82 | |||
83 | private bool m_enabled = false; | ||
84 | public bool Enabled | ||
85 | { | ||
86 | get { return m_enabled; } | ||
87 | } | ||
88 | |||
89 | private bool m_connected = false; | ||
90 | public bool Connected | ||
91 | { | ||
92 | get { return m_connected; } | ||
93 | } | ||
94 | |||
95 | private string m_ircChannel; | ||
96 | public string IrcChannel | ||
97 | { | ||
98 | get { return m_ircChannel; } | ||
99 | |||
100 | set { m_ircChannel = value; } | ||
101 | } | ||
102 | |||
103 | private bool m_relayPrivateChannels = false; | ||
104 | public bool RelayPrivateChannels | ||
105 | { | ||
106 | get { return m_relayPrivateChannels; } | ||
107 | set { m_relayPrivateChannels = value; } | ||
108 | } | ||
109 | |||
110 | private int m_relayChannel = 0; | ||
111 | public int RelayChannel | ||
112 | { | ||
113 | get { return m_relayChannel; } | ||
114 | set { m_relayChannel = value; } | ||
115 | } | ||
116 | |||
117 | private bool m_clientReporting = true; | ||
118 | public bool ClientReporting | ||
119 | { | ||
120 | get { return m_clientReporting; } | ||
121 | set { m_clientReporting = value; } | ||
122 | } | ||
123 | |||
124 | private uint m_port = 6667; | ||
125 | public uint Port | ||
126 | { | ||
127 | get { return m_port; } | ||
128 | set { m_port = value; } | ||
129 | } | ||
130 | |||
131 | private string m_server = null; | ||
132 | public string Server | ||
133 | { | ||
134 | get { return m_server; } | ||
135 | set { m_server = value; } | ||
136 | } | ||
137 | |||
138 | public string m_accessPassword = "badkitty"; | ||
139 | |||
140 | private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"; | ||
141 | private StreamReader m_reader; | ||
142 | private List<Scene> m_scenes = new List<Scene>(); | ||
143 | |||
144 | private NetworkStream m_stream = null; | ||
145 | internal object m_syncConnect = new object(); | ||
146 | private TcpClient m_tcp; | ||
147 | private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot"; | ||
148 | private StreamWriter m_writer; | ||
149 | |||
150 | |||
151 | public IRCConnector(IConfigSource config) | ||
152 | { | ||
153 | m_tcp = null; | ||
154 | m_writer = null; | ||
155 | m_reader = null; | ||
156 | |||
157 | // configuration in OpenSim.ini | ||
158 | // [IRC] | ||
159 | // server = chat.freenode.net | ||
160 | // nick = OSimBot_mysim | ||
161 | // nicknum = true | ||
162 | // ;nicknum set to true appends a 2 digit random number to the nick | ||
163 | // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot | ||
164 | // ; username is the IRC command line sent | ||
165 | // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname> | ||
166 | // channel = #opensim-regions | ||
167 | // port = 6667 | ||
168 | // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message | ||
169 | // ;for <bot>:<user in region> :<message> | ||
170 | // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}" | ||
171 | // ;for <bot>:<message> - <user of region> : | ||
172 | // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}" | ||
173 | // ;for <bot>:<message> - from <user> : | ||
174 | // ;msgformat = "PRIVMSG {0} : {3} - from {1}" | ||
175 | // Traps I/O disconnects so it does not crash the sim | ||
176 | // Trys to reconnect if disconnected and someone says something | ||
177 | // Tells IRC server "QUIT" when doing a close (just to be nice) | ||
178 | // Default port back to 6667 | ||
179 | |||
180 | try | ||
181 | { | ||
182 | m_server = config.Configs["IRC"].GetString("server"); | ||
183 | m_baseNick = config.Configs["IRC"].GetString("nick", "OSimBot"); | ||
184 | |||
185 | m_randomizeNick = config.Configs["IRC"].GetBoolean("randomize_nick", m_randomizeNick); | ||
186 | m_randomizeNick = config.Configs["IRC"].GetBoolean("nicknum", m_randomizeNick); // compat | ||
187 | m_ircChannel = config.Configs["IRC"].GetString("channel"); | ||
188 | m_port = (uint)config.Configs["IRC"].GetInt("port", (int)m_port); | ||
189 | m_user = config.Configs["IRC"].GetString("username", m_user); | ||
190 | m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat); | ||
191 | // m_commandChannel = config.Configs["IRC"].GetInt("commandchannel", m_commandChannel); | ||
192 | |||
193 | // m_verbosity = config.Configs["IRC"].GetInt("verbosity", m_verbosity); | ||
194 | m_clientReporting = config.Configs["IRC"].GetInt("verbosity", 2) > 0; | ||
195 | m_clientReporting = config.Configs["IRC"].GetBoolean("report_clients", m_clientReporting); | ||
196 | |||
197 | // m_messageOutChannel = config.Configs["IRC"].GetInt("outchannel", m_messageOutChannel); | ||
198 | // m_messageInChannel = config.Configs["IRC"].GetInt("inchannel", m_messageInChannel); | ||
199 | m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("relay_private_channels", m_relayPrivateChannels); | ||
200 | m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("useworldcomm", m_relayPrivateChannels); //compat | ||
201 | m_relayChannel = config.Configs["IRC"].GetInt("relay_private_channel_in", m_relayChannel); | ||
202 | m_relayChannel = config.Configs["IRC"].GetInt("inchannel", m_relayChannel); | ||
203 | m_accessPassword = config.Configs["IRC"].GetString("access_password",m_accessPassword); | ||
204 | // m_useWorldComm = config.Configs["IRC"].GetBoolean("useworldcomm", m_useWorldComm); | ||
205 | |||
206 | if (m_server != null && m_baseNick != null && m_ircChannel != null) | ||
207 | { | ||
208 | if (m_randomizeNick) | ||
209 | { | ||
210 | m_nick = m_baseNick + Util.RandomClass.Next(1, 99); | ||
211 | } | ||
212 | m_enabled = true; | ||
213 | } | ||
214 | } | ||
215 | catch (Exception ex) | ||
216 | { | ||
217 | m_log.Error("[IRCConnector]: Incomplete IRC configuration, skipping IRC bridge configuration"); | ||
218 | m_log.DebugFormat("[IRCConnector] Incomplete IRC configuration: {0}", ex.ToString()); | ||
219 | } | ||
220 | |||
221 | if (null == m_watchdog) | ||
222 | { | ||
223 | m_watchdog = new Thread(WatchdogRun); | ||
224 | m_watchdog.Name = "IRCWatchdog"; | ||
225 | m_watchdog.IsBackground = true; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | public void Start() | ||
230 | { | ||
231 | if (!m_watchdog.IsAlive) | ||
232 | { | ||
233 | m_watchdog.Start(); | ||
234 | ThreadTracker.Add(m_watchdog); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | public void AddScene(Scene scene) | ||
239 | { | ||
240 | lock(m_syncConnect) m_scenes.Add(scene); | ||
241 | } | ||
242 | |||
243 | public bool Connect() | ||
244 | { | ||
245 | lock (m_syncConnect) | ||
246 | { | ||
247 | try | ||
248 | { | ||
249 | if (m_connected) return true; | ||
250 | |||
251 | m_tcp = new TcpClient(m_server, (int)m_port); | ||
252 | m_stream = m_tcp.GetStream(); | ||
253 | m_reader = new StreamReader(m_stream); | ||
254 | m_writer = new StreamWriter(m_stream); | ||
255 | |||
256 | m_log.DebugFormat("[IRCConnector]: Connected to {0}:{1}", m_server, m_port); | ||
257 | |||
258 | m_pinger = new Thread(new ThreadStart(PingRun)); | ||
259 | m_pinger.Name = "PingSenderThread"; | ||
260 | m_pinger.IsBackground = true; | ||
261 | m_pinger.Start(); | ||
262 | ThreadTracker.Add(m_pinger); | ||
263 | |||
264 | m_listener = new Thread(new ThreadStart(ListenerRun)); | ||
265 | m_listener.Name = "IRCConnectorListenerThread"; | ||
266 | m_listener.IsBackground = true; | ||
267 | m_listener.Start(); | ||
268 | ThreadTracker.Add(m_listener); | ||
269 | |||
270 | m_writer.WriteLine(m_user); | ||
271 | m_writer.Flush(); | ||
272 | m_writer.WriteLine(String.Format("NICK {0}", m_nick)); | ||
273 | m_writer.Flush(); | ||
274 | m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); | ||
275 | m_writer.Flush(); | ||
276 | m_log.Info("[IRCConnector]: Connection fully established"); | ||
277 | m_connected = true; | ||
278 | } | ||
279 | catch (Exception e) | ||
280 | { | ||
281 | m_log.ErrorFormat("[IRCConnector] cannot connect to {0}:{1}: {2}", | ||
282 | m_server, m_port, e.Message); | ||
283 | } | ||
284 | m_log.Debug("[IRCConnector] Connected"); | ||
285 | return m_connected; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | public void Reconnect() | ||
290 | { | ||
291 | m_connected = false; | ||
292 | try | ||
293 | { | ||
294 | m_listener.Abort(); | ||
295 | m_pinger.Abort(); | ||
296 | |||
297 | m_writer.Close(); | ||
298 | m_reader.Close(); | ||
299 | |||
300 | m_tcp.Close(); | ||
301 | } | ||
302 | catch (Exception) | ||
303 | { | ||
304 | } | ||
305 | |||
306 | if (m_enabled) | ||
307 | { | ||
308 | Connect(); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | public void PrivMsg(string from, string region, string msg) | ||
313 | { | ||
314 | m_log.DebugFormat("[IRCConnector] Sending message to IRC from {0}: {1}", from, msg); | ||
315 | |||
316 | // One message to the IRC server | ||
317 | try | ||
318 | { | ||
319 | m_writer.WriteLine(m_privmsgformat, m_ircChannel, from, region, msg); | ||
320 | m_writer.Flush(); | ||
321 | m_log.InfoFormat("[IRCConnector]: PrivMsg {0} in {1}: {2}", from, region, msg); | ||
322 | } | ||
323 | catch (IOException) | ||
324 | { | ||
325 | m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)"); | ||
326 | Reconnect(); | ||
327 | } | ||
328 | catch (Exception ex) | ||
329 | { | ||
330 | m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString()); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | public void Send(string msg) | ||
335 | { | ||
336 | try | ||
337 | { | ||
338 | m_writer.WriteLine(msg); | ||
339 | m_writer.Flush(); | ||
340 | m_log.Info("IRC: Sent command string: " + msg); | ||
341 | } | ||
342 | catch (IOException) | ||
343 | { | ||
344 | m_log.Error("[IRCConnector]: Disconnected from IRC server.(PrivMsg)"); | ||
345 | Reconnect(); | ||
346 | } | ||
347 | catch (Exception ex) | ||
348 | { | ||
349 | m_log.ErrorFormat("[IRCConnector]: PrivMsg exception trap: {0}", ex.ToString()); | ||
350 | } | ||
351 | |||
352 | } | ||
353 | |||
354 | |||
355 | private Dictionary<string, string> ExtractMsg(string input) | ||
356 | { | ||
357 | //examines IRC commands and extracts any private messages | ||
358 | // which will then be reboadcast in the Sim | ||
359 | |||
360 | m_log.Info("[IRCConnector]: ExtractMsg: " + input); | ||
361 | Dictionary<string, string> result = null; | ||
362 | string regex = @":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)"; | ||
363 | Regex RE = new Regex(regex, RegexOptions.Multiline); | ||
364 | MatchCollection matches = RE.Matches(input); | ||
365 | |||
366 | // Get some direct matches $1 $4 is a | ||
367 | if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5)) | ||
368 | { | ||
369 | // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count); | ||
370 | // if (matches.Count > 0) | ||
371 | // { | ||
372 | // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count); | ||
373 | // } | ||
374 | return null; | ||
375 | } | ||
376 | |||
377 | result = new Dictionary<string, string>(); | ||
378 | result.Add("nick", matches[0].Groups[1].Value); | ||
379 | result.Add("user", matches[0].Groups[2].Value); | ||
380 | result.Add("channel", matches[0].Groups[3].Value); | ||
381 | result.Add("msg", matches[0].Groups[4].Value); | ||
382 | |||
383 | return result; | ||
384 | } | ||
385 | |||
386 | public void PingRun() | ||
387 | { | ||
388 | // IRC keep alive thread | ||
389 | // send PING ever 15 seconds | ||
390 | while (m_enabled) | ||
391 | { | ||
392 | try | ||
393 | { | ||
394 | if (m_connected == true) | ||
395 | { | ||
396 | m_writer.WriteLine(String.Format("PING :{0}", m_server)); | ||
397 | m_writer.Flush(); | ||
398 | Thread.Sleep(15000); | ||
399 | } | ||
400 | } | ||
401 | catch (IOException) | ||
402 | { | ||
403 | if (m_enabled) | ||
404 | { | ||
405 | m_log.Error("[IRCConnector]: Disconnected from IRC server.(PingRun)"); | ||
406 | Reconnect(); | ||
407 | } | ||
408 | } | ||
409 | catch (Exception ex) | ||
410 | { | ||
411 | m_log.ErrorFormat("[IRCConnector]: PingRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | static private Vector3 pos = new Vector3(128, 128, 20); | ||
417 | public void ListenerRun() | ||
418 | { | ||
419 | string inputLine; | ||
420 | |||
421 | while (m_enabled) | ||
422 | { | ||
423 | try | ||
424 | { | ||
425 | while ((m_connected) && ((inputLine = m_reader.ReadLine()) != null)) | ||
426 | { | ||
427 | // m_log.Info("[IRCConnector]: " + inputLine); | ||
428 | |||
429 | if (inputLine.Contains(m_ircChannel)) | ||
430 | { | ||
431 | Dictionary<string, string> data = ExtractMsg(inputLine); | ||
432 | // Any chat ??? | ||
433 | if (data != null) | ||
434 | { | ||
435 | OSChatMessage c = new OSChatMessage(); | ||
436 | c.Message = data["msg"]; | ||
437 | c.Type = ChatTypeEnum.Region; | ||
438 | c.Position = pos; | ||
439 | c.Channel = m_relayPrivateChannels ? m_relayChannel : 0; | ||
440 | c.From = data["nick"]; | ||
441 | c.Sender = null; | ||
442 | c.SenderUUID = UUID.Zero; | ||
443 | |||
444 | // is message "\001ACTION foo | ||
445 | // bar\001"? -> "/me foo bar" | ||
446 | if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION")) | ||
447 | c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9)); | ||
448 | |||
449 | m_log.DebugFormat("[IRCConnector] ListenerRun from: {0}, {1}", c.From, c.Message); | ||
450 | |||
451 | foreach (Scene scene in m_scenes) | ||
452 | { | ||
453 | c.Scene = scene; | ||
454 | scene.EventManager.TriggerOnChatBroadcast(this, c); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | Thread.Sleep(150); | ||
459 | continue; | ||
460 | } | ||
461 | |||
462 | ProcessIRCCommand(inputLine); | ||
463 | Thread.Sleep(150); | ||
464 | } | ||
465 | } | ||
466 | catch (IOException) | ||
467 | { | ||
468 | if (m_enabled) | ||
469 | { | ||
470 | m_log.Error("[IRCConnector]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)"); | ||
471 | Reconnect(); | ||
472 | } | ||
473 | } | ||
474 | catch (Exception ex) | ||
475 | { | ||
476 | m_log.ErrorFormat("[IRCConnector]: ListenerRun exception trap: {0}\n{1}", ex.ToString(), ex.StackTrace); | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | |||
481 | public void BroadcastSim(string sender, string format, params string[] args) | ||
482 | { | ||
483 | try | ||
484 | { | ||
485 | OSChatMessage c = new OSChatMessage(); | ||
486 | c.From = sender; | ||
487 | c.Message = String.Format(format, args); | ||
488 | c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say; | ||
489 | c.Channel = m_relayPrivateChannels ? m_relayChannel : 0; | ||
490 | c.Position = new Vector3(128, 128, 20); | ||
491 | c.Sender = null; | ||
492 | c.SenderUUID = UUID.Zero; | ||
493 | |||
494 | m_log.DebugFormat("[IRCConnector] BroadcastSim from {0}: {1}", c.From, c.Message); | ||
495 | |||
496 | foreach (Scene scene in m_scenes) | ||
497 | { | ||
498 | c.Scene = scene; | ||
499 | scene.EventManager.TriggerOnChatBroadcast(this, c); | ||
500 | // // m_scene.EventManager.TriggerOnChatFromWorld(this, c); | ||
501 | // IWorldComm wComm = m_scene.RequestModuleInterface<IWorldComm>(); | ||
502 | // wComm.DeliverMessage(ChatTypeEnum.Region, m_messageInChannel, sender, UUID.Zero, c.Message); | ||
503 | // //IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); | ||
504 | // //wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text); | ||
505 | |||
506 | } | ||
507 | } | ||
508 | catch (Exception ex) // IRC gate should not crash Sim | ||
509 | { | ||
510 | m_log.ErrorFormat("[IRCConnector]: BroadcastSim Exception Trap: {0}\n{1}", ex.ToString(), ex.StackTrace); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | public void ProcessIRCCommand(string command) | ||
515 | { | ||
516 | // m_log.Debug("[IRCConnector]: ProcessIRCCommand:" + command); | ||
517 | |||
518 | string[] commArgs = new string[command.Split(' ').Length]; | ||
519 | string c_server = m_server; | ||
520 | |||
521 | commArgs = command.Split(' '); | ||
522 | if (commArgs[0].Substring(0, 1) == ":") | ||
523 | { | ||
524 | commArgs[0] = commArgs[0].Remove(0, 1); | ||
525 | } | ||
526 | |||
527 | if (commArgs[1] == "002") | ||
528 | { | ||
529 | // fetch the correct servername | ||
530 | // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/... | ||
531 | // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch | ||
532 | |||
533 | c_server = (commArgs[6].Split('['))[0]; | ||
534 | m_server = c_server; | ||
535 | } | ||
536 | |||
537 | if (commArgs[0] == "ERROR") | ||
538 | { | ||
539 | m_log.ErrorFormat("[IRCConnector]: IRC SERVER ERROR: {0}", command); | ||
540 | } | ||
541 | |||
542 | if (commArgs[0] == "PING") | ||
543 | { | ||
544 | string p_reply = ""; | ||
545 | |||
546 | for (int i = 1; i < commArgs.Length; i++) | ||
547 | { | ||
548 | p_reply += commArgs[i] + " "; | ||
549 | } | ||
550 | |||
551 | m_writer.WriteLine(String.Format("PONG {0}", p_reply)); | ||
552 | m_writer.Flush(); | ||
553 | } | ||
554 | else if (commArgs[0] == c_server) | ||
555 | { | ||
556 | // server message | ||
557 | try | ||
558 | { | ||
559 | Int32 commandCode = Int32.Parse(commArgs[1]); | ||
560 | switch (commandCode) | ||
561 | { | ||
562 | case (int)ErrorReplies.NicknameInUse: | ||
563 | // Gen a new name | ||
564 | m_nick = m_baseNick + Util.RandomClass.Next(1, 99); | ||
565 | m_log.ErrorFormat("[IRCConnector]: IRC SERVER reports NicknameInUse, trying {0}", m_nick); | ||
566 | // Retry | ||
567 | m_writer.WriteLine(String.Format("NICK {0}", m_nick)); | ||
568 | m_writer.Flush(); | ||
569 | m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); | ||
570 | m_writer.Flush(); | ||
571 | break; | ||
572 | case (int)ErrorReplies.NotRegistered: | ||
573 | break; | ||
574 | case (int)Replies.EndOfMotd: | ||
575 | break; | ||
576 | } | ||
577 | } | ||
578 | catch (Exception) | ||
579 | { | ||
580 | } | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | // Normal message | ||
585 | string commAct = commArgs[1]; | ||
586 | switch (commAct) | ||
587 | { | ||
588 | case "JOIN": | ||
589 | eventIrcJoin(commArgs); | ||
590 | break; | ||
591 | case "PART": | ||
592 | eventIrcPart(commArgs); | ||
593 | break; | ||
594 | case "MODE": | ||
595 | eventIrcMode(commArgs); | ||
596 | break; | ||
597 | case "NICK": | ||
598 | eventIrcNickChange(commArgs); | ||
599 | break; | ||
600 | case "KICK": | ||
601 | eventIrcKick(commArgs); | ||
602 | break; | ||
603 | case "QUIT": | ||
604 | eventIrcQuit(commArgs); | ||
605 | break; | ||
606 | case "PONG": | ||
607 | break; // that's nice | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | public void eventIrcJoin(string[] commArgs) | ||
613 | { | ||
614 | string IrcChannel = commArgs[2]; | ||
615 | if (IrcChannel.StartsWith(":")) | ||
616 | IrcChannel = IrcChannel.Substring(1); | ||
617 | string IrcUser = commArgs[0].Split('!')[0]; | ||
618 | if (m_clientReporting) | ||
619 | BroadcastSim(IrcUser, "/me joins {0}", IrcChannel); | ||
620 | } | ||
621 | |||
622 | public void eventIrcPart(string[] commArgs) | ||
623 | { | ||
624 | string IrcChannel = commArgs[2]; | ||
625 | string IrcUser = commArgs[0].Split('!')[0]; | ||
626 | if (m_clientReporting) | ||
627 | BroadcastSim(IrcUser, "/me parts {0}", IrcChannel); | ||
628 | } | ||
629 | |||
630 | public void eventIrcMode(string[] commArgs) | ||
631 | { | ||
632 | string UserMode = ""; | ||
633 | for (int i = 3; i < commArgs.Length; i++) | ||
634 | { | ||
635 | UserMode += commArgs[i] + " "; | ||
636 | } | ||
637 | |||
638 | if (UserMode.Substring(0, 1) == ":") | ||
639 | { | ||
640 | UserMode = UserMode.Remove(0, 1); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | public void eventIrcNickChange(string[] commArgs) | ||
645 | { | ||
646 | string UserOldNick = commArgs[0].Split('!')[0]; | ||
647 | string UserNewNick = commArgs[2].Remove(0, 1); | ||
648 | if (m_clientReporting) | ||
649 | BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick); | ||
650 | } | ||
651 | |||
652 | public void eventIrcKick(string[] commArgs) | ||
653 | { | ||
654 | string UserKicker = commArgs[0].Split('!')[0]; | ||
655 | string UserKicked = commArgs[3]; | ||
656 | string IrcChannel = commArgs[2]; | ||
657 | string KickMessage = ""; | ||
658 | for (int i = 4; i < commArgs.Length; i++) | ||
659 | { | ||
660 | KickMessage += commArgs[i] + " "; | ||
661 | } | ||
662 | if (m_clientReporting) | ||
663 | BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); | ||
664 | if (UserKicked == m_nick) | ||
665 | { | ||
666 | BroadcastSim(m_nick, "Hey, that was me!!!"); | ||
667 | } | ||
668 | } | ||
669 | |||
670 | public void eventIrcQuit(string[] commArgs) | ||
671 | { | ||
672 | string IrcUser = commArgs[0].Split('!')[0]; | ||
673 | string QuitMessage = ""; | ||
674 | |||
675 | for (int i = 2; i < commArgs.Length; i++) | ||
676 | { | ||
677 | QuitMessage += commArgs[i] + " "; | ||
678 | } | ||
679 | if (m_clientReporting) | ||
680 | BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage); | ||
681 | } | ||
682 | |||
683 | public void Close() | ||
684 | { | ||
685 | m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing", | ||
686 | m_nick, m_ircChannel, m_server)); | ||
687 | m_writer.Flush(); | ||
688 | |||
689 | m_connected = false; | ||
690 | m_enabled = false; | ||
691 | |||
692 | //listener.Abort(); | ||
693 | //pingSender.Abort(); | ||
694 | |||
695 | m_writer.Close(); | ||
696 | m_reader.Close(); | ||
697 | m_stream.Close(); | ||
698 | m_tcp.Close(); | ||
699 | } | ||
700 | |||
701 | protected void WatchdogRun() | ||
702 | { | ||
703 | while (m_enabled) | ||
704 | { | ||
705 | if (!m_connected) Connect(); | ||
706 | Thread.Sleep(15000); | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | } \ No newline at end of file | ||