/// <summary> /// Represents one connection to one IRC server /// </summary> public IrcClient() { ServerInfo = new ServerInfoType(); Encoding = new System.Text.UTF8Encoding(false); Registered = false; LastMessageTime = DateTime.Now; Timeout = new TimeSpan(0, 2, 0); Connected = false; _thread = new IRCEventThread(this); _thread.OnRawMessageReceived += (sender, msg) => { if (OnRawMessageReceived != null) { foreach (var d in OnRawMessageReceived.GetInvocationList()) { Task.Run(() => d.DynamicInvoke(this, msg)); } } }; _thread.OnException += (sender, e) => { // Call to clean up resources and set flags Disconnect(); if (OnException != null) { foreach (var d in OnException.GetInvocationList()) { Task.Run(() => d.DynamicInvoke(this, e)); } } // Call on disconnect when there's an exception in the reading thread if (OnDisconnect != null) { foreach (var d in OnDisconnect.GetInvocationList()) { Task.Run(() => d.DynamicInvoke(this)); } } }; #region Register Delegates OnRawMessageReceived += ErrorHandler; // This one looks for ERROR messages OnRawMessageReceived += PingHandler; OnRawMessageReceived += NumericHandler; OnRawMessageReceived += PrivmsgHandler; OnRfcNumeric += (sender, source, numeric, target, other) => { if (numeric == 1 && OnConnect != null) foreach (var d in OnConnect.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this)); }; OnRfcNumeric += (sender, source, numeric, target, other) => { if (numeric == 353 && OnNamesReply != null) { String[] words = other.Split(' '); String channel = words[1]; foreach (var d in OnNamesReply.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this, channel, other.Substring(other.IndexOf(':') + 1))); } }; OnRfcNumeric += (sender, source, numeric, target, other) => { // Parses numeric 5 (List of things the server supports) and calls event with the parsed list if (numeric == 5 && OnISupport != null) { Dictionary<String, String> parameters = new Dictionary<string, string>(); String[] tokens = other.Split(' '); foreach (String token in tokens) { int equalIndex = token.IndexOf('='); if (equalIndex >= 0) parameters[token.Substring(0, equalIndex)] = token.Substring(equalIndex + 1); else parameters[token] = ""; } foreach (var d in OnISupport.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this, parameters)); } }; OnConnect += (sender) => { lock (_channels) { _channels.Clear(); } }; OnISupport += (sender, parameters) => { try { sender.ServerInfo.PREFIX = parameters["PREFIX"]; } catch (KeyNotFoundException) { }; try { sender.ServerInfo.CHANMODES = parameters["CHANMODES"]; } catch (KeyNotFoundException) { }; if (parameters.ContainsKey("UHNAMES")) { var task = SendRawMessage("PROTOCTL UHNAMES"); } if (parameters.ContainsKey("NAMESX")) { var task = SendRawMessage("PROTOCTL NAMESX"); } }; OnRawMessageReceived += (source, message) => { String[] tokens = message.Split(' '); if (OnRfcJoin != null && tokens.Length >= 3 && tokens[1].Equals("JOIN")) { foreach (var d in OnRfcJoin.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this, tokens[0].Replace(":", ""), tokens[2].Replace(":", ""))); } }; OnRfcJoin += (sender, source, channellist) => { /// If the user joining is me, add it to the channel list. /// If we have a channel already, add the guy to it. foreach (String channelName in channellist.Split(',')) { Channel c = null; lock (_channels) { _channels.TryGetValue(channelName.ToLower(), out c); if (c == null && ChannelUser.GetNickFromFullAddress(source).Equals(Nick, StringComparison.CurrentCultureIgnoreCase)) { c = new Channel(channelName); _channels[channelName.ToLower()] = c; } if (c != null) { ChannelUser u = new ChannelUser(source, c); c.Users[u.Nick.ToLower()] = u; } } } }; OnRawMessageReceived += (sender, message) => { String[] tokens = message.Split(' '); if (tokens.Length >= 5 && tokens[1].Equals("KICK")) { String source = tokens[0].Replace(":", ""), channel = tokens[2], target = tokens[3]; String reason = message.Substring(message.IndexOf(':', 1)); if (OnRfcKick != null) foreach (var d in OnRfcKick.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this, source, target, channel, reason)); } }; // Catches a part OnRawMessageReceived += (sender, message) => { String[] tokens = message.Split(' '); if (OnRfcPart != null && tokens.Length >= 3 && tokens[1].Equals("PART")) { String reason = tokens.Length >= 4 ? message.Substring(message.IndexOf(':', 1)) : null; foreach (var d in OnRfcPart.GetInvocationList()) Task.Run(() => d.DynamicInvoke(this, tokens[0].Replace(":", ""), tokens[2], reason)); } }; OnRawMessageReceived += (sender, message) => { String[] tokens = message.Split(' '); if (tokens.Length >= 4 && tokens[1].Equals("MODE") && OnRfcMode != null) { foreach (var d in OnRfcMode.GetInvocationList()) Task.Run(() => d.DynamicInvoke(sender, tokens[0].Replace(":", ""), tokens[2], message.Substring(message.IndexOf(tokens[2]) + tokens[2].Length + 1))); } }; // On part, we should remove the nick from the channel. If it's US parting, we should remove the channel from channels OnRfcPart += (sender, source, channel, reason) => { Channel channelObject = null; lock (_channels) { _channels.TryGetValue(channel.ToLower(), out channelObject); if (channelObject != null) { if (ChannelUser.GetNickFromFullAddress(source).Equals(Nick, StringComparison.CurrentCultureIgnoreCase)) _channels.Remove(channel.ToLower()); else { try { channelObject.Users.Remove(ChannelUser.GetNickFromFullAddress(source)); } catch (Exception) { } } } } }; OnRfcKick += (sender, source, target, channel, reason) => { Channel channelObject = null; _channels.TryGetValue(channel.ToLower(), out channelObject); if (channelObject != null) { if (Nick.Equals(target, StringComparison.CurrentCultureIgnoreCase)) // If it's us, remove the channel _channels.Remove(channel.ToLower()); else // else remove the nick from the channel { try { channelObject.Users.Remove(target.ToLower()); } catch (Exception) { } } } }; OnRawMessageReceived += (source, message) => { LastMessageTime = DateTime.Now; }; OnNamesReply += NamesReplyHandler; // Updates prefix list for users of a channel when modes are changed OnRfcMode += (sender, source, target, modes) => { Channel channel = null; _channels.TryGetValue(target.ToLower(), out channel); if (_channels == null) return; String[] tokens = modes.Split(' '); bool isSet = false; for (int modeIndex = 0, parameterIndex = 1; modeIndex < tokens[0].Length; ++modeIndex) { char mode = tokens[0][modeIndex]; if (mode == '+') isSet = true; else if (mode == '-') isSet = false; else if (ServerInfo.CHANMODES_parameterNever.Contains(mode)) continue; else if (ServerInfo.CHANMODES_paramaterToSet.Contains(mode)) { if (isSet) ++parameterIndex; else continue; } else { try { // If it's a user access mode if (ServerInfo.PREFIX_modes.Contains(mode)) { ChannelUser user = null; channel.Users.TryGetValue(tokens[parameterIndex].ToLower(), out user); if (user != null) { char prefix = ServerInfo.PREFIX_symbols[ServerInfo.PREFIX_modes.IndexOf(mode)]; if (isSet) user.InsertPrefix(ServerInfo, target, prefix); else user.DeletePrefix(target, prefix); } } } catch (Exception) { } finally { // These modes always have parameters so we need to always increase the index at the end ++parameterIndex; } } } }; OnRawMessageReceived += (sender, message) => { String[] tokens = message.Split(' '); if (tokens.Length >= 3 && tokens[1].Equals("NICK") && OnRfcNick != null) { foreach (var d in OnRfcNick.GetInvocationList()) { Task.Run(() => d.DynamicInvoke(sender, tokens[0].Replace(":", ""), tokens[2].Replace(":", ""))); } } }; OnRfcNick += (sender, source, newnick) => { String oldnick = ChannelUser.GetNickFromFullAddress(source).ToLower(); ChannelUser user = null; foreach (Channel c in _channels.Values) { c.Users.TryGetValue(oldnick, out user); if (user != null) { user.Nick = newnick; c.Users.Remove(oldnick); c.Users[newnick] = user; } } if (ChannelUser.GetNickFromFullAddress(source) == this.Nick) { this.Nick = newnick; } }; OnRawMessageReceived += (sender, message) => { String[] tokens = message.Split(' '); if (tokens.Length >= 3 && OnRfcQuit != null && tokens[1].Equals("QUIT")) { foreach (var d in OnRfcQuit.GetInvocationList()) Task.Run(() => d.DynamicInvoke(sender, tokens[0].Replace(":", ""), message.Substring(message.IndexOf(":", 1)))); } }; OnRfcQuit += (sender, source, message) => { String nick = ChannelUser.GetNickFromFullAddress(source); foreach (Channel c in _channels.Values) { try { c.Users.Remove(nick.ToLower()); } catch (Exception) { } } }; #endregion Register Delegates }
private void NamesReplyHandler(IrcClient sender, String channel, String names) { Channel channelObject = null; lock (_channels) { _channels.TryGetValue(channel.ToLower(), out channelObject); if (channelObject == null) channelObject = new Channel(channel); String[] namesArray = names.Split(' '); foreach (String name in namesArray) { if (String.IsNullOrEmpty(name)) continue; int nameStart = 0; for (nameStart = 0; sender.ServerInfo.PREFIX_symbols.Contains(name[nameStart]); ++nameStart) ; String justName = name.Substring(nameStart); ChannelUser user = null; channelObject.Users.TryGetValue(ChannelUser.GetNickFromFullAddress(justName), out user); if (user == null) { user = new ChannelUser(justName, channelObject); channelObject.Users[user.Nick.ToLower()] = user; /// If we are in the list, we need to be smart enough to add the channel to our list if it isnt there if (user.Nick.Equals(Nick, StringComparison.CurrentCultureIgnoreCase)) _channels[channelObject.Name.ToLower()] = channelObject; } for (int i = 0; i < nameStart; ++i) user.InsertPrefix(sender.ServerInfo, channel, name[i]); } } }
public ChannelUser(String nickOrFullAddress, Channel channel) { if (nickOrFullAddress.Contains('!') && nickOrFullAddress.Contains('@') && nickOrFullAddress.IndexOf('@') > nickOrFullAddress.IndexOf('!')) { Nick = GetNickFromFullAddress(nickOrFullAddress); Username = GetUserFromFullAddress(nickOrFullAddress); Host = GetHostFromFullAddress(nickOrFullAddress); } else Nick = nickOrFullAddress; }