Ejemplo n.º 1
0
        public bool TryParseText(string message, out MessageParseResult result)
        {
            var match = Pattern.Match(message);

            if (match.Success)
            {
                Inline converted = Convert(match.Value);
                result        = new MessageParseResult(converted);
                result.Prefix = message.Substring(0, match.Index);
                int lastIndex = match.Index + match.Length;
                result.Suffix = message.Substring(lastIndex);
            }
            else
            {
                result = null;
            }

            return(match.Success);
        }
Ejemplo n.º 2
0
        public static MessageParseResult ParseDuplexMessage(ArraySegment <byte> message)
        {
            var parseResult = new MessageParseResult();
            var reader      = new JsonReader(message.Array !, message.Offset);

            if (reader.ReadIsBeginObject())
            {
                try
                {
                    while (true)
                    {
                        reader.SkipWhiteSpace();
                        var         buffer    = reader.GetBufferUnsafe().AsSpan(reader.GetCurrentOffsetUnsafe());
                        ref var     bufferRef = ref MemoryMarshal.GetReference(buffer);
                        const uint  id        = (('"') | ('i' << 8) | ('d' << 16) | ('"' << 24));
                        const ulong method    = ((ulong)'"') | ((ulong)'m' << 8) | ((ulong)'e' << 16) | ((ulong)'t' << 24) | ((ulong)'h' << 32) | ((ulong)'o' << 40) | ((ulong)'d' << 48) | ((ulong)'"' << 56);
                        const ulong @params   = ((ulong)'"') | ((ulong)'p' << 8) | ((ulong)'a' << 16) | ((ulong)'r' << 24) | ((ulong)'a' << 32) | ((ulong)'m' << 40) | ((ulong)'s' << 48) | ((ulong)'"' << 56);
                        const ulong jsonrpc   = (((ulong)'"') | ((ulong)'j' << 8) | ((ulong)'s' << 16) | ((ulong)'o' << 24) | ((ulong)'n' << 32) | ((ulong)'r' << 40) | ((ulong)'p' << 48) | ((ulong)'c' << 56));
                        const ulong ___2_0    = (((ulong)'"') | ((ulong)'2' << 8) | ((ulong)'.' << 16) | ((ulong)'0' << 24) | ((ulong)'"' << 32)) << 24;
                        const ulong result    = (((ulong)'"') | ((ulong)'r' << 8) | ((ulong)'e' << 16) | ((ulong)'s' << 24) | ((ulong)'u' << 32) | ((ulong)'l' << 40) | ((ulong)'t' << 48) | ((ulong)'"' << 56));
                        const ulong error     = (((ulong)'"') | ((ulong)'e' << 8) | ((ulong)'r' << 16) | ((ulong)'r' << 24) | ((ulong)'o' << 32) | ((ulong)'r' << 40) | ((ulong)'"' << 48));

                        switch (buffer.Length)
                        {
                        case 0:
                        case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                            goto UnknownProperty;

                        //最短の正常な文字列パターンは"id":1}で7byteある
                        case 7:
                        case 8:
                        case 9:
                        case 10:

                        {
                            if (Unsafe.ReadUnaligned <uint>(ref bufferRef) == id)
                            {
                                goto ID;
                            }
                            else
                            {
                                goto UnknownProperty;
                            }
                        }

                        case 11:
                        {
                            var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef);

                            if ((uint)chars8 == id)
                            {
                                goto ID;
                            }
                            else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error)
                            {
                                goto Error;
                            }
                            else
                            {
                                goto UnknownProperty;
                            }
                        }

                        //その次に短いのは"params":[]}または"params":{}}または"method":""または"result":1}
                        case 12:
                        case 13:
                        case 14:
                        case 15:
                        {
                            var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef);
                            switch (chars8)
                            {
                            case result:
                            {
                                goto Result;
                            }

                            case method:
                            {
                                goto Method;
                            }

                            case @params:
                            {
                                goto Params;
                            }

                            default:
                            {
                                if ((uint)chars8 == id)
                                {
                                    goto ID;
                                }
                                else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error)
                                {
                                    goto Error;
                                }
                                else
                                {
                                    goto UnknownProperty;
                                }
                            }
                            }
                        }

                        //その次が"jsonrpc":"2.0"}
                        default:
                        {
                            var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef);
                            switch (chars8)
                            {
                            case jsonrpc:
                            {
                                goto JsonRpc;
                            }

                            case result:
                            {
                                goto Result;
                            }

                            case method:
                            {
                                goto Method;
                            }

                            case @params:
                            {
                                goto Params;
                            }

                            default:
                            {
                                if ((uint)chars8 == id)
                                {
                                    goto ID;
                                }
                                else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error)
                                {
                                    goto Error;
                                }
                                else
                                {
                                    goto UnknownProperty;
                                }
                            }
                            }
                        }
