/// <summary> /// IRC protocol implementation per IRC RFC 2812 https://tools.ietf.org/html/rfc2812 /// </summary> public void ReadProtocol() { var command = _sr.ReadLine(); Console.WriteLine(command); IRCCommand cmd = IRCCommand.Parse(command); if (command == null || cmd == null) { return; } switch (cmd.Command) { case "001": //RPL_WELCOME case "002": //RPL_YOURHOST case "003": //RPL_CREATED case "004": //RPL_MYINFO case "NOTICE": //NOTICE OnServerMessage(command); SendCommand("JOIN " + Channel); break; case "332": OnServerMessage(command); break; case "353": //RPL_NAMREPLY //make sure if for this channel, //i think i might get lists for all //channels in the server. if (cmd.Arguments[2] == Channel) { //lists of users for the channel we are connected //lets ignore the type of channels for now (@, =, *) var ulea = new UserListEventArgs { Users = new List <string>(cmd.Arguments[3].Split(' ')) }; //checks if the command before this one was a 353, //if it is, that means the list of users was not completely //received, so this packet is a continuation of the list. //otherwise, this is the beginning of the list. if (_previousCommand != "353") { ulea.Type = UserListMessageType.ListStart; } else if (_previousCommand == "353") { ulea.Type = UserListMessageType.ListContinue; } OnUserList(ulea); } break; case "366": //RPL_ENDOFNAMES //this is the end of the list of users. OnUserList(new UserListEventArgs() { Type = UserListMessageType.ListEnd }); break; case "433": //ERR_NICKNAMEINUSE //tries to log in with a different nickname SendCommand("NICK " + Nickname + "_" + new Random().Next(100)); break; case "PRIVMSG": //new message to the channel, or private ReceivedEventArgs rec = new ReceivedEventArgs { MessageFrom = cmd.Prefix.Substring(0, cmd.Prefix.IndexOf("!", StringComparison.Ordinal)) }; //TODO: handle messages that are for specific users, and show them in a unique way //maybe something like FromUser > ToUser: Hello, World! //let us worry about //public and private messages only if (cmd.Arguments[0] == Nickname) { rec.Type = MessageType.MessageToMe; } else { rec.Type = MessageType.MessageToChannel; } rec.Message = cmd.Arguments[1]; OnReceived(rec); break; case "PING": //reply with pong :p SendCommand("PONG " + command.Substring(5)); break; case "JOIN": //someone joined the channel //two options: We could either re-ask for the entire list //or simply add the specific user string userJoined = cmd.Prefix.Substring(0, cmd.Prefix.IndexOf("!", StringComparison.Ordinal)); if (userJoined != Nickname) { OnUserJoined(userJoined); } else { //this is when I joined the channel. OnConnected(); IsConnected = true; } break; case "PART": //someone has left/quit the channel case "QUIT": string userLeft = cmd.Prefix.Substring(0, cmd.Prefix.IndexOf("!", StringComparison.Ordinal)); if (userLeft != Nickname) { OnUserQuit(userLeft); } else { //leave chatroom gracefully OnQuit(); IsConnected = false; } break; case "NICK": //change in nick if (cmd.Arguments != null && cmd.Arguments.Count > 0) { var newNickname = cmd.Arguments[0]; var oldNickname = cmd.Prefix.Substring(0, cmd.Prefix.IndexOf("!", StringComparison.Ordinal)); //raise this event to update the nickname in the lists OnNicknameChanged(oldNickname, newNickname, NicknameChangedType.NickChanged); } break; case "ERROR": OnQuit(); IsConnected = false; break; } _previousCommand = cmd.Command; }
/// <summary> /// Get the IRC command, per IRC RFC 2812 https://tools.ietf.org/html/rfc2812 /// </summary> /// <param name="raw">Raw string to be parsed.</param> /// <returns>An IRCCommand object with all the members to make sense out of the protocol.</returns> public static IRCCommand Parse(string raw) { IRCCommand tmp = null; if (!string.IsNullOrEmpty(raw)) { string trailing = null; try { if (raw.StartsWith(":")) { tmp = new IRCCommand(); var prefixEnd = raw.IndexOf(" ", StringComparison.Ordinal); tmp.Prefix = raw.Substring(1, prefixEnd - 1); var trailingStart = raw.IndexOf(" :", StringComparison.Ordinal); if (trailingStart > -1) { trailing = raw.Substring(trailingStart + 2); } else { trailingStart = raw.Length; } var commandAndParameters = raw.Substring(prefixEnd + 1, trailingStart - prefixEnd - 1).Split(' '); tmp.Command = commandAndParameters.First(); //this is the command if (commandAndParameters.Length > 1) tmp.Arguments = commandAndParameters.Skip(1).ToList(); //dont take the first one, thats the command if (!string.IsNullOrEmpty(trailing)) { if (tmp.Arguments == null) { tmp.Arguments = new List<string>(); } tmp.Arguments = tmp.Arguments.Concat(new[] { trailing }).ToList(); } } else { if (raw.ToLower().StartsWith("ping")) { tmp = new IRCCommand { Command = "PING", Arguments = new List<string> {raw.Substring(5)} }; } else if (raw.ToLower().StartsWith("error")) { tmp = new IRCCommand { Command = "ERROR", Arguments = new List<string>() }; tmp.Arguments.AddRange(raw.Split(':').Skip(1)); } } } catch { tmp = null; } } return tmp; }
/// <summary> /// Get the IRC command, per IRC RFC 2812 https://tools.ietf.org/html/rfc2812 /// </summary> /// <param name="raw">Raw string to be parsed.</param> /// <returns>An IRCCommand object with all the members to make sense out of the protocol.</returns> public static IRCCommand Parse(string raw) { IRCCommand tmp = null; if (!string.IsNullOrEmpty(raw)) { string trailing = null; try { if (raw.StartsWith(":")) { tmp = new IRCCommand(); var prefixEnd = raw.IndexOf(" ", StringComparison.Ordinal); tmp.Prefix = raw.Substring(1, prefixEnd - 1); var trailingStart = raw.IndexOf(" :", StringComparison.Ordinal); if (trailingStart > -1) { trailing = raw.Substring(trailingStart + 2); } else { trailingStart = raw.Length; } var commandAndParameters = raw.Substring(prefixEnd + 1, trailingStart - prefixEnd - 1).Split(' '); tmp.Command = commandAndParameters.First(); //this is the command if (commandAndParameters.Length > 1) { tmp.Arguments = commandAndParameters.Skip(1).ToList(); //dont take the first one, thats the command } if (!string.IsNullOrEmpty(trailing)) { if (tmp.Arguments == null) { tmp.Arguments = new List <string>(); } tmp.Arguments = tmp.Arguments.Concat(new[] { trailing }).ToList(); } } else { if (raw.ToLower().StartsWith("ping")) { tmp = new IRCCommand { Command = "PING", Arguments = new List <string> { raw.Substring(5) } }; } else if (raw.ToLower().StartsWith("error")) { tmp = new IRCCommand { Command = "ERROR", Arguments = new List <string>() }; tmp.Arguments.AddRange(raw.Split(':').Skip(1)); } } } catch { tmp = null; } } return(tmp); }