/// <summary> /// The received message. /// </summary> /// <param name="sender"> /// The sender. /// </param> /// <param name="ea"> /// The new event args. /// </param> /// <remarks> /// TODO: upgrade this, get rid of PMEA call. /// </remarks> private static void ReceivedMessage(object sender, MessageReceivedEventArgs ea) { if (ea.Message.Command != "PRIVMSG") { return; } var parameters = ea.Message.Parameters.ToList(); string message = parameters[1]; var cmd = new LegacyCommandParser( ServiceLocator.Current.GetInstance<ICommandServiceHelper>(), Log.CreateChildLogger("LegacyCommandParser")); try { bool overrideSilence = cmd.OverrideBotSilence; if (cmd.IsRecognisedMessage(ref message, ref overrideSilence, (IIrcClient)sender)) { cmd.OverrideBotSilence = overrideSilence; string[] messageWords = message.Split(' '); string command = messageWords[0]; string joinedargs = string.Join(" ", messageWords, 1, messageWords.Length - 1); string[] commandArgs = joinedargs == string.Empty ? new string[0] : joinedargs.Split(' '); cmd.HandleCommand(LegacyUser.NewFromString(ea.Message.Prefix), parameters[0], command, commandArgs); } } catch (Exception ex) { Log.Error(ex.Message, ex); } }
/// <summary> /// The on part message received. /// </summary> /// <param name="e"> /// The e. /// </param> /// <param name="user"> /// The user. /// </param> private void OnPartMessageReceived(MessageReceivedEventArgs e, IUser user) { List<string> parameters = e.Message.Parameters.ToList(); string channel = parameters[0]; if (user.Nickname == this.Nickname) { this.logger.InfoFormat("Leaving channel {1}.", user, channel); lock (this.userOperationLock) { var channelUsers = this.channels[channel].Users.Select(x => x.Key); foreach (var u in channelUsers.Where(u => this.channels.Count(x => x.Value.Users.ContainsKey(u)) == 0)) { this.logger.InfoFormat( "{0} is no longer in any channel I'm in, removing them from tracking", u, channel); this.userCache.Remove(u); } this.channels.Remove(channel); } } else { lock (this.userOperationLock) { this.channels[channel].Users.Remove(user.Nickname); this.logger.InfoFormat("{0} has left channel {1}.", user, channel); if (this.channels.Count(x => x.Value.Users.ContainsKey(user.Nickname)) == 0) { this.logger.InfoFormat( "{0} has left all channels I'm in, removing them from tracking", user, channel); this.userCache.Remove(user.Nickname); } } } }
/// <summary> /// The on kick message received. /// </summary> /// <param name="e"> /// The e. /// </param> private void OnKickMessageReceived(MessageReceivedEventArgs e) { // Kick format is: // :n!u@h KICK #chan nick :reason List<string> parameters = e.Message.Parameters.ToList(); string channel = parameters[0]; if (parameters[1] == this.Nickname) { this.logger.WarnFormat("Kicked from channel {1}.", channel); lock (this.userOperationLock) { var channelUsers = this.channels[channel].Users.Select(x => x.Key); foreach (var u in channelUsers.Where(u => this.channels.Count(x => x.Value.Users.ContainsKey(u)) == 0)) { this.logger.InfoFormat( "{0} is no longer in any channel I'm in, removing them from tracking", u, channel); this.userCache.Remove(u); } this.channels.Remove(channel); } } else { lock (this.userOperationLock) { this.channels[channel].Users.Remove(parameters[1]); this.logger.InfoFormat("{0} has beem kicked from channel {1}.", parameters[1], channel); if (this.channels.Count(x => x.Value.Users.ContainsKey(parameters[1])) == 0) { this.logger.InfoFormat( "{0} has left all channels I'm in, removing them from tracking", parameters[1], channel); this.userCache.Remove(parameters[1]); } } } }
/// <summary> /// The on name reply received. /// </summary> /// <param name="e"> /// The e. /// </param> private void OnNameReplyReceived(MessageReceivedEventArgs e) { List<string> parameters = e.Message.Parameters.ToList(); string channel = parameters[2]; string names = parameters[3]; this.logger.DebugFormat("Names on {0}: {1}", channel, names); foreach (string name in names.Split(' ')) { string parsedName = name; bool voice = false; bool op = false; if (parsedName.StartsWith("+")) { parsedName = parsedName.Substring(1); voice = true; } if (parsedName.StartsWith("@")) { parsedName = parsedName.Substring(1); op = true; } lock (this.userOperationLock) { if (this.channels[channel].Users.ContainsKey(parsedName)) { IrcChannelUser channelUser = this.channels[channel].Users[parsedName]; channelUser.Operator = op; channelUser.Voice = voice; } else { var ircUser = new IrcUser { Nickname = parsedName }; if (this.UserCache.ContainsKey(parsedName)) { ircUser = this.UserCache[parsedName]; } else { this.UserCache.Add(parsedName, ircUser); } var channelUser = new IrcChannelUser(ircUser, channel) { Voice = voice, Operator = op }; this.channels[channel].Users.Add(parsedName, channelUser); } } } }
/// <summary> /// The on nick change received. /// </summary> /// <param name="e"> /// The e. /// </param> /// <param name="user"> /// The user. /// </param> private void OnNickChangeReceived(MessageReceivedEventArgs e, IUser user) { List<string> parameters = e.Message.Parameters.ToList(); string newNickname = parameters[0]; string oldNickname = user.Nickname; this.logger.InfoFormat("Changing {0} to {1} in nick tracking database.", oldNickname, newNickname); try { lock (this.userOperationLock) { // firstly, update the user cache. IrcUser ircUser = this.UserCache[oldNickname]; ircUser.Nickname = newNickname; try { this.UserCache.Remove(oldNickname); this.UserCache.Add(newNickname, ircUser); } catch (ArgumentException) { this.logger.Warn("Couldn't add the new entry to the dictionary. Nick tracking is no longer valid."); this.nickTrackingValid = false; throw; } // secondly, update the channels this user is in. foreach (var channelPair in this.channels) { if (channelPair.Value.Users.ContainsKey(oldNickname)) { IrcChannelUser channelUser = channelPair.Value.Users[oldNickname]; if (!channelUser.User.Equals(ircUser)) { this.logger.ErrorFormat( "Channel user {0} doesn't match irc user {1} for NICK in {2}", channelUser.User, ircUser, channelPair.Value.Name); this.logger.Error("Nick tracking is no longer valid."); this.nickTrackingValid = false; throw new Exception("Channel user doesn't match irc user"); } try { channelPair.Value.Users.Remove(oldNickname); channelPair.Value.Users.Add(newNickname, channelUser); } catch (ArgumentException) { this.logger.Warn("Couldn't add the new entry to the dictionary. Nick tracking is no longer valid."); this.nickTrackingValid = false; throw; } } } } } catch (Exception exception) { this.logger.Error("Nickname tracking is no longer valid.", exception); this.nickTrackingValid = false; } }
/// <summary> /// The on message received event. /// </summary> /// <param name="sender"> /// The sender. /// </param> /// <param name="e"> /// The e. /// </param> private void OnMessageReceivedEvent(object sender, MessageReceivedEventArgs e) { IUser user = null; if (e.Message.Prefix != null) { if (e.Message.Prefix == this.serverPrefix) { user = new ServerUser(); } else { // parse it into something reasonable user = IrcUser.FromPrefix(e.Message.Prefix); lock (this.userOperationLock) { // attempt to load from cache if (this.nickTrackingValid && this.userCache.ContainsKey(user.Nickname)) { user = this.userCache[user.Nickname]; } } } } if (e.Message.Command == "JOIN" && user != null) { this.OnJoinReceived(e, user); } if (e.Message.Command == Numerics.NameReply) { this.OnNameReplyReceived(e); } if (e.Message.Command == Numerics.WhoXReply) { this.logger.DebugFormat("WHOX Reply:{0}", e.Message.Parameters.Implode()); this.HandleWhoXReply(e.Message); } if (e.Message.Command == Numerics.EndOfWho) { this.logger.Debug("End of who list."); } if (e.Message.Command == "QUIT" && user != null) { this.OnQuitMessageReceived(user); } if (e.Message.Command == "MODE" && user != null) { List<string> parameters = e.Message.Parameters.ToList(); string target = parameters[0]; if (target.StartsWith("#")) { this.OnChannelModeReceived(parameters); } else { // User mode message this.logger.Debug("Received user mode message. Not processing."); } } if (e.Message.Command == "PART" && user != null) { this.OnPartMessageReceived(e, user); } if (e.Message.Command == "KICK") { this.OnKickMessageReceived(e); } if (e.Message.Command == "ACCOUNT" && user != null) { this.OnAccountMessageReceived(e, user); } if (e.Message.Command == "NICK" && user != null) { this.OnNickChangeReceived(e, user); } if (e.Message.Command == "INVITE") { EventHandler<InviteEventArgs> inviteReceivedEvent = this.InviteReceivedEvent; if (inviteReceivedEvent != null) { List<string> parameters = e.Message.Parameters.ToList(); inviteReceivedEvent(this, new InviteEventArgs(e.Message, user, parameters[1], parameters[0])); } } }
/// <summary> /// The on join received. /// </summary> /// <param name="e"> /// The e. /// </param> /// <param name="user"> /// The user. /// </param> private void OnJoinReceived(MessageReceivedEventArgs e, IUser user) { // this is a client join to a channel. // :stwalkerster!stwalkerst@wikimedia/stwalkerster JOIN ##stwalkerster List<string> parametersList = e.Message.Parameters.ToList(); lock (this.userOperationLock) { if (this.userCache.ContainsKey(user.Nickname)) { user = this.userCache[user.Nickname]; } else { this.userCache.Add(user.Nickname, (IrcUser)user); } } if (this.capExtendedJoin) { // :stwalkerster!stwalkerst@wikimedia/stwalkerster JOIN ##stwalkerster accountname :realname user.Account = parametersList[1]; } string channelName = parametersList[0]; if (user.Nickname == this.Nickname) { // we're joining this, so rate-limit from here. this.logger.InfoFormat("Joining channel {0}", channelName); this.logger.Debug("Requesting WHOX a information"); this.Send(new Message("WHO", new[] { channelName, "%uhnatfc,001" })); lock (this.userOperationLock) { // add the channel to the list of channels I'm in. this.Channels.Add(channelName, new IrcChannel(channelName)); } } else { this.logger.InfoFormat("Seen {0} join channel {1}.", user, channelName); lock (this.userOperationLock) { if (!this.Channels[channelName].Users.ContainsKey(user.Nickname)) { this.Channels[channelName].Users.Add( user.Nickname, new IrcChannelUser((IrcUser)user, channelName)); } else { this.logger.Error("Nickname tracking no longer valid."); this.nickTrackingValid = false; } } EventHandler<JoinEventArgs> temp = this.JoinReceivedEvent; if (temp != null) { temp(this, new JoinEventArgs(e.Message, user, channelName)); } } }
/// <summary> /// The on account message received. /// </summary> /// <param name="e"> /// The e. /// </param> /// <param name="user"> /// The user. /// </param> private void OnAccountMessageReceived(MessageReceivedEventArgs e, IUser user) { List<string> parameters = e.Message.Parameters.ToList(); lock (this.userOperationLock) { this.logger.DebugFormat("Seen {0} change account name to {1}", user, parameters[0]); if (this.UserCache.ContainsKey(user.Nickname)) { this.UserCache[user.Nickname].Account = parameters[0]; } else { this.UserCache.Add(user.Nickname, (IrcUser)user); user.Account = parameters[0]; } } }
/// <summary> /// The on account message received. /// </summary> /// <param name="e"> /// The e. /// </param> /// <param name="user"> /// The user. /// </param> private void OnAccountMessageReceived(MessageReceivedEventArgs e, IUser user) { List<string> parameters = e.Message.Parameters.ToList(); lock (this.userOperationLock) { this.logger.DebugFormat("Seen {0} change account name to {1}", user, parameters[0]); if (this.userCache.ContainsKey(user.Nickname)) { var cachedUser = this.userCache[user.Nickname]; cachedUser.Account = parameters[0]; // flesh out the skeleton if (cachedUser.Skeleton && !((IrcUser)user).Skeleton) { cachedUser.Username = user.Username; cachedUser.Hostname = user.Hostname; cachedUser.Skeleton = false; } } else { this.userCache.Add(user.Nickname, (IrcUser)user); user.Account = parameters[0]; } } }
/// <summary> /// The IRC private message event. /// </summary> /// <param name="sender"> /// The sender. /// </param> /// <param name="e"> /// The e. /// </param> private void IrcPrivateMessageEvent(object sender, MessageReceivedEventArgs e) { if (e.Message.Command == "PRIVMSG" || e.Message.Command == "NOTICE") { var parameters = e.Message.Parameters.ToList(); this.ParseMessage(parameters[1], parameters[0]); } }