Some solution stuff, licenses, etc.
Some solution stuff, licenses, etc.

using MiniJSON; // KerbalStuffWrapper
  //
  // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
  using MiniJSON;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
   
namespace KerbalStuff namespace KerbalStuff
{ {
public class KerbalStuff : KerbalStuffReadOnly public class KerbalStuff : KerbalStuffReadOnly
{ {
public static Dictionary<string, object> Login(string username, string password) public static Dictionary<string, object> Login(string username, string password)
{ {
string uri = KerbalStuffAction.Login.UriFormat; string uri = KerbalStuffAction.Login.UriFormat;
   
Dictionary<string, object> postParams = new Dictionary<string, object>(); Dictionary<string, object> postParams = new Dictionary<string, object>();
postParams.Add("username", username); postParams.Add("username", username);
postParams.Add("password", password); postParams.Add("password", password);
   
ExecutePostRequest(uri, postParams, null); ExecutePostRequest(uri, postParams, null);
   
if (currentResponse.Cookies.Count > 0) if (currentResponse.Cookies.Count > 0)
{ {
cookies = currentResponse.Cookies; cookies = currentResponse.Cookies;
} }
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
return currentJson as Dictionary<string, object>; return currentJson as Dictionary<string, object>;
} }
   
return null; return null;
} }
   
public static Dictionary<string, object> Create(Mod mod, string fileName, string filePath) public static Dictionary<string, object> Create(Mod mod, string fileName, string filePath)
{ {
if (mod == null) if (mod == null)
{ {
throw new ArgumentNullException("KerbalStuffWrapper.Create: mod argument cannot be null."); throw new ArgumentNullException("KerbalStuffWrapper.Create: mod argument cannot be null.");
} }
else else
{ {
if (mod.name == string.Empty) if (mod.name == string.Empty)
throw new ArgumentException("mod.name cannot be empty."); throw new ArgumentException("mod.name cannot be empty.");
if (mod.license == string.Empty) if (mod.license == string.Empty)
throw new ArgumentException("mod.license cannot be empty."); throw new ArgumentException("mod.license cannot be empty.");
if (mod.short_description == string.Empty) if (mod.short_description == string.Empty)
throw new ArgumentException("mod.short_description cannot be empty."); throw new ArgumentException("mod.short_description cannot be empty.");
if (mod.versions.Count < 1) if (mod.versions.Count < 1)
throw new ArgumentException("mod must have a single version to create."); throw new ArgumentException("mod must have a single version to create.");
else if (mod.versions[0] == null) else if (mod.versions[0] == null)
{ {
throw new ArgumentNullException("mod.versions[0] cannot be null."); throw new ArgumentNullException("mod.versions[0] cannot be null.");
} }
else else
{ {
if (mod.versions[0].friendly_version == string.Empty) if (mod.versions[0].friendly_version == string.Empty)
throw new ArgumentException("mod.versions[0].friendly_version cannot be empty."); throw new ArgumentException("mod.versions[0].friendly_version cannot be empty.");
if (mod.versions[0].ksp_version == string.Empty) if (mod.versions[0].ksp_version == string.Empty)
throw new ArgumentException("mod.versions[0].ksp_version cannot be empty."); throw new ArgumentException("mod.versions[0].ksp_version cannot be empty.");
} }
} }
   
if (cookies == null) if (cookies == null)
{ {
throw new Exception("KerbalStuffWrapper.Create: Must log in first."); throw new Exception("KerbalStuffWrapper.Create: Must log in first.");
} }
   
if (!File.Exists(filePath)) if (!File.Exists(filePath))
{ {
throw new IOException(string.Format("KerbalStuffWrapper.Create: File '{0}' does not exist.", filePath)); throw new IOException(string.Format("KerbalStuffWrapper.Create: File '{0}' does not exist.", filePath));
} }
   
Dictionary<string, object> postParams = new Dictionary<string, object>(); Dictionary<string, object> postParams = new Dictionary<string, object>();
postParams.Add("name", mod.name); postParams.Add("name", mod.name);
postParams.Add("short-description", mod.short_description); postParams.Add("short-description", mod.short_description);
postParams.Add("license", mod.license); postParams.Add("license", mod.license);
postParams.Add("version", mod.versions[0].friendly_version); postParams.Add("version", mod.versions[0].friendly_version);
postParams.Add("ksp-version", mod.versions[0].ksp_version); postParams.Add("ksp-version", mod.versions[0].ksp_version);
postParams.Add("zipball", ReadZipballParameter(fileName, filePath)); postParams.Add("zipball", ReadZipballParameter(fileName, filePath));
   
ExecutePostRequest(KerbalStuffAction.Create.UriFormat, postParams, cookies); ExecutePostRequest(KerbalStuffAction.Create.UriFormat, postParams, cookies);
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
var rval = currentJson as Dictionary<string, object>; var rval = currentJson as Dictionary<string, object>;
   
if (rval.ContainsKey("reason")) if (rval.ContainsKey("reason"))
{ {
rval["message"] = rval["reason"]; rval["message"] = rval["reason"];
} }
   
return rval; return rval;
} }
   
return null; return null;
} }
   
public static Dictionary<string, object> Update(long modId, ModVersion version, bool notifyFollowers, string fileName, string filePath) public static Dictionary<string, object> Update(long modId, ModVersion version, bool notifyFollowers, string fileName, string filePath)
{ {
if (version == null) if (version == null)
{ {
throw new ArgumentNullException("KerbalStuffWrapper.Update: version cannot be null"); throw new ArgumentNullException("KerbalStuffWrapper.Update: version cannot be null");
} }
if (version.friendly_version == string.Empty) if (version.friendly_version == string.Empty)
throw new ArgumentException("KerbalStuffWrapper.Update: version.friendly_version cannot be empty"); throw new ArgumentException("KerbalStuffWrapper.Update: version.friendly_version cannot be empty");
if (version.ksp_version == string.Empty) if (version.ksp_version == string.Empty)
throw new ArgumentException("KerbalStuffWrapper.Update: version.ksp_version cannot be empty"); throw new ArgumentException("KerbalStuffWrapper.Update: version.ksp_version cannot be empty");
   
if (cookies == null) if (cookies == null)
{ {
throw new Exception("KerbalStuffWrapper.Update: Must log in first."); throw new Exception("KerbalStuffWrapper.Update: Must log in first.");
} }
   
if (!File.Exists(filePath)) if (!File.Exists(filePath))
{ {
throw new IOException(string.Format("KerbalStuffWrapper.Update: File '{0}' does not exist.", filePath)); throw new IOException(string.Format("KerbalStuffWrapper.Update: File '{0}' does not exist.", filePath));
} }
   
string uri = string.Format(KerbalStuffAction.Update.UriFormat, modId); string uri = string.Format(KerbalStuffAction.Update.UriFormat, modId);
   
Dictionary<string, object> postParams = new Dictionary<string, object>(); Dictionary<string, object> postParams = new Dictionary<string, object>();
postParams.Add("version", version.friendly_version); postParams.Add("version", version.friendly_version);
postParams.Add("ksp-version", version.ksp_version); postParams.Add("ksp-version", version.ksp_version);
   
if (version.changelog != null && version.changelog != string.Empty) if (version.changelog != null && version.changelog != string.Empty)
{ {
postParams.Add("changelog", version.changelog); postParams.Add("changelog", version.changelog);
} }
   
postParams.Add("notify-followers", notifyFollowers ? "yes" : "no"); postParams.Add("notify-followers", notifyFollowers ? "yes" : "no");
   
postParams.Add("zipball", ReadZipballParameter(fileName, filePath)); postParams.Add("zipball", ReadZipballParameter(fileName, filePath));
   
ExecutePostRequest(uri, postParams, cookies); ExecutePostRequest(uri, postParams, cookies);
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
return currentJson as Dictionary<string, object>; return currentJson as Dictionary<string, object>;
} }
   
