/// <summary> /// Sends the message to the associated server. /// </summary> /// <param name="sender">The source tab page.</param> /// <param name="message">The message to send.</param> public void Send(IRCTabPage sender, Message message) { message = MessageFactory.AssimilateMessage(message); if (this.Connection.IsConnected) { if ((message is PrivMsgMessage) || (message is NoticeMessage)) { IRCTabPage tabPage = null; string source = this.Connection.Nickname; if (message is PrivMsgMessage) { IRCChannel channel = this.Channels.Find(i => i.Name.Equals(message.Target, StringComparison.OrdinalIgnoreCase)); if (channel == null) { channel = this.CreateChannel(message.Target, true); } tabPage = channel.TabPage; } else { source = string.Format("to({0})", message.Target); tabPage = sender; } tabPage.AppendMessage(message.Command, source, message.Content, message.Type); } else if (message is JoinMessage) { IRCChannel channel = this.Channels.Find(i => i.Name.Equals(message.Parameters[0], StringComparison.OrdinalIgnoreCase)); if (channel == null) { channel = this.CreateChannel(message.Parameters[0], true); } else { // If we're already in the channel, just switch tabs. this.TabHost.InvokeAction(() => this.TabHost.SelectedTab = channel.TabPage); } } else if (message is NickMessage) { this.previousNickName = this.connection.Nickname; this.connection.Nickname = (message as NickMessage).NewNickname; } if (message is QuitMessage) { this.disconnecting = true; } this.Connection.Send(message.ToString()); } if (message is QuitMessage) { this.Dispose(); } }
/// <summary> /// Handles the Disposed event of Yaircc.UI.IRCChannel. /// </summary> /// <param name="sender">The source of the event.</param> private void ChannelDisposed(object sender) { if ((!this.disposing) && (sender is IRCChannel)) { IRCChannel channel = sender as IRCChannel; this.Channels.Remove(channel); } }
/// <summary> /// Creates a new channel and tab. /// </summary> /// <param name="displayName">The name of the channel.</param> /// <param name="switchTo">A value indicating whether or not to switch to the new channel.</param> /// <returns>The new channel.</returns> public IRCChannel CreateChannel(string displayName, bool switchTo) { IRCChannel retval = new IRCChannel(this, this.Connection); retval.Disposed += new IRCChannel.DisposedHandler(this.ChannelDisposed); IRCTabType type = IRCTabType.Channel; Regex regex = new Regex(@"(?<channel>[#&][^\x07\x2C\s]{1,199})", RegexOptions.IgnoreCase); if (!regex.Match(displayName).Success) { type = IRCTabType.PM; } this.TabHost.InvokeAction(() => { string tabName = string.Format("{0}_{1}", this.Connection.ToString(), displayName); IRCTabPage tabPage = new IRCTabPage(this.ServerTab.OwningForm, tabName, displayName, type); tabPage.Connection = this.Connection; tabPage.ConnectionSpecificName = displayName; retval.TabPage = tabPage; retval.TabPage.Marshal = this; retval.Name = displayName; // Iterate through the tab pages to figure out how to place // this channels tab page in a group of other ones on the // same network, in alphabetical order. int index = this.TabHost.TabPages.IndexOf(this.ServerTab) + 1; for (int i = index; i < this.TabHost.TabPages.Count; i++) { IRCTabPage tab = this.TabHost.TabPages[i] as IRCTabPage; if (tab != null && tab.Marshal == this && tab.Text.CompareTo(retval.TabPage.Text) < 0) { index = i + 1; } else if (tab != null && tab.Marshal != this) { break; } } this.TabHost.TabPages.Insert(index, tabPage); if (switchTo) { this.TabHost.SelectedTab = tabPage; } }); this.Channels.Add(retval); if (this.channelCreated != null) { this.channelCreated.Invoke(this, retval); } return retval; }
/// <summary> /// Handles the ChannelCreated event of Yaircc.UI.IRCMarshal. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="channel">The newly created channel.</param> public void ChannelCreated(object sender, IRCChannel channel) { this.splitContainer.Panel1.InvokeAction(() => { channel.NamesPopulated += new IRCChannel.NamesPopulatedHandler(this.ChannelUsersPopulated); TreeView userTreeView = new TreeView(); userTreeView.Name = string.Format("{0}_TreeView", channel.ToString()); userTreeView.ImageList = userModeImageList; userTreeView.TreeViewNodeSorter = new UserNodeSorter(); userTreeView.MouseDown += new MouseEventHandler(UserTreeView_MouseDown); if (channel.TabPage.TabType == IRCTabType.Channel) { userTreeView.Nodes.Add("Fetching user list..."); } else if (channel.TabPage.TabType == IRCTabType.PM) { TreeNode node = new TreeNode(); node.Text = channel.Name; node.ImageKey = "user"; node.SelectedImageKey = node.ImageKey; userTreeView.Nodes.Add(node); } splitContainer.Panel1.Controls.Add(userTreeView); userTreeView.Dock = DockStyle.Fill; channel.TabPage.UserTreeView = userTreeView; channel.TabPage.NickNameMentioned += new IRCTabPage.NickNameMentionedHandler(this.FlashWindowInTaskBar); if (channelsTabControl.SelectedTab == channel.TabPage) { userTreeView.BringToFront(); this.inputTextBox.MaxLength = this.CurrentTab.Marshal.GetChannelByTab(this.CurrentTab).MaximumMessageSize; this.UpdateStatusBarText(); } this.RefreshWindowsMenuItems(null); }); }
/// <summary> /// Process a message that contains a text based command. /// </summary> /// <param name="message">The message to process.</param> private void ProcessMessage(Message message) { message = MessageFactory.AssimilateMessage(message); string target = message.Target.Equals(this.Connection.Nickname, StringComparison.OrdinalIgnoreCase) ? message.Source : message.Target; if (message.MustBeHandledByTarget) { IRCChannel channel = this.Channels.Find(i => i.Name.Equals(target, StringComparison.OrdinalIgnoreCase)); if (channel == null) { channel = this.CreateChannel(target, false); } channel.HandleMessage(message); } else if (message.IsMultiChannelMessage) { for (int i = 0; i < this.Channels.Count; i++) { this.Channels[i].HandleMessage(message); } } else if (message.IsGlobalMessage) { this.Channels.ForEach(i => i.HandleMessage(message)); this.ServerTab.AppendMessage(message.Command, message.Source, message.Content, message.Type); } else { // If the message can be handled by both the server tab // and a channel tab, then we need to check if the currently // focused tab is a channel and if so handle it in the channel. // Otherwise we can just print it in the server tab this.TabHost.InvokeAction(() => { if (this.TabHost.SelectedTab is IRCTabPage) { IRCChannel channel = this.Channels.Find(i => i.TabPage.Equals(this.TabHost.SelectedTab)); if ((channel != null) && (!this.AwaitingModeMessage)) { channel.HandleMessage(message); } else { this.ServerTab.AppendMessage(message.Command, message.Source, message.Content, message.Type); } } }); } // If we are still awaiting the MODE message (i.e. we are awaiting confirmation we have finished connecting) // then also re-join any channels that we have in the Channels collection (i.e. reconnect to any channels) if (this.AwaitingModeMessage && message is ModeMessage) { this.AwaitingModeMessage = false; this.Send(this.ServerTab, new ModeMessage(new string[] { this.Connection.Nickname, this.Connection.Mode })); // Send the user host message so we can determine the full user host string. this.Send(this.ServerTab, new UserHostMessage(new string[] { this.connection.Nickname })); } }
/// <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)); } } } }