public void Parse(String sender, String command, String parameters) { //Logger.Trace(" Sender: {0}", Sender); //Logger.Trace(" Command: {0}", Command); //Logger.Trace(" Parameters: {0}", Parameters); String[] paramSplit = parameters.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); switch (command.ToUpper()) { case "376": // RAW: 376 - RPL_ENDOFMOTD - ":End of /MOTD command" Logger.Info("Logged in. Negotiating Capabilities..."); // Query capabilities for later registration QueueSend(IrcFunctions.CapabilityLs(), true); break; case "353": // 353 - RPL_NAMREPLY - "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]" break; case "366": // 366 - RPL_ENDOFNAMES - "<channel> :End of /NAMES list" break; case "433": //433 - ERR_NICKNAMEINUSE - "<nick> :Nickname is already in use" Logger.Info("Nick already in use. Attempting change to {0}.", Nick); QueueSend("NICK " + AltNick, true); Nick = AltNick; ExtendedUser = String.Format("{0}!{0}@{0}.tmi.twitch.tv", Nick.ToLower()); break; case "470": // Channel Forward // :adams.freenode.net 470 SomethingKewl #windows ##windows :Forwarding to another channel //Channel OldChannel; //if (Channels.ContainsKey(ParamSplit[1])) { // OldChannel = Channels[ParamSplit[1]]; // OldChannel.Name = ParamSplit[2]; // // Should we really remove the old channel? Does it hurt? // //m_Channels.Remove(ParamSplit[1]); // Channels.Add(OldChannel.Name, OldChannel); // // TODO: add code here to check for old channel and rename it. //} else { // // Conceivably this could happen if you were forcejoined to a channel which then got moved. // OldChannel = new Channel(this); // OldChannel.Name = ParamSplit[2]; // OldChannel.StatsEnabled = true; // throw new Exception("This should never happen. How is this happening? Case 470: Else"); //} break; case "CAP": // See IRCv3 Specification: // http://ircv3.net/specs/core/capability-negotiation-3.1.html // http://ircv3.net/specs/core/capability-negotiation-3.2.html // Note: This may not be 100% compliant, but it works for Twitch.tv. if (paramSplit[0] == "*") { // Not sure what the * denotes switch (paramSplit[1].ToUpper()) { case "LS": // Response to LS (list of capabilities supported by the server) String capabilities = parameters.Substring(parameters.IndexOf(":", StringComparison.Ordinal) + 1); if (Properties.Settings.Default.TwitchMembershipCapabilityEnable == false) { Logger.Debug("Ignoring twitch.tv/membership IRCv3 capability"); capabilities = capabilities.Replace("twitch.tv/membership", "").Trim(); } Logger.Debug("Requesting Capabilities: {0}", capabilities); QueueSend(IrcFunctions.CapabilityReq(capabilities), true); break; case "LIST": // Response to LIST (list of active capabilities) break; case "ACK": // Response to REQ command (approved). // Would send "CAP END" here, but twitch doesn't respond. Logger.Info("Successfully Negotiated Capabilities: {0}", parameters.Substring(parameters.IndexOf(":", StringComparison.Ordinal) + 1)); JoinOrPartChannels(); break; case "NAK": // Response to REQ command (rejected). break; case "END": // Response to END command. break; } } break; case "JOIN": if (paramSplit[0].Contains(":")) { // Fix because some IRCds send "JOIN :#channel" instead of "JOIN #channel" paramSplit[0] = paramSplit[0].Substring(1); } if (sender.ToLower() == ExtendedUser) { // Add it as zero, or if it exists, set it to 0. Substring portion cuts off # _channelStatus.AddOrUpdate(paramSplit[0].ToLower().Substring(1), 0, (name, count) => 0); //_channels.Add(paramSplit[0].ToLower()); Logger.Debug("Channel List: {0}", String.Join(", ", _channelStatus.Keys)); } break; case "PART": if (paramSplit.Length >= 2) { String partMsg = parameters.Substring(parameters.IndexOf(":", StringComparison.Ordinal) + 1); if (partMsg.Length == 0) { //Channels[ParamSplit[0]].Part(Sender, String.Empty); } else { if ((partMsg.Substring(0, 1) == "\"") && (partMsg.Substring(partMsg.Length - 1, 1) == "\"")) { // ReSharper disable once RedundantAssignment partMsg = partMsg.Substring(1, partMsg.Length - 2); } } if (sender.ToLower() == ExtendedUser) { Int32 temp; _channelStatus.TryRemove(paramSplit[0].ToLower().Substring(1), out temp); //_channels.TryTake(paramSplit[0].ToLower()); Logger.Debug("Channel List: {0}", String.Join(", ", _channelStatus.Keys)); } //Channels[ParamSplit[0]].Part(Sender, PartMsg); } break; case "KICK": //Channels[ParamSplit[0]].Kick(Sender, ParamSplit[1], Functions.CombineAfterIndex(ParamSplit, " ", 2).Substring(1)); break; case "INVITE": // TODO: Not sure how we want to handle this. break; case "NICK": if (IrcFunctions.GetNickFromHostString(sender) == Nick) { Nick = parameters.Substring(1); } //foreach (KeyValuePair<string, Channel> CurKVP in Channels) { // Channels[CurKVP.Key].Nick(Sender, Parameters.Substring(1)); //} //BotCommands.CheckAdminChange(Sender, Parameters.Substring(1)); break; case "QUIT": //foreach (KeyValuePair<string, Channel> CurKVP in Channels) { // Channels[CurKVP.Key].Quit(Sender, Parameters.Substring(1)); //} break; case "MODE": if (paramSplit[0].Substring(0, 1) == "#") { // Is a channel mode //Channels[ParamSplit[0]].Mode(Sender, Functions.CombineAfterIndex(ParamSplit, " ", 1)); } break; case "PRIVMSG": String msgText = parameters.Substring(parameters.IndexOf(":", StringComparison.Ordinal) + 1); if (paramSplit[0].Substring(0, 1) == "#") { // Is going to a channel //if (MsgText.Substring(0, 1) == "\x1") { // // If this is a special PRIVMSG, like an action or CTCP // MsgText = MsgText.Substring(1, MsgText.Length - 2); // String[] PrivMsgSplit = MsgText.Split(" ".ToCharArray(), 2); // switch (PrivMsgSplit[0].ToUpper()) { // case "ACTION": // //Channels[ParamSplit[0]].Action(Sender, PrivMsgSplit[1]); // break; // // Maybe other stuff goes here like channel wide CTCPs? // } //} else { // // If this is just a normal PRIVMSG. // //Channels[ParamSplit[0]].Message(Sender, MsgText); //} } else { // Is not going to a channel. Probably just me? if (msgText.Substring(0, 1) == "\x1") { // If this is a special PRIVMSG, like an action or CTCP msgText = msgText.Substring(1, msgText.Length - 2); String[] privMsgSplit = msgText.Split(" ".ToCharArray(), 2); switch (privMsgSplit[0].ToUpper()) { case "ACTION": // Not sure what to do here... break; case "VERSION": QueueSend(IrcFunctions.CtcpVersionReply(IrcFunctions.GetNickFromHostString(sender))); break; case "TIME": QueueSend(IrcFunctions.CtcpTimeReply(IrcFunctions.GetNickFromHostString(sender))); break; case "PING": QueueSend(IrcFunctions.CtcpPingReply(IrcFunctions.GetNickFromHostString(sender), privMsgSplit[1])); break; } } } break; case "NOTICE": // Needed for NickServ stuff //string[] MsgSplitNtc = Parameters.Substring(Parameters.IndexOf(":") + 1).Split(" ".ToCharArray()); //BotCommands.HandleNotice(Sender, MsgSplitNtc); break; } }