return null; return null;
} }
   
protected static void ExecutePostRequest(string uri, Dictionary<string, object> postParams, CookieCollection cookieCollection = null) protected static void ExecutePostRequest(string uri, Dictionary<string, object> postParams, CookieCollection cookieCollection = null)
{ {
currentJson = null; currentJson = null;
currentRequest = null; currentRequest = null;
currentResponse = null; currentResponse = null;
   
CookieContainer jar = new CookieContainer(); CookieContainer jar = new CookieContainer();
   
if (cookieCollection != null) if (cookieCollection != null)
{ {
jar.Add(cookieCollection); jar.Add(cookieCollection);
} }
   
try try
{ {
currentResponse = FormUpload.MultipartFormDataPost( currentResponse = FormUpload.MultipartFormDataPost(
uri, uri,
"KerbalStuffWrapper by toadicus", "KerbalStuffWrapper by toadicus",
postParams, postParams,
jar jar
); );
} }
catch (WebException ex) catch (WebException ex)
{ {
currentResponse = ex.Response as HttpWebResponse; currentResponse = ex.Response as HttpWebResponse;
} }
   
if (currentResponse.ContentType == "application/json") if (currentResponse.ContentType == "application/json")
{ {
var responseReader = new StreamReader(currentResponse.GetResponseStream()); var responseReader = new StreamReader(currentResponse.GetResponseStream());
   
string json = responseReader.ReadToEnd(); string json = responseReader.ReadToEnd();
   
currentJson = Json.Deserialize(json); currentJson = Json.Deserialize(json);
} }
} }
   
protected static FormUpload.FileParameter ReadZipballParameter(string fileName, string filePath) protected static FormUpload.FileParameter ReadZipballParameter(string fileName, string filePath)
{ {
using (FileStream file = File.OpenRead(filePath)) using (FileStream file = File.OpenRead(filePath))
{ {
byte[] buffer = new byte[1 << 16]; byte[] buffer = new byte[1 << 16];
int bytesRead; int bytesRead;
   
MemoryStream stream = new MemoryStream(); MemoryStream stream = new MemoryStream();
   
while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0) while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0)
{ {
stream.Write(buffer, 0, bytesRead); stream.Write(buffer, 0, bytesRead);
} }
   
byte[] fileBytes = stream.GetBuffer(); byte[] fileBytes = stream.GetBuffer();
   
return new FormUpload.FileParameter(fileBytes, fileName, "application/zip"); return new FormUpload.FileParameter(fileBytes, fileName, "application/zip");
} }
} }
   
protected KerbalStuff() {} protected KerbalStuff() {}
} }
} }
   
   
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}</ProjectGuid> <ProjectGuid>{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>KerbalStuff</RootNamespace> <RootNamespace>KerbalStuff</RootNamespace>
<AssemblyName>KerbalStuff</AssemblyName> <AssemblyName>KerbalStuff</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <DebugType>full</DebugType>
  <Optimize>true</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants> <DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>  
<WarningLevel>4</WarningLevel>  
<ConsolePause>false</ConsolePause>  
<PlatformTarget>x86</PlatformTarget>  
</PropertyGroup>  
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">  
<DebugType>full</DebugType>  
<Optimize>true</Optimize>  
<OutputPath>bin\Release</OutputPath>  
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\KerbalStuffReadOnly\KerbalStuffReadOnly.csproj"> <ProjectReference Include="..\KerbalStuffReadOnly\KerbalStuffReadOnly.csproj">
<Project>{720FA70F-D785-48ED-BA45-561921E0EEEC}</Project> <Project>{720FA70F-D785-48ED-BA45-561921E0EEEC}</Project>
<Name>KerbalStuffReadOnly</Name> <Name>KerbalStuffReadOnly</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Net" /> <Reference Include="System.Net" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="KerbalStuff.cs" /> <Compile Include="KerbalStuff.cs" />
<Compile Include="FormUpload.cs" /> <Compile Include="FormUpload.cs" />
</ItemGroup> </ItemGroup>
</Project> </Project>
using MiniJSON; // KerbalStuffWrapper
  //
  // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
  using MiniJSON;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
   
namespace KerbalStuff namespace KerbalStuff
{ {
public class KerbalStuffReadOnly public class KerbalStuffReadOnly
{ {
public const string RootUri = "https://kerbalstuff.com"; public const string RootUri = "https://kerbalstuff.com";
   
public const string APIUri = RootUri + "/api"; public const string APIUri = RootUri + "/api";
   
public const string UserAgent = "KerbalStuffWrapper by toadicus"; public const string UserAgent = "KerbalStuffWrapper by toadicus";
   
public static Mod ModInfo(long modId) public static Mod ModInfo(long modId)
{ {
string uri = string.Format(KerbalStuffAction.ModInfo.UriFormat, modId); string uri = string.Format(KerbalStuffAction.ModInfo.UriFormat, modId);
   
ExecuteGetRequest(uri, KerbalStuffAction.ModInfo.RequestMethod); ExecuteGetRequest(uri, KerbalStuffAction.ModInfo.RequestMethod);
   
Mod mod = null; Mod mod = null;
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
mod = new Mod(currentJson as Dictionary<string, object>); mod = new Mod(currentJson as Dictionary<string, object>);
} }
   
return mod; return mod;
} }
   
public static ModVersion ModLatest(long modId) public static ModVersion ModLatest(long modId)
{ {
string uri = string.Format(KerbalStuffAction.ModLatest.UriFormat, modId); string uri = string.Format(KerbalStuffAction.ModLatest.UriFormat, modId);
   
ExecuteGetRequest(uri, KerbalStuffAction.ModLatest.RequestMethod); ExecuteGetRequest(uri, KerbalStuffAction.ModLatest.RequestMethod);
   
ModVersion ver = null; ModVersion ver = null;
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
ver = new ModVersion(currentJson as Dictionary<string, object>); ver = new ModVersion(currentJson as Dictionary<string, object>);
} }
   
return ver; return ver;
} }
   
public static List<Mod> ModSearch(string query) public static List<Mod> ModSearch(string query)
{ {
string uri = string.Format(KerbalStuffAction.ModSearch.UriFormat, query); string uri = string.Format(KerbalStuffAction.ModSearch.UriFormat, query);
   
ExecuteGetRequest(uri, KerbalStuffAction.ModSearch.RequestMethod); ExecuteGetRequest(uri, KerbalStuffAction.ModSearch.RequestMethod);
   
List<Mod> rList = new List<Mod>(); List<Mod> rList = new List<Mod>();
   
if (currentJson != null && currentJson is List<object>) if (currentJson != null && currentJson is List<object>)
{ {
foreach (var modObj in (currentJson as List<object>)) foreach (var modObj in (currentJson as List<object>))
{ {
if (modObj is Dictionary<string, object>) if (modObj is Dictionary<string, object>)
{ {
rList.Add(new Mod(modObj as Dictionary<string, object>)); rList.Add(new Mod(modObj as Dictionary<string, object>));
} }
} }
} }
   
return rList; return rList;
} }
   
public static User UserInfo(string username) public static User UserInfo(string username)
{ {
ExecuteGetRequest(KerbalStuffAction.UserInfo, false, username); ExecuteGetRequest(KerbalStuffAction.UserInfo, false, username);
   
   
User user = null; User user = null;
   
if (currentJson != null && currentJson is Dictionary<string, object>) if (currentJson != null && currentJson is Dictionary<string, object>)
{ {
user = new User(currentJson); user = new User(currentJson);
} }
   
return user; return user;
} }
   
public static List<User> UserSearch(string query) public static List<User> UserSearch(string query)
{ {
ExecuteGetRequest(KerbalStuffAction.UserSearch, false, query); ExecuteGetRequest(KerbalStuffAction.UserSearch, false, query);
   
List<User> users = new List<User>(); List<User> users = new List<User>();
   
if (currentJson != null && currentJson is List<object>) if (currentJson != null && currentJson is List<object>)
{ {
foreach (object userObj in (currentJson as List<object>)) foreach (object userObj in (currentJson as List<object>))
{ {
users.Add(new User(userObj)); users.Add(new User(userObj));
} }
} }
   
return users; return users;
} }
   
public static HttpWebResponse currentResponse public static HttpWebResponse currentResponse
{ {
get; get;
protected set; protected set;
} }
   
public static CookieCollection cookies public static CookieCollection cookies
{ {
get; get;
protected set; protected set;
} }
   
protected static HttpWebRequest currentRequest; protected static HttpWebRequest currentRequest;
   
public static object currentJson public static object currentJson
{ {
get; get;
protected set; protected set;
} }
   
protected static void ExecuteGetRequest(KerbalStuffAction action, bool assignCookies, params object[] formatArgs) protected static void ExecuteGetRequest(KerbalStuffAction action, bool assignCookies, params object[] formatArgs)
{ {
string uri = string.Format(action.UriFormat, formatArgs); string uri = string.Format(action.UriFormat, formatArgs);
   
ExecuteGetRequest(uri, action.RequestMethod); ExecuteGetRequest(uri, action.RequestMethod);
} }
   
protected static void ExecuteGetRequest(string uri, string method) protected static void ExecuteGetRequest(string uri, string method)
{ {
currentJson = null; currentJson = null;
currentRequest = null; currentRequest = null;
currentResponse = null; currentResponse = null;
   
if (uri == string.Empty) if (uri == string.Empty)
{ {
throw new ArgumentOutOfRangeException("KerbalStuffWrapper.ExecuteRequest: uri must not be empty."); throw new ArgumentOutOfRangeException("KerbalStuffWrapper.ExecuteRequest: uri must not be empty.");
} }
   
uri = Uri.EscapeUriString(uri); uri = Uri.EscapeUriString(uri);
   
method = method.ToUpper(); method = method.ToUpper();
   
if (method != "POST" && method != "GET") if (method != "POST" && method != "GET")
{ {
throw new ArgumentOutOfRangeException("KerbalStuffWrapper.ExecuteRequest: method must be POST or GET."); throw new ArgumentOutOfRangeException("KerbalStuffWrapper.ExecuteRequest: method must be POST or GET.");
} }
   
currentRequest = (HttpWebRequest)WebRequest.Create(uri); currentRequest = (HttpWebRequest)WebRequest.Create(uri);
currentRequest.Method = method; currentRequest.Method = method;
   
try try
{ {
currentResponse = currentRequest.GetResponse() as HttpWebResponse; currentResponse = currentRequest.GetResponse() as HttpWebResponse;
} }
catch (WebException ex) catch (WebException ex)
{ {
currentResponse = ex.Response as HttpWebResponse; currentResponse = ex.Response as HttpWebResponse;
} }
   
if (currentResponse.ContentType == "application/json") if (currentResponse.ContentType == "application/json")
{ {
var responseReader = new StreamReader(currentResponse.GetResponseStream()); var responseReader = new StreamReader(currentResponse.GetResponseStream());
   
string json = responseReader.ReadToEnd(); string json = responseReader.ReadToEnd();
   
currentJson = Json.Deserialize(json); currentJson = Json.Deserialize(json);
} }
} }
   
protected KerbalStuffReadOnly() {} protected KerbalStuffReadOnly() {}
} }
   
