Represents a message received from an IRC server.
Inheritance: IAssimilable
コード例 #1
0
        /// <summary>
        /// Add a channel to the list of channels that will be displayed upon flushing them to the screen.
        /// </summary>
        /// <param name="reply">The LIST reply to create an item from.</param>
        public void AddChannel(IRCMessage reply)
        {
            string cleanTopic = reply.TrailingParameter;

            cleanTopic = Regex.Replace(cleanTopic, @"(\x03+[0-9]{1,2}(,[0-9]{1,2})*|\x02|\x31|\x29|\x15|\x03)", string.Empty, RegexOptions.IgnoreCase);
            string[] subitems = new string[] { reply.Parameters[1], reply.Parameters[2], cleanTopic };
            this.items.Add(new ListViewItem(subitems));
        }
コード例 #2
0
ファイル: MessageFactory.cs プロジェクト: rastating/yaircc
        /// <summary>
        /// Assimilates the message into the appropriate subclass.
        /// </summary>
        /// <param name="message">The message to assimilate.</param>
        /// <returns>The assimilated message, or the original message if it cannot be mapped to a subclass.</returns>
        internal static Message AssimilateMessage(Message message)
        {
            Message retval = message;
            string className = GetClassNameFromRawCommand(message.Command);

            if (!string.IsNullOrEmpty(className))
            {
                retval = (Message)Assembly.GetExecutingAssembly().CreateInstance(string.Format("Yaircc.Net.IRC.{0}", className));
                retval.Assimilate(message);
            }

            return retval;
        }
コード例 #3
0
ファイル: MessageFactory.cs プロジェクト: rastating/yaircc
        /// <summary>
        /// Creates a new <see cref="Message"/>, encapsulating the data from the payload.
        /// </summary>
        /// <param name="payload">The payload to be encapsulated.</param>
        /// <param name="sourceChannel">The name of the channel the message is being generated on.</param>
        /// <returns>A <see cref="MessageParseResult"/> containing the result of the operation.</returns>
        internal static MessageParseResult CreateFromUserInput(string payload, string sourceChannel)
        {
            MessageParseResult retval = null;
            string className = GetClassNameFromUserCommand(payload);

            if (!string.IsNullOrEmpty(className))
            {
                Message message = (Message)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string.Format("Yaircc.Net.IRC.{0}", className));
                message.ChannelName = sourceChannel;
                ParseResult parseResult = message.TryParse(payload);
                retval = new MessageParseResult(parseResult.Success, parseResult.Message, message);
            }
            else
            {
                Message message = new Message();
                ParseResult parseResult = message.TryParse(payload);
                retval = new MessageParseResult(parseResult.Success, parseResult.Message, message);
            }

            return retval;
        }
コード例 #4
0
ファイル: IRCMarshal.cs プロジェクト: rastating/yaircc
        /// <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));
                    }
                }
            }
        }
コード例 #5
0
ファイル: IRCMarshal.cs プロジェクト: rastating/yaircc
        /// <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 }));
            }
        }
コード例 #6
0
ファイル: IRCMarshal.cs プロジェクト: rastating/yaircc
        /// <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();
            }
        }
コード例 #7
0
ファイル: Message.cs プロジェクト: rastating/yaircc
        /// <summary>
        /// Parses a text based message into a Yaircc.Net.IRC.Message.
        /// </summary>
        /// <param name="message">A string that meets the RFC 1459 or 2812 standard.</param>
        /// <returns>A new instance of Yaircc.Net.IRC.Message encapsulating the specified message.</returns>
        public static Message ParseMessage(string message)
        {
            Message retval = new Message();

            // The format of the message must meet the RFC 1459 standard
            // that being: [':' <prefix> <SPACE> ] <command> <params> <crlf>

            // -- Breakdown of Message Sections --
            // <prefix>     :=  <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
            // <command>    :=  <letter> { <letter> } | <number> <number> <number>
            // <params>     :=  <SPACE> [ ':' <trailing> | <middle> <params> ]
            // <middle>     :=  <Any *non-empty* sequence of octets not including SPACE or NUL or CR or LF, the first of which may not be ':'>
            // <trailing>   :=  <Any, possibly *empty*, sequence of octets not including NUL or CR or LF>
            try
            {
                int prefixEnd = -1;
                int trailingStart = message.Length;

                string prefix = null;
                string command = null;
                string[] parameters = null;
                string trailingParameter = null;

                // Get the prefix
                if (message.StartsWith(":"))
                {
                    prefixEnd = message.IndexOf(' ');
                    prefix = message.Substring(1, prefixEnd - 1);
                }

                // Grab the trailing parameter
                trailingStart = message.IndexOf(" :");
                if (trailingStart >= 0)
                {
                    trailingParameter = message.Substring(trailingStart + 2);
                }
                else
                {
                    trailingStart = message.Length;
                }

                // Use the prefix end position and trailing parameter start position to get the command and remaining parameters
                string[] commandAndParameters = message.Substring(prefixEnd + 1, trailingStart - prefixEnd - 1).Split(' ');
                command = commandAndParameters[0];

                // If there were parameters add them all in
                if (commandAndParameters.Length > 1)
                {
                    // Loop through the standard parameters and add them to the array
                    parameters = new string[commandAndParameters.Length - 1];
                    for (int i = 0; i < (commandAndParameters.Length - 1); i++)
                    {
                        parameters[i] = commandAndParameters[i + 1].Trim(new char[] { ' ', '\r', '\n' });
                    }
                }

                if (!string.IsNullOrEmpty(prefix))
                {
                    retval.Prefix = prefix;
                }

                if (!string.IsNullOrEmpty(command))
                {
                    retval.Command = command;
                }

                if (parameters != null)
                {
                    retval.Parameters = parameters;
                }

                if (!string.IsNullOrEmpty(trailingParameter))
                {
                    retval.TrailingParameter = trailingParameter.Trim(new char[] { '\r', '\n' });
                }
            }
            catch
            {
            }

            return retval;
        }
