/// <summary> /// Initialises a new instance of the <see cref="IRCChannel"/> class. /// </summary> /// <param name="marshal">The network marshal for the channel.</param> /// <param name="connection">The connection the channel operates on.</param> public IRCChannel(IRCMarshal marshal, Connection connection) { this.marshal = marshal; this.connection = connection; this.users = new List <IRCUser>(); this.expectingNamesMessage = true; }
/// <summary> /// Do any channel level processing required for the reply. /// </summary> /// <param name="message">The reply message to process.</param> public void HandleReply(Message message) { Reply reply = (Reply)int.Parse(message.Command); 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 (this.expectingNamesMessage && reply == Reply.RPL_NAMREPLY) { this.PopulateChannelNamesFromMessage(message); } else if (this.expectingNamesMessage && reply == Reply.RPL_ENDOFNAMES) { this.expectingNamesMessage = false; if (this.namesPopulated != null) { this.namesPopulated.Invoke(this, this.users); } } else { if (settings.DebugMode == GlobalSettings.Boolean.Yes) { this.tabPage.AppendMessage(reply.ToString(), "[RAW]", message.ToString(), MessageType.WarningMessage); } this.tabPage.AppendMessage(reply.ToString(), source, content, messageType); } }
/// <summary> /// Indicates that a marshal has unregistered from a network. /// </summary> /// <param name="marshal">The marshal that has unregistered.</param> public void MarshalUnregistered(IRCMarshal marshal) { if (this.CurrentTab != null && this.CurrentTab.Marshal == marshal) { this.channelBrowserToolStripButton.Enabled = false; this.channelBrowserToolStripMenuItem.Enabled = false; } }
/// <summary> /// Indicates that a marshal has successfully registered on a network. /// </summary> /// <param name="marshal">The marshal that has registered.</param> public void MarshalRegistered(IRCMarshal marshal) { if (this.CurrentTab != null && this.CurrentTab.Marshal == marshal) { this.channelBrowserToolStripButton.Enabled = true; this.channelBrowserToolStripMenuItem.Enabled = true; if (this.CurrentTab.TabType == IRCTabType.Channel) { IRCChannel channel = this.CurrentTab.Marshal.GetChannelByTab(this.CurrentTab); if (channel != null) { this.inputTextBox.MaxLength = this.CurrentTab.Marshal.GetChannelByTab(this.CurrentTab).MaximumMessageSize; } } this.UpdateStatusBarText(); } }
/// <summary> /// Configures a newly created Yaircc.UI.IRCMarshal. /// </summary> /// <param name="sender">The source of the invocation.</param> /// <param name="marshal">The marshal that was created.</param> public void ConfigureNewIRCMarshal(object sender, IRCMarshal marshal) { TreeView treeView = new TreeView(); treeView.Name = string.Format("{0}_TreeView", marshal.Connection.ToString()); treeView.ImageList = this.userModeImageList; TreeNode node = new TreeNode(); node.Text = marshal.Connection.ToString(); node.ImageKey = "lightning.png"; node.SelectedImageKey = node.ImageKey; treeView.Nodes.Add(node); this.splitContainer.Panel1.Controls.Add(treeView); treeView.Dock = DockStyle.Fill; marshal.ServerTab.UserTreeView = treeView; marshal.ServerTab.NickNameMentioned += new IRCTabPage.NickNameMentionedHandler(this.FlashWindowInTaskBar); treeView.BringToFront(); this.RefreshWindowsMenuItems(null); this.BuildFavouriteButtons(); }
/// <summary> /// Processes a connection request and creates marshals and tabs were needed. /// </summary> /// <param name="input">The raw connection command.</param> /// <param name="server">The associated server, null if not applicable.</param> private void ProcessConnectionRequest(string input, Server server) { Connection connection = new Connection(); ParseResult result = connection.Parse(input); Action<IRCTabPage> connectAction = (t) => { IRCTabPage serverTab; if (t == null) { serverTab = new IRCTabPage(this, connection.ToString(), server == null ? connection.Server : server.Alias, IRCTabType.Server); serverTab.Connection = connection; serverTab.Connection.UserName = server == null ? GlobalSettings.Instance.UserName : server.UserName; serverTab.Connection.RealName = server == null ? GlobalSettings.Instance.RealName : server.RealName; serverTab.Connection.Nickname = server == null ? GlobalSettings.Instance.NickName : server.NickName; serverTab.Connection.Mode = server == null ? GlobalSettings.Instance.Mode : server.Mode; List<string> commands = null; if (server != null) { commands = server.Commands; } IRCMarshal marshal = new IRCMarshal(connection, this.channelsTabControl, commands, this); marshal.ChannelCreated += new IRCMarshal.ChannelCreatedHandler(this.ChannelCreated); marshal.NetworkRegistered += (s, e) => this.InvokeAction(() => this.UpdateStatusBarText()); serverTab.Marshal = marshal; marshal.ServerTab = serverTab; channelsTabControl.TabPages.Add(serverTab); this.ConfigureNewIRCMarshal(this, marshal); } else { serverTab = t; } channelsTabControl.SelectedTab = serverTab; serverTab.Connection.Connect(); }; if (result.Success) { if (this.channelsTabControl.TabPages.ContainsKey(connection.ToString())) { IRCTabPage tabPage = this.channelsTabControl.TabPages[connection.ToString()] as IRCTabPage; if (tabPage.Marshal.IsConnected) { this.channelsTabControl.SelectedTab = tabPage; } else { connectAction.Invoke(tabPage); } } else { connectAction.Invoke(null); } } }
/// <summary> /// Initialises a new instance of the <see cref="IRCChannel"/> class. /// </summary> /// <param name="marshal">The network marshal for the channel.</param> /// <param name="connection">The connection the channel operates on.</param> public IRCChannel(IRCMarshal marshal, Connection connection) { this.marshal = marshal; this.connection = connection; this.users = new List<IRCUser>(); this.expectingNamesMessage = true; }
/// <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)); } } } }