public struct KerbalStuffAction public struct KerbalStuffAction
{ {
public static readonly KerbalStuffAction Create = new KerbalStuffAction("create", "/mod/create", "POST"); public static readonly KerbalStuffAction Create = new KerbalStuffAction("create", "/mod/create", "POST");
public static readonly KerbalStuffAction Login = new KerbalStuffAction("login", "/login", "POST"); public static readonly KerbalStuffAction Login = new KerbalStuffAction("login", "/login", "POST");
public static readonly KerbalStuffAction ModInfo = new KerbalStuffAction("modinfo", "/mod/{0:d}", "GET"); public static readonly KerbalStuffAction ModInfo = new KerbalStuffAction("modinfo", "/mod/{0:d}", "GET");
public static readonly KerbalStuffAction ModLatest = new KerbalStuffAction( public static readonly KerbalStuffAction ModLatest = new KerbalStuffAction(
"modlatest", "modlatest",
"/mod/{0:d}/latest", "/mod/{0:d}/latest",
"GET" "GET"
); );
public static readonly KerbalStuffAction ModSearch = new KerbalStuffAction( public static readonly KerbalStuffAction ModSearch = new KerbalStuffAction(
"modsearch", "modsearch",
"/search/mod?query={0}", "/search/mod?query={0}",
"GET" "GET"
); );
public static readonly KerbalStuffAction Update = new KerbalStuffAction("update", "/mod/{0:d}/update", "POST"); public static readonly KerbalStuffAction Update = new KerbalStuffAction("update", "/mod/{0:d}/update", "POST");
public static readonly KerbalStuffAction UserInfo = new KerbalStuffAction("userinfo", "/user/{0}", "GET"); public static readonly KerbalStuffAction UserInfo = new KerbalStuffAction("userinfo", "/user/{0}", "GET");
public static readonly KerbalStuffAction UserSearch = new KerbalStuffAction( public static readonly KerbalStuffAction UserSearch = new KerbalStuffAction(
"usersearch", "usersearch",
"/search/user?query={0}", "/search/user?query={0}",
"GET" "GET"
); );
   
public string Action; public string Action;
   
public string UriPathFormat; public string UriPathFormat;
   
public string RequestMethod; public string RequestMethod;
   
public string UriFormat public string UriFormat
{ {
get get
{ {
return string.Format("{0}{1}", KerbalStuffReadOnly.APIUri, this.UriPathFormat); return string.Format("{0}{1}", KerbalStuffReadOnly.APIUri, this.UriPathFormat);
} }
} }
   
public KerbalStuffAction(string action, string uriFormat, string requestMethod) : this() public KerbalStuffAction(string action, string uriFormat, string requestMethod) : this()
{ {
this.Action = action; this.Action = action;
this.UriPathFormat = uriFormat; this.UriPathFormat = uriFormat;
this.RequestMethod = requestMethod; this.RequestMethod = requestMethod;
} }
} }
} }
   
   
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{720FA70F-D785-48ED-BA45-561921E0EEEC}</ProjectGuid> <ProjectGuid>{720FA70F-D785-48ED-BA45-561921E0EEEC}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>KerbalStuff</RootNamespace> <RootNamespace>KerbalStuff</RootNamespace>
<AssemblyName>KerbalStuffReadOnly</AssemblyName> <AssemblyName>KerbalStuffReadOnly</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <DebugType>full</DebugType>
  <Optimize>true</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants> <DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>  
<WarningLevel>4</WarningLevel>  
<ConsolePause>false</ConsolePause>  
<PlatformTarget>x86</PlatformTarget>  
</PropertyGroup>  
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">  
<DebugType>full</DebugType>  
<Optimize>true</Optimize>  
<OutputPath>bin\Release</OutputPath>  
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Net" /> <Reference Include="System.Net" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Mod.cs" /> <Compile Include="Mod.cs" />
<Compile Include="User.cs" /> <Compile Include="User.cs" />
<Compile Include="MiniJSON.cs" /> <Compile Include="MiniJSON.cs" />
<Compile Include="KerbalStuffReadOnly.cs" /> <Compile Include="KerbalStuffReadOnly.cs" />
</ItemGroup> </ItemGroup>
</Project> </Project>
using System; // KerbalStuffWrapper
  //
  // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
  using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
