/// <summary>
/// Process a message that is categorised as being a numeric reply in the RFC documents.
/// </summary>
/// <param name="message">The message to process.</param>
private void ProcessNumericReply(Message message)
{
Reply reply = (Reply)int.Parse(message.Command);
Action<IRCTabPage> appendMessage = (IRCTabPage tabPage) =>
{
MessageTypeAttribute attributes = IRCMarshal.GetReplyAttributes(reply);
MessageType messageType = attributes.MessageType;
GlobalSettings settings = GlobalSettings.Instance;
string source = attributes.Source;
string content;
if (attributes.OutputAction == null)
{
content = message.ToString(attributes.OutputFormat, attributes.ParameterDelimiter, attributes.RemoveFirstParameter);
}
else
{
content = attributes.OutputAction.Invoke(message);
}
if (settings.DebugMode == GlobalSettings.Boolean.Yes)
{
tabPage.AppendMessage(reply.ToString(), "[RAW]", message.ToString(), MessageType.WarningMessage);
}
tabPage.AppendMessage(reply.ToString(), source, content, messageType);
};
// If we are retrieving list replies we need to populate the channel browser
if (reply == Reply.RPL_LISTSTART)
{
this.parent.InvokeAction(() => this.ChannelBrowser.BeginRefresh(true));
return;
}
else if (reply == Reply.RPL_LIST)
{
this.ChannelBrowser.AddChannel(message);
return;
}
else if (reply == Reply.RPL_LISTEND)
{
this.parent.InvokeAction(() => this.ChannelBrowser.FlushChannels());
return;
}
// If we are still awaiting the UserHost reply (i.e. we are awaiting confirmation of the full userhost
// prefix that we will use to determine the max PRIVMSG lengths) then cache it in the marshal for future
// reference.
if (this.AwaitingUserHostMessage && reply == Reply.RPL_USERHOST)
{
this.fullUserHost = message.TrailingParameter;
this.AwaitingUserHostMessage = false;
// Execute any auto commands.
if (!this.hasExecutedAutoCommands && this.AutoCommands.Count > 0)
{
for (int i = 0; i < this.AutoCommands.Count; i++)
{
MessageParseResult parseResult = MessageFactory.CreateFromUserInput(this.AutoCommands[i], null);
if (parseResult.Success)
{
this.Send(this.ServerTab, parseResult.IRCMessage);
}
}
this.hasExecutedAutoCommands = true;
}
if (this.reconnecting)
{
// Pause the thread for a second to give time for any authentication to
// take place and then rejoin the channels.
System.Threading.Thread.Sleep(1000);
this.Channels.ForEach(i =>
{
if (i.TabPage.TabType == IRCTabType.Channel)
{
this.Send(this.ServerTab, new JoinMessage(i.Name));
}
});
this.reconnecting = false;
}
return;
}
// If the user has received a new hidden host then we need to re-evaluate
// their full user host mask that will be seen by other clients.
if (reply == Reply.RPL_HOSTHIDDEN)
{
this.AwaitingUserHostMessage = true;
this.Send(this.ServerTab, new UserHostMessage(new string[] { this.connection.Nickname }));
}
// If we have a names reply or an end of names reply, then we need to check the channel
// it is in regards to exists in our channel list, and if it does check to see if it
// is awaiting a reply from a names request (i.e. it is wanting to refresh the user list).
//
// If this is indeed the case, we need to force it through to that channel rather than
// following the default procedure of going to the selected tab.
if ((reply == Reply.RPL_NAMREPLY) || (reply == Reply.RPL_ENDOFNAMES))
{
string target = string.Empty;
if (reply == Reply.RPL_NAMREPLY)
{
target = message.Parameters[2];
}
else
{
target = message.Parameters[1];
}
IRCChannel channel = this.channels.Find(i => i.Name.Equals(target, StringComparison.OrdinalIgnoreCase));
if (channel != null && channel.ExpectingNamesMessage)
{
channel.HandleReply(message);
return;
}
}
// If the currently selected tab belongs to the channel list for this connection
// AND we aren't awaiting a mode message (i.e. connecting to the server)
// then marshal the message to the owning channel, otherwise default to the server tab
this.TabHost.InvokeAction(() =>
{
IRCChannel selectedChannel = this.Channels.Find(i => this.TabHost.SelectedTab.Equals(i.TabPage));
if ((selectedChannel != null) && (!this.AwaitingModeMessage))
{
selectedChannel.HandleReply(message);
}
else
{
appendMessage.Invoke(this.ServerTab);
}
});
// If a nick in use message comes through, we need to revert the nick against the connection
// back to the previously assigned nick (if there is one).
// If there wasn't one, then we'll append an underscore to the current one and resend the nick message
// we couldn't possibly get stuck in a loop, right?
if (reply == Reply.ERR_NICKNAMEINUSE)
{
if (this.previousNickName.Equals(this.Connection.Nickname, StringComparison.OrdinalIgnoreCase))
{
this.previousNickName = string.Format("{0}_", this.previousNickName);
this.connection.Nickname = this.previousNickName;
this.Send(this.ServerTab, new NickMessage(this.previousNickName));
}
else
{
if (!this.AwaitingModeMessage)
{
this.Connection.Nickname = this.previousNickName;
}
else
{
this.previousNickName = string.Format("{0}_", this.connection.Nickname);
this.connection.Nickname = this.previousNickName;
this.Send(this.ServerTab, new NickMessage(this.previousNickName));
}
}
}
}