private void AddFileInfo(XmlTextWriter xml, DAVFileDirInfo info, string item)
        {
            xml.WriteStartElement("response", "DAV:");
            {
                xml.WriteElementString("href", "DAV:", BaseHref + EscapeSpecialChars(item));
                xml.WriteStartElement("propstat", "DAV:");
                {
                    xml.WriteStartElement("prop", "DAV:");
                    {
                        if (info != null)
                        {
                            xml.WriteElementString("creationdate", "DAV:", info.CreationTimeUtc.ToString("r", CultureInfo.InvariantCulture));
                            xml.WriteElementString("getlastmodified", "DAV:", info.LastWriteTimeUtc.ToString("r", CultureInfo.InvariantCulture));
                            xml.WriteElementString("getcontenttype", "DAV:", GetMimeType(info.FullName));
                            xml.WriteElementString("getcontentlength", "DAV:", "" + Math.Min(info.Length, Int32.MaxValue));
                            xml.WriteElementString("getetag", "DAV:", "1/" + BaseHref + EscapeSpecialChars(item));
                            xml.WriteElementString("displayname", "DAV:", info.DisplayName);
                        }
                        xml.WriteElementString("getresourcetype", "DAV:", "");
                        xml.WriteElementString("resourcetype", "DAV:", "");
                        xml.WriteElementString("supportedlock", "DAV:", "");
                    }
                    xml.WriteEndElement();

                    xml.WriteElementString("status", "DAV:", GetStatusCode(200));
                }
                xml.WriteEndElement();
            }
            xml.WriteEndElement();

            #if false
            xml.WriteStartElement("response", "DAV:");

            //Load the valid items HTTP/1.1 200 OK
            xml.WriteElementString("href", "DAV:", EscapeSpecialChars(href));

            //Open the propstat element section
            xml.WriteStartElement("propstat", "DAV:");
            xml.WriteElementString("status", "DAV:", GetStatusCode(200));

            //Open the prop element section
            xml.WriteStartElement("prop", "DAV:");

            xml.WriteElementString("getcontenttype", "DAV:", GetMimeType(info.FullName));

            xml.WriteStartElement("getlastmodified", "DAV:");
            xml.WriteAttributeString("b:dt", "dateTime.rfc1123");
            xml.WriteString(DateTime.Now.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture));
            xml.WriteEndElement();

            xml.WriteElementString("getcontentlength", "DAV:", "" + Math.Min(info.Length, Int32.MaxValue));
            xml.WriteElementString("getresourcetype", "DAV:", "");

            xml.WriteElementString("getetag", "DAV:", "\"" + info.GetHashCode() + "\"");

            //Close the prop element section
            xml.WriteEndElement();

            //Close the propstat element section
            xml.WriteEndElement();
            xml.WriteEndElement();
            #endif
        }
        public override void HandleRequest(Stream stream)
        {
            if (IsAccessDenied())
            {
                base.HandleRequest(stream);
                return;
            }

            using (Stream mem = new MemoryStream())
            {
                VirtualFileType type = VirtualFileType.Resolve(RequestPath);

                switch (type.Type)
                {
                    case FileType.Invalid:
                        StatusCode = GetStatusCode(400);
                        break;

                    case FileType.PureVirtualDir:
                        {
                            try
                            {
                                XmlTextWriter xml = new XmlTextWriter(mem, Encoding.UTF8);
                                FileInfo mlvFileInfo = new FileInfo(type.MlvFilePath);

                                xml.Formatting = Formatting.Indented;
                                xml.IndentChar = ' ';
                                xml.Indentation = 1;
                                xml.WriteStartDocument();

                                xml.WriteStartElement("D", "multistatus", "DAV:");

                                /* infos about current directory */
                                AddDirectoryInfo(xml, mlvFileInfo, RequestPath);

                                int depth = 0;

                                if (DepthHeaderLine == "1")
                                {
                                    depth = 1;
                                }
                                else if (DepthHeaderLine.ToLower() == "infinity")
                                {
                                    depth = int.MaxValue;
                                }

                                /* add children only if propfind is called with a depth > 0 */
                                if (depth > 0)
                                {
                                    if (Program.Instance.Server.Settings.ShowInfos)
                                    {
                                        foreach (string file in MLVAccessor.GetInfoFields(mlvFileInfo.FullName))
                                        {
                                            string virtFile = ValidateFileName(type.MlvBaseName + "__" + file);
                                            DAVFileDirInfo mlvMiscInfo = new DAVFileDirInfo(virtFile);

                                            mlvMiscInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".txt");
                                            mlvMiscInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".txt");
                                            mlvMiscInfo.Length = 0;
                                            mlvMiscInfo.FullName = RequestPath + "/" + mlvMiscInfo.Name;

                                            AddFileInfo(xml, mlvMiscInfo, mlvMiscInfo.FullName);
                                        }

                                        DAVFileDirInfo mlvInfoInfo = new DAVFileDirInfo(type.MlvBaseName + ".txt");

                                        mlvInfoInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".txt");
                                        mlvInfoInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".txt");
                                        mlvInfoInfo.Length = MLVAccessor.GetFileSize(mlvFileInfo.FullName, ".txt");
                                        mlvInfoInfo.FullName = RequestPath + "/" + mlvInfoInfo.Name;

                                        if (!File.Exists(type.MlvStoreDir + Path.DirectorySeparatorChar + mlvInfoInfo.Name))
                                        {
                                            AddFileInfo(xml, mlvInfoInfo, mlvInfoInfo.FullName);
                                        }
                                    }

                                    /* wav file*/
                                    if (Program.Instance.Server.Settings.ShowWav)
                                    {
                                        if (MLVAccessor.HasAudio(mlvFileInfo.FullName))
                                        {
                                            DAVFileDirInfo mlvWavInfo = new DAVFileDirInfo(type.MlvBaseName + ".wav");

                                            mlvWavInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".wav");
                                            mlvWavInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, ".wav");
                                            mlvWavInfo.Length = MLVAccessor.GetFileSize(mlvFileInfo.FullName, ".wav");
                                            mlvWavInfo.FullName = RequestPath + "/" + mlvWavInfo.Name;

                                            if (!File.Exists(type.MlvStoreDir + Path.DirectorySeparatorChar + mlvWavInfo.Name))
                                            {
                                                AddFileInfo(xml, mlvWavInfo, mlvWavInfo.FullName);
                                            }
                                        }
                                    }

                                    /* add one file per frame */
                                    foreach (uint frame in MLVAccessor.GetFrameNumbers(mlvFileInfo.FullName))
                                    {
                                        if (Program.Instance.Server.Settings.ShowDng)
                                        {
                                            string frameName = frame.ToString("000000") + ".dng";
                                            DAVFileDirInfo frameInfo = new DAVFileDirInfo(type.MlvBaseName + "_" + frameName);

                                            /* one DNG file per frame */
                                            frameInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.Length = MLVAccessor.GetFileSize(mlvFileInfo.FullName, frameName);
                                            frameInfo.FullName = RequestPath + "/" + frameInfo.Name;
                                            frameInfo.DisplayName = "Frame " + frame + " as DNG";

                                            if (!File.Exists(type.MlvStoreDir + Path.DirectorySeparatorChar + frameInfo.Name))
                                            {
                                                AddFileInfo(xml, frameInfo, frameInfo.FullName);
                                            }
                                        }

                                        /* one JPEG file per frame if enabled */
                                        if (Program.Instance.Server.Settings.ShowJpeg)
                                        {
                                            string frameName = frame.ToString("000000") + ".jpg";
                                            DAVFileDirInfo frameInfo = new DAVFileDirInfo(type.MlvBaseName + "_" + frameName);

                                            frameInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.Length = MLVAccessor.GetFileSize(mlvFileInfo.FullName, frameName);
                                            frameInfo.FullName = RequestPath + "/" + frameInfo.Name;
                                            frameInfo.DisplayName = "Frame " + frame + " as Jpeg";

                                            if (!File.Exists(type.MlvStoreDir + Path.DirectorySeparatorChar + frameInfo.Name))
                                            {
                                                AddFileInfo(xml, frameInfo, frameInfo.FullName);
                                            }
                                        }

                                        /* one FITS file per frame if enabled */
                                        if (Program.Instance.Server.Settings.ShowFits)
                                        {
                                            string frameName = frame.ToString("000000") + ".fits";
                                            DAVFileDirInfo frameInfo = new DAVFileDirInfo(type.MlvBaseName + "_" + frameName);

                                            frameInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(mlvFileInfo.FullName, frameName);
                                            frameInfo.Length = MLVAccessor.GetFileSize(mlvFileInfo.FullName, frameName);
                                            frameInfo.FullName = RequestPath + "/" + frameInfo.Name;
                                            frameInfo.DisplayName = "Frame " + frame + " as FITS";

                                            if (!File.Exists(type.MlvStoreDir + Path.DirectorySeparatorChar + frameInfo.Name))
                                            {
                                                AddFileInfo(xml, frameInfo, frameInfo.FullName);
                                            }
                                        }
                                    }

                                    /* add locally stored files */
                                    if (Directory.Exists(type.MlvStoreDir))
                                    {
                                        AddFilesAndFolders(xml, type.MlvStoreDir, depth - 1);
                                    }
                                }

                                xml.WriteEndElement();
                                xml.WriteEndDocument();
                                xml.Flush();

                                StatusCode = GetStatusCode(207);
                                ResponseTextContent = RequestHandler.StreamToString(mem);

                                Server.LogRequest("Providing file list for MLV file: " + type.MlvFilePath);
                            }
                            catch(FileNotFoundException e)
                            {
                                Server.Log("[E] Invalid MLV location: " + type.RequestPath);
                                StatusCode = GetStatusCode(404);
                            }
                            catch(Exception e)
                            {
                                Server.Log("[E] Error while browsing " + type.RequestPath + ": " + e.GetType() + ", " + e.Message);
                                StatusCode = GetStatusCode(500);
                            }
                        }
                        break;

                    case FileType.PureVirtualFile:
                        {
                            XmlTextWriter xml = new XmlTextWriter(mem, Encoding.UTF8);

                            xml.Formatting = Formatting.Indented;
                            xml.IndentChar = ' ';
                            xml.Indentation = 1;
                            xml.WriteStartDocument();

                            //Set the Multistatus
                            xml.WriteStartElement("D", "multistatus", "DAV:");
                            DAVFileDirInfo mlvItemInfo = new DAVFileDirInfo(type.MlvFileContent);

                            mlvItemInfo.CreationTimeUtc = MLVAccessor.GetFileDateUtc(type.MlvFilePath, type.MlvFileContent);
                            mlvItemInfo.LastWriteTimeUtc = MLVAccessor.GetFileDateUtc(type.MlvFilePath, type.MlvFileContent);
                            mlvItemInfo.Length = MLVAccessor.GetFileSize(type.MlvFilePath, type.MlvFileContent);
                            mlvItemInfo.FullName = RequestPath + "/" + mlvItemInfo.Name;

                            AddFileInfo(xml, mlvItemInfo, RequestPath);

                            xml.WriteEndElement();
                            xml.WriteEndDocument();
                            xml.Flush();

                            StatusCode = GetStatusCode(207);
                            ResponseTextContent = RequestHandler.StreamToString(mem);
                            MimeType = "text/xml; charset=\"utf-8\"";
                        }
                        break;

                    case FileType.Redirected:
                    case FileType.Direct:
                        if (Directory.Exists(type.LocalPath))
                        {
                            XmlTextWriter xml = new XmlTextWriter(mem, Encoding.UTF8);

                            xml.Formatting = Formatting.Indented;
                            xml.IndentChar = ' ';
                            xml.Indentation = 1;
                            xml.WriteStartDocument();

                            //Set the Multistatus
                            xml.WriteStartElement("D", "multistatus", "DAV:");

                            AddDirectoryInfo(xml, new DirectoryInfo(type.LocalPath), RequestPath);

                            int depth = 0;
                            if (DepthHeaderLine == "1")
                            {
                                depth = 1;
                            }
                            else if (DepthHeaderLine == "infinity")
                            {
                                depth = int.MaxValue;
                            }

                            AddFilesAndFolders(xml, type.LocalPath, depth - 1);

                            xml.WriteEndElement();
                            xml.WriteEndDocument();
                            xml.Flush();

                            StatusCode = GetStatusCode(207);
                            ResponseTextContent = RequestHandler.StreamToString(mem);

                            Server.LogRequest("Providing file list for " + type.LocalPath);
                        }
                        else if (File.Exists(type.LocalPath))
                        {
                            XmlTextWriter xml = new XmlTextWriter(mem, Encoding.UTF8);

                            xml.Formatting = Formatting.Indented;
                            xml.IndentChar = ' ';
                            xml.Indentation = 1;
                            xml.WriteStartDocument();

                            //Set the Multistatus
                            xml.WriteStartElement("D", "multistatus", "DAV:");

                            AddFileInfo(xml, new FileInfo(type.LocalPath), RequestPath);

                            xml.WriteEndElement();
                            xml.WriteEndDocument();
                            xml.Flush();

                            StatusCode = GetStatusCode(207);
                            ResponseTextContent = RequestHandler.StreamToString(mem);
                            MimeType = "text/xml; charset=\"utf-8\"";

                            Server.LogRequest("Providing file info for " + type.LocalPath);
                        }
                        else
                        {
                            StatusCode = GetStatusCode(404);
                        }
                        break;
                }
            }

            base.HandleRequest(stream);
        }
        private void AddDirectoryInfo(XmlTextWriter xml, DAVFileDirInfo info, string item)
        {
            xml.WriteStartElement("response", "DAV:");
            {
                xml.WriteElementString("href", "DAV:", BaseHref + EscapeSpecialChars(item));
                xml.WriteStartElement("propstat", "DAV:");
                {
                    xml.WriteStartElement("prop", "DAV:");
                    {
                        if (info != null)
                        {
                            xml.WriteElementString("creationdate", "DAV:", info.CreationTimeUtc.ToString("r", CultureInfo.InvariantCulture));
                            xml.WriteElementString("getlastmodified", "DAV:", info.LastWriteTimeUtc.ToString("r", CultureInfo.InvariantCulture));
                            //xml.WriteElementString("quota-available-bytes", "DAV:", GetTotalFreeSpace(info.FullName).ToString());
                            //xml.WriteElementString("quota-used-bytes", "DAV:", GetTotalUsedSpace(info.FullName).ToString());
                        }

                        xml.WriteStartElement("resourcetype", "DAV:");
                        {
                            xml.WriteElementString("collection", "DAV:","");
                        }
                        xml.WriteEndElement();
                    }
                    xml.WriteEndElement();

                    xml.WriteElementString("status", "DAV:", GetStatusCode(200));
                }
                xml.WriteEndElement();
            }
            xml.WriteEndElement();

            #if false

            xml.WriteStartElement("response", "DAV:");

            //Load the valid items HTTP/1.1 200 OK
            xml.WriteElementString("href", "DAV:", EscapeSpecialChars(href));

            //Open the propstat element section
            xml.WriteStartElement("propstat", "DAV:");
            xml.WriteElementString("status", "DAV:", GetStatusCode(200));

            //Open the prop element section
            xml.WriteStartElement("prop", "DAV:");

            xml.WriteElementString("contenttype", "DAV:", "application/webdav-collection");

            xml.WriteStartElement("lastmodified", "DAV:");
            xml.WriteAttributeString("b:dt", "dateTime.rfc1123");
            xml.WriteString(DateTime.Now.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture));
            xml.WriteEndElement();

            xml.WriteElementString("contentlength", "DAV:", "0");

            xml.WriteStartElement("resourcetype", "DAV:");
            xml.WriteElementString("collection", "DAV:", "");
            xml.WriteEndElement();

            //Close the prop element section
            xml.WriteEndElement();

            //Close the propstat element section
            xml.WriteEndElement();
            xml.WriteEndElement();
            #endif
        }