JsonRpc:
                            {
                                if (Unsafe.AddByteOffset(ref bufferRef, (IntPtr)(8)) == (byte)'"')
                                {
                                    reader.AdvanceOffset(9);
                                    if (reader.ReadIsNameSeparator())
                                    {
                                        reader.SkipWhiteSpace();
                                        buffer    = reader.GetBufferUnsafe().AsSpan(reader.GetCurrentOffsetUnsafe());
                                        bufferRef = ref MemoryMarshal.GetReference(buffer);
                                        if ((Unsafe.ReadUnaligned <ulong>(ref Unsafe.AddByteOffset(ref bufferRef, (IntPtr)(-3))) & 0xFFFFFFFFFF000000) == ___2_0)
                                        {
                                            reader.AdvanceOffset(5);
                                            parseResult[MessagePropertyKind.JsonRpcVersion] = PropertyState.Valid;
                                            break;
                                        }
                                        else
                                        {
                                            goto UnExpectedFormatProperty;
                                        }
                                    }
                                    else
                                    {
                                        goto InvalidJson;
                                    }
                                }
                                else
                                {
                                    goto UnknownProperty;
                                }
                            }
Method:
                            {
                                reader.AdvanceOffset(8);
                                if (reader.ReadIsNameSeparator())
                                {
                                    try
                                    {
                                        parseResult.Method = EscapedUTF8String.FromEscapedNonQuoted(reader.ReadStringSegmentRaw());
                                    }
                                    catch (JsonParsingException)
                                    {
                                        parseResult[MessagePropertyKind.Method] = PropertyState.Invalid;
                                        goto UnExpectedFormatProperty;
                                    }
                                    parseResult[MessagePropertyKind.Method] = PropertyState.Valid;
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
Params:
                            {
                                reader.AdvanceOffset(8);
                                if (reader.ReadIsNameSeparator())
                                {
                                    try
                                    {
                                        parseResult.Params = reader.ReadNextBlockSegment();
                                    }
                                    catch (JsonParsingException)
                                    {
                                        parseResult[MessagePropertyKind.Params] = PropertyState.Invalid;
                                        goto UnExpectedFormatProperty;
                                    }
                                    parseResult[MessagePropertyKind.Params] = PropertyState.Valid;
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
ID:
                            {
                                reader.AdvanceOffset(4);
                                if (reader.ReadIsNameSeparator())
                                {
                                    try
                                    {
                                        parseResult.id = ID.Formatter.DeserializeNullableSafe(ref reader);
                                    }
                                    catch (JsonParsingException)
                                    {
                                        parseResult[MessagePropertyKind.ID] = PropertyState.Invalid;
                                        goto UnExpectedFormatProperty;
                                    }
                                    parseResult[MessagePropertyKind.ID] = PropertyState.Valid;
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
Result:
                            {
                                reader.AdvanceOffset(8);
                                if (reader.ReadIsNameSeparator())
                                {
                                    try
                                    {
                                        parseResult.Result = reader.ReadNextBlockSegment();
                                    }
                                    catch (JsonParsingException)
                                    {
                                        parseResult[MessagePropertyKind.Result] = PropertyState.Invalid;
                                        goto UnExpectedFormatProperty;
                                    }
                                    parseResult[MessagePropertyKind.Result] = PropertyState.Valid;
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
Error:
                            {
                                reader.AdvanceOffset(7);
                                if (reader.ReadIsNameSeparator())
                                {
                                    try
                                    {
                                        parseResult.Error = reader.ReadNextBlockSegment();     //Client.JsonResolver.GetFormatterWithVerify<Client.ResponseError<object?>>().Deserialize(ref reader, Client.JsonResolver);
                                    }
                                    catch (JsonParsingException)
                                    {
                                        parseResult[MessagePropertyKind.Error] = PropertyState.Invalid;
                                        goto UnExpectedFormatProperty;
                                    }
                                    parseResult[MessagePropertyKind.Error] = PropertyState.Valid;
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
UnknownProperty:
                            {
                                parseResult.ParseErrors |= MessageParseErrors.HasUnknownProperty;
                                try
                                {
                                    reader.ReadStringSegmentRaw();
                                }
                                catch (JsonParsingException)
                                {
                                    goto InvalidJson;
                                }

                                if (reader.ReadIsValueSeparator())
                                {
                                    try
                                    {
                                        reader.ReadNextBlock();
                                    }
                                    catch (JsonParsingException)
                                    {
                                        goto InvalidJson;
                                    }
                                    break;
                                }
                                else
                                {
                                    goto InvalidJson;
                                }
                            }
UnExpectedFormatProperty:
                            {
                                parseResult.ParseErrors = MessageParseErrors.HasInvalidProperty;
                                try
                                {
                                    reader.ReadNextBlock();
                                }
                                catch (JsonParsingException)
                                {
                                    goto InvalidJson;
                                }
                                break;
                            }
                        }
                        switch (reader.GetCurrentJsonToken())
                        {
                        case JsonToken.ValueSeparator:
                        {
                            reader.AdvanceOffset(1);
                            continue;
                        }

                        case JsonToken.EndObject:
                        {
                            return(parseResult);
                        }

                        default:
                            goto InvalidJson;
                        }
                    }
                }
Ejemplo n.º 3
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));
                    }
                }
            }
        }