diff --git a/OpenRAUploader/OpenRAUploader.csproj b/OpenRAUploader/OpenRAUploader.csproj
new file mode 100644
index 0000000000..73827f6e69
--- /dev/null
+++ b/OpenRAUploader/OpenRAUploader.csproj
@@ -0,0 +1,59 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}
+ Exe
+ Properties
+ OpenRAUploader
+ OpenRAUploader
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OpenRAUploader/OpenRAUploader.sln b/OpenRAUploader/OpenRAUploader.sln
new file mode 100644
index 0000000000..0063fbd014
--- /dev/null
+++ b/OpenRAUploader/OpenRAUploader.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRAUploader", "OpenRAUploader.csproj", "{B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B56CAEB1-F805-48D6-8EBF-CB30CE5F1F35}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/OpenRAUploader/Program.cs b/OpenRAUploader/Program.cs
new file mode 100644
index 0000000000..49e7714f1b
--- /dev/null
+++ b/OpenRAUploader/Program.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.IO;
+
+namespace OpenRAUploader
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Length != 6) { PrintUsage(); return; }
+ var server = args[0];
+ var user = args[1];
+ var password = args[2];
+ var platform = args[3];
+ var version = args[4];
+ var filename = args[5];
+
+ var uri = new UriBuilder("ftp", server);
+ uri.UserName = user;
+ uri.Password = password;
+ uri.Path += platform + "/";
+
+ var mainFileUri = new UriBuilder(uri.Uri);
+ mainFileUri.Path += Path.GetFileName(filename);
+
+ if (!File.Exists(filename)) { Console.WriteLine(filename + " does not exist."); return; }
+
+ Console.WriteLine(string.Format("Uploading {0} to {1}", Path.GetFileName(filename), mainFileUri.Uri));
+ var fileStream = File.Open(filename, FileMode.Open, FileAccess.Read);
+ var size = fileStream.Length;
+
+ var response = UploadFile(mainFileUri.Uri, fileStream, false);
+ if (response != null) Console.WriteLine("Response: " + response.StatusDescription);
+ fileStream.Close();
+
+ var jsonUri = new UriBuilder(uri.Uri);
+ jsonUri.Path += "_version.json";
+
+ string formatString = "{{\n" +
+ "\t\"version\":\"{0}\",\n" +
+ "\t\"size\":\"{1:F2}MB\"\n" +
+ "}}";
+
+ string json = string.Format(formatString,
+ version,
+ ((double)size / 1048576));
+
+ MemoryStream jsonStream = new MemoryStream(Encoding.ASCII.GetBytes(json));
+
+ Console.WriteLine("Uploading version JSON file");
+ response = UploadFile(jsonUri.Uri, jsonStream, true);
+ if (response != null) Console.WriteLine("Response: " + response.StatusDescription);
+ jsonStream.Close();
+
+ var latestUri = new UriBuilder(uri.Uri);
+ latestUri.Path += "latest.txt";
+ MemoryStream latestStream = new MemoryStream(Encoding.ASCII.GetBytes(Path.GetFileName(filename)));
+
+ Console.WriteLine("Uploading latest.txt");
+ response = UploadFile(latestUri.Uri, latestStream, true);
+ if (response != null) Console.WriteLine("Response: " + response.StatusDescription);
+ latestStream.Close();
+ }
+
+ static FtpWebResponse UploadFile(Uri uri, Stream file, bool text)
+ {
+ var ftp = WebRequest.Create(uri) as FtpWebRequest;
+ if (ftp == null) { Console.WriteLine("Couldn't create FTP client. URI incorrect?\n" + uri.ToString()); return null; }
+ ftp.Method = WebRequestMethods.Ftp.UploadFile;
+ ftp.UseBinary = !text;
+ var stream = ftp.GetRequestStream();
+ const int bufferLength = 2048;
+ byte[] buffer = new byte[bufferLength];
+ int readBytes = 0;
+
+ while ((readBytes = file.Read(buffer, 0, bufferLength)) != 0)
+ stream.Write(buffer, 0, readBytes);
+
+ stream.Close();
+ return ftp.GetResponse() as FtpWebResponse;
+ }
+
+ static void PrintUsage()
+ {
+ Console.WriteLine("Usage:\n OpenRAUploader.exe ");
+ }
+ }
+}
diff --git a/OpenRAUploader/Properties/AssemblyInfo.cs b/OpenRAUploader/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..ecb0029b1a
--- /dev/null
+++ b/OpenRAUploader/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("OpenRAUploader")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("OpenRAUploader")]
+[assembly: AssemblyCopyright("Copyright © Matthew Bowra-Dean 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("560074b7-5fdf-4e21-aa72-4cb4f664b639")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]