namespace KerbalStuff namespace KerbalStuff
{ {
public class Mod public class Mod
{ {
public long downloads public long downloads
{ {
get; get;
private set; private set;
} }
   
public string name public string name
{ {
get; get;
private set; private set;
} }
   
public long followers public long followers
{ {
get; get;
private set; private set;
} }
   
public string author public string author
{ {
get; get;
private set; private set;
} }
   
public long default_version_id public long default_version_id
{ {
get; get;
private set; private set;
} }
   
public List<ModVersion> versions public List<ModVersion> versions
{ {
get; get;
private set; private set;
} }
   
public long id public long id
{ {
get; get;
private set; private set;
} }
   
public string short_description public string short_description
{ {
get; get;
private set; private set;
} }
   
public string license public string license
{ {
get; get;
private set; private set;
} }
   
public Mod(Dictionary<string, object> jsonDict) : this() public Mod(Dictionary<string, object> jsonDict) : this()
{ {
this.downloads = (long)jsonDict["downloads"]; this.downloads = (long)jsonDict["downloads"];
this.name = (string)jsonDict["name"]; this.name = (string)jsonDict["name"];
this.followers = (long)jsonDict["followers"]; this.followers = (long)jsonDict["followers"];
this.author = (string)jsonDict["author"]; this.author = (string)jsonDict["author"];
this.default_version_id = (long)jsonDict["default_version_id"]; this.default_version_id = (long)jsonDict["default_version_id"];
this.id = (long)jsonDict["id"]; this.id = (long)jsonDict["id"];
this.short_description = (string)jsonDict["short_description"]; this.short_description = (string)jsonDict["short_description"];
   
if (jsonDict.ContainsKey("versions")) if (jsonDict.ContainsKey("versions"))
{ {
foreach (var ver in (jsonDict["versions"] as List<object>)) foreach (var ver in (jsonDict["versions"] as List<object>))
{ {
if (ver is Dictionary<string, object>) if (ver is Dictionary<string, object>)
{ {
this.versions.Add(new ModVersion(ver as Dictionary<string, object>)); this.versions.Add(new ModVersion(ver as Dictionary<string, object>));
} }
} }
} }
} }
   
public Mod(string name, string short_description, string version, string ksp_version, string license) : this() public Mod(string name, string short_description, string version, string ksp_version, string license) : this()
{ {
this.name = name; this.name = name;
this.short_description = short_description; this.short_description = short_description;
this.license = license; this.license = license;
   
this.versions.Add(new ModVersion(version, ksp_version)); this.versions.Add(new ModVersion(version, ksp_version));
} }
   
private Mod() private Mod()
{ {
this.versions = new List<ModVersion>(); this.versions = new List<ModVersion>();
} }
   
public override string ToString() public override string ToString()
{ {
return string.Format("Mod: {1}\nid: {6}\nauthor: {3}\ndownloads: {0}\nfollowers: {2}\nshort_description: {7}\ndefault_version_id: {4}\nversions:\n[\n{5}\n]\n", downloads, name, followers, author, default_version_id, string.Join("\n", versions.Select(v => v.ToString()).ToArray()), id, short_description); return string.Format("Mod: {1}\nid: {6}\nauthor: {3}\ndownloads: {0}\nfollowers: {2}\nshort_description: {7}\ndefault_version_id: {4}\nversions:\n[\n{5}\n]\n", downloads, name, followers, author, default_version_id, string.Join("\n", versions.Select(v => v.ToString()).ToArray()), id, short_description);
} }
} }
   
public class ModVersion public class ModVersion
{ {
public string changelog public string changelog
{ {
get; get;
private set; private set;
} }
   
public string ksp_version public string ksp_version
{ {
get; get;
private set; private set;
} }
   
public string download_path public string download_path
{ {
get; get;
private set; private set;
} }
   
public long id public long id
{ {
get; get;
private set; private set;
} }
   
public string friendly_version public string friendly_version
{ {
get; get;
private set; private set;
} }
   
public ModVersion(Dictionary<string, object> jsonDict) : this() public ModVersion(Dictionary<string, object> jsonDict) : this()
{ {
this.changelog = (string)jsonDict["changelog"]; this.changelog = (string)jsonDict["changelog"];
this.ksp_version = (string)jsonDict["ksp_version"]; this.ksp_version = (string)jsonDict["ksp_version"];
this.download_path = (string)jsonDict["download_path"]; this.download_path = (string)jsonDict["download_path"];
this.id = (long)jsonDict["id"]; this.id = (long)jsonDict["id"];
this.friendly_version = (string)jsonDict["friendly_version"]; this.friendly_version = (string)jsonDict["friendly_version"];
} }
   
public ModVersion(string version, string ksp_version, string changelog) : this(version, ksp_version) public ModVersion(string version, string ksp_version, string changelog) : this(version, ksp_version)
{ {
this.changelog = changelog; this.changelog = changelog;
} }
   
public ModVersion(string version, string ksp_version) : this() public ModVersion(string version, string ksp_version) : this()
{ {
this.friendly_version = version; this.friendly_version = version;
this.ksp_version = ksp_version; this.ksp_version = ksp_version;
} }
   
private ModVersion() {} private ModVersion() {}
   
public override string ToString() public override string ToString()
{ {
return string.Format("ModVersion {4}:\nid: {3}\nksp_version: {1}\ndownload_path: {2}\nchangelog: {0}", changelog, ksp_version, download_path, id, friendly_version); return string.Format("ModVersion {4}:\nid: {3}\nksp_version: {1}\ndownload_path: {2}\nchangelog: {0}", changelog, ksp_version, download_path, id, friendly_version);
} }
} }
} }
   
   
using System; // KerbalStuffWrapper
  //
  // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
  using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
   
