/// <summary>
 /// Worker thread for remove directory
 /// </summary>
 private void RMDThread()
 {
     if (RequestPath.Length < 2)
     {
         Debug.Print("the path is not long enough");
         throw new ArgumentException("The path is not a directory");
     }
     else if (RequestPath[RequestPath.Length - 1] != "")
     {
         // the path is a directory
         Debug.Print("the path does not lead to a directory");
         throw new ArgumentException("The path is not a directory");
     }
     try
     {
         string command;
         int    responseNumber;
         if (RequestPath.Length > 2)
         {
             command = "CWD ";
             for (int i = 0; i < RequestPath.Length - 2; i++)
             {
                 command += RequestPath[i] + "/";
             }
             command += "\r\n";
             CommandSocket.Send(Encoding.UTF8.GetBytes(command));
             responseNumber = WaitResponse();
             if (responseNumber != 250)
             {
                 // change directory failed
                 return;
             }
         }
         command = "RMD " + RequestPath[RequestPath.Length - 2] + "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         responseNumber = WaitResponse();
         if (responseNumber != 250)
         {
             Debug.Print("cannot remove directory with wrong number: " + responseNumber.ToString());
             if (responseNumber == 550)
             {
                 m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
             }
             else
             {
                 m_StatusCode = FTPStatusCode.CommandFailed;
             }
             return;
         }
     }
     catch (SocketException se)
     {
         Debug.Print(se.Message);
         throw new WebException("Deleting directory fail due to connection problem.");
     }
 }
        /// <summary>
        /// Logging into the ftp server
        /// </summary>
        /// <returns>
        ///  -1: unknown errors or exceptions happened
        ///   0: login succeed
        ///  >0: reply code tells why server rejects the login process
        /// </returns>
        private int Login()
        {
            string command = null;

            byte[] dataBuffer     = new byte[1000];
            int    responseNumber = 0;

            m_StatusCode = FTPStatusCode.NotLoggedIn;
            try
            {
                CommandSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                CommandSocket.ReceiveTimeout = m_CommandTimeout;
                IPAddress hostIP = IPAddress.Parse(ServerIP);
                CommandSocket.Connect(new IPEndPoint(hostIP, ServerPort));
                responseNumber = WaitResponse();
                if (responseNumber != 220)
                {
                    // server not ready for new user login
                    return(responseNumber);
                }
                command = "USER " + m_Credential.UserName + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 331)
                {
                    // user name is not allowed
                    return(responseNumber);
                }
                command = "PASS " + m_Credential.Password + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 230)
                {
                    // password does not match
                    return(responseNumber);
                }
                m_StatusCode   = FTPStatusCode.LoggedInProceed;
                responseNumber = 0;
            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Login fail due to connection problem.");
            }
            return(responseNumber);
        }
 /// <summary>
 /// parse the response number to a status code
 /// </summary>
 /// <param name="responseNumber"></param>
 /// <returns>
 /// true if response number is less than 400
 /// </returns>
 private bool SetStatusCode(int responseNumber)
 {
     if (responseNumber >= 500)
     {
         Debug.Print(Method + " with wrong number: " + responseNumber.ToString());
         if (responseNumber == 502)
         {
             m_StatusCode = FTPStatusCode.CommandNotImplemented;
         }
         else if (responseNumber == 550)
         {
             m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
         }
         else if (responseNumber == 553)
         {
             m_StatusCode = FTPStatusCode.FilenameNotAllowed;
         }
         else
         {
             m_StatusCode = FTPStatusCode.CommandFailed;
         }
         return(false);
     }
     else if (responseNumber >= 400)
     {
         Debug.Print(Method + " with wrong number: " + responseNumber.ToString());
         if (responseNumber == 452)
         {
             m_StatusCode = FTPStatusCode.InsufficientSpace;
         }
         else
         {
             m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
         }
         return(false);
     }
     else
     {
         return(true);
     }
 }
        /// <summary>
        /// Functionality to run LIST scenario
        /// </summary>
        private void LISTThread()
        {
            if (RequestPath[RequestPath.Length - 1] != "")
            {
                // the path is a directory
                Debug.Print("the path does not lead to a directory");
                throw new ArgumentException("The path is not a directory");
            }
            try
            {
                string command = "CWD ";
                for (int i = 0; i < RequestPath.Length - 1; i++)
                {
                    command += RequestPath[i] + "/";
                }
                command += "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                int responseNumber = WaitResponse();
                if (responseNumber != 250)
                {
                    // change directory failed
                    m_StatusCode = FTPStatusCode.CommandFailed;
                    return;
                }
                using (Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    ConfigureListenSocket(listenSocket);

                    FTPActivePort = (listenSocket.LocalEndPoint as IPEndPoint).Port;
                    command = "PORT " + FormatFTPAddress(FTPActiveAddress, FTPActivePort) + "\r\n";
                    CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                    responseNumber = WaitResponse();
                    while (responseNumber == 230)
                    {
                        responseNumber = WaitResponse();
                    }
                    if (responseNumber != 200)
                    {
                        Debug.Print("port with wrong number: " + responseNumber.ToString());
                        m_StatusCode = FTPStatusCode.CommandFailed;
                        return;
                    }
                    CommandSocket.Send(Encoding.UTF8.GetBytes("LIST\r\n"));
                    responseNumber = WaitResponse();
                    if (!SetStatusCode(responseNumber))
                    {
                        return;
                    }

                    using (Timer timer = new Timer(TimerCallback, null, m_DataTimeout, -1))
                    {
                        DataSocket = listenSocket.Accept();
                    }

                    DataSocketReady = true;
                    m_DataStream = new NetworkStream(DataSocket);
                    m_FtpResponse = new FtpWebResponse(m_DataStream);
                    m_StreamReady.Set();

                    responseNumber = WaitResponse(-1);
                    TransmissionFinished = true;
                    if (responseNumber != 226)
                    {
                        Debug.Print("list end with wrong number: " + responseNumber.ToString());
                        m_StatusCode = FTPStatusCode.CommandFailed;
                        return;
                    }
                    m_StatusCode = FTPStatusCode.CommandProceed;

                    //while (!m_RequestClosed)
                    //{
                    //    // do not release the resource until the request is closed
                    //}
                    m_StatusCode = FTPStatusCode.ClosingData;
                }
            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Downloading fail due to connection problem.");
            }
        }
 /// <summary>
 /// Worker thread to rename a file or directory
 /// </summary>
 private void RenameThread()
 {
     if (RenameTo == null)
     {
         Debug.Print("New name is not selected");
         throw new ArgumentNullException("New name is not selected");
     }
     int oldIndex;
     if (RequestPath[RequestPath.Length - 1] == "")
     {
         throw new WebException("The requested URI is invalid for this FTP command.");
     }
     else
     {
         oldIndex = RequestPath.Length - 1;
     }
     try
     {
         string command = "CWD ";
         for (int i = 0; i < oldIndex; i++)
         {
             command += RequestPath[i] + "/";
         }
         command += "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         int responseNumber = WaitResponse();
         if (responseNumber != 250)
         {
             // change directory failed
             m_StatusCode = FTPStatusCode.CommandFailed;
             return;
         }
         command = "RNFR " + RequestPath[oldIndex] + "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         responseNumber = WaitResponse();
         if (responseNumber != 350)
         {
             Debug.Print("REFR fail with wrong number: " + responseNumber.ToString());
             if (responseNumber == 550)
             {
                 m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
             }
             else
             {
                 m_StatusCode = FTPStatusCode.CommandFailed;
             }
             return;
         }
         command = "RNTO " + RenameTo + "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         responseNumber = WaitResponse();
         if (responseNumber != 250)
         {
             Debug.Print("RETO fail with wrong number: " + responseNumber.ToString());
             m_StatusCode = FTPStatusCode.CommandFailed;
             return;
         }
     }
     catch (SocketException se)
     {
         Debug.Print(se.Message);
         throw new WebException("Renaming fail due to connection problem.");
     }
 }
 /// <summary>
 /// Worker thread for delete file
 /// </summary>
 private void DELEThread()
 {
     if (RequestPath[RequestPath.Length - 1] == "")
     {
         // the path is a directory
         Debug.Print("the path leads to a directory");
         throw new ArgumentException("The path is a directory");
     }
     try
     {
         string command = "CWD ";
         for (int i = 0; i < RequestPath.Length - 1; i++)
         {
             command += RequestPath[i] + "/";
         }
         command += "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         int responseNumber = WaitResponse();
         if (responseNumber != 250)
         {
             // change directory failed
             m_StatusCode = FTPStatusCode.CommandFailed;
             return;
         }
         command = "DELE " + RequestPath[RequestPath.Length - 1] + "\r\n";
         CommandSocket.Send(Encoding.UTF8.GetBytes(command));
         responseNumber = WaitResponse();
         if (responseNumber != 250)
         {
             Debug.Print("deletion fail with wrong number: " + responseNumber.ToString());
             if (responseNumber == 550)
             {
                 m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
             }
             else
             {
                 m_StatusCode = FTPStatusCode.CommandFailed;
             }
             return;
         }
     }
     catch (SocketException se)
     {
         Debug.Print(se.Message);
         throw new WebException("Deleting file fail due to connection problem.");
     }
 }
        /// <summary>
        /// Worker thread for make directory
        /// </summary>
        private void MKDThread()
        {
            if (RequestPath.Length < 2)
            {
                Debug.Print("the path is not long enough");
                throw new ArgumentException("The path is not a directory");
            }
            else if (RequestPath[RequestPath.Length - 1] != "")
            {
                // the path is a directory
                Debug.Print("the path does not lead to a directory");
                throw new ArgumentException("The path is not a directory");
            }
            try
            {
                string command;
                int responseNumber;

                // need to change directory
                if (RequestPath.Length > 2)
                {
                    command = "CWD ";
                    for (int i = 0; i < RequestPath.Length - 2; i++)
                    {
                        command += RequestPath[i] + "/";
                    }
                    command += "\r\n";
                    CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                    responseNumber = WaitResponse();
                    if (responseNumber != 250)
                    {
                        // change directory failed
                        m_StatusCode = FTPStatusCode.CommandFailed;
                        return;
                    }
                }
                command = "MKD " + RequestPath[RequestPath.Length - 2] + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 257)
                {
                    Debug.Print("cannot create directory with wrong number: " + responseNumber.ToString());
                    m_StatusCode = FTPStatusCode.CommandFailed;
                    return;
                }
            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Making directory fail due to connection problem.");
            }
        }
        /// <summary>
        /// Logging into the ftp server
        /// </summary>
        /// <returns>
        ///  -1: unknown errors or exceptions happened
        ///   0: login succeed
        ///  >0: reply code tells why server rejects the login process 
        /// </returns>
        private int Login()
        {
            string command = null;
            byte[] dataBuffer = new byte[1000];
            int responseNumber = 0;
            m_StatusCode = FTPStatusCode.NotLoggedIn;
            try
            {
                CommandSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                CommandSocket.ReceiveTimeout = m_CommandTimeout;
                IPAddress hostIP = IPAddress.Parse(ServerIP);
                CommandSocket.Connect(new IPEndPoint(hostIP, ServerPort));
                responseNumber = WaitResponse();
                if (responseNumber != 220)
                {
                    // server not ready for new user login
                    return responseNumber;
                }
                command = "USER " + m_Credential.UserName + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 331)
                {
                    // user name is not allowed
                    return responseNumber;
                }
                command = "PASS " + m_Credential.Password + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 230)
                {
                    // password does not match
                    return responseNumber;
                }
                m_StatusCode = FTPStatusCode.LoggedInProceed;
                responseNumber = 0;

            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Login fail due to connection problem.");
            }
            return responseNumber;
        }
 /// <summary>
 /// parse the response number to a status code
 /// </summary>
 /// <param name="responseNumber"></param>
 /// <returns>
 /// true if response number is less than 400
 /// </returns>
 private bool SetStatusCode(int responseNumber)
 {
     if (responseNumber >= 500)
     {
         Debug.Print(Method + " with wrong number: " + responseNumber.ToString());
         if (responseNumber == 502)
         {
             m_StatusCode = FTPStatusCode.CommandNotImplemented;
         }
         else if (responseNumber == 550)
         {
             m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
         }
         else if (responseNumber == 553)
         {
             m_StatusCode = FTPStatusCode.FilenameNotAllowed;
         }
         else
         {
             m_StatusCode = FTPStatusCode.CommandFailed;
         }
         return false;
     }
     else if (responseNumber >= 400)
     {
         Debug.Print(Method + " with wrong number: " + responseNumber.ToString());
         if (responseNumber == 452)
         {
             m_StatusCode = FTPStatusCode.InsufficientSpace;
         }
         else
         {
             m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
         }
         return false;
     }
     else
     {
         return true;
     }
 }
        /// <summary>
        /// Functionality to run LIST scenario
        /// </summary>
        private void LISTThread()
        {
            if (RequestPath[RequestPath.Length - 1] != "")
            {
                // the path is a directory
                Debug.Print("the path does not lead to a directory");
                throw new ArgumentException("The path is not a directory");
            }
            try
            {
                string command = "CWD ";
                for (int i = 0; i < RequestPath.Length - 1; i++)
                {
                    command += RequestPath[i] + "/";
                }
                command += "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                int responseNumber = WaitResponse();
                if (responseNumber != 250)
                {
                    // change directory failed
                    m_StatusCode = FTPStatusCode.CommandFailed;
                    return;
                }
                using (Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    ConfigureListenSocket(listenSocket);

                    FTPActivePort = (listenSocket.LocalEndPoint as IPEndPoint).Port;
                    command       = "PORT " + FormatFTPAddress(FTPActiveAddress, FTPActivePort) + "\r\n";
                    CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                    responseNumber = WaitResponse();
                    while (responseNumber == 230)
                    {
                        responseNumber = WaitResponse();
                    }
                    if (responseNumber != 200)
                    {
                        Debug.Print("port with wrong number: " + responseNumber.ToString());
                        m_StatusCode = FTPStatusCode.CommandFailed;
                        return;
                    }
                    CommandSocket.Send(Encoding.UTF8.GetBytes("LIST\r\n"));
                    responseNumber = WaitResponse();
                    if (!SetStatusCode(responseNumber))
                    {
                        return;
                    }

                    using (Timer timer = new Timer(TimerCallback, null, m_DataTimeout, -1))
                    {
                        DataSocket = listenSocket.Accept();
                    }

                    DataSocketReady = true;
                    m_DataStream    = new NetworkStream(DataSocket);
                    m_FtpResponse   = new FtpWebResponse(m_DataStream);
                    m_StreamReady.Set();

                    responseNumber       = WaitResponse(-1);
                    TransmissionFinished = true;
                    if (responseNumber != 226)
                    {
                        Debug.Print("list end with wrong number: " + responseNumber.ToString());
                        m_StatusCode = FTPStatusCode.CommandFailed;
                        return;
                    }
                    m_StatusCode = FTPStatusCode.CommandProceed;

                    //while (!m_RequestClosed)
                    //{
                    //    // do not release the resource until the request is closed
                    //}
                    m_StatusCode = FTPStatusCode.ClosingData;
                }
            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Downloading fail due to connection problem.");
            }
        }
        /// <summary>
        /// Worker thread to rename a file or directory
        /// </summary>
        private void RenameThread()
        {
            if (RenameTo == null)
            {
                Debug.Print("New name is not selected");
                throw new ArgumentNullException("New name is not selected");
            }
            int oldIndex;

            if (RequestPath[RequestPath.Length - 1] == "")
            {
                throw new WebException("The requested URI is invalid for this FTP command.");
            }
            else
            {
                oldIndex = RequestPath.Length - 1;
            }
            try
            {
                string command = "CWD ";
                for (int i = 0; i < oldIndex; i++)
                {
                    command += RequestPath[i] + "/";
                }
                command += "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                int responseNumber = WaitResponse();
                if (responseNumber != 250)
                {
                    // change directory failed
                    m_StatusCode = FTPStatusCode.CommandFailed;
                    return;
                }
                command = "RNFR " + RequestPath[oldIndex] + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 350)
                {
                    Debug.Print("REFR fail with wrong number: " + responseNumber.ToString());
                    if (responseNumber == 550)
                    {
                        m_StatusCode = FTPStatusCode.ResourceUnavailableOrBusy;
                    }
                    else
                    {
                        m_StatusCode = FTPStatusCode.CommandFailed;
                    }
                    return;
                }
                command = "RNTO " + RenameTo + "\r\n";
                CommandSocket.Send(Encoding.UTF8.GetBytes(command));
                responseNumber = WaitResponse();
                if (responseNumber != 250)
                {
                    Debug.Print("RETO fail with wrong number: " + responseNumber.ToString());
                    m_StatusCode = FTPStatusCode.CommandFailed;
                    return;
                }
            }
            catch (SocketException se)
            {
                Debug.Print(se.Message);
                throw new WebException("Renaming fail due to connection problem.");
            }
        }