Represents a marshal that sits between an IRC connection and the application's UI.
상속: IDisposable
예제 #1
0
 /// <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;
 }
예제 #2
0
        /// <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);
            }
        }
예제 #3
0
 /// <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;
     }
 }
예제 #4
0
        /// <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();
            }
        }
예제 #5
0
        /// <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();
        }
예제 #6
0
        /// <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);
                }
            }
        }
예제 #7
0
 /// <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;
 }
예제 #8
0
        /// <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));
                    }
                }
            }
        }