namespace KerbalStuff namespace KerbalStuff
{ {
public class User public class User
{ {
public string username public string username
{ {
get; get;
private set; private set;
} }
   
public string twitterUsername public string twitterUsername
{ {
get; get;
private set; private set;
} }
   
public List<Mod> mods public List<Mod> mods
{ {
get; get;
private set; private set;
} }
   
public string redditUsername public string redditUsername
{ {
get; get;
private set; private set;
} }
   
public string ircNick public string ircNick
{ {
get; get;
private set; private set;
} }
   
public string description public string description
{ {
get; get;
private set; private set;
} }
   
public string forumUsername public string forumUsername
{ {
get; get;
private set; private set;
} }
   
public User(Dictionary<string, object> jsonDict) : this() public User(Dictionary<string, object> jsonDict) : this()
{ {
this.username = (string)jsonDict["username"]; this.username = (string)jsonDict["username"];
this.twitterUsername = (string)jsonDict["twitterUsername"]; this.twitterUsername = (string)jsonDict["twitterUsername"];
this.redditUsername = (string)jsonDict["redditUsername"]; this.redditUsername = (string)jsonDict["redditUsername"];
this.ircNick = (string)jsonDict["ircNick"]; this.ircNick = (string)jsonDict["ircNick"];
this.forumUsername = (string)jsonDict["forumUsername"]; this.forumUsername = (string)jsonDict["forumUsername"];
   
this.description = (string)jsonDict["description"]; this.description = (string)jsonDict["description"];
   
this.mods = new List<Mod>(); this.mods = new List<Mod>();
   
foreach (object modObj in (jsonDict["mods"] as List<object>)) foreach (object modObj in (jsonDict["mods"] as List<object>))
{ {
this.mods.Add(new Mod(modObj as Dictionary<string, object>)); this.mods.Add(new Mod(modObj as Dictionary<string, object>));
} }
} }
   
public User(object jsonObj) : this((Dictionary<string, object>)jsonObj) {} public User(object jsonObj) : this((Dictionary<string, object>)jsonObj) {}
   
private User() {} private User() {}
   
public override string ToString() public override string ToString()
{ {
return string.Format( return string.Format(
"User: username={0}, twitterUsername={1}, redditUsername={3}, ircNick={4}, description={5}, forumUsername={6}\nmods:\n{2}", "User: username={0}, twitterUsername={1}, redditUsername={3}, ircNick={4}, description={5}, forumUsername={6}\nmods:\n{2}",
username, username,
twitterUsername, twitterUsername,
string.Join( string.Join(
"\n", "\n",
mods.Select(m => m.ToString()).ToArray() mods.Select(m => m.ToString()).ToArray()
), ),
redditUsername, redditUsername,
ircNick, ircNick,
description, description,
forumUsername forumUsername
); );
} }
} }
} }
   
   
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuffWrapper", "KerbalStuffWrapper\KerbalStuffWrapper.csproj", "{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuffWrapper", "KerbalStuffWrapper\KerbalStuffWrapper.csproj", "{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuffReadOnly", "KerbalStuffReadOnly\KerbalStuffReadOnly.csproj", "{720FA70F-D785-48ED-BA45-561921E0EEEC}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuffReadOnly", "KerbalStuffReadOnly\KerbalStuffReadOnly.csproj", "{720FA70F-D785-48ED-BA45-561921E0EEEC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuff", "KerbalStuff\KerbalStuff.csproj", "{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KerbalStuff", "KerbalStuff\KerbalStuff.csproj", "{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86 Debug|Any CPU = Debug|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Debug|x86.ActiveCfg = Debug|x86 {0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Debug|x86.Build.0 = Debug|x86 {0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Release|x86.ActiveCfg = Release|x86 {0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Release|x86.Build.0 = Release|x86 {0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}.Release|Any CPU.Build.0 = Release|Any CPU
{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Debug|x86.ActiveCfg = Debug|x86 {1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Debug|x86.Build.0 = Debug|x86 {1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Release|x86.ActiveCfg = Release|x86 {1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Release|x86.Build.0 = Release|x86 {1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}.Release|Any CPU.Build.0 = Release|Any CPU
{720FA70F-D785-48ED-BA45-561921E0EEEC}.Debug|x86.ActiveCfg = Debug|x86 {720FA70F-D785-48ED-BA45-561921E0EEEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{720FA70F-D785-48ED-BA45-561921E0EEEC}.Debug|x86.Build.0 = Debug|x86 {720FA70F-D785-48ED-BA45-561921E0EEEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{720FA70F-D785-48ED-BA45-561921E0EEEC}.Release|x86.ActiveCfg = Release|x86 {720FA70F-D785-48ED-BA45-561921E0EEEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{720FA70F-D785-48ED-BA45-561921E0EEEC}.Release|x86.Build.0 = Release|x86 {720FA70F-D785-48ED-BA45-561921E0EEEC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = KerbalStuffWrapper\KerbalStuffWrapper.csproj StartupItem = KerbalStuffWrapper\KerbalStuffWrapper.csproj
  Policies = $0
  $0.DotNetNamingPolicy = $1
  $1.DirectoryNamespaceAssociation = None
  $1.ResourceNamePolicy = FileFormatDefault
  $0.TextStylePolicy = $2
  $2.inheritsSet = null
  $2.scope = text/x-csharp
  $0.CSharpFormattingPolicy = $3
  $3.IndentSwitchBody = True
  $3.AnonymousMethodBraceStyle = NextLine
  $3.PropertyBraceStyle = NextLine
  $3.EventBraceStyle = NextLine
  $3.StatementBraceStyle = NextLine
  $3.ElseNewLinePlacement = NewLine
  $3.CatchNewLinePlacement = NewLine
  $3.FinallyNewLinePlacement = NewLine
  $3.WhileNewLinePlacement = NewLine
  $3.BeforeMethodDeclarationParentheses = False
  $3.BeforeMethodCallParentheses = False
  $3.BeforeConstructorDeclarationParentheses = False
  $3.BeforeIndexerDeclarationBracket = False
  $3.BeforeDelegateDeclarationParentheses = False
  $3.AfterDelegateDeclarationParameterComma = True
  $3.NewParentheses = False
  $3.SpacesBeforeBrackets = False
  $3.BlankLinesBetweenEventFields = 1
  $3.inheritsSet = Mono
  $3.inheritsScope = text/x-csharp
  $3.scope = text/x-csharp
  $0.StandardHeader = $4
  $4.Text = @KerbalStuffWrapper\n\nAuthor:\n\t${AuthorName}\n\nCopyright © ${Year}, ${AuthorName}\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n\t* Redistributions of source code must retain the above copyright notice, this list of conditions and the\n\t following disclaimer.\n\t* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the\n\t following disclaimer in the documentation and/or other materials provided with the distribution.\n\t* Neither the name of the author nor the names of other contributors may be used to endorse or promote products\n\t derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nThis software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.\nUsed under license.\n\nThis software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.\n\nThis software uses the FormUpload multipart/form-data library,\nhttp://www.briangrinstead.com/blog/multipart-form-post-in-c.\n
  $4.IncludeInNewFiles = True
  $0.TextStylePolicy = $5
  $5.FileWidth = 120
  $5.TabsToSpaces = False
  $5.inheritsSet = VisualStudio
  $5.inheritsScope = text/plain
  $5.scope = text/plain
  $0.NameConventionPolicy = $6
  $6.Rules = $7
  $7.NamingRule = $8
  $8.Name = Namespaces
  $8.AffectedEntity = Namespace
  $8.VisibilityMask = VisibilityMask
  $8.NamingStyle = PascalCase
  $8.IncludeInstanceMembers = True
  $8.IncludeStaticEntities = True
  $7.NamingRule = $9
  $9.Name = Types
  $9.AffectedEntity = Class, Struct, Enum, Delegate
  $9.VisibilityMask = Public
  $9.NamingStyle = PascalCase
  $9.IncludeInstanceMembers = True
  $9.IncludeStaticEntities = True
  $7.NamingRule = $10
  $10.Name = Interfaces
  $10.RequiredPrefixes = $11
  $11.String = I
  $10.AffectedEntity = Interface
  $10.VisibilityMask = Public
  $10.NamingStyle = PascalCase
  $10.IncludeInstanceMembers = True
  $10.IncludeStaticEntities = True
  $7.NamingRule = $12
  $12.Name = Attributes
  $12.RequiredSuffixes = $13
  $13.String = Attribute
  $12.AffectedEntity = CustomAttributes
  $12.VisibilityMask = Public
  $12.NamingStyle = PascalCase
  $12.IncludeInstanceMembers = True
  $12.IncludeStaticEntities = True
  $7.NamingRule = $14
  $14.Name = Event Arguments
  $14.RequiredSuffixes = $15
  $15.String = EventArgs
  $14.AffectedEntity = CustomEventArgs
  $14.VisibilityMask = Public
  $14.NamingStyle = PascalCase
  $14.IncludeInstanceMembers = True
  $14.IncludeStaticEntities = True
  $7.NamingRule = $16
  $16.Name = Exceptions
  $16.RequiredSuffixes = $17
  $17.String = Exception
  $16.AffectedEntity = CustomExceptions
  $16.VisibilityMask = VisibilityMask
  $16.NamingStyle = PascalCase
  $16.IncludeInstanceMembers = True
  $16.IncludeStaticEntities = True
  $7.NamingRule = $18
  $18.Name = Methods
  $18.AffectedEntity = Methods
  $18.VisibilityMask = Protected, Public
  $18.NamingStyle = PascalCase
  $18.IncludeInstanceMembers = True
  $18.IncludeStaticEntities = True
  $7.NamingRule = $19
  $19.Name = Static Readonly Fields
  $19.AffectedEntity = ReadonlyField
  $19.VisibilityMask = Protected, Public
  $19.NamingStyle = PascalCase
  $19.IncludeInstanceMembers = False
  $19.IncludeStaticEntities = True
  $7.NamingRule = $20
  $20.Name = Fields
  $20.AffectedEntity = Field
  $20.VisibilityMask = Protected, Public
  $20.NamingStyle = PascalCase
  $20.IncludeInstanceMembers = True
  $20.IncludeStaticEntities = True
  $7.NamingRule = $21
  $21.Name = ReadOnly Fields
  $21.AffectedEntity = ReadonlyField
  $21.VisibilityMask = Protected, Public
  $21.NamingStyle = PascalCase
  $21.IncludeInstanceMembers = True
  $21.IncludeStaticEntities = False
  $7.NamingRule = $22
  $22.Name = Constant Fields
  $22.AffectedEntity = ConstantField
  $22.VisibilityMask = Protected, Public
  $22.NamingStyle = PascalCase
  $22.IncludeInstanceMembers = True
  $22.IncludeStaticEntities = True
  $7.NamingRule = $23
  $23.Name = Properties
  $23.AffectedEntity = Property
  $23.VisibilityMask = Protected, Public
  $23.NamingStyle = PascalCase
  $23.IncludeInstanceMembers = True
  $23.IncludeStaticEntities = True
  $7.NamingRule = $24
  $24.Name = Events
  $24.AffectedEntity = Event
  $24.VisibilityMask = Protected, Public
  $24.NamingStyle = PascalCase
  $24.IncludeInstanceMembers = True
  $24.IncludeStaticEntities = True
  $7.NamingRule = $25
  $25.Name = Enum Members
  $25.AffectedEntity = EnumMember
  $25.VisibilityMask = VisibilityMask
  $25.NamingStyle = PascalCase
  $25.IncludeInstanceMembers = True
  $25.IncludeStaticEntities = True
  $7.NamingRule = $26
  $26.Name = Parameters
  $26.AffectedEntity = Parameter
  $26.VisibilityMask = VisibilityMask
  $26.NamingStyle = CamelCase
  $26.IncludeInstanceMembers = True
  $26.IncludeStaticEntities = True
  $7.NamingRule = $27
  $27.Name = Type Parameters
  $27.RequiredPrefixes = $28
  $28.String = T
  $27.AffectedEntity = TypeParameter
  $27.VisibilityMask = VisibilityMask
  $27.NamingStyle = PascalCase
  $27.IncludeInstanceMembers = True
  $27.IncludeStaticEntities = True
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
   
using CLAP; // KerbalStuffWrapper
  //
  // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  // * Neither the name of the author nor the names of other contributors may be used to endorse or promote products
  // derived from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
  using CLAP;
using CLAP.Interception; using CLAP.Interception;
using CLAP.Validation; using CLAP.Validation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
   
// TODO: Write a console program that uses the KerbalStuff wrapper API. // TODO: Write a console program that uses the KerbalStuff wrapper API.
   
namespace KerbalStuff.Wrapper namespace KerbalStuff.Wrapper
{ {
public class KerbalStuffWrapper public class KerbalStuffWrapper
{ {
private static Parser<KerbalStuffWrapper> parser; private static Parser<KerbalStuffWrapper> parser;
private static string[] args; private static string[] args;
   
public static int Main(string[] args) public static int Main(string[] args)
{ {
KerbalStuffWrapper.args = args; KerbalStuffWrapper.args = args;
parser = new Parser<KerbalStuffWrapper>(); parser = new Parser<KerbalStuffWrapper>();
   
return parser.RunStatic(args); return parser.RunStatic(args);
} }
   
private static void Write(string message, TextWriter output) private static void Write(string message, TextWriter output)
{ {
   
output.Write(string.Format("{0}: {1}", appName, message)); output.Write(string.Format("{0}: {1}", appName, message));
} }
   
private static void WriteOut(string message) private static void WriteOut(string message)
{ {
Write(message, Console.Out); Write(message, Console.Out);
} }
   
private static void WriteOut(string format, params object[] args) private static void WriteOut(string format, params object[] args)
{ {
WriteOut(string.Format(format, args)); WriteOut(string.Format(format, args));
} }
   
private static void WriteOutLine(string format, params object[] args) private static void WriteOutLine(string format, params object[] args)
{ {
WriteOut(format, args); WriteOut(format, args);
Console.Out.WriteLine(); Console.Out.WriteLine();
} }
   
private static void WriteError(string message) private static void WriteError(string message)
{ {
Write(message, Console.Error); Write(message, Console.Error);
} }
   
private static void WriteError(string format, params object[] args) private static void WriteError(string format, params object[] args)
{ {
WriteError(string.Format(format, args)); WriteError(string.Format(format, args));
} }
   
private static void WriteErrorLine(string format, params object[] args) private static void WriteErrorLine(string format, params object[] args)
{ {
WriteError(format, args); WriteError(format, args);
Console.Error.WriteLine(); Console.Error.WriteLine();
} }
   
private const string appName = "KerbalStuffWrapper"; private const string appName = "KerbalStuffWrapper";
   
// TODO: Action methods. // TODO: Action methods.
   
[Verb(Aliases = "mod,m")] [Verb(Aliases = "mod,m")]
public static void ModInfo([Required]long modId) public static void ModInfo([Required]long modId)
{ {
Mod mod = KerbalStuff.ModInfo(modId); Mod mod = KerbalStuff.ModInfo(modId);
   
if (mod == null) if (mod == null)
{ {
WriteErrorLine("Couldn't get Mod info for mod {0}: {1}.", modId, KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Couldn't get Mod info for mod {0}: {1}.", modId, KerbalStuff.currentResponse.StatusDescription);
} }
else else
{ {
Console.WriteLine(mod); Console.WriteLine(mod);
} }
} }
   
[Verb(Aliases = "latest,l")] [Verb(Aliases = "latest,l")]
public static void ModLatest([Required]long modId) public static void ModLatest([Required]long modId)
{ {
ModVersion ver = KerbalStuff.ModLatest(modId); ModVersion ver = KerbalStuff.ModLatest(modId);
   
if (ver == null) if (ver == null)
{ {
WriteErrorLine("Couldn't get version info for mod {0}: {1}.", modId, KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Couldn't get version info for mod {0}: {1}.", modId, KerbalStuff.currentResponse.StatusDescription);
} }
else else
{ {
Console.WriteLine(ver); Console.WriteLine(ver);
} }
} }
   
[Verb(Aliases = "search,s")] [Verb(Aliases = "search,s")]
public static void ModSearch([Required]string query) public static void ModSearch([Required]string query)
{ {
List<Mod> mods = KerbalStuff.ModSearch(query); List<Mod> mods = KerbalStuff.ModSearch(query);
   
if (mods.Count < 1) if (mods.Count < 1)
{ {
WriteOutLine("Query yielded no results."); WriteOutLine("Query yielded no results.");
} }
else else
{ {
foreach (Mod mod in mods) foreach (Mod mod in mods)
{ {
Console.WriteLine(mod); Console.WriteLine(mod);
Console.WriteLine(); Console.WriteLine();
} }
} }
} }
   
[Verb(Aliases = "user,u")] [Verb(Aliases = "user,u")]
public static void UserInfo([Required]string username) public static void UserInfo([Required]string username)
{ {
User user = KerbalStuff.UserInfo(username); User user = KerbalStuff.UserInfo(username);
   
if (user == null) if (user == null)
{ {
WriteErrorLine("Couldn't get user info for username '{0}': {1}", username, KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Couldn't get user info for username '{0}': {1}", username, KerbalStuff.currentResponse.StatusDescription);
} }
else else
{ {
Console.WriteLine(user); Console.WriteLine(user);
} }
} }
   
[Verb(Aliases = "us")] [Verb(Aliases = "us")]
public static void UserSearch([Required]string query) public static void UserSearch([Required]string query)
{ {
List<User> users = KerbalStuff.UserSearch(query); List<User> users = KerbalStuff.UserSearch(query);
   
if (users.Count < 1) if (users.Count < 1)
{ {
WriteOutLine("Query yielded no results."); WriteOutLine("Query yielded no results.");
} }
else else
{ {
foreach (User user in users) foreach (User user in users)
{ {
Console.WriteLine(user); Console.WriteLine(user);
Console.WriteLine(); Console.WriteLine();
} }
} }
} }
   
[Verb(Aliases = "create,c")] [Verb(Aliases = "create,c")]
public static void CreateMod( public static void CreateMod(
[Required] [Required]
[Aliases("user,u")] [Aliases("user,u")]
string username, string username,
[Required] [Required]
[Aliases("pass,p")] [Aliases("pass,p")]
string password, string password,
[Required] [Required]
[Aliases("n")] [Aliases("n")]
string name, string name,
[Required] [Required]
[Aliases("desc,d")] [Aliases("desc,d")]
string short_description, string short_description,
[Required] [Required]
[Aliases("ver,v")] [Aliases("ver,v")]
string version, string version,
[Required] [Required]
[Aliases("ksp,k")] [Aliases("ksp,k")]
string ksp_version, string ksp_version,
[Required] [Required]
[Aliases("lic,l")] [Aliases("lic,l")]
string license, string license,
[Required] [Required]
[Aliases("file,f")] [Aliases("file,f")]
string filePath string filePath
) )
{ {
Mod mod = new Mod(name, short_description, version, ksp_version, license); Mod mod = new Mod(name, short_description, version, ksp_version, license);
   
var loginDict = KerbalStuff.Login(username, password); var loginDict = KerbalStuff.Login(username, password);
   
if (loginDict == null) if (loginDict == null)
{ {
WriteErrorLine("Could not complete login attempt: {0}", KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Could not complete login attempt: {0}", KerbalStuff.currentResponse.StatusDescription);
} }
else if (loginDict.ContainsKey("error") && loginDict["error"].ToString().ToLower() == "true") else if (loginDict.ContainsKey("error") && loginDict["error"].ToString().ToLower() == "true")
{ {
WriteErrorLine("Login failed: {0}", loginDict["reason"]); WriteErrorLine("Login failed: {0}", loginDict["reason"]);
} }
else else
{ {
var createDict = KerbalStuff.Create(mod, Path.GetFileName(filePath), filePath); var createDict = KerbalStuff.Create(mod, Path.GetFileName(filePath), filePath);
   
if (createDict == null) if (createDict == null)
{ {
WriteErrorLine("Could not complete creation attempt: {0}", KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Could not complete creation attempt: {0}", KerbalStuff.currentResponse.StatusDescription);
} }
else if (createDict.ContainsKey("error") && createDict["error"].ToString().ToLower() == "true") else if (createDict.ContainsKey("error") && createDict["error"].ToString().ToLower() == "true")
{ {
WriteErrorLine("Creation failed: {0}", createDict["message"]); WriteErrorLine("Creation failed: {0}", createDict["message"]);
} }
else else
{ {
WriteOutLine("New mod '{0}' created with id #{2}! You can view and publish the mod at {1}", WriteOutLine("New mod '{0}' created with id #{2}! You can view and publish the mod at {1}",
createDict["name"], createDict["name"],
string.Concat(KerbalStuff.RootUri, createDict["url"]), string.Concat(KerbalStuff.RootUri, createDict["url"]),
createDict["id"] createDict["id"]
); );
} }
} }
} }
   
[Verb(Aliases = "update,up")] [Verb(Aliases = "update,up")]
public static void UpdateMod( public static void UpdateMod(
[Required] [Required]
[Aliases("user,u")] [Aliases("user,u")]
string username, string username,
[Required] [Required]
[Aliases("pass,p")] [Aliases("pass,p")]
string password, string password,
[Required] [Required]
[Aliases("mod,m")] [Aliases("mod,m")]
long modId, long modId,
[Required] [Required]
[Aliases("ver,v")] [Aliases("ver,v")]
string version, string version,
[Required] [Required]
[Aliases("ksp,k")] [Aliases("ksp,k")]
string ksp_version, string ksp_version,
[Aliases("log,l")] [Aliases("log,l")]
string changelog, string changelog,
[DefaultValue(false)] [DefaultValue(false)]
[Aliases("notify,n")] [Aliases("notify,n")]
bool notifyFollowers, bool notifyFollowers,
[Required] [Required]
[Aliases("file,f")] [Aliases("file,f")]
string filePath string filePath
) )
{ {
ModVersion ver; ModVersion ver;
if (changelog != string.Empty) if (changelog != string.Empty)
{ {
ver = new ModVersion(version, ksp_version, changelog); ver = new ModVersion(version, ksp_version, changelog);
} }
else else
{ {
ver = new ModVersion(version, ksp_version); ver = new ModVersion(version, ksp_version);
} }
   
var loginDict = KerbalStuff.Login(username, password); var loginDict = KerbalStuff.Login(username, password);
   
if (loginDict == null) if (loginDict == null)
{ {
WriteErrorLine("Could not complete login attempt: {0}", KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Could not complete login attempt: {0}", KerbalStuff.currentResponse.StatusDescription);
} }
else if (loginDict.ContainsKey("error") && loginDict["error"].ToString().ToLower() == "true") else if (loginDict.ContainsKey("error") && loginDict["error"].ToString().ToLower() == "true")
{ {
WriteErrorLine("Login failed: {0}", loginDict["reason"]); WriteErrorLine("Login failed: {0}", loginDict["reason"]);
} }
else else
{ {
var updateDict = KerbalStuff.Update(modId, ver, notifyFollowers, Path.GetFileName(filePath), filePath); var updateDict = KerbalStuff.Update(modId, ver, notifyFollowers, Path.GetFileName(filePath), filePath);
   
if (updateDict == null) if (updateDict == null)
{ {
WriteErrorLine("Could not complete creation attempt: {0}", KerbalStuff.currentResponse.StatusDescription); WriteErrorLine("Could not complete creation attempt: {0}", KerbalStuff.currentResponse.StatusDescription);
} }
else if (updateDict.ContainsKey("error") && updateDict["error"].ToString().ToLower() == "true") else if (updateDict.ContainsKey("error") && updateDict["error"].ToString().ToLower() == "true")
{ {
WriteErrorLine("Creation failed: {0}", updateDict["message"]); WriteErrorLine("Creation failed: {0}", updateDict["message"]);
} }
else else
{ {
WriteOutLine("Mod #{0}! You can view the update at {1}", WriteOutLine("Mod #{0}! You can view the update at {1}",
updateDict["id"], updateDict["id"],
string.Concat(KerbalStuff.RootUri, updateDict["url"]) string.Concat(KerbalStuff.RootUri, updateDict["url"])
); );
} }
} }
} }
[Empty, Help, Global] [Empty, Help, Global]
public static void Help(string help) public static void Help(string help)
{ {
Console.Error.WriteLine(string.Format("Usage: {0} <ACTION> /OPTION[:ARG] [/OPTION[:ARG]...]", appName)); Console.Error.WriteLine(string.Format("Usage: {0} <ACTION> /OPTION[:ARG] [/OPTION[:ARG]...]", appName));
Console.Error.WriteLine("\nActions:"); Console.Error.WriteLine("\nActions:");
Console.Error.WriteLine(parser.GetHelpString()); Console.Error.WriteLine(parser.GetHelpString());
} }
   
[Error] [Error]
public static void HandleError(ExceptionContext context) public static void HandleError(ExceptionContext context)
{ {
if (context.Exception is VerbNotFoundException) if (context.Exception is VerbNotFoundException)
{ {
var ex = context.Exception as VerbNotFoundException; var ex = context.Exception as VerbNotFoundException;
WriteErrorLine("Action '{0}' does not exist.", ex.Verb); WriteErrorLine("Action '{0}' does not exist.", ex.Verb);
} }
else if (context.Exception is MissingDefaultVerbException) else if (context.Exception is MissingDefaultVerbException)
{ {
WriteErrorLine("An action is required."); WriteErrorLine("An action is required.");
} }
else if (context.Exception is UnhandledParametersException) else if (context.Exception is UnhandledParametersException)
{ {
var ex = context.Exception as UnhandledParametersException; var ex = context.Exception as UnhandledParametersException;
var keys = ex.UnhandledParameters.Keys; var keys = ex.UnhandledParameters.Keys;
   
WriteError("invalid option"); WriteError("invalid option");
   
if (keys.Count > 1) if (keys.Count > 1)
{ {
Console.Error.Write("s"); Console.Error.Write("s");
} }
   
Console.Error.Write(string.Format(" for action {0}: '{1}'", args[0], string.Join(", ", keys.ToArray()))); Console.Error.Write(string.Format(" for action {0}: '{1}'", args[0], string.Join(", ", keys.ToArray())));
} }
else if (context.Exception is MissingArgumentPrefixException) else if (context.Exception is MissingArgumentPrefixException)
{ {
var ex = context.Exception as MissingArgumentPrefixException; var ex = context.Exception as MissingArgumentPrefixException;
   
WriteErrorLine("{0}: option {1}", args[0], ex.Message); WriteErrorLine("{0}: option {1}", args[0], ex.Message);
} }
else if (context.Exception is MissingArgumentValueException) else if (context.Exception is MissingArgumentValueException)
{ {
var ex = context.Exception as MissingArgumentValueException; var ex = context.Exception as MissingArgumentValueException;
   
WriteErrorLine("{0}: option '{1}' requires an argument.", args[0], ex.ParameterName); WriteErrorLine("{0}: option '{1}' requires an argument.", args[0], ex.ParameterName);
} }
else if (context.Exception is TypeConvertionException) else if (context.Exception is TypeConvertionException)
{ {
var ex = context.Exception as TypeConvertionException; var ex = context.Exception as TypeConvertionException;
WriteErrorLine("Invalid argument for {2}: '{0}' cannot be converted to {1}.\n", ex.Value, ex.Type.HumanName(), args[0]); WriteErrorLine("Invalid argument for {2}: '{0}' cannot be converted to {1}.\n", ex.Value, ex.Type.HumanName(), args[0]);
Help(string.Empty); Help(string.Empty);
} }
else if (context.Exception is CommandLineParserException) else if (context.Exception is CommandLineParserException)
{ {
WriteErrorLine(context.Exception.Message); WriteErrorLine(context.Exception.Message);
} }
else else
{ {
WriteErrorLine("An unexpected error occured. {0}: {1}", context.Exception.GetType().Name, context.Exception.Message); WriteErrorLine("An unexpected error occured. {0}: {1}", context.Exception.GetType().Name, context.Exception.Message);
Console.Error.WriteLine(); Console.Error.WriteLine();
WriteErrorLine(context.Exception.StackTrace); WriteErrorLine(context.Exception.StackTrace);
   
Console.Error.WriteLine(); Console.Error.WriteLine();
Console.Error.WriteLine("Response:"); Console.Error.WriteLine("Response:");
Console.Error.WriteLine(); Console.Error.WriteLine();
   
if (KerbalStuff.currentResponse != null) if (KerbalStuff.currentResponse != null)
{ {
Console.Error.WriteLine((new StreamReader(KerbalStuff.currentResponse.GetResponseStream())).ReadToEnd()); Console.Error.WriteLine((new StreamReader(KerbalStuff.currentResponse.GetResponseStream())).ReadToEnd());
} }
   
if (KerbalStuff.currentJson != null) if (KerbalStuff.currentJson != null)
{ {
if (KerbalStuff.currentJson is Dictionary<string, object>) if (KerbalStuff.currentJson is Dictionary<string, object>)
{ {
var json = KerbalStuff.currentJson as Dictionary<string, object>; var json = KerbalStuff.currentJson as Dictionary<string, object>;
foreach (KeyValuePair<string, object> item in json) foreach (KeyValuePair<string, object> item in json)
{ {
Console.Error.WriteLine(string.Format("{0}: {1}", item.Key, item.Value)); Console.Error.WriteLine(string.Format("{0}: {1}", item.Key, item.Value));
} }
} }
} }
   
return; return;
} }
   
Console.Error.WriteLine(); Console.Error.WriteLine();
   
Help(string.Empty); Help(string.Empty);
} }
} }
} }
   
   
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}</ProjectGuid> <ProjectGuid>{1E93CDA7-56A8-410F-A5A2-0ABB9210CA58}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>KerbalStuff.Wrapper</RootNamespace> <RootNamespace>KerbalStuff.Wrapper</RootNamespace>
<AssemblyName>KerbalStuffWrapper</AssemblyName> <AssemblyName>KerbalStuffWrapper</AssemblyName>
<UseMSBuildEngine>False</UseMSBuildEngine> <UseMSBuildEngine>False</UseMSBuildEngine>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <DebugType>full</DebugType>
  <Optimize>true</Optimize>
  <OutputPath>bin\Release</OutputPath>
  <ErrorReport>prompt</ErrorReport>
  <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
  <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath> <OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants> <DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
  <ConsolePause>false</ConsolePause>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<ConsolePause>false</ConsolePause>  
</PropertyGroup>  
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">  
<DebugType>full</DebugType>  
<Optimize>true</Optimize>  
<OutputPath>bin\Release</OutputPath>  
<ErrorReport>prompt</ErrorReport>  
<WarningLevel>4</WarningLevel>  
<PlatformTarget>x86</PlatformTarget>  
<ConsolePause>false</ConsolePause>  
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="CLAP"> <Reference Include="CLAP">
<HintPath>..\..\CLAP.4.6\lib\net35\CLAP.dll</HintPath> <HintPath>CLAP.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="KerbalStuffWrapper.cs" /> <Compile Include="KerbalStuffWrapper.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs">
  <DeployService-Deploy>True</DeployService-Deploy>
  </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\KerbalStuff\KerbalStuff.csproj"> <ProjectReference Include="..\KerbalStuff\KerbalStuff.csproj">
<Project>{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}</Project> <Project>{0CA12F64-AD3B-41E6-8A35-8781A8DAD1C1}</Project>
<Name>KerbalStuff</Name> <Name>KerbalStuff</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\KerbalStuffReadOnly\KerbalStuffReadOnly.csproj"> <ProjectReference Include="..\KerbalStuffReadOnly\KerbalStuffReadOnly.csproj">
<Project>{720FA70F-D785-48ED-BA45-561921E0EEEC}</Project> <Project>{720FA70F-D785-48ED-BA45-561921E0EEEC}</Project>
<Name>KerbalStuffReadOnly</Name> <Name>KerbalStuffReadOnly</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
</Project> </Project>
using CLAP; // KerbalStuffWrapper
using CLAP.Interception; //
using CLAP.Validation; // Author:
  // toadicus
  //
  // Copyright © 2014, toadicus
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice, this list of conditions and the
  // following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  // * Neither the name of the author nor the names of other contributors may be used to endorse or promote products
  // derived from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // This software uses the CLAP .NET Command-Line Parser, Copyright © 2011 Adrian Aisemberg, SharpRegion.
  // Used under license.
  //
  // This software uses the MiniJSON .NET JSON Parser, Copyright © 2013 Calvin Rien. Used under license.
  //
  // This software uses the FormUpload multipart/form-data library,
  // http://www.briangrinstead.com/blog/multipart-form-post-in-c.
  //
   
using System; using System;
using System.IO;  
using System.Collections.Generic; using System.Collections.Generic;
   
namespace KerbalStuff.Wrapper namespace KerbalStuff.Wrapper
{ {
public static class Utils public static class Utils
{ {
public static string HumanName(this Type type) public static string HumanName(this Type type)
{ {
switch (type.Name) switch (type.Name)
{ {
case "Int64": case "Int64":
case "Int32": case "Int32":
case "Int16": case "Int16":
return "integer"; return "integer";
case "Single": case "Single":
case "Double": case "Double":
return "decimal number"; return "decimal number";
default: default:
return type.Name.ToLower(); return type.Name.ToLower();
} }
} }
} }
} }