summaryrefslogtreecommitdiff
path: root/src/client/Client.cpp
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
commit058a2edd75debbd0297f92572316daa704bd379f (patch)
treead303f091f9a08b209b91eb34a9fcad996a3de69 /src/client/Client.cpp
parente3594aba9e05c6865d396418c028049cda92c2f3 (diff)
parent7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff)
downloadpowder-058a2edd75debbd0297f92572316daa704bd379f.zip
powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/client/Client.cpp')
-rw-r--r--src/client/Client.cpp2351
1 files changed, 2351 insertions, 0 deletions
diff --git a/src/client/Client.cpp b/src/client/Client.cpp
new file mode 100644
index 0000000..763814a
--- /dev/null
+++ b/src/client/Client.cpp
@@ -0,0 +1,2351 @@
+#include <stdlib.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iomanip>
+#include <time.h>
+#include <stdio.h>
+#include <deque>
+#include <fstream>
+#include <dirent.h>
+
+#ifdef MACOSX
+#include <mach-o/dyld.h>
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+#ifdef WIN
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <windows.h>
+#include <direct.h>
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include "Config.h"
+#include "Format.h"
+#include "Client.h"
+#include "MD5.h"
+#include "graphics/Graphics.h"
+#include "Misc.h"
+#include "Update.h"
+#include "HTTP.h"
+
+#include "simulation/SaveRenderer.h"
+#include "interface/Point.h"
+#include "client/SaveInfo.h"
+#include "client/SaveFile.h"
+#include "client/GameSave.h"
+#include "search/Thumbnail.h"
+#include "preview/Comment.h"
+#include "ClientListener.h"
+#include "ThumbnailBroker.h"
+
+#include "cajun/reader.h"
+#include "cajun/writer.h"
+
+extern "C"
+{
+#if defined(WIN) && !defined(__GNUC__)
+#include <io.h>
+#else
+#include <dirent.h>
+#endif
+}
+
+Client::Client():
+ authUser(0, ""),
+ updateAvailable(false),
+ versionCheckRequest(NULL),
+ messageOfTheDay("")
+{
+ int i = 0;
+ for(i = 0; i < THUMB_CACHE_SIZE; i++)
+ {
+ thumbnailCache[i] = NULL;
+ }
+ for(i = 0; i < IMGCONNS; i++)
+ {
+ activeThumbRequests[i] = NULL;
+ activeThumbRequestTimes[i] = 0;
+ activeThumbRequestCompleteTimes[i] = 0;
+ }
+
+ //Read config
+ std::ifstream configFile;
+ configFile.open("powder.pref", std::ios::binary);
+ if(configFile)
+ {
+ int fsize = configFile.tellg();
+ configFile.seekg(0, std::ios::end);
+ fsize = configFile.tellg() - (std::streampos)fsize;
+ configFile.seekg(0, std::ios::beg);
+ if(fsize)
+ {
+ try
+ {
+ json::Reader::Read(configDocument, configFile);
+ authUser.ID = ((json::Number)(configDocument["User"]["ID"])).Value();
+ authUser.SessionID = ((json::String)(configDocument["User"]["SessionID"])).Value();
+ authUser.SessionKey = ((json::String)(configDocument["User"]["SessionKey"])).Value();
+ authUser.Username = ((json::String)(configDocument["User"]["Username"])).Value();
+
+ std::string userElevation = ((json::String)(configDocument["User"]["Elevation"])).Value();
+ if(userElevation == "Admin")
+ authUser.UserElevation = User::ElevationAdmin;
+ else if(userElevation == "Mod")
+ authUser.UserElevation = User::ElevationModerator;
+ else
+ authUser.UserElevation = User::ElevationNone;
+ }
+ catch (json::Exception &e)
+ {
+ authUser = User(0, "");
+ std::cerr << "Error: Could not read data from prefs: " << e.what() << std::endl;
+ }
+ }
+ configFile.close();
+ }
+}
+
+void Client::Initialise(std::string proxyString)
+{
+
+ if(GetPrefBool("version.update", false)==true)
+ {
+ SetPref("version.update", false);
+ update_finish();
+ }
+
+ if(proxyString.length())
+ http_init((char*)proxyString.c_str());
+ else
+ http_init(NULL);
+
+ //Read stamps library
+ std::ifstream stampsLib;
+ stampsLib.open(STAMPS_DIR PATH_SEP "stamps.def", std::ios::binary);
+ while(!stampsLib.eof())
+ {
+ char data[11];
+ memset(data, 0, 11);
+ stampsLib.read(data, 10);
+ if(!data[0])
+ break;
+ stampIDs.push_back(data);
+ }
+ stampsLib.close();
+
+ //Begin version check
+ versionCheckRequest = http_async_req_start(NULL, SERVER "/Startup.json", NULL, 0, 1);
+
+ if(authUser.ID)
+ {
+ http_auth_headers(versionCheckRequest, (char *)format::NumberToString<int>(authUser.ID).c_str(), NULL, (char *)authUser.SessionID.c_str());
+ }
+}
+
+bool Client::DoInstallation()
+{
+#if defined(WIN)
+ int returnval;
+ LONG rresult;
+ HKEY newkey;
+ char *currentfilename = exe_name();
+ char *iconname = NULL;
+ char *opencommand = NULL;
+ //char AppDataPath[MAX_PATH];
+ char *AppDataPath = NULL;
+ iconname = (char*)malloc(strlen(currentfilename)+6);
+ sprintf(iconname, "%s,-102", currentfilename);
+
+ //Create Roaming application data folder
+ /*if(!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, AppDataPath)))
+ {
+ returnval = 0;
+ goto finalise;
+ }*/
+
+ AppDataPath = _getcwd(NULL, 0);
+
+ //Move Game executable into application data folder
+ //TODO: Implement
+
+ opencommand = (char*)malloc(strlen(currentfilename)+53+strlen(AppDataPath));
+ /*if((strlen(AppDataPath)+strlen(APPDATA_SUBDIR "\\Powder Toy"))<MAX_PATH)
+ {
+ strappend(AppDataPath, APPDATA_SUBDIR);
+ _mkdir(AppDataPath);
+ strappend(AppDataPath, "\\Powder Toy");
+ _mkdir(AppDataPath);
+ } else {
+ returnval = 0;
+ goto finalise;
+ }*/
+ sprintf(opencommand, "\"%s\" open \"%%1\" ddir \"%s\"", currentfilename, AppDataPath);
+
+ //Create extension entry
+ rresult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\.cps", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, NULL);
+ if (rresult != ERROR_SUCCESS) {
+ returnval = 0;
+ goto finalise;
+ }
+ rresult = RegSetValueEx(newkey, 0, 0, REG_SZ, (LPBYTE)"PowderToySave", strlen("PowderToySave")+1);
+ if (rresult != ERROR_SUCCESS) {
+ RegCloseKey(newkey);
+ returnval = 0;
+ goto finalise;
+ }
+ RegCloseKey(newkey);
+
+ rresult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\.stm", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, NULL);
+ if (rresult != ERROR_SUCCESS) {
+ returnval = 0;
+ goto finalise;
+ }
+ rresult = RegSetValueEx(newkey, 0, 0, REG_SZ, (LPBYTE)"PowderToySave", strlen("PowderToySave")+1);
+ if (rresult != ERROR_SUCCESS) {
+ RegCloseKey(newkey);
+ returnval = 0;
+ goto finalise;
+ }
+ RegCloseKey(newkey);
+
+ //Create program entry
+ rresult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\PowderToySave", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, NULL);
+ if (rresult != ERROR_SUCCESS) {
+ returnval = 0;
+ goto finalise;
+ }
+ rresult = RegSetValueEx(newkey, 0, 0, REG_SZ, (LPBYTE)"Powder Toy Save", strlen("Powder Toy Save")+1);
+ if (rresult != ERROR_SUCCESS) {
+ RegCloseKey(newkey);
+ returnval = 0;
+ goto finalise;
+ }
+ RegCloseKey(newkey);
+
+ //Set DefaultIcon
+ rresult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\PowderToySave\\DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, NULL);
+ if (rresult != ERROR_SUCCESS) {
+ returnval = 0;
+ goto finalise;
+ }
+ rresult = RegSetValueEx(newkey, 0, 0, REG_SZ, (LPBYTE)iconname, strlen(iconname)+1);
+ if (rresult != ERROR_SUCCESS) {
+ RegCloseKey(newkey);
+ returnval = 0;
+ goto finalise;
+ }
+ RegCloseKey(newkey);
+
+ //Set Launch command
+ rresult = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\PowderToySave\\shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newkey, NULL);
+ if (rresult != ERROR_SUCCESS) {
+ returnval = 0;
+ goto finalise;
+ }
+ rresult = RegSetValueEx(newkey, 0, 0, REG_SZ, (LPBYTE)opencommand, strlen(opencommand)+1);
+ if (rresult != ERROR_SUCCESS) {
+ RegCloseKey(newkey);
+ returnval = 0;
+ goto finalise;
+ }
+ RegCloseKey(newkey);
+
+ returnval = 1;
+ finalise:
+
+ if(iconname) free(iconname);
+ if(opencommand) free(opencommand);
+ if(currentfilename) free(currentfilename);
+
+ return returnval;
+#elif defined(LIN)
+ #include "icondoc.h"
+
+ char *currentfilename = exe_name();
+ FILE *f;
+ char *mimedata =
+"<?xml version=\"1.0\"?>\n"
+" <mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>\n"
+" <mime-type type=\"application/vnd.powdertoy.save\">\n"
+" <comment>Powder Toy save</comment>\n"
+" <glob pattern=\"*.cps\"/>\n"
+" <glob pattern=\"*.stm\"/>\n"
+" </mime-type>\n"
+"</mime-info>\n";
+ f = fopen("powdertoy-save.xml", "wb");
+ if (!f)
+ return 0;
+ fwrite(mimedata, 1, strlen(mimedata), f);
+ fclose(f);
+
+ char *protocolfiledata_tmp =
+"[Desktop Entry]\n"
+"Type=Application\n"
+"Name=Powder Toy\n"
+"Comment=Physics sandbox game\n"
+"MimeType=x-scheme-handler/ptsave;\n"
+"NoDisplay=true\n";
+ char *protocolfiledata = (char *)malloc(strlen(protocolfiledata_tmp)+strlen(currentfilename)+100);
+ strcpy(protocolfiledata, protocolfiledata_tmp);
+ strappend(protocolfiledata, "Exec=");
+ strappend(protocolfiledata, currentfilename);
+ strappend(protocolfiledata, " ptsave %u\n");
+ f = fopen("powdertoy-tpt-ptsave.desktop", "wb");
+ if (!f)
+ return 0;
+ fwrite(protocolfiledata, 1, strlen(protocolfiledata), f);
+ fclose(f);
+ system("xdg-desktop-menu install powdertoy-tpt-ptsave.desktop");
+
+ char *desktopfiledata_tmp =
+"[Desktop Entry]\n"
+"Type=Application\n"
+"Name=Powder Toy\n"
+"Comment=Physics sandbox game\n"
+"MimeType=application/vnd.powdertoy.save;\n"
+"NoDisplay=true\n";
+ char *desktopfiledata = (char *)malloc(strlen(desktopfiledata_tmp)+strlen(currentfilename)+100);
+ strcpy(desktopfiledata, desktopfiledata_tmp);
+ strappend(desktopfiledata, "Exec=");
+ strappend(desktopfiledata, currentfilename);
+ strappend(desktopfiledata, " open %f\n");
+ f = fopen("powdertoy-tpt.desktop", "wb");
+ if (!f)
+ return 0;
+ fwrite(desktopfiledata, 1, strlen(desktopfiledata), f);
+ fclose(f);
+ system("xdg-mime install powdertoy-save.xml");
+ system("xdg-desktop-menu install powdertoy-tpt.desktop");
+ f = fopen("powdertoy-save-32.png", "wb");
+ if (!f)
+ return 0;
+ fwrite(icon_doc_32_png, 1, sizeof(icon_doc_32_png), f);
+ fclose(f);
+ f = fopen("powdertoy-save-16.png", "wb");
+ if (!f)
+ return 0;
+ fwrite(icon_doc_16_png, 1, sizeof(icon_doc_16_png), f);
+ fclose(f);
+ system("xdg-icon-resource install --noupdate --context mimetypes --size 32 powdertoy-save-32.png application-vnd.powdertoy.save");
+ system("xdg-icon-resource install --noupdate --context mimetypes --size 16 powdertoy-save-16.png application-vnd.powdertoy.save");
+ system("xdg-icon-resource forceupdate");
+ system("xdg-mime default powdertoy-tpt.desktop application/vnd.powdertoy.save");
+ system("xdg-mime default powdertoy-tpt-ptsave.desktop x-scheme-handler/ptsave");
+ unlink("powdertoy-save-32.png");
+ unlink("powdertoy-save-16.png");
+ unlink("powdertoy-save.xml");
+ unlink("powdertoy-tpt.desktop");
+ unlink("powdertoy-tpt-ptsave.desktop");
+ return true;
+#elif defined MACOSX
+ return false;
+#endif
+}
+
+void Client::SetProxy(std::string proxy)
+{
+ http_done();
+ if(proxy.length())
+ http_init((char*)proxy.c_str());
+ else
+ http_init(NULL);
+}
+
+std::vector<std::string> Client::DirectorySearch(std::string directory, std::string search, std::string extension)
+{
+ std::vector<std::string> extensions;
+ extensions.push_back(extension);
+ return DirectorySearch(directory, search, extensions);
+}
+
+std::vector<std::string> Client::DirectorySearch(std::string directory, std::string search, std::vector<std::string> extensions)
+{
+ //Get full file listing
+ std::vector<std::string> directoryList;
+#if defined(WIN) && !defined(__GNUC__)
+ //Windows
+ struct _finddata_t currentFile;
+ intptr_t findFileHandle;
+ std::string fileMatch = directory + "*.*";
+ findFileHandle = _findfirst(fileMatch.c_str(), &currentFile);
+ if (findFileHandle == -1L)
+ {
+ printf("Unable to open directory\n");
+ return std::vector<std::string>();
+ }
+ do
+ {
+ std::string currentFileName = std::string(currentFile.name);
+ if(currentFileName.length()>4)
+ directoryList.push_back(directory+currentFileName);
+ }
+ while (_findnext(findFileHandle, &currentFile) == 0);
+ _findclose(findFileHandle);
+#else
+ //Linux or MinGW
+ struct dirent * directoryEntry;
+ DIR *directoryHandle = opendir(directory.c_str());
+ if(!directoryHandle)
+ {
+ printf("Unable to open directory\n");
+ return std::vector<std::string>();
+ }
+ while(directoryEntry = readdir(directoryHandle))
+ {
+ std::string currentFileName = std::string(directoryEntry->d_name);
+ if(currentFileName.length()>4)
+ directoryList.push_back(directory+currentFileName);
+ }
+ closedir(directoryHandle);
+#endif
+
+ std::vector<std::string> searchResults;
+ for(std::vector<std::string>::iterator iter = directoryList.begin(), end = directoryList.end(); iter != end; ++iter)
+ {
+ std::string filename = *iter;
+ bool extensionMatch = !extensions.size();
+ for(std::vector<std::string>::iterator extIter = extensions.begin(), extEnd = extensions.end(); extIter != extEnd; ++extIter)
+ {
+ if(filename.find(*extIter)==filename.length()-(*extIter).length())
+ {
+ extensionMatch = true;
+ break;
+ }
+ }
+ bool searchMatch = !search.size();
+ if(search.size() && filename.find(search)!=std::string::npos)
+ searchMatch = true;
+
+ if(searchMatch && extensionMatch)
+ searchResults.push_back(filename);
+ }
+
+ //Filter results
+ return searchResults;
+}
+
+int Client::MakeDirectory(const char * dirName)
+{
+#ifdef WIN
+ return _mkdir(dirName);
+#else
+ return mkdir(dirName, 0755);
+#endif
+}
+
+void Client::WriteFile(std::vector<unsigned char> fileData, std::string filename)
+{
+ try
+ {
+ std::ofstream fileStream;
+ fileStream.open(std::string(filename).c_str(), std::ios::binary);
+ if(fileStream.is_open())
+ {
+ fileStream.write((char*)&fileData[0], fileData.size());
+ fileStream.close();
+ }
+ }
+ catch (std::exception & e)
+ {
+ std::cerr << "WriteFile:" << e.what() << std::endl;
+ throw;
+ }
+}
+
+bool Client::FileExists(std::string filename)
+{
+ bool exists = false;
+ try
+ {
+ std::ifstream fileStream;
+ fileStream.open(std::string(filename).c_str(), std::ios::binary);
+ if(fileStream.is_open())
+ {
+ exists = true;
+ fileStream.close();
+ }
+ }
+ catch (std::exception & e)
+ {
+ exists = false;
+ }
+ return exists;
+}
+
+void Client::WriteFile(std::vector<char> fileData, std::string filename)
+{
+ try
+ {
+ std::ofstream fileStream;
+ fileStream.open(std::string(filename).c_str(), std::ios::binary);
+ if(fileStream.is_open())
+ {
+ fileStream.write(&fileData[0], fileData.size());
+ fileStream.close();
+ }
+ }
+ catch (std::exception & e)
+ {
+ std::cerr << "WriteFile:" << e.what() << std::endl;
+ throw;
+ }
+}
+
+std::vector<unsigned char> Client::ReadFile(std::string filename)
+{
+ try
+ {
+ std::ifstream fileStream;
+ fileStream.open(std::string(filename).c_str(), std::ios::binary);
+ if(fileStream.is_open())
+ {
+ fileStream.seekg(0, std::ios::end);
+ size_t fileSize = fileStream.tellg();
+ fileStream.seekg(0);
+
+ unsigned char * tempData = new unsigned char[fileSize];
+ fileStream.read((char *)tempData, fileSize);
+ fileStream.close();
+
+ std::vector<unsigned char> fileData;
+ fileData.insert(fileData.end(), tempData, tempData+fileSize);
+ delete[] tempData;
+
+ return fileData;
+ }
+ else
+ {
+ return std::vector<unsigned char>();
+ }
+ }
+ catch(std::exception & e)
+ {
+ std::cerr << "Readfile: " << e.what() << std::endl;
+ throw;
+ }
+}
+
+void Client::SetMessageOfTheDay(std::string message)
+{
+ messageOfTheDay = message;
+ notifyMessageOfTheDay();
+}
+
+std::string Client::GetMessageOfTheDay()
+{
+ return messageOfTheDay;
+}
+
+void Client::Tick()
+{
+ //Check thumbnail queue
+ ThumbnailBroker::Ref().FlushThumbQueue();
+
+ //Check status on version check request
+ if(versionCheckRequest && http_async_req_status(versionCheckRequest))
+ {
+ int status;
+ int dataLength;
+ char * data = http_async_req_stop(versionCheckRequest, &status, &dataLength);
+ versionCheckRequest = NULL;
+
+ if(status != 200)
+ {
+ if(data)
+ free(data);
+ }
+ else
+ {
+ std::istringstream dataStream(data);
+
+ try
+ {
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ //Check session
+ json::Boolean sessionStatus = objDocument["Session"];
+ if(!sessionStatus.Value())
+ {
+ authUser = User(0, "");
+ }
+
+ //MOTD
+ json::String messageOfTheDay = objDocument["MessageOfTheDay"];
+ this->messageOfTheDay = messageOfTheDay.Value();
+ notifyMessageOfTheDay();
+
+ //Check for updates
+ json::Object versions = objDocument["Updates"];
+
+ json::Object stableVersion = versions["Stable"];
+ json::Object betaVersion = versions["Beta"];
+ json::Object snapshotVersion = versions["Snapshot"];
+
+ json::Number stableMajor = stableVersion["Major"];
+ json::Number stableMinor = stableVersion["Minor"];
+ json::Number stableBuild = stableVersion["Build"];
+ json::String stableFile = stableVersion["File"];
+
+ json::Number betaMajor = betaVersion["Major"];
+ json::Number betaMinor = betaVersion["Minor"];
+ json::Number betaBuild = betaVersion["Build"];
+ json::String betaFile = betaVersion["File"];
+
+ json::Number snapshotSnapshot = snapshotVersion["Snapshot"];
+ json::String snapshotFile = snapshotVersion["File"];
+
+ if(stableMajor.Value()>SAVE_VERSION || (stableMinor.Value()>MINOR_VERSION && stableMajor.Value()==SAVE_VERSION) || stableBuild.Value()>BUILD_NUM)
+ {
+ updateAvailable = true;
+ updateInfo = UpdateInfo(stableMajor.Value(), stableMinor.Value(), stableBuild.Value(), stableFile.Value(), UpdateInfo::Stable);
+ }
+
+#ifdef BETA
+ if(betaMajor.Value()>SAVE_VERSION || (betaMinor.Value()>MINOR_VERSION && betaMajor.Value()==SAVE_VERSION) || betaBuild.Value()>BUILD_NUM)
+ {
+ updateAvailable = true;
+ updateInfo = UpdateInfo(betaMajor.Value(), betaMinor.Value(), betaBuild.Value(), betaFile.Value(), UpdateInfo::Beta);
+ }
+#endif
+
+#ifdef SNAPSHOT
+ if(snapshotSnapshot.Value() > SNAPSHOT_ID)
+ {
+ updateAvailable = true;
+ updateInfo = UpdateInfo(snapshotSnapshot.Value(), snapshotFile.Value(), UpdateInfo::Snapshot);
+ }
+#endif
+
+ if(updateAvailable)
+ {
+ notifyUpdateAvailable();
+ }
+ }
+ catch (json::Exception &e)
+ {
+ //Do nothing
+ }
+
+ if(data)
+ free(data);
+ }
+ }
+}
+
+UpdateInfo Client::GetUpdateInfo()
+{
+ return updateInfo;
+}
+
+void Client::notifyUpdateAvailable()
+{
+ for (std::vector<ClientListener*>::iterator iterator = listeners.begin(), end = listeners.end(); iterator != end; ++iterator)
+ {
+ (*iterator)->NotifyUpdateAvailable(this);
+ }
+}
+
+void Client::notifyMessageOfTheDay()
+{
+ for (std::vector<ClientListener*>::iterator iterator = listeners.begin(), end = listeners.end(); iterator != end; ++iterator)
+ {
+ (*iterator)->NotifyMessageOfTheDay(this);
+ }
+}
+
+void Client::notifyAuthUserChanged()
+{
+ for (std::vector<ClientListener*>::iterator iterator = listeners.begin(), end = listeners.end(); iterator != end; ++iterator)
+ {
+ (*iterator)->NotifyAuthUserChanged(this);
+ }
+}
+
+void Client::AddListener(ClientListener * listener)
+{
+ listeners.push_back(listener);
+}
+
+void Client::RemoveListener(ClientListener * listener)
+{
+ for (std::vector<ClientListener*>::iterator iterator = listeners.begin(), end = listeners.end(); iterator != end; ++iterator)
+ {
+ if((*iterator) == listener)
+ {
+ listeners.erase(iterator);
+ return;
+ }
+ }
+}
+
+void Client::WritePrefs()
+{
+ std::ofstream configFile;
+ configFile.open("powder.pref", std::ios::trunc);
+ if(configFile)
+ {
+ if(authUser.ID)
+ {
+ configDocument["User"]["ID"] = json::Number(authUser.ID);
+ configDocument["User"]["SessionID"] = json::String(authUser.SessionID);
+ configDocument["User"]["SessionKey"] = json::String(authUser.SessionKey);
+ configDocument["User"]["Username"] = json::String(authUser.Username);
+ if(authUser.UserElevation == User::ElevationAdmin)
+ configDocument["User"]["Elevation"] = json::String("Admin");
+ else if(authUser.UserElevation == User::ElevationModerator)
+ configDocument["User"]["Elevation"] = json::String("Mod");
+ else
+ configDocument["User"]["Elevation"] = json::String("None");
+ }
+ else
+ {
+ configDocument["User"] = json::Null();
+ }
+ json::Writer::Write(configDocument, configFile);
+ configFile.close();
+ }
+}
+
+void Client::Shutdown()
+{
+ ClearThumbnailRequests();
+ http_done();
+
+ //Save config
+ WritePrefs();
+}
+
+Client::~Client()
+{
+}
+
+
+void Client::SetAuthUser(User user)
+{
+ authUser = user;
+ notifyAuthUserChanged();
+}
+
+User Client::GetAuthUser()
+{
+ return authUser;
+}
+
+RequestStatus Client::UploadSave(SaveInfo & save)
+{
+ lastError = "";
+ int gameDataLength;
+ char * gameData = NULL;
+ int dataStatus;
+ char * data;
+ int dataLength = 0;
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ if(authUser.ID)
+ {
+ if(!save.GetGameSave())
+ {
+ lastError = "Empty game save";
+ return RequestFailure;
+ }
+ save.SetID(0);
+
+ gameData = save.GetGameSave()->Serialise(gameDataLength);
+
+ if(!gameData)
+ {
+ lastError = "Cannot upload game save";
+ return RequestFailure;
+ }
+
+ char *saveName = new char[save.GetName().length() + 1];
+ std::strcpy ( saveName, save.GetName().c_str() );
+ char *saveDescription = new char[save.GetDescription().length() + 1];
+ std::strcpy ( saveDescription, save.GetDescription().c_str() );
+
+ char * postNames[] = { "Name", "Description", "Data:save.bin", "Publish", NULL };
+ char * postDatas[] = { saveName, saveDescription, gameData, (char *)(save.GetPublished()?"Public":"Private") };
+ int postLengths[] = { save.GetName().length(), save.GetDescription().length(), gameDataLength, save.GetPublished()?6:7 };
+ //std::cout << postNames[0] << " " << postDatas[0] << " " << postLengths[0] << std::endl;
+ data = http_multipart_post("http://" SERVER "/Save.api", postNames, postDatas, postLengths, (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+
+ delete[] saveDescription;
+ delete[] saveName;
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(data && dataStatus == 200)
+ {
+ if(strncmp((const char *)data, "OK", 2)!=0)
+ {
+ if(gameData) free(gameData);
+ lastError = std::string((const char *)data);
+ free(data);
+ return RequestFailure;
+ }
+ else
+ {
+ int tempID;
+ std::stringstream saveIDStream((char *)(data+3));
+ saveIDStream >> tempID;
+ if(!tempID)
+ {
+ lastError = "Server did not return Save ID";
+ return RequestFailure;
+ }
+ else
+ {
+ save.SetID(tempID);
+ }
+ }
+ free(data);
+ if(gameData) free(gameData);
+ return RequestOkay;
+ }
+ else if(data)
+ {
+ free(data);
+ }
+ if(gameData) free(gameData);
+ return RequestFailure;
+}
+
+SaveFile * Client::GetStamp(std::string stampID)
+{
+ std::string stampFile = std::string(STAMPS_DIR PATH_SEP + stampID + ".stm");
+ if(FileExists(stampFile))
+ {
+ SaveFile * file = new SaveFile(stampID);
+ try
+ {
+ GameSave * tempSave = new GameSave(ReadFile(stampFile));
+ file->SetGameSave(tempSave);
+ }
+ catch (ParseException & e)
+ {
+ std::cerr << "Client: Invalid stamp file, " << stampID << " " << std::string(e.what()) << std::endl;
+ }
+ return file;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void Client::DeleteStamp(std::string stampID)
+{
+ for (std::list<std::string>::iterator iterator = stampIDs.begin(), end = stampIDs.end(); iterator != end; ++iterator)
+ {
+ if((*iterator) == stampID)
+ {
+ std::stringstream stampFilename;
+ stampFilename << STAMPS_DIR;
+ stampFilename << PATH_SEP;
+ stampFilename << stampID;
+ stampFilename << ".stm";
+ remove(stampFilename.str().c_str());
+ stampIDs.erase(iterator);
+ return;
+ }
+ }
+
+ updateStamps();
+}
+
+std::string Client::AddStamp(GameSave * saveData)
+{
+ unsigned t=(unsigned)time(NULL);
+ if (lastStampTime!=t)
+ {
+ lastStampTime=t;
+ lastStampName=0;
+ }
+ else
+ lastStampName++;
+ std::stringstream saveID;
+ //sprintf(saveID, "%08x%02x", lastStampTime, lastStampName);
+ saveID
+ << std::setw(8) << std::setfill('0') << std::hex << lastStampTime
+ << std::setw(2) << std::setfill('0') << std::hex << lastStampName;
+
+ MakeDirectory(STAMPS_DIR);
+
+ int gameDataLength;
+ char * gameData = saveData->Serialise(gameDataLength);
+
+ std::ofstream stampStream;
+ stampStream.open(std::string(STAMPS_DIR PATH_SEP + saveID.str()+".stm").c_str(), std::ios::binary);
+ stampStream.write((const char *)gameData, gameDataLength);
+ stampStream.close();
+
+ delete[] gameData;
+
+ stampIDs.push_front(saveID.str());
+
+ updateStamps();
+
+ return saveID.str();
+}
+
+void Client::updateStamps()
+{
+ MakeDirectory(STAMPS_DIR);
+
+ std::ofstream stampsStream;
+ stampsStream.open(std::string(STAMPS_DIR PATH_SEP "stamps.def").c_str(), std::ios::binary);
+ for (std::list<std::string>::const_iterator iterator = stampIDs.begin(), end = stampIDs.end(); iterator != end; ++iterator)
+ {
+ stampsStream.write((*iterator).c_str(), 10);
+ }
+ stampsStream.write("\0", 1);
+ stampsStream.close();
+ return;
+}
+
+void Client::RescanStamps()
+{
+ DIR * directory;
+ struct dirent * entry;
+ directory = opendir("stamps");
+ if (directory != NULL)
+ {
+ stampIDs.clear();
+ while (entry = readdir(directory))
+ {
+ if(strncmp(entry->d_name, "..", 3) && strncmp(entry->d_name, ".", 2) && strstr(entry->d_name, ".stm") && strlen(entry->d_name) == 14)
+ {
+ char stampname[11];
+ strncpy(stampname, entry->d_name, 10);
+ stampIDs.push_front(stampname);
+ }
+ }
+ closedir(directory);
+ updateStamps();
+ }
+}
+
+int Client::GetStampsCount()
+{
+ return stampIDs.size();
+}
+
+std::vector<std::string> Client::GetStamps(int start, int count)
+{
+ if(start+count > stampIDs.size()) {
+ if(start > stampIDs.size())
+ return std::vector<std::string>();
+ count = stampIDs.size()-start;
+ }
+
+ std::vector<std::string> stampRange;
+ int index = 0;
+ for (std::list<std::string>::const_iterator iterator = stampIDs.begin(), end = stampIDs.end(); iterator != end; ++iterator, ++index) {
+ if(index>=start && index < start+count)
+ stampRange.push_back(*iterator);
+ }
+ return stampRange;
+}
+
+RequestStatus Client::ExecVote(int saveID, int direction)
+{
+ lastError = "";
+ int dataStatus;
+ char * data;
+ int dataLength = 0;
+ std::stringstream idStream;
+ idStream << saveID;
+
+ std::string saveIDText = format::NumberToString<int>(saveID);
+ std::string directionText = direction==1?"Up":"Down";
+
+ std::string userIDText = format::NumberToString<int>(authUser.ID);
+ if(authUser.ID)
+ {
+ char * postNames[] = { "ID", "Action", NULL };
+ char * postDatas[] = { (char*)(saveIDText.c_str()), (char*)(directionText.c_str()) };
+ int postLengths[] = { saveIDText.length(), directionText.length() };
+ //std::cout << postNames[0] << " " << postDatas[0] << " " << postLengths[0] << std::endl;
+ data = http_multipart_post("http://" SERVER "/Vote.api", postNames, postDatas, postLengths, (char *)(userIDText.c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(data && dataStatus == 200)
+ {
+ if(strncmp((const char *)data, "OK", 2)!=0)
+ {
+ lastError = std::string((const char *)data);
+ free(data);
+ return RequestFailure;
+ }
+ free(data);
+ return RequestOkay;
+ }
+ else if(data)
+ {
+ free(data);
+ }
+ lastError = http_ret_text(dataStatus);
+ return RequestFailure;
+}
+
+unsigned char * Client::GetSaveData(int saveID, int saveDate, int & dataLength)
+{
+ lastError = "";
+ int dataStatus;
+ unsigned char * data;
+ dataLength = 0;
+ std::stringstream urlStream;
+ if(saveDate)
+ {
+ urlStream << "http://" << STATICSERVER << "/" << saveID << "_" << saveDate << ".cps";
+ }
+ else
+ {
+ urlStream << "http://" << STATICSERVER << "/" << saveID << ".cps";
+ }
+
+ data = (unsigned char *)http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
+ if(data && dataStatus == 200)
+ {
+ return data;
+ }
+ else if(data)
+ {
+ free(data);
+ }
+ return NULL;
+}
+
+std::vector<unsigned char> Client::GetSaveData(int saveID, int saveDate)
+{
+ int dataSize;
+ unsigned char * data = GetSaveData(saveID, saveDate, dataSize);
+
+ std::vector<unsigned char> saveData(data, data+dataSize);
+
+ delete[] data;
+ return saveData;
+}
+
+LoginStatus Client::Login(std::string username, std::string password, User & user)
+{
+ lastError = "";
+ std::stringstream urlStream;
+ std::stringstream hashStream;
+ char passwordHash[33];
+ char totalHash[33];
+
+ user.ID = 0;
+ user.Username = "";
+ user.SessionID = "";
+ user.SessionKey = "";
+
+ //Doop
+ md5_ascii(passwordHash, (const unsigned char *)password.c_str(), password.length());
+ passwordHash[32] = 0;
+ hashStream << username << "-" << passwordHash;
+ md5_ascii(totalHash, (const unsigned char *)(hashStream.str().c_str()), hashStream.str().length());
+ totalHash[32] = 0;
+
+ char * data;
+ int dataStatus, dataLength;
+ char * postNames[] = { "Username", "Hash", NULL };
+ char * postDatas[] = { (char*)username.c_str(), totalHash };
+ int postLengths[] = { username.length(), 32 };
+ data = http_multipart_post("http://" SERVER "/Login.json", postNames, postDatas, postLengths, NULL, NULL, NULL, &dataStatus, &dataLength);
+ //data = http_auth_get("http://" SERVER "/Login.json", (char*)username.c_str(), (char*)password.c_str(), NULL, &dataStatus, &dataLength);
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+ json::Number tempStatus = objDocument["Status"];
+
+ free(data);
+ if(tempStatus.Value() == 1)
+ {
+ json::Number userIDTemp = objDocument["UserID"];
+ json::String sessionIDTemp = objDocument["SessionID"];
+ json::String sessionKeyTemp = objDocument["SessionKey"];
+ json::String userElevationTemp = objDocument["Elevation"];
+ user.Username = username;
+ user.ID = userIDTemp.Value();
+ user.SessionID = sessionIDTemp.Value();
+ user.SessionKey = sessionKeyTemp.Value();
+ std::string userElevation = userElevationTemp.Value();
+ if(userElevation == "Admin")
+ user.UserElevation = User::ElevationAdmin;
+ else if(userElevation == "Mod")
+ user.UserElevation = User::ElevationModerator;
+ else
+ user.UserElevation= User::ElevationNone;
+ return LoginOkay;
+ }
+ else
+ {
+ json::String tempError = objDocument["Error"];
+ lastError = tempError.Value();
+ return LoginError;
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Server responded with crap";
+ return LoginError;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ {
+ free(data);
+ }
+ return LoginError;
+}
+
+RequestStatus Client::DeleteSave(int saveID)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Delete.json?ID=" << saveID << "&Mode=Delete&Key=" << authUser.SessionKey;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ int status = ((json::Number)objDocument["Status"]).Value();
+
+ if(status!=1)
+ goto failure;
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ goto failure;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ goto failure;
+ }
+ if(data)
+ free(data);
+ return RequestOkay;
+failure:
+ if(data)
+ free(data);
+ return RequestFailure;
+}
+
+RequestStatus Client::AddComment(int saveID, std::string comment)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Comments.json?ID=" << saveID << "&Key=" << authUser.SessionKey;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+
+ char * postNames[] = { "Comment", NULL };
+ char * postDatas[] = { (char*)(comment.c_str()) };
+ int postLengths[] = { comment.length() };
+ data = http_multipart_post((char *)urlStream.str().c_str(), postNames, postDatas, postLengths, (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ int status = ((json::Number)objDocument["Status"]).Value();
+
+ if(status!=1)
+ {
+ lastError = ((json::Number)objDocument["Error"]).Value();
+ }
+
+ if(status!=1)
+ goto failure;
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ goto failure;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ goto failure;
+ }
+ if(data)
+ free(data);
+ return RequestOkay;
+failure:
+ if(data)
+ free(data);
+ return RequestFailure;
+}
+
+RequestStatus Client::FavouriteSave(int saveID, bool favourite)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Favourite.json?ID=" << saveID << "&Key=" << authUser.SessionKey;
+ if(!favourite)
+ urlStream << "&Mode=Remove";
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ int status = ((json::Number)objDocument["Status"]).Value();
+
+ if(status!=1)
+ {
+ lastError = ((json::String)objDocument["Error"]).Value();
+ goto failure;
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ goto failure;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ goto failure;
+ }
+ if(data)
+ free(data);
+ return RequestOkay;
+failure:
+ if(data)
+ free(data);
+ return RequestFailure;
+}
+
+RequestStatus Client::ReportSave(int saveID, std::string message)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Report.json?ID=" << saveID << "&Key=" << authUser.SessionKey;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+
+ char * postNames[] = { "Reason", NULL };
+ char * postDatas[] = { (char*)(message.c_str()) };
+ int postLengths[] = { message.length() };
+ data = http_multipart_post((char *)urlStream.str().c_str(), postNames, postDatas, postLengths, (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ int status = ((json::Number)objDocument["Status"]).Value();
+
+ if(status!=1)
+ {
+ lastError = ((json::String)objDocument["Error"]).Value();
+ goto failure;
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ goto failure;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ goto failure;
+ }
+ if(data)
+ free(data);
+ return RequestOkay;
+failure:
+ if(data)
+ free(data);
+ return RequestFailure;
+}
+
+RequestStatus Client::UnpublishSave(int saveID)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Delete.json?ID=" << saveID << "&Mode=Unpublish&Key=" << authUser.SessionKey;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return RequestFailure;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ int status = ((json::Number)objDocument["Status"]).Value();
+
+ if(status!=1)
+ goto failure;
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ goto failure;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ goto failure;
+ }
+ if(data)
+ free(data);
+ return RequestOkay;
+failure:
+ if(data)
+ free(data);
+ return RequestFailure;
+}
+
+SaveInfo * Client::GetSave(int saveID, int saveDate)
+{
+ lastError = "";
+ std::stringstream urlStream;
+ urlStream << "http://" << SERVER << "/Browse/View.json?ID=" << saveID;
+ if(saveDate)
+ {
+ urlStream << "&Date=" << saveDate;
+ }
+ char * data;
+ int dataStatus, dataLength;
+ //Save(int _id, int _votesUp, int _votesDown, string _userName, string _name, string description_, string date_, bool published_):
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ data = http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ json::Number tempID = objDocument["ID"];
+ json::Number tempScoreUp = objDocument["ScoreUp"];
+ json::Number tempScoreDown = objDocument["ScoreDown"];
+ json::Number tempMyScore = objDocument["ScoreMine"];
+ json::String tempUsername = objDocument["Username"];
+ json::String tempName = objDocument["Name"];
+ json::String tempDescription = objDocument["Description"];
+ json::Number tempDate = objDocument["Date"];
+ json::Boolean tempPublished = objDocument["Published"];
+ json::Boolean tempFavourite = objDocument["Favourite"];
+ json::Number tempComments = objDocument["Comments"];
+ json::Number tempViews = objDocument["Views"];
+ json::Number tempVersion = objDocument["Version"];
+
+ json::Array tagsArray = objDocument["Tags"];
+ std::vector<std::string> tempTags;
+
+ for(int j = 0; j < tagsArray.Size(); j++)
+ {
+ json::String tempTag = tagsArray[j];
+ tempTags.push_back(tempTag.Value());
+ }
+
+ SaveInfo * tempSave = new SaveInfo(
+ tempID.Value(),
+ tempDate.Value(),
+ tempScoreUp.Value(),
+ tempScoreDown.Value(),
+ tempMyScore.Value(),
+ tempUsername.Value(),
+ tempName.Value(),
+ tempDescription.Value(),
+ tempPublished.Value(),
+ tempTags
+ );
+ tempSave->Comments = tempComments.Value();
+ tempSave->Favourite = tempFavourite.Value();
+ tempSave->Views = tempViews.Value();
+ tempSave->Version = tempVersion.Value();
+ return tempSave;
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ return NULL;
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ return NULL;
+}
+
+Thumbnail * Client::GetPreview(int saveID, int saveDate)
+{
+ std::stringstream urlStream;
+ urlStream << "http://" << STATICSERVER << "/" << saveID;
+ if(saveDate)
+ {
+ urlStream << "_" << saveDate;
+ }
+ urlStream << "_large.pti";
+ pixel * thumbData;
+ char * data;
+ int status, data_size, imgw, imgh;
+ data = http_simple_get((char *)urlStream.str().c_str(), &status, &data_size);
+ if (status == 200 && data)
+ {
+ thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh);
+ if(data)
+ {
+ free(data);
+ }
+ if(thumbData)
+ {
+ return new Thumbnail(saveID, saveDate, thumbData, ui::Point(imgw, imgh));
+ free(thumbData);
+ }
+ else
+ {
+ thumbData = (pixel *)malloc((128*128) * PIXELSIZE);
+ return new Thumbnail(saveID, saveDate, thumbData, ui::Point(128, 128));
+ free(thumbData);
+ }
+ }
+ else
+ {
+ if(data)
+ {
+ free(data);
+ }
+ }
+ return new Thumbnail(saveID, saveDate, (pixel *)malloc((128*128) * PIXELSIZE), ui::Point(128, 128));
+}
+
+std::vector<SaveComment*> * Client::GetComments(int saveID, int start, int count)
+{
+ lastError = "";
+ std::vector<SaveComment*> * commentArray = new std::vector<SaveComment*>();
+
+ std::stringstream urlStream;
+ char * data;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Comments.json?ID=" << saveID << "&Start=" << start << "&Count=" << count;
+ data = http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Array commentsArray;
+ json::Reader::Read(commentsArray, dataStream);
+
+ for(int j = 0; j < commentsArray.Size(); j++)
+ {
+ json::Number tempUserID = commentsArray[j]["UserID"];
+ json::String tempUsername = commentsArray[j]["FormattedUsername"];
+ json::String tempComment = commentsArray[j]["Text"];
+ commentArray->push_back(
+ new SaveComment(
+ tempUserID.Value(),
+ tempUsername.Value(),
+ tempComment.Value()
+ )
+ );
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ free(data);
+ return commentArray;
+}
+
+std::vector<std::pair<std::string, int> > * Client::GetTags(int start, int count, std::string query, int & resultCount)
+{
+ lastError = "";
+ resultCount = 0;
+ std::vector<std::pair<std::string, int> > * tagArray = new std::vector<std::pair<std::string, int> >();
+ std::stringstream urlStream;
+ char * data;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/Tags.json?Start=" << start << "&Count=" << count;
+ if(query.length())
+ {
+ urlStream << "&Search_Query=";
+ if(query.length())
+ urlStream << URLEscape(query);
+ }
+
+ data = http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ json::Number tempCount = objDocument["TagTotal"];
+ resultCount = tempCount.Value();
+ json::Array tagsArray = objDocument["Tags"];
+ for(int j = 0; j < tagsArray.Size(); j++)
+ {
+ json::Number tagCount = tagsArray[j]["Count"];
+ json::String tag = tagsArray[j]["Tag"];
+ tagArray->push_back(std::pair<std::string, int>(tag.Value(), tagCount.Value()));
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ free(data);
+ return tagArray;
+}
+
+std::vector<SaveInfo*> * Client::SearchSaves(int start, int count, std::string query, std::string sort, std::string category, int & resultCount)
+{
+ lastError = "";
+ resultCount = 0;
+ std::vector<SaveInfo*> * saveArray = new std::vector<SaveInfo*>();
+ std::stringstream urlStream;
+ char * data;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse.json?Start=" << start << "&Count=" << count;
+ if(query.length() || sort.length())
+ {
+ urlStream << "&Search_Query=";
+ if(query.length())
+ urlStream << URLEscape(query);
+ if(sort == "date")
+ {
+ if(query.length())
+ urlStream << URLEscape(" ");
+ urlStream << URLEscape("sort:") << URLEscape(sort);
+ }
+ }
+ if(category.length())
+ {
+ urlStream << "&Category=" << URLEscape(category);
+ }
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ data = http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object objDocument;
+ json::Reader::Read(objDocument, dataStream);
+
+ json::Number tempCount = objDocument["Count"];
+ resultCount = tempCount.Value();
+ json::Array savesArray = objDocument["Saves"];
+ for(int j = 0; j < savesArray.Size(); j++)
+ {
+ json::Number tempID = savesArray[j]["ID"];
+ json::Number tempDate = savesArray[j]["Date"];
+ json::Number tempScoreUp = savesArray[j]["ScoreUp"];
+ json::Number tempScoreDown = savesArray[j]["ScoreDown"];
+ json::String tempUsername = savesArray[j]["Username"];
+ json::String tempName = savesArray[j]["Name"];
+ json::Number tempVersion = savesArray[j]["Version"];
+ json::Boolean tempPublished = savesArray[j]["Published"];
+ SaveInfo * tempSaveInfo = new SaveInfo(
+ tempID.Value(),
+ tempDate.Value(),
+ tempScoreUp.Value(),
+ tempScoreDown.Value(),
+ tempUsername.Value(),
+ tempName.Value()
+ );
+ tempSaveInfo->Version = tempVersion.Value();
+ tempSaveInfo->SetPublished(tempPublished);
+ saveArray->push_back(tempSaveInfo);
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ free(data);
+ return saveArray;
+}
+
+void Client::ClearThumbnailRequests()
+{
+ for(int i = 0; i < IMGCONNS; i++)
+ {
+ if(activeThumbRequests[i])
+ {
+ http_async_req_close(activeThumbRequests[i]);
+ activeThumbRequests[i] = NULL;
+ activeThumbRequestTimes[i] = 0;
+ activeThumbRequestCompleteTimes[i] = 0;
+ }
+ }
+}
+
+Thumbnail * Client::GetThumbnail(int saveID, int saveDate)
+{
+ std::stringstream urlStream;
+ std::stringstream idStream;
+ int i = 0, currentTime = time(NULL);
+ //Check active requests for any "forgotten" requests
+ for(i = 0; i < IMGCONNS; i++)
+ {
+ //If the request is active, and we've recieved a response
+ if(activeThumbRequests[i] && http_async_req_status(activeThumbRequests[i]))
+ {
+ //If we haven't already, mark the request as completed
+ if(!activeThumbRequestCompleteTimes[i])
+ {
+ activeThumbRequestCompleteTimes[i] = time(NULL);
+ }
+ else if(activeThumbRequestCompleteTimes[i] < (currentTime-2)) //Otherwise, if it completed more than 2 seconds ago, destroy it.
+ {
+ http_async_req_close(activeThumbRequests[i]);
+ activeThumbRequests[i] = NULL;
+ activeThumbRequestTimes[i] = 0;
+ activeThumbRequestCompleteTimes[i] = 0;
+ }
+ }
+ }
+ for(i = 0; i < THUMB_CACHE_SIZE; i++)
+ {
+ if(thumbnailCache[i] && thumbnailCache[i]->ID == saveID && thumbnailCache[i]->Datestamp == saveDate)
+ return thumbnailCache[i];
+ }
+ urlStream << "http://" << STATICSERVER << "/" << saveID;
+ if(saveDate)
+ {
+ urlStream << "_" << saveDate;
+ }
+ urlStream << "_small.pti";
+ idStream << saveID << ":" << saveDate;
+ std::string idString = idStream.str();
+ bool found = false;
+ for(i = 0; i < IMGCONNS; i++)
+ {
+ if(activeThumbRequests[i] && activeThumbRequestIDs[i] == idString)
+ {
+ found = true;
+ if(http_async_req_status(activeThumbRequests[i]))
+ {
+ pixel * thumbData;
+ char * data;
+ int status, data_size, imgw, imgh;
+ data = http_async_req_stop(activeThumbRequests[i], &status, &data_size);
+ free(activeThumbRequests[i]);
+ activeThumbRequests[i] = NULL;
+ if (status == 200 && data)
+ {
+ thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh);
+ if(data)
+ {
+ free(data);
+ }
+ thumbnailCacheNextID %= THUMB_CACHE_SIZE;
+ if(thumbnailCache[thumbnailCacheNextID])
+ {
+ delete thumbnailCache[thumbnailCacheNextID];
+ }
+ if(thumbData)
+ {
+ thumbnailCache[thumbnailCacheNextID] = new Thumbnail(saveID, saveDate, thumbData, ui::Point(imgw, imgh));
+ free(thumbData);
+ }
+ else
+ {
+ thumbData = (pixel *)malloc((128*128) * PIXELSIZE);
+ thumbnailCache[thumbnailCacheNextID] = new Thumbnail(saveID, saveDate, thumbData, ui::Point(128, 128));
+ free(thumbData);
+ }
+ return thumbnailCache[thumbnailCacheNextID++];
+ }
+ else
+ {
+ if(data)
+ {
+ free(data);
+ }
+ thumbnailCacheNextID %= THUMB_CACHE_SIZE;
+ if(thumbnailCache[thumbnailCacheNextID])
+ {
+ delete thumbnailCache[thumbnailCacheNextID];
+ }
+ thumbData = (pixel *)malloc((128*128) * PIXELSIZE);
+ thumbnailCache[thumbnailCacheNextID] = new Thumbnail(saveID, saveDate, thumbData, ui::Point(128, 128));
+ free(thumbData);
+ return thumbnailCache[thumbnailCacheNextID++];
+ }
+ }
+ }
+ }
+ if(!found)
+ {
+ for(i = 0; i < IMGCONNS; i++)
+ {
+ if(!activeThumbRequests[i])
+ {
+ activeThumbRequests[i] = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 1);
+ activeThumbRequestTimes[i] = currentTime;
+ activeThumbRequestCompleteTimes[i] = 0;
+ activeThumbRequestIDs[i] = idString;
+ return NULL;
+ }
+ }
+ }
+ //http_async_req_start(http, urlStream.str().c_str(), NULL, 0, 1);
+ return NULL;
+}
+
+std::vector<std::string> * Client::RemoveTag(int saveID, std::string tag)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/EditTag.json?Op=delete&ID=" << saveID << "&Tag=" << tag << "&Key=" << authUser.SessionKey;;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return NULL;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object responseObject;
+ json::Reader::Read(responseObject, dataStream);
+
+ json::Number status = responseObject["Status"];
+
+ if(status.Value()==0)
+ {
+ json::String error = responseObject["Error"];
+ lastError = error.Value();
+ }
+ else
+ {
+ json::Array tagsArray = responseObject["Tags"];
+
+ tags = new std::vector<std::string>();
+
+ for(int j = 0; j < tagsArray.Size(); j++)
+ {
+ json::String tempTag = tagsArray[j];
+ tags->push_back(tempTag.Value());
+ }
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ free(data);
+ return tags;
+}
+
+std::vector<std::string> * Client::AddTag(int saveID, std::string tag)
+{
+ lastError = "";
+ std::vector<std::string> * tags = NULL;
+ std::stringstream urlStream;
+ char * data = NULL;
+ int dataStatus, dataLength;
+ urlStream << "http://" << SERVER << "/Browse/EditTag.json?Op=add&ID=" << saveID << "&Tag=" << tag << "&Key=" << authUser.SessionKey;
+ if(authUser.ID)
+ {
+ std::stringstream userIDStream;
+ userIDStream << authUser.ID;
+ data = http_auth_get((char *)urlStream.str().c_str(), (char *)(userIDStream.str().c_str()), NULL, (char *)(authUser.SessionID.c_str()), &dataStatus, &dataLength);
+ }
+ else
+ {
+ lastError = "Not authenticated";
+ return NULL;
+ }
+ if(dataStatus == 200 && data)
+ {
+ try
+ {
+ std::istringstream dataStream(data);
+ json::Object responseObject;
+ json::Reader::Read(responseObject, dataStream);
+
+ json::Number status = responseObject["Status"];
+
+ if(status.Value()==0)
+ {
+ json::String error = responseObject["Error"];
+ lastError = error.Value();
+ }
+ else
+ {
+ json::Array tagsArray = responseObject["Tags"];
+
+ tags = new std::vector<std::string>();
+
+ for(int j = 0; j < tagsArray.Size(); j++)
+ {
+ json::String tempTag = tagsArray[j];
+ tags->push_back(tempTag.Value());
+ }
+ }
+ }
+ catch (json::Exception &e)
+ {
+ lastError = "Could not read response";
+ }
+ }
+ else
+ {
+ lastError = http_ret_text(dataStatus);
+ }
+ if(data)
+ free(data);
+ return tags;
+}
+
+std::vector<std::string> Client::explodePropertyString(std::string property)
+{
+ std::vector<std::string> stringArray;
+ std::string current = "";
+ for (std::string::iterator iter = property.begin(); iter != property.end(); ++iter) {
+ if (*iter == '.') {
+ if (current.length() > 0) {
+ stringArray.push_back(current);
+ current = "";
+ }
+ } else {
+ current += *iter;
+ }
+ }
+ if(current.length() > 0)
+ stringArray.push_back(current);
+ return stringArray;
+}
+
+std::string Client::GetPrefString(std::string property, std::string defaultValue)
+{
+ try
+ {
+ json::String value = GetPref(property);
+ return value.Value();
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return defaultValue;
+}
+
+double Client::GetPrefNumber(std::string property, double defaultValue)
+{
+ try
+ {
+ json::Number value = GetPref(property);
+ return value.Value();
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return defaultValue;
+}
+
+int Client::GetPrefInteger(std::string property, int defaultValue)
+{
+ try
+ {
+ std::stringstream defHexInt;
+ defHexInt << std::hex << defaultValue;
+
+ std::string hexString = GetPrefString(property, defHexInt.str());
+ int finalValue = defaultValue;
+
+ std::stringstream hexInt;
+ hexInt << hexString;
+
+ hexInt >> std::hex >> finalValue;
+
+ return finalValue;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ catch(std::exception & e)
+ {
+
+ }
+ return defaultValue;
+}
+
+unsigned int Client::GetPrefUInteger(std::string property, unsigned int defaultValue)
+{
+ try
+ {
+ std::stringstream defHexInt;
+ defHexInt << std::hex << defaultValue;
+
+ std::string hexString = GetPrefString(property, defHexInt.str());
+ unsigned int finalValue = defaultValue;
+
+ std::stringstream hexInt;
+ hexInt << hexString;
+
+ hexInt >> std::hex >> finalValue;
+
+ return finalValue;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ catch(std::exception & e)
+ {
+
+ }
+ return defaultValue;
+}
+
+std::vector<std::string> Client::GetPrefStringArray(std::string property)
+{
+ try
+ {
+ json::Array value = GetPref(property);
+ std::vector<std::string> strArray;
+ for(json::Array::iterator iter = value.Begin(); iter != value.End(); ++iter)
+ {
+ try
+ {
+ json::String cValue = *iter;
+ strArray.push_back(cValue.Value());
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ }
+ return strArray;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return std::vector<std::string>();
+}
+
+std::vector<double> Client::GetPrefNumberArray(std::string property)
+{
+ try
+ {
+ json::Array value = GetPref(property);
+ std::vector<double> strArray;
+ for(json::Array::iterator iter = value.Begin(); iter != value.End(); ++iter)
+ {
+ try
+ {
+ json::Number cValue = *iter;
+ strArray.push_back(cValue.Value());
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ }
+ return strArray;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return std::vector<double>();
+}
+
+std::vector<int> Client::GetPrefIntegerArray(std::string property)
+{
+ try
+ {
+ json::Array value = GetPref(property);
+ std::vector<int> intArray;
+ for(json::Array::iterator iter = value.Begin(); iter != value.End(); ++iter)
+ {
+ try
+ {
+ json::String cValue = *iter;
+ int finalValue = 0;
+
+ std::string hexString = cValue.Value();
+ std::stringstream hexInt;
+ hexInt << std::hex << hexString;
+ hexInt >> finalValue;
+
+ intArray.push_back(finalValue);
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ }
+ return intArray;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return std::vector<int>();
+}
+
+std::vector<unsigned int> Client::GetPrefUIntegerArray(std::string property)
+{
+ try
+ {
+ json::Array value = GetPref(property);
+ std::vector<unsigned int> intArray;
+ for(json::Array::iterator iter = value.Begin(); iter != value.End(); ++iter)
+ {
+ try
+ {
+ json::String cValue = *iter;
+ unsigned int finalValue = 0;
+
+ std::string hexString = cValue.Value();
+ std::stringstream hexInt;
+ hexInt << std::hex << hexString;
+ hexInt >> finalValue;
+
+ intArray.push_back(finalValue);
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ }
+ return intArray;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return std::vector<unsigned int>();
+}
+
+std::vector<bool> Client::GetPrefBoolArray(std::string property)
+{
+ try
+ {
+ json::Array value = GetPref(property);
+ std::vector<bool> strArray;
+ for(json::Array::iterator iter = value.Begin(); iter != value.End(); ++iter)
+ {
+ try
+ {
+ json::Boolean cValue = *iter;
+ strArray.push_back(cValue.Value());
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ }
+ return strArray;
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return std::vector<bool>();
+}
+
+bool Client::GetPrefBool(std::string property, bool defaultValue)
+{
+ try
+ {
+ json::Boolean value = GetPref(property);
+ return value.Value();
+ }
+ catch (json::Exception & e)
+ {
+
+ }
+ return defaultValue;
+}
+
+void Client::SetPref(std::string property, std::string value)
+{
+ json::UnknownElement stringValue = json::String(value);
+ SetPref(property, stringValue);
+}
+
+void Client::SetPref(std::string property, double value)
+{
+ json::UnknownElement numberValue = json::Number(value);
+ SetPref(property, numberValue);
+}
+
+void Client::SetPref(std::string property, int value)
+{
+ std::stringstream hexInt;
+ hexInt << std::hex << value;
+ json::UnknownElement intValue = json::String(hexInt.str());
+ SetPref(property, intValue);
+}
+
+void Client::SetPref(std::string property, unsigned int value)
+{
+ std::stringstream hexInt;
+ hexInt << std::hex << value;
+ json::UnknownElement intValue = json::String(hexInt.str());
+ SetPref(property, intValue);
+}
+
+void Client::SetPref(std::string property, std::vector<std::string> value)
+{
+ json::Array newArray;
+ for(std::vector<std::string>::iterator iter = value.begin(); iter != value.end(); ++iter)
+ {
+ newArray.Insert(json::String(*iter));
+ }
+ json::UnknownElement newArrayValue = newArray;
+ SetPref(property, newArrayValue);
+}
+
+void Client::SetPref(std::string property, std::vector<double> value)
+{
+ json::Array newArray;
+ for(std::vector<double>::iterator iter = value.begin(); iter != value.end(); ++iter)
+ {
+ newArray.Insert(json::Number(*iter));
+ }
+ json::UnknownElement newArrayValue = newArray;
+ SetPref(property, newArrayValue);
+}
+
+void Client::SetPref(std::string property, std::vector<bool> value)
+{
+ json::Array newArray;
+ for(std::vector<bool>::iterator iter = value.begin(); iter != value.end(); ++iter)
+ {
+ newArray.Insert(json::Boolean(*iter));
+ }
+ json::UnknownElement newArrayValue = newArray;
+ SetPref(property, newArrayValue);
+}
+
+void Client::SetPref(std::string property, std::vector<int> value)
+{
+ json::Array newArray;
+ for(std::vector<int>::iterator iter = value.begin(); iter != value.end(); ++iter)
+ {
+ std::stringstream hexInt;
+ hexInt << std::hex << *iter;
+
+ newArray.Insert(json::String(hexInt.str()));
+ }
+ json::UnknownElement newArrayValue = newArray;
+ SetPref(property, newArrayValue);
+}
+
+void Client::SetPref(std::string property, std::vector<unsigned int> value)
+{
+ json::Array newArray;
+ for(std::vector<unsigned int>::iterator iter = value.begin(); iter != value.end(); ++iter)
+ {
+ std::stringstream hexInt;
+ hexInt << std::hex << *iter;
+
+ newArray.Insert(json::String(hexInt.str()));
+ }
+ json::UnknownElement newArrayValue = newArray;
+ SetPref(property, newArrayValue);
+}
+
+void Client::SetPref(std::string property, bool value)
+{
+ json::UnknownElement boolValue = json::Boolean(value);
+ SetPref(property, boolValue);
+}
+
+json::UnknownElement Client::GetPref(std::string property)
+{
+ std::vector<std::string> pTokens = Client::explodePropertyString(property);
+ const json::UnknownElement & configDocumentCopy = configDocument;
+ json::UnknownElement currentRef = configDocumentCopy;
+ for(std::vector<std::string>::iterator iter = pTokens.begin(); iter != pTokens.end(); ++iter)
+ {
+ currentRef = ((const json::UnknownElement &)currentRef)[*iter];
+ }
+ return currentRef;
+}
+
+void Client::setPrefR(std::deque<std::string> tokens, json::UnknownElement & element, json::UnknownElement & value)
+{
+ if(tokens.size())
+ {
+ std::string token = tokens.front();
+ tokens.pop_front();
+ setPrefR(tokens, element[token], value);
+ }
+ else
+ element = value;
+}
+
+void Client::SetPref(std::string property, json::UnknownElement & value)
+{
+ std::vector<std::string> pTokens = Client::explodePropertyString(property);
+ std::deque<std::string> dTokens(pTokens.begin(), pTokens.end());
+ std::string token = dTokens.front();
+ dTokens.pop_front();
+ setPrefR(dTokens, configDocument[token], value);
+}