From 50bf2ff1439d8a14f3627e8d4121bbaecfec5f6e Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Wed, 6 Jul 2016 11:04:02 +0100
Subject: [PATCH] Return dir listing as XML. Also begin to return XSLT
 stylesheet, but it doesn't work just  yet.

---
 GalleryShare/GalleryServer.cs | 88 ++++++++++++++++++++++++++++++++++-
 GalleryShare/Utilities.cs     | 15 ++++++
 2 files changed, 101 insertions(+), 2 deletions(-)

diff --git a/GalleryShare/GalleryServer.cs b/GalleryShare/GalleryServer.cs
index ee2dc04..6ff801a 100644
--- a/GalleryShare/GalleryServer.cs
+++ b/GalleryShare/GalleryServer.cs
@@ -3,6 +3,11 @@ using System.Net;
 using System.Threading.Tasks;
 using System.Runtime.InteropServices;
 using System.IO;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Messaging;
+using System.Threading;
+using System.Xml;
+using System.Reflection;
 
 namespace GalleryShare
 {
@@ -12,8 +17,9 @@ namespace GalleryShare
 		string prefix;
 		int port;
 
-		public int Port { get { return port; } }
+		string servingDirectory = Environment.CurrentDirectory;
 
+		public int Port { get { return port; } }
 
 		public GalleryServer(int inPort)
 		{
@@ -52,13 +58,91 @@ namespace GalleryShare
 		/// <param name="cycle">The Http request to handle.</param>
 		private async Task Handle(HttpListenerContext cycle)
 		{
+			if(cycle.Request.RawUrl == @"/!Transform-DirListing.xslt")
+			{
+				/*string[] resNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
+				foreach (string resName in resNames)
+					Console.WriteLine(resName);*/
+				cycle.Response.ContentType = "text/xsl";
+				byte[] xsltData = await Utilities.GetEmbeddedResourceContent(@"GalleryShare.XSLT.DirectoryListing.xslt");
+				cycle.Response.OutputStream.WriteAsync(xsltData, 0, xsltData.Length);
+				cycle.Response.Close();
+			}
+			string requestedPath = Path.GetFullPath(Path.Combine(servingDirectory, "." + cycle.Request.RawUrl));
+
+			if (!File.Exists(requestedPath) && !Directory.Exists(requestedPath))
+			{
+				await sendMessage(cycle, 404, "Error: File or directory '{0}' not found.", requestedPath);
+				logCycle(cycle);
+				return;
+			}
+
+			FileAttributes reqPathAttrs = File.GetAttributes(requestedPath);
+
 			StreamWriter responseData = new StreamWriter(cycle.Response.OutputStream);
 
-			await responseData.WriteLineAsync(string.Format("You requested {0}", cycle.Request.RawUrl));
+			if(reqPathAttrs.HasFlag(FileAttributes.Directory))
+			{
+				List<string> dirFiles = new List<string>(Directory.GetFiles(requestedPath));
+				List<string> dirDirectories = new List<string>(Directory.GetDirectories(requestedPath));
+
+				cycle.Response.ContentType = "text/xml";
+				
+				await responseData.FlushAsync();
+				XmlWriterSettings writerSettings = new XmlWriterSettings();
+				writerSettings.Async = true;
+				XmlWriter xmlData = XmlWriter.Create(cycle.Response.OutputStream, writerSettings);
+
+				await xmlData.WriteStartDocumentAsync();
+				await xmlData.WriteProcessingInstructionAsync("xsl-stylesheet", "type=\"text/xsl\" href=\"/!Transform-DirListing.xslt\"");
+				await xmlData.WriteStartElementAsync(null, "DirectoryListing", null);
+
+				foreach (string directoryname in dirDirectories)
+				{
+					await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
+					await xmlData.WriteAttributeStringAsync(null, "Type", null, "Directory");
+
+					await xmlData.WriteElementStringAsync(null, "Name", null, directoryname);
+
+					// TODO: Write out the number of items in directory
+					// TODO: Write out thumbnail url
+
+					await xmlData.WriteEndElementAsync();
+				}
+				foreach (string filename in dirFiles)
+				{
+					await xmlData.WriteStartElementAsync(null, "ListingEntry", null);
+					await xmlData.WriteAttributeStringAsync(null, "Type", null, "File");
+
+					await xmlData.WriteElementStringAsync(null, "Name", null, filename);
+
+					// TODO: Write out thumbnail url
+
+					await xmlData.WriteEndElementAsync();
+				}
+
+				await xmlData.WriteEndDocumentAsync();
+				await xmlData.FlushAsync();
+			}
 
 			responseData.Close();
 			cycle.Response.Close();
 
+			logCycle(cycle);
+		}
+
+		private async Task sendMessage(HttpListenerContext cycle, int statusCode, string message, params object[] paramObjects)
+		{
+			StreamWriter responseData = new StreamWriter(cycle.Response.OutputStream);
+
+			cycle.Response.StatusCode = statusCode;
+			await responseData.WriteLineAsync(string.Format(message, paramObjects));
+			responseData.Close();
+			cycle.Response.Close();
+		}
+
+		private void logCycle(HttpListenerContext cycle)
+		{
 			Console.WriteLine("[{0}] [{1}] [{2}] {3} {4}",
 				DateTime.Now.ToString("hh:mm tt"),
 				cycle.Request.RemoteEndPoint,
diff --git a/GalleryShare/Utilities.cs b/GalleryShare/Utilities.cs
index 83d59b6..5783da0 100644
--- a/GalleryShare/Utilities.cs
+++ b/GalleryShare/Utilities.cs
@@ -1,6 +1,9 @@
 ﻿using System;
 using System.Threading.Tasks;
 using System.Linq;
+using System.Reflection;
+using System.IO;
+using System.Net.Mime;
 
 namespace GalleryShare
 {
@@ -31,6 +34,18 @@ namespace GalleryShare
 					throw;
 			}
 		}
+
+		public static async Task<byte[]> GetEmbeddedResourceContent(string resourceName)
+		{
+			Assembly asm = Assembly.GetExecutingAssembly();
+			Stream stream = asm.GetManifestResourceStream(resourceName);
+			MemoryStream ms = new MemoryStream();
+			await stream.CopyToAsync(ms);
+			byte[] embeddedContent = ms.ToArray();
+			ms.Dispose();
+			stream.Dispose();
+			return embeddedContent;
+		}
 	}
 }
 
