protected List <TerminalMode> ReadTerminalModes(byte[] encodedModes)
        {
            var termModes = new List <TerminalMode>();
            TerminalModeOpCode opCode;

            // Read modes from encoded byte stream.
            using (var streamReader = new SshStreamReader(new MemoryStream(encodedModes)))
            {
                while (true)
                {
                    opCode = (TerminalModeOpCode)streamReader.ReadByte();

                    if (opCode == TerminalModeOpCode.TtyOpEnd)
                    {
                        break;
                    }
                    if ((byte)opCode >= 1 && (byte)opCode <= 160)
                    {
                        // Add mode to list.
                        termModes.Add(new TerminalMode(opCode, streamReader.ReadUInt32()));
                    }
                    else
                    {
                        // Undefined op code.
                        break;
                    }
                }
            }

            return(termModes);
        }
        protected void ProcessMsgChannelWindowAdjust(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel adjust window size.
            var bytesToAdd = msgReader.ReadUInt32();

            channel.ProcessWindowAdjust(bytesToAdd);
        }
        protected void ProcessMsgChannelExtendedData(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel read extended data.
            var dataType = (SshExtendedDataType)msgReader.ReadUInt32();
            var data     = msgReader.ReadByteString();

            channel.ProcessExtendedData(dataType, data);
        }
        protected void ProcessMsgChannelRequest(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel number and get channel object.
            uint       channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            string requestType = msgReader.ReadString();
            bool   wantReply   = msgReader.ReadBoolean();

            // Let channel process request.
            channel.ProcessRequest(requestType, wantReply, msgReader);
        }
        protected void ProcessMsgChannelOpen(SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            // Read channel information.
            string channelType       = msgReader.ReadString();
            uint   senderChannel     = msgReader.ReadUInt32();
            uint   initialWindowSize = msgReader.ReadUInt32();
            uint   maxPacketSize     = msgReader.ReadUInt32();

            // Check channel type.
            switch (channelType)
            {
            default:
                // Raise event to request channel.
                var channelRequestedEventArgs = new ChannelOpenRequestEventArgs(senderChannel,
                                                                                (uint)_channels.Count, channelType, initialWindowSize, maxPacketSize);

                if (ChannelOpenRequest != null)
                {
                    ChannelOpenRequest(this, channelRequestedEventArgs);
                }

                var channel = channelRequestedEventArgs.Channel;

                // Check if channel was created.
                if (channel != null)
                {
                    channel.Opened          += new EventHandler <EventArgs>(channel_Opened);
                    channel.Closed          += new EventHandler <EventArgs>(channel_Closed);
                    channel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(
                        channel_PropertyChanged);
                    channel.Open(this);

                    _channels.Add(channel);

                    // Send confirmation message.
                    SendMsgChannelOpenConfirmation(channel);
                }
                else
                {
                    string failureDescription = channelRequestedEventArgs.FailureDescription;

                    if (failureDescription != null)
                    {
                        // Create description of failure from reason code.
                        switch (channelRequestedEventArgs.FailureReason)
                        {
                        case SshChannelOpenFailureReason.AdministrativelyProhibited:
                            failureDescription = "Administratively prohibited.";
                            break;

                        case SshChannelOpenFailureReason.ConnectFailed:
                            failureDescription = "Connect attempt failed.";
                            break;

                        case SshChannelOpenFailureReason.UnknownChannelType:
                            failureDescription = string.Format("Unknown channel type '{0}'.",
                                                               channelType);
                            break;

                        case SshChannelOpenFailureReason.ResourceShortage:
                            failureDescription = "Resource shortage on server.";
                            break;
                        }
                    }

                    // Channel open request has failed.
                    SendMsgChannelOpenFailure(channel, channelRequestedEventArgs.FailureReason,
                                              failureDescription, "");
                    return;
                }

                break;
            }
        }
        protected void ProcessMsgChannelWindowAdjust(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel adjust window size.
            var bytesToAdd = msgReader.ReadUInt32();

            channel.ProcessWindowAdjust(bytesToAdd);
        }
        protected void ProcessMsgChannelRequest(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            string requestType = msgReader.ReadString();
            bool wantReply = msgReader.ReadBoolean();

            // Let channel process request.
            channel.ProcessRequest(requestType, wantReply, msgReader);
        }
        protected void ProcessMsgChannelOpen(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel information.
            string channelType = msgReader.ReadString();
            uint senderChannel = msgReader.ReadUInt32();
            uint initialWindowSize = msgReader.ReadUInt32();
            uint maxPacketSize = msgReader.ReadUInt32();

            // Check channel type.
            switch (channelType)
            {
                default:
                    // Raise event to request channel.
                    var channelRequestedEventArgs = new ChannelOpenRequestEventArgs(senderChannel,
                        (uint)_channels.Count, channelType, initialWindowSize, maxPacketSize);

                    if (ChannelOpenRequest != null) ChannelOpenRequest(this, channelRequestedEventArgs);

                    var channel = channelRequestedEventArgs.Channel;

                    // Check if channel was created.
                    if (channel != null)
                    {
                        channel.Opened += new EventHandler<EventArgs>(channel_Opened);
                        channel.Closed += new EventHandler<EventArgs>(channel_Closed);
                        channel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(
                            channel_PropertyChanged);
                        channel.Open(this);

                        _channels.Add(channel);

                        // Send confirmation message.
                        SendMsgChannelOpenConfirmation(channel);
                    }
                    else
                    {
                        string failureDescription = channelRequestedEventArgs.FailureDescription;

                        if (failureDescription != null)
                        {
                            // Create description of failure from reason code.
                            switch (channelRequestedEventArgs.FailureReason)
                            {
                                case SshChannelOpenFailureReason.AdministrativelyProhibited:
                                    failureDescription = "Administratively prohibited.";
                                    break;
                                case SshChannelOpenFailureReason.ConnectFailed:
                                    failureDescription = "Connect attempt failed.";
                                    break;
                                case SshChannelOpenFailureReason.UnknownChannelType:
                                    failureDescription = string.Format("Unknown channel type '{0}'.",
                                        channelType);
                                    break;
                                case SshChannelOpenFailureReason.ResourceShortage:
                                    failureDescription = "Resource shortage on server.";
                                    break;
                            }
                        }

                        // Channel open request has failed.
                        SendMsgChannelOpenFailure(channel, channelRequestedEventArgs.FailureReason,
                            failureDescription, "");
                        return;
                    }

                    break;
            }
        }
        protected void ProcessMsgChannelExtendedData(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            // Let channel read extended data.
            var dataType = (SshExtendedDataType)msgReader.ReadUInt32();
            var data = msgReader.ReadByteString();

            channel.ProcessExtendedData(dataType, data);
        }
        protected void ProcessMsgChannelClose(SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            // Read channel number and get channel object.
            uint channelNum = msgReader.ReadUInt32();
            SshChannel channel;

            try { channel = _channels.SingleOrDefault(item => item.ServerChannel == channelNum); }
            catch (InvalidOperationException) { return; }

            channel.Close();
        }
        protected internal override void ProcessRequest(string requestType, bool wantReply,
                                                        SshStreamReader msgReader)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            switch (requestType)
            {
            case "pty-req":
                // Read information about pseudo-terminal.
                var termEnvVar       = msgReader.ReadString();
                var termCharsWidth   = msgReader.ReadUInt32();
                var termCharsHeight  = msgReader.ReadUInt32();
                var termPixelsWidth  = msgReader.ReadUInt32();
                var termPixelsHeight = msgReader.ReadUInt32();
                var termModes        = ReadTerminalModes(msgReader.ReadByteString());

                // Raise event to request pseudo terminal.
                var pseudoTerminalRequestedEventArgs = new PseudoTerminalRequestedEventArgs(termEnvVar);

                OnPseudoTerminalRequested(pseudoTerminalRequestedEventArgs);

                // Check if request to allocate pseudo terminal failed.
                if (!pseudoTerminalRequestedEventArgs.Success)
                {
                    break;
                }

                _termEnvVar       = termEnvVar;
                _termCharsWidth   = termCharsWidth;
                _termCharsHeight  = termCharsHeight;
                _termPixelsWidth  = termPixelsWidth;
                _termPixelsHeight = termPixelsHeight;
                _termModes        = termModes;

                // Add TERM to list of environment variables.
                _envVars.Add("TERM", _termEnvVar);

                // Raise event, pseudo terminal has been allocated.
                OnPseudoTerminalAllocated(new EventArgs());

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "env":
                // Read name and value of environment variable.
                var varName  = msgReader.ReadString();
                var varValue = msgReader.ReadString();

                // Add variable to list.
                _envVars.Add(varName, varValue);

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "shell":
                // Start default shell.
                StartShell();

                if (wantReply)
                {
                    _connService.SendMsgChannelSuccess(this);
                }
                return;

            case "exec":
                // not implemented

                break;

            default:
                base.ProcessRequest(requestType, wantReply, msgReader);
                return;
            }

            // Request has failed.
            if (wantReply)
            {
                _connService.SendMsgChannelFailure(this);
            }
        }
        protected List<TerminalMode> ReadTerminalModes(byte[] encodedModes)
        {
            var termModes = new List<TerminalMode>();
            TerminalModeOpCode opCode;

            // Read modes from encoded byte stream.
            using (var streamReader = new SshStreamReader(new MemoryStream(encodedModes)))
            {
                while (true)
                {
                    opCode = (TerminalModeOpCode)streamReader.ReadByte();

                    if (opCode == TerminalModeOpCode.TtyOpEnd) break;
                    if ((byte)opCode >= 1 && (byte)opCode <= 160)
                    {
                        // Add mode to list.
                        termModes.Add(new TerminalMode(opCode, streamReader.ReadUInt32()));
                    }
                    else
                    {
                        // Undefined op code.
                        break;
                    }
                }
            }

            return termModes;
        }
        protected internal override void ProcessRequest(string requestType, bool wantReply,
            SshStreamReader msgReader)
        {
            if (_isDisposed) throw new ObjectDisposedException(this.GetType().FullName);

            switch (requestType)
            {
                case "pty-req":
                    // Read information about pseudo-terminal.
                    var termEnvVar = msgReader.ReadString();
                    var termCharsWidth = msgReader.ReadUInt32();
                    var termCharsHeight = msgReader.ReadUInt32();
                    var termPixelsWidth = msgReader.ReadUInt32();
                    var termPixelsHeight = msgReader.ReadUInt32();
                    var termModes = ReadTerminalModes(msgReader.ReadByteString());

                    // Raise event to request pseudo terminal.
                    var pseudoTerminalRequestedEventArgs = new PseudoTerminalRequestedEventArgs(termEnvVar);

                    OnPseudoTerminalRequested(pseudoTerminalRequestedEventArgs);

                    // Check if request to allocate pseudo terminal failed.
                    if (!pseudoTerminalRequestedEventArgs.Success) break;

                    _termEnvVar = termEnvVar;
                    _termCharsWidth = termCharsWidth;
                    _termCharsHeight = termCharsHeight;
                    _termPixelsWidth = termPixelsWidth;
                    _termPixelsHeight = termPixelsHeight;
                    _termModes = termModes;

                    // Add TERM to list of environment variables.
                    _envVars.Add("TERM", _termEnvVar);

                    // Raise event, pseudo terminal has been allocated.
                    OnPseudoTerminalAllocated(new EventArgs());

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;

                case "env":
                    // Read name and value of environment variable.
                    var varName = msgReader.ReadString();
                    var varValue = msgReader.ReadString();

                    // Add variable to list.
                    _envVars.Add(varName, varValue);

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;
                case "shell":
                    // Start default shell.
                    StartShell();

                    if (wantReply) _connService.SendMsgChannelSuccess(this);
                    return;
                case "exec":
                    // not implemented

                    break;
                default:
                    base.ProcessRequest(requestType, wantReply, msgReader);
                    return;
            }

            // Request has failed.
            if (wantReply) _connService.SendMsgChannelFailure(this);
        }