/// <summary>
        /// Opens a data stream.
        /// </summary>
        /// <param name='request'>The command to execute that requires a data stream</param>
        /// <returns>The data stream.</returns>
        public async Task <FtpStreamChannel> OpenDataStreamAsync(FtpRequest request)
        {
            FtpStreamChannel      stream = null;
            FtpDataConnectionType type   = m_DataConnectionType;

            // The PORT and PASV commands do not work with IPv6 so
            // if either one of those types are set change them
            // to EPSV or EPRT appropriately.
            if (m_Stream.LocalEndPoint.Type == HostNameType.Ipv6)
            {
                switch (type)
                {
                case FtpDataConnectionType.PORT:
                    type = FtpDataConnectionType.EPRT;
                    Debug.WriteLine("Changed data connection type to EPRT because we are connected with IPv6.");
                    break;

                case FtpDataConnectionType.PASV:
                case FtpDataConnectionType.PASVEX:
                    type = FtpDataConnectionType.EPSV;
                    Debug.WriteLine("Changed data connection type to EPSV because we are connected with IPv6.");
                    break;
                }
            }

            switch (type)
            {
            case FtpDataConnectionType.AutoPassive:
            case FtpDataConnectionType.EPSV:
            case FtpDataConnectionType.PASV:
            case FtpDataConnectionType.PASVEX:
                stream = await m_Stream.OpenPassiveDataStreamAsync(type, request);

                break;

            case FtpDataConnectionType.AutoActive:
            case FtpDataConnectionType.EPRT:
            case FtpDataConnectionType.PORT:
                // TODO:
                break;
            }

            if (stream == null)
            {
                throw new InvalidOperationException("The specified data channel type is not implemented.");
            }


            return(stream);
        }
        public async Task <FtpStreamChannel> OpenPassiveDataStreamAsync(FtpDataConnectionType connectionType, FtpRequest request)
        {
            FtpPassiveModeResponse reply;

            if (connectionType == FtpDataConnectionType.EPSV || connectionType == FtpDataConnectionType.AutoPassive)
            {
                if (!(reply = await SetExtendedPassiveMode()).Success)
                {
                    // if we're connected with IPv4 and data channel type is AutoPassive then fallback to IPv4
                    if (reply.Type == FtpResponseType.PermanentNegativeCompletion && connectionType == FtpDataConnectionType.AutoPassive && LocalEndPoint.Type == HostNameType.Ipv4)
                    {
                        return(await OpenPassiveDataStreamAsync(FtpDataConnectionType.PASV, request));
                    }

                    throw new FtpCommandException(reply);
                }
            }
            else
            {
                if (LocalEndPoint.Type != HostNameType.Ipv4)
                {
                    throw new FtpException("Only IPv4 is supported by the PASV command. Use EPSV instead.");
                }

                if (!(reply = await SetPassiveMode()).Success)
                {
                    throw new FtpCommandException(reply);
                }
            }

            var passiveConnection = new FtpStreamChannel();

            await passiveConnection.ConnectAsync(reply.HostName, reply.ServiceName);


            // NOTE: Maybe it is better to just to open the passive channel, and execute the command else where..
            if (!(await ExecuteAsync <FtpResponse>(request)).Success)
            {
                passiveConnection.Dispose();
                throw new FtpCommandException(reply);
            }

            return(passiveConnection);
        }
        public async Task <FtpResponse> CloseDataStreamAsync(FtpStreamChannel channel)
        {
            var finalResponse = await m_Stream.GetReplyAsync <FtpResponse>();

            return(finalResponse);
        }
        /// <summary>
        /// Connect to the server
        /// </summary>
        public async Task ConnectAsync()
        {
            if (m_Stream == null)
            {
                m_Stream = new FtpStreamChannel();
            }
            else
            {
                if (IsConnected)
                {
                    await DisconnectAsync();
                }
            }

            if (HostName == null)
            {
                throw new FtpException("No host has been specified");
            }

            if (Credentials == null)
            {
                throw new FtpException("No credentials have been specified");
            }

            FtpResponse reply;

            if (await m_Stream.ConnectAsync(HostName, ServiceName))
            {
                if (!(reply = await GetReplyAsync()).Success)
                {
                    if (reply.Code == null)
                    {
                        throw new IOException("The connection was terminated before a greeting could be read.");
                    }

                    throw new FtpCommandException(reply);
                }
            }

            // TODO: If the encryption mode is set to explicit, raise to SSL

            if (Credentials != null)
            {
                await AuthenticateAsync(Credentials);
            }

            if ((reply = await m_Stream.GetFeaturesAsync()).Success)
            {
                m_Caps = ((FtpFeaturesResponse)reply).Features;
            }

            // Enable UTF8 if it's available
            if (m_Caps.HasFlag(FtpCapability.UTF8))
            {
                // If the server supports UTF8 it should already be enabled and this
                // command should not matter however there are conflicting drafts
                // about this so we'll just execute it to be safe.
                await m_Stream.SetOptionsAsync("UTF8 ON");

                m_Stream.Encoding = Encoding.UTF8;
            }
        }