Esempio n. 1
0
        /// <summary>
        /// Parses the raw messages coming from the server and triggers an event based on the type of message.
        /// </summary>
        /// <param name="tcpMessage">The raw string read from the TCP stream.</param>
        internal async void ParseTCPMessage(string tcpMessage)
        {
            DateTime messageTime  = DateTime.Now;
            Regex    messageRegex = new Regex(@"^:(?<Sender>[^\s]+)\s(?<Type>[^\s]+)\s(?<Recipient>[^\s]+)\s?:?(?<Args>.*)", RegexOptions.None);
            Regex    senderRegex  = new Regex(@"^(?<Nick>[^\s]+)!(?<Realname>[^\s]+)@(?<Host>[^\s]+)", RegexOptions.None);
            Regex    pingRegex    = new Regex(@"^PING :(?<Message>.+)", RegexOptions.None);
            Regex    pongRegex    = new Regex(@"^PONG :(?<Message>.+)", RegexOptions.None);
            Regex    errorRegex   = new Regex(@"^ERROR :(?<Message>.+)", RegexOptions.None);
            Regex    CTCPRegex    = new Regex(@"^\u0001(?<Command>[^\s]+)\s?(?<Args>.*)\u0001", RegexOptions.None);

            string[] messages = tcpMessage.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string message in messages)
            {
                if (messageRegex.IsMatch(message))
                {
                    Match  match          = messageRegex.Match(message);
                    string type           = match.Groups["Type"].Value;
                    string sender         = match.Groups["Sender"].Value;
                    string recipient      = match.Groups["Recipient"].Value;
                    string args           = match.Groups["Args"].Value;
                    Match  senderMatch    = senderRegex.Match(sender);
                    string senderNick     = sender;
                    string senderRealname = null;
                    string senderHost     = null;
                    if (senderMatch.Success)
                    {
                        senderNick     = senderMatch.Groups["Nick"].Value;
                        senderRealname = senderMatch.Groups["Realname"].Value;
                        senderHost     = senderMatch.Groups["Host"].Value;
                    }

                    int replyCode;
                    if (int.TryParse(type, out replyCode))
                    {
                        // The message was a reply to a command sent
                        if (Enum.IsDefined(typeof(IRCReplyCode), replyCode))
                        {
                            await Task.Run(() =>
                            {
                                if (ServerReplyEvent != null)
                                {
                                    ServerReplyEvent(this,
                                                     new ServerReplyMessage()
                                    {
                                        TimeStamp = messageTime,
                                        ReplyCode = (IRCReplyCode)replyCode,
                                        Message   = args
                                    });
                                }
                            });
                        }
                        else if (Enum.IsDefined(typeof(IRCErrorCode), replyCode))
                        {
                            await Task.Run(() =>
                            {
                                if (ServerReplyEvent != null)
                                {
                                    ServerReplyEvent(this,
                                                     new ServerErrorMessage()
                                    {
                                        TimeStamp = messageTime,
                                        ErrorCode = (IRCErrorCode)replyCode,
                                        Message   = args
                                    });
                                }
                            });
                        }
                    }
                    else
                    {
                        switch (type)
                        {
                        // The message was a private message to a channel or nick
                        case "PRIVMSG":
                            if (CTCPRegex.IsMatch(args))
                            {
                                Match       ctcpMatch   = CTCPRegex.Match(args);
                                CTCPMessage ctcpMessage = new CTCPMessage();
                                ctcpMessage.Location = recipient;
                                ctcpMessage.Sender   = new Nick()
                                {
                                    Nickname = senderNick,
                                    Realname = senderRealname,
                                    Host     = senderHost
                                };
                                ctcpMessage.Command   = ctcpMatch.Groups["Command"].Value;
                                ctcpMessage.Arguments = ctcpMatch.Groups["Args"].Value;

                                await Task.Run(() =>
                                {
                                    if (CTCPMessageReceivedEvent != null)
                                    {
                                        CTCPMessageReceivedEvent(this, ctcpMessage);
                                    }
                                });
                            }
                            else
                            {
                                if (Channel.IsChannel(recipient))
                                {
                                    ChannelMessage msg = new ChannelMessage();
                                    msg.Channel = recipient;
                                    msg.Sender  = new Nick()
                                    {
                                        Nickname = senderNick,
                                        Realname = senderRealname,
                                        Host     = senderHost
                                    };
                                    msg.Message = args;

                                    await Task.Run(() =>
                                    {
                                        if (ChannelMessageReceivedEvent != null)
                                        {
                                            ChannelMessageReceivedEvent(this, msg);
                                        }
                                    });
                                }
                                else
                                {
                                    PrivateMessage msg = new PrivateMessage();
                                    msg.Sender = new Nick()
                                    {
                                        Nickname = senderNick,
                                        Realname = senderRealname,
                                        Host     = senderHost
                                    };
                                    msg.Message = args;

                                    await Task.Run(() =>
                                    {
                                        if (PrivateMessageReceivedEvent != null)
                                        {
                                            PrivateMessageReceivedEvent(this, msg);
                                        }
                                    });
                                }
                            }
                            break;

                        // The message was a notice to a channel or nick
                        case "NOTICE":
                            if (CTCPRegex.IsMatch(args))
                            {
                                Match       ctcpMatch   = CTCPRegex.Match(args);
                                CTCPMessage ctcpMessage = new CTCPMessage();
                                ctcpMessage.Sender = new Nick()
                                {
                                    Nickname = senderNick,
                                    Realname = senderRealname,
                                    Host     = senderHost
                                };
                                ctcpMessage.Command   = ctcpMatch.Groups["Command"].Value;
                                ctcpMessage.Arguments = ctcpMatch.Groups["Args"].Value;

                                await Task.Run(() =>
                                {
                                    if (CTCPNoticeReceivedEvent != null)
                                    {
                                        CTCPNoticeReceivedEvent(this, ctcpMessage);
                                    }
                                });
                            }
                            if (Channel.IsChannel(recipient))
                            {
                                ChannelNotice msg = new ChannelNotice();
                                msg.Channel = recipient;
                                msg.Sender  = new Nick()
                                {
                                    Nickname = senderNick, Realname = senderRealname, Host = senderHost
                                };
                                msg.Message = args;

                                await Task.Run(() =>
                                {
                                    if (ChannelNoticeReceivedEvent != null)
                                    {
                                        ChannelNoticeReceivedEvent(this, msg);
                                    }
                                });
                            }
                            else
                            {
                                PrivateNotice msg = new PrivateNotice();
                                msg.Sender = new Nick()
                                {
                                    Nickname = senderNick, Realname = senderRealname, Host = senderHost
                                };
                                msg.Message = args;

                                await Task.Run(() =>
                                {
                                    if (PrivateNoticeReceivedEvent != null)
                                    {
                                        PrivateNoticeReceivedEvent(this, msg);
                                    }
                                });
                            }
                            break;

                        // The message was a mode change message for a channel or nick
                        case "MODE":
                            if (Channel.IsChannel(recipient))
                            {
                                ChannelModeChangeInfo modeMsg = new ChannelModeChangeInfo();
                                modeMsg.Modes   = new List <ChannelModeInfo>();
                                modeMsg.Channel = recipient;
                                modeMsg.Nick    = new Nick()
                                {
                                    Nickname = senderNick, Realname = senderRealname, Host = senderHost
                                };

                                if (!string.IsNullOrEmpty(args))
                                {
                                    string[]      modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                                    List <string> argList  = modeArgs.ToList();
                                    argList.RemoveAt(0);
                                    modeMsg.Modes.AddRange(_IRC.ParseChannelModeString(modeArgs[0].TrimStart(':'), string.Join(" ", argList)));
                                }

                                await Task.Run(() =>
                                {
                                    if (ChannelModeChangeEvent != null)
                                    {
                                        ChannelModeChangeEvent(this, modeMsg);
                                    }
                                });
                            }
                            else
                            {
                                UserModeChangeInfo modeMsg = new UserModeChangeInfo();
                                modeMsg.Modes = new List <UserModeInfo>();
                                modeMsg.Nick  = new Nick()
                                {
                                    Nickname = senderNick, Realname = senderRealname, Host = senderHost
                                };

                                if (!string.IsNullOrEmpty(args))
                                {
                                    string[] modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                                    char[]   modeInfo = modeArgs[0].TrimStart(':').ToCharArray();
                                    bool     set      = true;
                                    foreach (char mode in modeInfo)
                                    {
                                        if (mode.Equals('-'))
                                        {
                                            set = false;
                                        }
                                        else if (mode.Equals('+'))
                                        {
                                            set = true;
                                        }
                                        else if (!string.IsNullOrEmpty(mode.ToString()))
                                        {
                                            UserModeInfo newMode = new UserModeInfo();
                                            newMode.Set = set;
                                            UserMode md;
                                            Enum.TryParse(mode.ToString(), out md);
                                            newMode.Mode = md;
                                            modeMsg.Modes.Add(newMode);
                                        }
                                    }
                                }

                                await Task.Run(() =>
                                {
                                    if (UserModeChangeEvent != null)
                                    {
                                        UserModeChangeEvent(this, modeMsg);
                                    }
                                });
                            }
                            break;

                        // The message was a topic change for a channel
                        case "TOPIC":
                            TopicChangeInfo topicMsg = new TopicChangeInfo();
                            topicMsg.Channel = recipient;
                            topicMsg.Nick    = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };
                            topicMsg.Topic = args;

                            await Task.Run(() =>
                            {
                                if (TopicChangeEvent != null)
                                {
                                    TopicChangeEvent(this, topicMsg);
                                }
                            });

                            break;

                        // The message was a nick change
                        case "NICK":
                            NickChangeInfo nickMsg = new NickChangeInfo();
                            nickMsg.OldNick = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };
                            nickMsg.NewNick = new Nick()
                            {
                                Nickname = recipient.TrimStart(':'), Realname = senderRealname, Host = senderHost
                            };

                            await Task.Run(() =>
                            {
                                if (NickChangeEvent != null)
                                {
                                    NickChangeEvent(this, nickMsg);
                                }
                            });

                            break;

                        // The message was an invite to a channel
                        case "INVITE":
                            InviteChannelInfo inviteMsg = new InviteChannelInfo();
                            inviteMsg.Requester = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };
                            inviteMsg.Recipient = new Nick()
                            {
                                Nickname = recipient
                            };
                            inviteMsg.Channel = args;

                            await Task.Run(() =>
                            {
                                if (InviteChannelEvent != null)
                                {
                                    InviteChannelEvent(this, inviteMsg);
                                }
                            });

                            break;

                        // The message was a nick joining a channel
                        case "JOIN":
                            JoinChannelInfo joinMsg = new JoinChannelInfo();
                            joinMsg.Channel = recipient.TrimStart(':');
                            joinMsg.Nick    = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };

                            await Task.Run(() =>
                            {
                                if (JoinChannelEvent != null)
                                {
                                    JoinChannelEvent(this, joinMsg);
                                }
                            });

                            break;

                        // The message was a nick parting a channel
                        case "PART":
                            PartChannelInfo partMsg = new PartChannelInfo();
                            partMsg.Channel = recipient;
                            partMsg.Nick    = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };

                            await Task.Run(() =>
                            {
                                if (PartChannelEvent != null)
                                {
                                    PartChannelEvent(this, partMsg);
                                }
                            });

                            break;

                        // The message was a nick being kicked from a channel
                        case "KICK":
                            KickInfo kickMsg = new KickInfo();
                            kickMsg.Channel = recipient;
                            kickMsg.Nick    = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };
                            string[] argSplit = args.Split(new char[] { ' ' }, StringSplitOptions.None);

                            kickMsg.KickedNick = new Nick()
                            {
                                Nickname = argSplit[0]
                            };

                            List <string> reasonArgs = argSplit.ToList <string>();
                            reasonArgs.RemoveAt(0);
                            kickMsg.Reason = string.Join(" ", reasonArgs.ToArray()).Remove(0, 1);

                            await Task.Run(() =>
                            {
                                if (KickEvent != null)
                                {
                                    KickEvent(this, kickMsg);
                                }
                            });

                            break;

                        // The message was a nick quiting the irc network
                        case "QUIT":
                            QuitInfo quitMsg = new QuitInfo();
                            quitMsg.Nick = new Nick()
                            {
                                Nickname = senderNick, Realname = senderRealname, Host = senderHost
                            };
                            quitMsg.Message = string.Join(" ", recipient.Remove(0, 1), args);

                            await Task.Run(() =>
                            {
                                if (QuitEvent != null)
                                {
                                    QuitEvent(this, quitMsg);
                                }
                            });

                            break;

                        default:
                            break;
                        }
                    }
                }
                else if (pingRegex.IsMatch(message)) // The message was a PING
                {
                    Match    match = pingRegex.Match(message);
                    PingInfo ping  = new PingInfo();
                    ping.Message = match.Groups["Message"].Value;

                    await Task.Run(() =>
                    {
                        if (PingEvent != null)
                        {
                            PingEvent(this, ping);
                        }
                    });
                }
                else if (pongRegex.IsMatch(message)) // The message was a PONG
                {
                    Match    match = pongRegex.Match(message);
                    PongInfo pong  = new PongInfo();
                    pong.Message = match.Groups["Message"].Value;

                    await Task.Run(() =>
                    {
                        if (PongEvent != null)
                        {
                            PongEvent(this, pong);
                        }
                    });
                }
                else if (errorRegex.IsMatch(message)) // The message was a server error
                {
                    Match        match = errorRegex.Match(message);
                    ErrorMessage error = new ErrorMessage();
                    error.Message = match.Groups["Message"].Value;

                    await Task.Run(() =>
                    {
                        if (ErrorMessageEvent != null)
                        {
                            ErrorMessageEvent(this, error);
                        }
                    });
                }

                string rawMessage = message;
                await Task.Run(() =>
                {
                    if (RawMessageEvent != null)
                    {
                        RawMessageEvent(this, rawMessage);
                    }
                });
            }
        }