コード例 #8
0
ファイル: IRCChannel.cs プロジェクト: rastating/yaircc
 /// <summary>
 /// Populate the user list from a names message.
 /// </summary>
 /// <param name="message">The message to process.</param>
 private void PopulateChannelNamesFromMessage(Message message)
 {
     string[] names = message.TrailingParameter.Split(new char[] { ' ' });
     for (int i = 0; i < names.GetLength(0); i++)
     {
         if (!string.IsNullOrEmpty(names[i]))
         {
             this.users.Add(IRCUser.Parse(names[i]));
         }
     }
 }
コード例 #9
0
ファイル: IRCChannel.cs プロジェクト: rastating/yaircc
        /// <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);
            }
        }
コード例 #10
0
ファイル: IRCChannel.cs プロジェクト: rastating/yaircc
        /// <summary>
        /// Do any channel level processing required for the message.
        /// </summary>
        /// <param name="message">The message to process.</param>
        public void HandleMessage(Message message)
        {
            Action namesRequest = () =>
            {
                if (!this.expectingNamesMessage)
                {
                    this.users.Clear();
                    this.expectingNamesMessage = true;
                    this.marshal.Send(this.TabPage, new NamesMessage(this.Name));
                }
            };

            if (message is JoinMessage)
            {
                namesRequest.Invoke();
            }
            else if (message is PartMessage)
            {
                PartMessage partMessage = message as PartMessage;
                if (partMessage.NickName.Equals(this.marshal.Connection.Nickname, StringComparison.OrdinalIgnoreCase))
                {
                    this.Dispose();
                    return;
                }
                else
                {
                    IRCUser user = this.users.Find(i => i.NickName.Equals(partMessage.NickName, StringComparison.OrdinalIgnoreCase));
                    this.TabPage.RemoveUserFromList(user);
                    this.users.Remove(user);
                }
            }
            else if (message is KickMessage)
            {
                KickMessage kickMessage = message as KickMessage;
                IRCUser user = this.users.Find(i => i.NickName.Equals(kickMessage.NickName, StringComparison.OrdinalIgnoreCase));
                this.TabPage.RemoveUserFromList(user);
                this.users.Remove(user);
            }
            else if (message is NickMessage)
            {
                NickMessage nickMessage = message as NickMessage;
                IRCUser user = this.users.Find(i => i.NickName.Equals(nickMessage.OldNickname, StringComparison.OrdinalIgnoreCase));
                if (user != null)
                {
                    this.TabPage.RemoveUserFromList(user);
                    user.NickName = nickMessage.NewNickname;
                    this.TabPage.AddUserToList(user, true);
                }
                else
                {
                    return;
                }
            }
            else if (message is QuitMessage)
            {
                QuitMessage quitMessage = message as QuitMessage;
                IRCUser user = this.users.Find(i => i.NickName.Equals(quitMessage.NickName, StringComparison.OrdinalIgnoreCase));
                if (user != null)
                {
                    this.TabPage.RemoveUserFromList(user);
                    this.users.Remove(user);
                }
                else
                {
                    return;
                }
            }
            else if (message is ModeMessage)
            {
                namesRequest.Invoke();
            }

            GlobalSettings settings = GlobalSettings.Instance;
            if (settings.DebugMode == GlobalSettings.Boolean.Yes)
            {
                this.TabPage.AppendMessage(message.Command, "[RAW]", message.ToString(), MessageType.WarningMessage);
            }

            this.TabPage.AppendMessage(message.Command, message.Source, message.Content, message.Type);
        }