void HandleMessage([NotNull] string message) { if (message == null) { throw new ArgumentNullException("message"); } IRCMessage msg = MessageParser(message, ActualBotNick); #if DEBUG_IRC Logger.Log(LogType.IRC, "[{0}]: {1}", msg.Type, msg.RawMessage); #endif switch (msg.Type) { case IRCMessageType.Login: if (ConfigKey.IRCRegisteredNick.Enabled()) { Send(IRCCommands.Privmsg(ConfigKey.IRCNickServ.GetString(), ConfigKey.IRCNickServMessage.GetString())); } foreach (string channel in channelNames) { Send(IRCCommands.Join(channel)); } IsReady = true; AssignBotForInputParsing(); // bot should be ready to receive input after joining return; case IRCMessageType.Ping: // ping-pong Send(IRCCommands.Pong(msg.RawMessageArray[1].Substring(1))); return; case IRCMessageType.ChannelAction: case IRCMessageType.ChannelMessage: // channel chat if (!ResponsibleForInputParsing) { return; } if (!IsBotNick(msg.Nick)) { string processedMessage = msg.Message; if (msg.Type == IRCMessageType.ChannelAction) { if (processedMessage.StartsWith("\u0001ACTION")) { processedMessage = processedMessage.Substring(8); } else { return; } } processedMessage = NonPrintableChars.Replace(processedMessage, ""); if (processedMessage.Length > 0) { if (ConfigKey.IRCBotForwardFromIRC.Enabled()) { if (msg.Type == IRCMessageType.ChannelAction) { Server.Message("&i(IRC) * {0} {1}", msg.Nick, processedMessage); } else { Server.Message("&i(IRC) {0}{1}: {2}", msg.Nick, Color.White, processedMessage); } } else if (msg.Message.StartsWith("#")) { Server.Message("&i(IRC) {0}{1}: {2}", msg.Nick, Color.White, processedMessage.Substring(1)); } } } return; case IRCMessageType.Join: if (!ResponsibleForInputParsing) { return; } if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled()) { Server.Message("&i(IRC) {0} joined {1}", msg.Nick, msg.Channel); } return; case IRCMessageType.Kick: string kicked = msg.RawMessageArray[3]; if (kicked == ActualBotNick) { Logger.Log(LogType.IRC, "Bot was kicked from {0} by {1} ({2}), rejoining.", msg.Channel, msg.Nick, msg.Message); Thread.Sleep(ReconnectDelay); Send(IRCCommands.Join(msg.Channel)); } else { if (!ResponsibleForInputParsing) { return; } Server.Message("&i(IRC) {0} kicked {1} from {2} ({3})", msg.Nick, kicked, msg.Channel, msg.Message); } return; case IRCMessageType.Part: case IRCMessageType.Quit: if (!ResponsibleForInputParsing) { return; } if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled()) { Server.Message("&i(IRC) {0} left {1}", msg.Nick, msg.Channel); } return; case IRCMessageType.NickChange: if (!ResponsibleForInputParsing) { return; } Server.Message("&i(IRC) {0} is now known as {1}", msg.Nick, msg.Message); return; case IRCMessageType.ErrorMessage: case IRCMessageType.Error: bool die = false; switch (msg.ReplyCode) { case IRCReplyCode.ErrorNicknameInUse: case IRCReplyCode.ErrorNicknameCollision: Logger.Log(LogType.IRC, "Error: Nickname \"{0}\" is already in use. Trying \"{0}_\"", ActualBotNick); ActualBotNick += "_"; Send(IRCCommands.Nick(ActualBotNick)); break; case IRCReplyCode.ErrorBannedFromChannel: case IRCReplyCode.ErrorNoSuchChannel: Logger.Log(LogType.IRC, "Error: {0} ({1})", msg.ReplyCode, msg.Channel); die = true; break; case IRCReplyCode.ErrorBadChannelKey: Logger.Log(LogType.IRC, "Error: Channel password required for {0}. fCraft does not currently support passworded channels.", msg.Channel); die = true; break; default: Logger.Log(LogType.IRC, "Error ({0}): {1}", msg.ReplyCode, msg.RawMessage); break; } if (die) { Logger.Log(LogType.IRC, "Error: Disconnecting."); reconnect = false; DisconnectThread(); } return; case IRCMessageType.QueryAction: // TODO: PMs Logger.Log(LogType.IRC, "Query: {0}", msg.RawMessage); break; case IRCMessageType.Kill: Logger.Log(LogType.IRC, "Bot was killed from {0} by {1} ({2}), reconnecting.", hostName, msg.Nick, msg.Message); reconnect = true; isConnected = false; return; } }
// runs in its own thread, started from Connect() void IoThread() { string outputLine = ""; lastMessageSent = DateTime.UtcNow; do { try { ActualBotNick = desiredBotNick; reconnect = false; Logger.Log(LogType.IRC, "Connecting to {0}:{1} as {2}", hostName, port, ActualBotNick); Connect(); // register Send(IRCCommands.User(ActualBotNick, 8, ConfigKey.ServerName.GetString())); Send(IRCCommands.Nick(ActualBotNick)); while (isConnected && !reconnect) { Thread.Sleep(10); if (localQueue.Length > 0 && DateTime.UtcNow.Subtract(lastMessageSent).TotalMilliseconds >= SendDelay && localQueue.Dequeue(ref outputLine)) { writer.Write(outputLine + "\r\n"); lastMessageSent = DateTime.UtcNow; writer.Flush(); } if (OutputQueue.Length > 0 && DateTime.UtcNow.Subtract(lastMessageSent).TotalMilliseconds >= SendDelay && OutputQueue.Dequeue(ref outputLine)) { writer.Write(outputLine + "\r\n"); lastMessageSent = DateTime.UtcNow; writer.Flush(); } if (client.Client.Available > 0) { string line = reader.ReadLine(); if (line == null) { break; } HandleMessage(line); } } } catch (SocketException) { Logger.Log(LogType.Warning, "IRC: Disconnected. Will retry in {0} seconds.", ReconnectDelay / 1000); reconnect = true; } catch (IOException) { Logger.Log(LogType.Warning, "IRC: Disconnected. Will retry in {0} seconds.", ReconnectDelay / 1000); reconnect = true; #if !DEBUG } catch (Exception ex) { Logger.Log(LogType.Error, "IRC: {0}", ex); reconnect = true; #endif } if (reconnect) { Thread.Sleep(ReconnectDelay); } } while(reconnect); }
// runs in its own thread, started from Connect() void IoThread() { string outputLine = ""; lastMessageSent = DateTime.UtcNow; do { try { ActualBotNick = desiredBotNick; reconnect = false; Logger.Log(LogType.SystemActivity, "Connecting to LegendCraft Global Chat as {2}", hostName, port, ActualBotNick); if (ActualBotNick == "Custom Minecraft Server (LegendCraft)") { Logger.Log(LogType.Error, "You must set a server name to connect to global chat."); reconnect = false; DisconnectThread(); } else { Connect(); } // register Send(IRCCommands.User(ActualBotNick, 8, ConfigKey.ServerName.GetString())); Send(IRCCommands.Nick(ActualBotNick)); while (isConnected && !reconnect) { Thread.Sleep(10); if (localQueue.Count > 0 && DateTime.UtcNow.Subtract(lastMessageSent).TotalMilliseconds >= SendDelay && localQueue.TryDequeue(out outputLine)) { writer.Write(outputLine + "\r\n"); lastMessageSent = DateTime.UtcNow; writer.Flush(); } if (OutputQueue.Count > 0 && DateTime.UtcNow.Subtract(lastMessageSent).TotalMilliseconds >= SendDelay && OutputQueue.TryDequeue(out outputLine)) { writer.Write(outputLine + "\r\n"); lastMessageSent = DateTime.UtcNow; writer.Flush(); } if (client.Client.Available > 0) { string line = reader.ReadLine(); if (line == null) { break; } HandleMessage(line); } } } catch (SocketException) { Logger.Log(LogType.Warning, "GlobalChat: Socket Error. Disconnected. Will retry in {0} seconds.", ReconnectDelay / 1000); reconnect = true; } catch (IOException) { Logger.Log(LogType.Warning, "GlobalChat: IO Error. Disconnected. Will retry in {0} seconds.", ReconnectDelay / 1000); reconnect = true; #if !DEBUG } catch (Exception ex) { Logger.Log(LogType.Error, "GlobalChat: {0}", ex); reconnect = true; #endif } if (reconnect) { Thread.Sleep(ReconnectDelay); } } while (reconnect); }
void HandleMessage([NotNull] string message) { if (message == null) { throw new ArgumentNullException("message"); } IRCMessage msg = IRC.MessageParser(message, ActualBotNick); var SendList = Server.Players.Where(p => !p.IsDeaf && !p.GlobalChatIgnore); #if DEBUG_IRC Logger.Log(LogType.IRC, "[{0}]: {1}", msg.Type, msg.RawMessage); #endif switch (msg.Type) { case IRCMessageType.Login: foreach (string channel in channelNames) { Send(IRCCommands.Join(channel)); } IsReady = true; AssignBotForInputParsing(); // bot should be ready to receive input after joining return; case IRCMessageType.Ping: // ping-pong Send(IRCCommands.Pong(msg.RawMessageArray[1].Substring(1))); return; case IRCMessageType.ChannelAction: case IRCMessageType.ChannelMessage: // channel chat if (!ResponsibleForInputParsing) { return; } string processedMessage = msg.Message; if (msg.Type == IRCMessageType.ChannelAction) { if (processedMessage.StartsWith("\u0001ACTION")) { processedMessage = processedMessage.Substring(8); } else { return; } } processedMessage = IRC.NonPrintableChars.Replace(processedMessage, ""); if (processedMessage.Length > 0) { if (msg.Type == IRCMessageType.ChannelAction) { SendList.Message("&g[Global] * {1} {2}", ActualBotNick, msg.Nick, processedMessage); Logger.Log(LogType.GlobalChat, "[Global] * {1} {2}", ActualBotNick, msg.Nick, processedMessage); } else { SendList.Message("&g[Global] {1}: {2}", ActualBotNick, msg.Nick, processedMessage); Logger.Log(LogType.GlobalChat, "[Global] {1}: {2}", ActualBotNick, msg.Nick, processedMessage); } } else if (msg.Message.StartsWith("#")) { SendList.Message("&g[Global] {1}: {2}", ActualBotNick, msg.Nick, processedMessage.Substring(1)); Logger.Log(LogType.GlobalChat, "[Global] {1}: {2}", ActualBotNick, msg.Nick, processedMessage.Substring(1)); } return; case IRCMessageType.Join: if (!ResponsibleForInputParsing) { return; } if (msg.Nick.StartsWith("(")) { SendList.Message("&g[Global] Server {0} joined the LegendCraft Global Chat", msg.Nick); Logger.Log(LogType.GlobalChat, "[Global] Server {0} joined the LegendCraft Global Chat", msg.Nick); } else { SendList.Message("&g[Global] {0} joined the LegendCraft Global Chat", msg.Nick); Logger.Log(LogType.GlobalChat, "[Global] {0} joined the LegendCraft Global Chat", msg.Nick); } return; case IRCMessageType.Kick: string kicked = msg.RawMessageArray[3]; if (kicked == ActualBotNick) { Logger.Log(LogType.SystemActivity, "Bot was kicked from {0} by {1} ({2}), rejoining.", msg.Channel, msg.Nick, msg.Message); Thread.Sleep(ReconnectDelay); Send(IRCCommands.Join(msg.Channel)); } else { if (!ResponsibleForInputParsing) { return; } SendList.Message("&g[Global] {0} kicked {1} ({2})", msg.Nick, kicked, msg.Message); Logger.Log(LogType.GlobalChat, "[Global] {0} kicked {1} ({2})", msg.Nick, kicked, msg.Message); } return; case IRCMessageType.Part: case IRCMessageType.Quit: if (!ResponsibleForInputParsing) { return; } SendList.Message("&g[Global] Server {0} left the LegendCraft Global Chat", msg.Nick); Logger.Log(LogType.GlobalChat, "[Global] Server {0} left the LegendCraft Global Chat", msg.Nick); return; case IRCMessageType.NickChange: if (!ResponsibleForInputParsing) { return; } SendList.Message("&g[Global] {0} is now known as {1}", msg.Nick, msg.Message); Logger.Log(LogType.GlobalChat, "[Global] {0} is now known as {1}", msg.Nick, msg.Message); return; case IRCMessageType.ErrorMessage: case IRCMessageType.Error: bool die = false; switch (msg.ReplyCode) { case IRCReplyCode.ErrorNicknameInUse: case IRCReplyCode.ErrorNicknameCollision: ActualBotNick = ActualBotNick.Remove(ActualBotNick.Length - 4) + "_"; Logger.Log(LogType.SystemActivity, "Error: Global Chat Nickname is already in use. Trying \"{0}\"", ActualBotNick); Send(IRCCommands.Nick(ActualBotNick)); break; case IRCReplyCode.ErrorBannedFromChannel: case IRCReplyCode.ErrorNoSuchChannel: Logger.Log(LogType.SystemActivity, "Error: {0} ({1})", msg.ReplyCode, msg.Channel); GCReady = false; die = true; break; //wont happen case IRCReplyCode.ErrorBadChannelKey: Logger.Log(LogType.SystemActivity, "Error: Channel password required for {0}. LegendCraft does not currently support passworded channels.", msg.Channel); die = true; GCReady = false; break; default: Logger.Log(LogType.SystemActivity, "Error ({0}): {1}", msg.ReplyCode, msg.RawMessage); GCReady = false; break; } if (die) { Logger.Log(LogType.SystemActivity, "Error: Disconnecting from Global Chat."); reconnect = false; DisconnectThread(); } return; case IRCMessageType.QueryAction: // TODO: PMs Logger.Log(LogType.SystemActivity, "Query: {0}", msg.RawMessage); break; case IRCMessageType.Kill: Logger.Log(LogType.SystemActivity, "Bot was killed from {0} by {1} ({2}), reconnecting.", hostName, msg.Nick, msg.Message); reconnect = true; isConnected = false; return; } }
void HandleMessage([NotNull] string message) { if (message == null) { throw new ArgumentNullException("message"); } IRCMessage msg = MessageParser(message, ActualBotNick); #if DEBUG_IRC Logger.Log(LogType.IRC, "[{0}]: {1}", msg.Type, msg.RawMessage); #endif switch (msg.Type) { case IRCMessageType.Login: if (ConfigKey.IRCRegisteredNick.Enabled()) { Send(IRCCommands.Privmsg(ConfigKey.IRCNickServ.GetString(), ConfigKey.IRCNickServMessage.GetString())); } foreach (string channel in channelNames) { if (ConfigKey.IRCChannelPassword.GetString() != "password") { Send(IRCCommands.Join(channel + " " + ConfigKey.IRCChannelPassword.GetString())); } else { Send(IRCCommands.Join(channel)); } } IsReady = true; AssignBotForInputParsing(); // bot should be ready to receive input after joining return; case IRCMessageType.Ping: // ping-pong Send(IRCCommands.Pong(msg.RawMessageArray[1].Substring(1))); return; case IRCMessageType.ChannelAction: case IRCMessageType.ChannelMessage: // channel chat if (!ResponsibleForInputParsing) { return; } if (!IsBotNick(msg.Nick)) { string processedMessage = msg.Message; if (msg.Type == IRCMessageType.ChannelAction) { if (processedMessage.StartsWith("\u0001ACTION")) { processedMessage = processedMessage.Substring(8); } else { return; } } processedMessage = NonPrintableChars.Replace(processedMessage, ""); if (processedMessage.Length > 0) { if (ConfigKey.IRCBotForwardFromIRC.Enabled()) { if (msg.Type == IRCMessageType.ChannelAction) { Server.Message("&i(IRC) * {0} {1}", msg.Nick, processedMessage); Logger.Log(LogType.IRC, "(IRC) * {0} {1}", msg.Nick, processedMessage); } else { Server.Message("&i(IRC) {0}{1}: {2}", msg.Nick, Color.White, processedMessage); Logger.Log(LogType.IRC, "(IRC) {0}: {1}", msg.Nick, processedMessage); } } else if (msg.Message.StartsWith("#")) { Server.Message("&i(IRC) {0}{1}: {2}", msg.Nick, Color.White, processedMessage.Substring(1)); Logger.Log(LogType.IRC, "(IRC) {0}: {1}", msg.Nick, processedMessage.Substring(1)); } } } return; case IRCMessageType.Join: if (!ResponsibleForInputParsing) { return; } if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled()) { Server.Message("&i(IRC) {0} joined {1}", msg.Nick, msg.Channel); } return; case IRCMessageType.Kick: string kicked = msg.RawMessageArray[3]; if (kicked == ActualBotNick) { Logger.Log(LogType.IRC, "Bot was kicked from {0} by {1} ({2}), rejoining.", msg.Channel, msg.Nick, msg.Message); Thread.Sleep(ReconnectDelay); Send(IRCCommands.Join(msg.Channel)); } else { if (!ResponsibleForInputParsing) { return; } Server.Message("&i(IRC) {0} kicked {1} from {2} ({3})", msg.Nick, kicked, msg.Channel, msg.Message); } return; case IRCMessageType.Part: case IRCMessageType.Quit: if (!ResponsibleForInputParsing) { return; } if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled()) { Server.Message("&i(IRC) {0} left {1}", msg.Nick, msg.Channel); } return; case IRCMessageType.NickChange: if (!ResponsibleForInputParsing) { return; } Server.Message("&i(IRC) {0} is now known as {1}", msg.Nick, msg.Message); return; case IRCMessageType.ErrorMessage: case IRCMessageType.Error: bool die = false; switch (msg.ReplyCode) { case IRCReplyCode.ErrorNicknameInUse: case IRCReplyCode.ErrorNicknameCollision: Logger.Log(LogType.IRC, "Error: Nickname \"{0}\" is already in use. Trying \"{0}_\"", ActualBotNick); ActualBotNick += "_"; Send(IRCCommands.Nick(ActualBotNick)); break; case IRCReplyCode.ErrorPasswordMismatch: if (triedPass) { Logger.Log(LogType.IRC, "Could not connect with irc server password. Please configure your correct irc server password in the ConfigGUI."); die = true; break; } if (ConfigKey.IRCBotNetworkPass.GetString() == "defaultPass") { Logger.Log(LogType.IRC, "Requested irc server is password-locked. Please set your irc server password in the ConfigGUI."); break; } Logger.Log(LogType.IRC, "Requested irc server is password-locked, attempting to connect with " + ConfigKey.IRCBotNetworkPass.GetString()); //give the irc client a second to prompt for password before sending Scheduler.NewTask(t => SendChannelMessage("/pass " + ConfigKey.IRCBotNetworkPass.GetString())).RunManual(TimeSpan.FromSeconds(2)); triedPass = true; break; case IRCReplyCode.ErrorBannedFromChannel: case IRCReplyCode.ErrorNoSuchChannel: Logger.Log(LogType.IRC, "Error: {0} ({1})", msg.ReplyCode, msg.Channel); die = true; break; default: Logger.Log(LogType.IRC, "Error ({0}): {1}", msg.ReplyCode, msg.RawMessage); break; } if (die) { Logger.Log(LogType.IRC, "Error: Disconnecting."); reconnect = false; DisconnectThread(); } return; case IRCMessageType.QueryAction: // TODO: PMs Logger.Log(LogType.IRC, "Query: {0}", msg.RawMessage); break; case IRCMessageType.Kill: Logger.Log(LogType.IRC, "Bot was killed from {0} by {1} ({2}), reconnecting.", hostName, msg.Nick, msg.Message); reconnect = true; isConnected = false; return; } }