protected virtual void Run()
        {
            for (; ;)
            {
                FtpListenerContext context = this.GetContext();
                if (context == null)
                {
                    // the listener has been closed
                    return;
                }
                FtpResponseStream stream = context.Response.OutputStream;
                switch (context.Request.Method)
                {
                case WebRequestMethodsEx.Ftp.ChangeDirectory:
                    context.Response.StatusCode = DirectoryExists(context.Request.QueryString) ? FtpStatusCode.FileActionOK : FtpStatusCode.ActionNotTakenFileUnavailable;
                    break;

                case WebRequestMethods.Ftp.ListDirectory:
                case WebRequestMethods.Ftp.ListDirectoryDetails:
                    WriteDirInfo(context.Request.QueryString, stream);
                    context.Response.StatusCode = FtpStatusCode.ClosingData;
                    break;

                case WebRequestMethods.Ftp.RemoveDirectory:
                    context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    break;

                default:
                    context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError;
                    break;
                }
                stream.Close();
            }
        }
        private static void WriteDirInfo(string path, FtpResponseStream stream)
        {
            ArrayList sent = new ArrayList();

            foreach (FtpListener item in FtpListenerManager.GetFtpManager().Listeners)
            {
                foreach (String prefix in item.Prefixes)
                {
                    if (prefix.Length >= path.Length && path.Equals(prefix.Substring(0, path.Length)))
                    {
                        //this is "our" directory
                        String rest = prefix.Substring(path.Length);

                        int idx = rest.IndexOf("/");
                        if (idx >= 0)
                        {
                            rest = rest.Substring(0, idx);
                        }

                        if (rest.Length < 1)
                        {
                            continue;
                        }

                        bool alreadySent = false;
                        foreach (var itemSent in sent)
                        {
                            if (rest.Equals(itemSent))
                            {
                                alreadySent = true;
                                break;
                            }
                        }

                        if (alreadySent)
                        {
                            continue;
                        }

                        sent.Add(rest);

                        DirectoryInfo dir = new DirectoryInfo(rest);
                        stream.Write(new DirectoryInfo(rest));
                    }
                }
            }
        }
        private static bool WriteDirInfo(string path, FtpResponseStream stream)
        {
            if (!Directory.Exists(path))
            {
                return(false);
            }

            string[] dirs = Directory.GetDirectories(path);
            foreach (string d in dirs)
            {
                DirectoryInfo info = new DirectoryInfo(d);
                stream.Write(info);
            }

            string[] files = Directory.GetFiles(path);
            foreach (string file in files)
            {
                FileInfo info = new FileInfo(file);
                stream.Write(info);
            }

            return(true);
        }
        private static bool WriteDirInfo(string path, FtpResponseStream stream)
        {
            if (!Directory.Exists(path)) return false;

            string[] dirs = Directory.GetDirectories(path);
            foreach (string d in dirs)
            {
                DirectoryInfo info = new DirectoryInfo(d);
                stream.Write(info);
            }

            string[] files = Directory.GetFiles(path);
            foreach (string file in files)
            {
                FileInfo info = new FileInfo(file);
                stream.Write(info);
            }

            return true;
        }
        private static void WriteDirInfo(string path, FtpResponseStream stream)
        {
            ArrayList sent = new ArrayList();

            foreach (FtpListener item in FtpListenerManager.GetFtpManager().Listeners)
            {
                foreach (String prefix in item.Prefixes)
                {
                    if (prefix.Length >= path.Length && path.Equals(prefix.Substring(0, path.Length)))
                    {
                        //this is "our" directory
                        String rest = prefix.Substring(path.Length);

                        int idx = rest.IndexOf("/");
                        if (idx >= 0)
                        {
                            rest = rest.Substring(0, idx);
                        }

                        if (rest.Length < 1) continue;

                        bool alreadySent = false;
                        foreach (var itemSent in sent)
                        {
                            if (rest.Equals(itemSent))
                            {
                                alreadySent = true;
                                break;
                            }
                        }

                        if (alreadySent) continue;

                        sent.Add(rest);

                        DirectoryInfo dir = new DirectoryInfo(rest);
                        stream.Write(new DirectoryInfo(rest));
                    }
                }
            }
        }
        private void Run()
        {
            for (; ;)
            {
                FtpListenerContext context = this.GetContext();

                if (context == null)
                {
                    // the listener has been closed
                    return;
                }
                try
                {
                    switch (context.Request.Method)
                    {
                    case WebRequestMethodsEx.Ftp.ChangeDirectory:
                    {
                        String fsPath = MapToFilesystem(context.Request.QueryString);

                        if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar)
                        {
                            fsPath = fsPath.Substring(0, fsPath.Length - 1);
                        }

                        context.Response.StatusCode = Directory.Exists(fsPath) ? FtpStatusCode.FileActionOK : FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                    case WebRequestMethods.Ftp.ListDirectory:
                    case WebRequestMethods.Ftp.ListDirectoryDetails:
                    {
                        String fsPath = MapToFilesystem(context.Request.QueryString);

                        if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar)
                        {
                            fsPath = fsPath.Substring(0, fsPath.Length - 1);
                        }

                        if (WriteDirInfo(fsPath, context.Response.OutputStream))
                        {
                            context.Response.StatusCode = FtpStatusCode.ClosingData;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                        }
                    }
                    break;

                    case WebRequestMethods.Ftp.MakeDirectory:
                    {
                        String fsPath = MapToFilesystem(context.Request.QueryString);

                        if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar)
                        {
                            fsPath = fsPath.Substring(0, fsPath.Length - 1);
                        }

                        DirectoryInfo dinfo = Directory.CreateDirectory(fsPath);
                        context.Response.StatusCode = (null != dinfo && dinfo.Exists) ? FtpStatusCode.PathnameCreated : FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                    case WebRequestMethods.Ftp.RemoveDirectory:
                    {
                        DirectoryInfo info = new DirectoryInfo(MapToFilesystem(context.Request.QueryString));
                        if (info.Exists)
                        {
                            info.Delete();
                            context.Response.StatusCode = FtpStatusCode.FileActionOK;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed;
                        }
                    }
                    break;


                    case WebRequestMethods.Ftp.DownloadFile:
                    {
                        FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString));
                        if (info.Exists)
                        {
                            using (FileStream dataFile = new FileStream(MapToFilesystem(context.Request.QueryString), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                            {
                                context.Response.OutputStream.Write(dataFile);
                            }
                            context.Response.StatusCode = FtpStatusCode.ClosingData;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                        }
                    }
                    break;

                    case WebRequestMethods.Ftp.UploadFile:
                        if (!UploadsAllowed)
                        {
                            Logging.Print("Uploads forbidden by configuration: " + context.Request.QueryString);
                            context.Response.StatusCode = FtpStatusCode.FileActionAborted;
                        }
                        else
                        {
                            FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString));

                            FtpResponseStream istream = context.Request.InputStream;

                            using (FileStream dataFile = new FileStream(MapToFilesystem(context.Request.QueryString), FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                            {
                                istream.ReadTo(dataFile);
                                dataFile.Close();
                            }

                            context.Response.StatusCode = FtpStatusCode.ClosingData;
                        }
                        break;

                    case WebRequestMethods.Ftp.GetFileSize:
                    {
                        FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString));
                        if (info.Exists)
                        {
                            context.Response.OutputStream.Write(((int)info.Length).ToString());
                            context.Response.StatusCode = FtpStatusCode.FileStatus;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                        }
                    }
                    break;

                    case WebRequestMethods.Ftp.DeleteFile:
                    {
                        FileInfo info = new FileInfo(MapToFilesystem(context.Request.QueryString));
                        if (info.Exists)
                        {
                            info.Delete();
                            context.Response.StatusCode = FtpStatusCode.FileActionOK;
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed;
                        }
                    }
                    break;

                    case WebRequestMethodsEx.Ftp.RenameFrom:
                    {
                        FileInfo fInfo = new FileInfo(MapToFilesystem(context.Request.QueryString));

                        String fsPath = MapToFilesystem(context.Request.QueryString);
                        if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar)
                        {
                            fsPath = fsPath.Substring(0, fsPath.Length - 1);
                        }
                        DirectoryInfo dInfo = new DirectoryInfo(fsPath);

                        if (fInfo.Exists)
                        {
                            context.Response.StatusCode = FtpStatusCode.FileCommandPending;
                            context.Response.OutputStream.Close();

                            context = this.GetContext();

                            if (context.Request.Method != WebRequestMethodsEx.Ftp.RenameTo)
                            {
                                context.Response.StatusCode = FtpStatusCode.BadCommandSequence;
                            }
                            else
                            {
                                File.Move(fInfo.FullName, MapToFilesystem(context.Request.QueryString));

                                context.Response.StatusCode = FtpStatusCode.FileActionOK;
                            }
                        }
                        else if (dInfo.Exists)
                        {
                            context.Response.StatusCode = FtpStatusCode.FileCommandPending;
                            context.Response.OutputStream.Close();

                            context = this.GetContext();

                            if (context.Request.Method != WebRequestMethodsEx.Ftp.RenameTo)
                            {
                                context.Response.StatusCode = FtpStatusCode.BadCommandSequence;
                            }
                            else
                            {
                                fsPath = MapToFilesystem(context.Request.QueryString);
                                if (fsPath[fsPath.Length - 1] == Path.DirectorySeparatorChar)
                                {
                                    fsPath = fsPath.Substring(0, fsPath.Length - 1);
                                }

                                Directory.Move(dInfo.FullName, fsPath);

                                context.Response.StatusCode = FtpStatusCode.FileActionOK;
                            }
                        }
                        else
                        {
                            context.Response.StatusCode = FtpStatusCode.ActionNotTakenFilenameNotAllowed;
                        }
                    }
                    break;

                    default:
                        context.Response.StatusCode = FtpStatusCode.FileActionAborted;
                        break;
                    }
                }
                catch (Exception e)
                {
                    Logging.Print("could not process command: " + e);

                    context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError;
                }

                context.Response.OutputStream.Close();
            }
        }
        private void WorkerThread()
        {
            for (; ;)
            {
                FtpListenerContext context = this.GetContext();
                string             log     = "Get new context. Request type: " + context.Request.Method + " Query string: " + context.Request.QueryString;
                m_Logging.Add(log);
                FtpResponseStream stream = context.Response.OutputStream;
                switch (context.Request.Method)
                {
                case WebRequestMethodsEx.Ftp.ChangeDirectory:
                    bool accepted = false;
                    foreach (string prefix in m_Prefixes)
                    {
                        if (context.Request.QueryString == prefix)
                        {
                            accepted = true;
                            break;
                        }
                    }
                    if (accepted)
                    {
                        context.Response.StatusCode = FtpStatusCode.FileActionOK;
                    }
                    else
                    {
                        context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                case WebRequestMethods.Ftp.ListDirectoryDetails:
                    foreach (FileInfo info in m_FileInfo)
                    {
                        stream.Write(info);
                    }
                    stream.Write(new FileInfo("\\log"));
                    context.Response.StatusCode = FtpStatusCode.ClosingData;
                    break;

                case WebRequestMethods.Ftp.GetFileSize:
                    if (context.Request.QueryString.IndexOf("log") >= 0)
                    {
                        int length = 0;
                        foreach (string s in m_Logging)
                        {
                            length += s.Length + 2;
                        }
                        stream.Write(length.ToString());
                        context.Response.StatusCode = FtpStatusCode.FileStatus;
                    }
                    else
                    {
                        context.Response.StatusCode = FtpStatusCode.ActionNotTakenFileUnavailable;
                    }
                    break;

                default:
                    context.Response.StatusCode = FtpStatusCode.ActionAbortedLocalProcessingError;
                    break;
                }
                stream.Close();
            }
        }