From 42c71884a27a0e5a1435f72834bfe4d0ab214ca6 Mon Sep 17 00:00:00 2001 From: Sude Date: Thu, 14 Nov 2019 18:25:12 +0200 Subject: [PATCH] Remove old GOG downloader API Removed all remaining code related to old API. Removed dead or commented out code that I noticed while checking the code for references to old API. --- CMakeLists.txt | 1 - include/api.h | 95 ------ include/config.h | 3 +- include/downloader.h | 3 - main.cpp | 28 +- src/api.cpp | 706 ------------------------------------------- src/blacklist.cpp | 1 - src/downloader.cpp | 136 +-------- src/ziputil.cpp | 1 - 9 files changed, 11 insertions(+), 963 deletions(-) delete mode 100644 include/api.h delete mode 100644 src/api.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3918f54..6b2356a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,6 @@ find_package(ZLIB REQUIRED) file(GLOB SRC_FILES main.cpp - src/api.cpp src/website.cpp src/downloader.cpp src/progressbar.cpp diff --git a/include/api.h b/include/api.h deleted file mode 100644 index d50e668..0000000 --- a/include/api.h +++ /dev/null @@ -1,95 +0,0 @@ -/* This program is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://www.wtfpl.net/ for more details. */ - -#ifndef API_H -#define API_H - -#include "globalconstants.h" -#include "gamedetails.h" -#include "globals.h" - -#include -#include -#include -extern "C" { - #include -} -#include -#include - -class userDetails { - public: - std::string avatar_small; - std::string avatar_big; - std::string username; - std::string email; - unsigned long long id; - int notifications_forum; - int notifications_games; - int notifications_messages; -}; - -class apiConfig { - public: - std::string oauth_authorize_temp_token; - std::string oauth_get_temp_token; - std::string oauth_get_token; - std::string get_user_games; - std::string get_user_details; - std::string get_installer_link; - std::string get_game_details; - std::string get_extra_link; - std::string set_app_status; - std::string oauth_token; - std::string oauth_secret; -}; - -size_t writeMemoryCallback(char *ptr, size_t size, size_t nmemb, void *userp); - -class API -{ - public: - userDetails user; - - API(const std::string& token,const std::string& secret); - int init(); - bool isLoggedIn(); - int login(const std::string& email, const std::string& password); - int getAPIConfig(); - std::string getResponse(const std::string& url); - std::string getResponseOAuth(const std::string& url); - int getUserDetails(); - int getGames(); - gameDetails getGameDetails(const std::string& game_name, const unsigned int& platform = (GlobalConstants::PLATFORM_WINDOWS | GlobalConstants::PLATFORM_LINUX), const unsigned int& lang = GlobalConstants::LANGUAGE_EN, const bool& useDuplicateHandler = false); - std::string getInstallerLink(const std::string& game_name, const std::string& id); - std::string getExtraLink(const std::string& game_name, const std::string& id); - std::string getPatchLink(const std::string& game_name, const std::string& id); - std::string getLanguagePackLink(const std::string& game_name, const std::string& id); - std::string getXML(const std::string& game_name, const std::string& id); - void clearError(); - bool getError() { return this->error; }; - std::string getErrorMessage() { return this->error_message; }; - std::string getToken() { return this->config.oauth_token; }; - std::string getSecret() { return this->config.oauth_secret; }; - template CURLcode curlSetOpt(CURLoption option, T value) { return curl_easy_setopt(this->curlhandle, option, value); } - virtual ~API(); - protected: - private: - apiConfig config; - CURL* curlhandle; - void setError(const std::string& err); - bool error; - std::string error_message; - - // API constants - const std::string CONSUMER_KEY = "1f444d14ea8ec776585524a33f6ecc1c413ed4a5"; - const std::string CONSUMER_SECRET = "20d175147f9db9a10fc0584aa128090217b9cf88"; - const int OAUTH_VERIFIER_LENGTH = 14; - const int OAUTH_TOKEN_LENGTH = 11; - const int OAUTH_SECRET_LENGTH = 18; -}; - -#endif // API_H diff --git a/include/config.h b/include/config.h index 3f269d4..fcecf82 100644 --- a/include/config.h +++ b/include/config.h @@ -211,8 +211,7 @@ class Config virtual ~Config() {}; // Booleans - bool bLoginHTTP; - bool bLoginAPI; + bool bLogin; bool bSaveConfig; bool bResetConfig; diff --git a/include/downloader.h b/include/downloader.h index bc99fc6..91bbfa6 100644 --- a/include/downloader.h +++ b/include/downloader.h @@ -22,7 +22,6 @@ #endif #include "config.h" -#include "api.h" #include "progressbar.h" #include "website.h" #include "threadsafequeue.h" @@ -124,7 +123,6 @@ class Downloader int loadGameDetailsCache(); int saveGameDetailsCache(); std::vector getGameDetailsFromJsonNode(Json::Value root, const int& recursion_level = 0); - static std::vector getExtrasFromJSON(const Json::Value& json, const std::string& gamename, const Config& config); static std::string getSerialsFromJSON(const Json::Value& json); void saveSerials(const std::string& serials, const std::string& filepath); static std::string getChangelogFromJSON(const Json::Value& json); @@ -149,7 +147,6 @@ class Downloader std::vector galaxyGetDepotItemVectorFromJson(const Json::Value& json, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); Website *gogWebsite; - API *gogAPI; galaxyAPI *gogGalaxy; std::vector gameItems; std::vector games; diff --git a/main.cpp b/main.cpp index 0be55b0..ac12c99 100644 --- a/main.cpp +++ b/main.cpp @@ -167,7 +167,6 @@ int main(int argc, char *argv[]) bool bNoRemoteXML = false; bool bNoSubDirectories = false; bool bNoPlatformDetection = false; - bool bLogin = false; bool bNoGalaxyDependencies = false; std::string sInstallerPlatform; std::string sInstallerLanguage; @@ -182,7 +181,7 @@ int main(int argc, char *argv[]) options_cli_no_cfg.add_options() ("help,h", "Print help message") ("version", "Print version information") - ("login", bpo::value(&bLogin)->zero_tokens()->default_value(false), "Login") + ("login", bpo::value(&Globals::globalConfig.bLogin)->zero_tokens()->default_value(false), "Login") ("list", bpo::value(&Globals::globalConfig.bList)->zero_tokens()->default_value(false), "List games") ("list-details", bpo::value(&Globals::globalConfig.bListDetails)->zero_tokens()->default_value(false), "List games with detailed info") ("download", bpo::value(&Globals::globalConfig.bDownload)->zero_tokens()->default_value(false), "Download") @@ -202,8 +201,6 @@ int main(int argc, char *argv[]) ("download-file", bpo::value(&Globals::globalConfig.sFileIdString)->default_value(""), "Download files using fileid\n\nFormat:\n\"gamename/fileid\"\nor: \"gogdownloader://gamename/fileid\"\n\nMultiple files:\n\"gamename1/fileid1,gamename2/fileid2\"\nor: \"gogdownloader://gamename1/fileid1,gamename2/fileid2\"\n\nThis option ignores all subdir options. The files are downloaded to directory specified with --directory option.") ("output-file,o", bpo::value(&Globals::globalConfig.sOutputFilename)->default_value(""), "Set filename of file downloaded with --download-file.") ("wishlist", bpo::value(&Globals::globalConfig.bShowWishlist)->zero_tokens()->default_value(false), "Show wishlist") - ("login-api", bpo::value(&Globals::globalConfig.bLoginAPI)->zero_tokens()->default_value(false), "Login (API only)") - ("login-website", bpo::value(&Globals::globalConfig.bLoginHTTP)->zero_tokens()->default_value(false), "Login (website only)") ("cacert", bpo::value(&Globals::globalConfig.curlConf.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format") ("respect-umask", bpo::value(&Globals::globalConfig.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files") ("user-agent", bpo::value(&Globals::globalConfig.curlConf.sUserAgent)->default_value(DEFAULT_USER_AGENT), "Set user agent") @@ -410,7 +407,7 @@ int main(int argc, char *argv[]) } } - if (bLogin || Globals::globalConfig.bLoginAPI || Globals::globalConfig.bLoginHTTP) + if (Globals::globalConfig.bLogin) { std::string login_conf = Globals::globalConfig.sConfigDirectory + "/login.txt"; if (boost::filesystem::exists(login_conf)) @@ -491,12 +488,6 @@ int main(int argc, char *argv[]) return 1; } - if (bLogin) - { - Globals::globalConfig.bLoginAPI = true; - Globals::globalConfig.bLoginHTTP = true; - } - if (Globals::globalConfig.sXMLFile == "automatic") Globals::globalConfig.dlConf.bAutomaticXMLCreation = true; @@ -605,19 +596,13 @@ int main(int argc, char *argv[]) ssl_thread_setup(); curl_global_init(CURL_GLOBAL_ALL); - if (Globals::globalConfig.bLoginAPI) - { - Globals::globalConfig.apiConf.sToken = ""; - Globals::globalConfig.apiConf.sSecret = ""; - } - Downloader downloader; int iLoginTries = 0; bool bLoginOK = false; // Login because --login, --login-api or --login-website was used - if (Globals::globalConfig.bLoginAPI || Globals::globalConfig.bLoginHTTP) + if (Globals::globalConfig.bLogin) bLoginOK = downloader.login(); bool bIsLoggedin = downloader.isLoggedIn(); @@ -650,11 +635,6 @@ int main(int argc, char *argv[]) if (Globals::globalConfig.bSaveConfig || bLoginOK) { - if (bLoginOK) - { - set_vm_value(vm, "token", Globals::globalConfig.apiConf.sToken); - set_vm_value(vm, "secret", Globals::globalConfig.apiConf.sSecret); - } std::ofstream ofs(Globals::globalConfig.sConfigFilePath.c_str()); if (ofs) { @@ -803,7 +783,7 @@ int main(int argc, char *argv[]) } else { - if (!(Globals::globalConfig.bLoginAPI || Globals::globalConfig.bLoginHTTP)) + if (!Globals::globalConfig.bLogin) { // Show help message std::cerr << Globals::globalConfig.sVersionString << std::endl diff --git a/src/api.cpp b/src/api.cpp deleted file mode 100644 index 87b8ccb..0000000 --- a/src/api.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* This program is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://www.wtfpl.net/ for more details. */ - -#include "api.h" -#include "gamefile.h" - -#include -#include -#include -#include -#include - -#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900 -# define _regex_namespace_ std -# include -#else -# define _regex_namespace_ boost -# include -#endif - -size_t writeMemoryCallback(char *ptr, size_t size, size_t nmemb, void *userp) { - std::ostringstream *stream = (std::ostringstream*)userp; - std::streamsize count = (std::streamsize) size * nmemb; - stream->write(ptr, count); - return count; -} - -API::API(const std::string& token, const std::string& secret) -{ - curlhandle = curl_easy_init(); - curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(curlhandle, CURLOPT_PROGRESSDATA, this); - curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true); - curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1); - - this->error = false; - this->config.oauth_token = token; - this->config.oauth_secret = secret; -} - -/* Initialize the API - returns 0 if failed - returns 1 if successful -*/ -int API::init() -{ - int res = 0; - - this->getAPIConfig(); - - if (!this->getError()) - res = 1; - else - this->clearError(); - - return res; -} - -/* Login check - returns false if not logged in - returns true if logged in -*/ -bool API::isLoggedIn() -{ - int res = 0; - - // Check if we already have token and secret - if (!this->config.oauth_token.empty() && !this->config.oauth_secret.empty()) - { - // Test authorization by getting user details - res = this->getUserDetails(); // res = 1 if successful - } - - return res; -} - -int API::getAPIConfig() -{ - std::string url = "https://api.gog.com/downloader2/status/stable/"; // Stable API - //std::string url = "https://api.gog.com/downloader2/status/beta/"; // Beta API - //std::string url = "https://api.gog.com/downloader2/status/e77989ed21758e78331b20e477fc5582/"; // Development API? Not sure because the downloader version number it reports is lower than beta. - - std::string json = this->getResponse(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return 0; - } - - Json::Value root; - std::istringstream json_stream(json); - - try { - json_stream >> root; - } catch (const Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getAPIConfig)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - return 0; - } - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getAPIConfig)" << std::endl << root << std::endl; - #endif - this->config.oauth_authorize_temp_token = root["config"]["oauth_authorize_temp_token"].asString() + "/"; - this->config.oauth_get_temp_token = root["config"]["oauth_get_temp_token"].asString() + "/"; - this->config.oauth_get_token = root["config"]["oauth_get_token"].asString() + "/"; - this->config.get_user_games = root["config"]["get_user_games"].asString() + "/"; - this->config.get_user_details = root["config"]["get_user_details"].asString() + "/"; - this->config.get_installer_link = root["config"]["get_installer_link"].asString() + "/"; - this->config.get_game_details = root["config"]["get_game_details"].asString() + "/"; - this->config.get_extra_link = root["config"]["get_extra_link"].asString() + "/"; - this->config.set_app_status = root["config"]["set_app_status"].asString() + "/"; - return 1; -} - -int API::login(const std::string& email, const std::string& password) -{ - int res = 0; - std::string url; - - std::string token, secret; - - // Get temporary request token - url = oauth_sign_url2(this->config.oauth_get_temp_token.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), NULL /* token */, NULL /* secret */); - - std::string request_token_resp = this->getResponse(url); - - char **rv = NULL; - int rc = oauth_split_url_parameters(request_token_resp.c_str(), &rv); - qsort(rv, rc, sizeof(char *), oauth_cmpstringp); - if (rc == 3 && !strncmp(rv[1], "oauth_token=", OAUTH_TOKEN_LENGTH) && !strncmp(rv[2], "oauth_token_secret=", OAUTH_SECRET_LENGTH)) { - token = rv[1]+OAUTH_TOKEN_LENGTH+1; - secret = rv[2]+OAUTH_SECRET_LENGTH+1; - rv = NULL; - } - else - { - return res; - } - - usleep(500); // Wait to avoid "429 Too Many Requests" - - // Authorize temporary token and get verifier - url = this->config.oauth_authorize_temp_token + "?username=" + oauth_url_escape(email.c_str()) + "&password=" + oauth_url_escape(password.c_str()); - url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str()); - std::string authorize_resp = this->getResponse(url); - - std::string verifier; - rc = oauth_split_url_parameters(authorize_resp.c_str(), &rv); - qsort(rv, rc, sizeof(char *), oauth_cmpstringp); - if (rc == 2 && !strncmp(rv[1], "oauth_verifier=", OAUTH_VERIFIER_LENGTH)) { - verifier = rv[1]+OAUTH_VERIFIER_LENGTH+1; - rv = NULL; - } - else - { - return res; - } - - usleep(500); // Wait to avoid "429 Too Many Requests" - - // Get final token and secret - url = this->config.oauth_get_token + "?oauth_verifier=" + verifier; - url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str()); - std::string token_resp = this->getResponse(url); - - rc = oauth_split_url_parameters(token_resp.c_str(), &rv); - qsort(rv, rc, sizeof(char *), oauth_cmpstringp); - if (rc == 2 && !strncmp(rv[0], "oauth_token=", OAUTH_TOKEN_LENGTH) && !strncmp(rv[1], "oauth_token_secret=", OAUTH_SECRET_LENGTH)) { - this->config.oauth_token = rv[0]+OAUTH_TOKEN_LENGTH+1; - this->config.oauth_secret = rv[1]+OAUTH_SECRET_LENGTH+1; - free(rv); - res = 1; - } - - return res; -} - -int API::getUserDetails() -{ - std::string url; - - url = this->config.get_user_details; - std::string json = this->getResponseOAuth(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return 0; - } - - Json::Value root; - std::istringstream json_stream(json); - - try { - json_stream >> root; - } catch (const Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getUserDetails)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - return 0; - } - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getUserDetails)" << std::endl << root << std::endl; - #endif - this->user.id = std::stoull(root["user"]["id"].asString()); - this->user.username = root["user"]["xywka"].asString(); - this->user.email = root["user"]["email"].asString(); - this->user.avatar_big = root["user"]["avatar"]["big"].asString(); - this->user.avatar_small = root["user"]["avatar"]["small"].asString(); - this->user.notifications_forum = root["user"]["notifications"]["forum"].isInt() ? root["user"]["notifications"]["forum"].asInt() : std::stoi(root["user"]["notifications"]["forum"].asString()); - this->user.notifications_games = root["user"]["notifications"]["games"].isInt() ? root["user"]["notifications"]["games"].asInt() : std::stoi(root["user"]["notifications"]["games"].asString()); - this->user.notifications_messages = root["user"]["notifications"]["messages"].isInt() ? root["user"]["notifications"]["messages"].asInt() : std::stoi(root["user"]["notifications"]["messages"].asString()); - return 1; -} - - -int API::getGames() -{ - // Not implemented on the server side currently - - //std::string json = this->getResponseOAuth(this->config.get_user_games); - - return 0; -} - -std::string API::getResponse(const std::string& url) -{ - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getResponse)" << std::endl << "URL: " << url << std::endl; - #endif - std::ostringstream memory; - - curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, writeMemoryCallback); - curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, &memory); - - int retries = 0; - CURLcode result; - std::string response; - do - { - if (Globals::globalConfig.iWait > 0) - usleep(Globals::globalConfig.iWait); // Delay the request by specified time - result = curl_easy_perform(curlhandle); - response = memory.str(); - memory.str(std::string()); - } - while ((result != CURLE_OK) && response.empty() && (retries++ < Globals::globalConfig.iRetries)); - - if (result == CURLE_HTTP_RETURNED_ERROR) - { - long int response_code = 0; - result = curl_easy_getinfo(curlhandle, CURLINFO_RESPONSE_CODE, &response_code); - if (result == CURLE_OK) - this->setError("HTTP ERROR: " + std::to_string(response_code) + " (" + url + ")"); - else - this->setError("HTTP ERROR: failed to get error code: " + static_cast(curl_easy_strerror(result)) + " (" + url + ")"); - - #ifdef DEBUG - curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, false); - result = curl_easy_perform(curlhandle); - std::string debug_response = memory.str(); - memory.str(std::string()); - std::cerr << "Response (CURLE_HTTP_RETURNED_ERROR):"; - if (debug_response.empty()) - std::cerr << " Response was empty" << std::endl; - else - std::cerr << std::endl << debug_response << std::endl; - curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true); - #endif - } - - return response; -} - -std::string API::getResponseOAuth(const std::string& url) -{ - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getResponseOAuth)" << std::endl << "URL: " << url << std::endl; - #endif - std::string url_oauth = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), this->config.oauth_token.c_str(), this->config.oauth_secret.c_str()); - std::string response = this->getResponse(url_oauth); - - return response; -} - -gameDetails API::getGameDetails(const std::string& game_name, const unsigned int& platform, const unsigned int& lang, const bool& useDuplicateHandler) -{ - std::string url; - gameDetails game; - struct gameFileInfo - { - Json::Value jsonNode; - unsigned int platform; - unsigned int language; - }; - - url = this->config.get_game_details + game_name + "/" + "installer_win_en"; // can't get game details without file id, any file id seems to return all details which is good for us - std::string json = this->getResponseOAuth(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return game; - } - - Json::Value root; - std::istringstream json_stream(json); - - try { - json_stream >> root; - } catch (Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getGameDetails)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - return game; - } - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getGameDetails)" << std::endl << root << std::endl; - #endif - game.gamename = game_name; - game.title = root["game"]["title"].asString(); - game.icon = root["game"]["icon"].asString(); - std::vector membernames = root["game"].getMemberNames(); - - // Installer details - // Create a list of installers from JSON - std::vector installers; - for (unsigned int i = 0; i < GlobalConstants::PLATFORMS.size(); ++i) - { // Check against the specified platforms - if (platform & GlobalConstants::PLATFORMS[i].id) - { - std::string installer = "installer_" + GlobalConstants::PLATFORMS[i].code + "_"; - for (unsigned int j = 0; j < GlobalConstants::LANGUAGES.size(); ++j) - { // Check against the specified languages - if (lang & GlobalConstants::LANGUAGES[j].id) - { // Make sure that the installer exists in the JSON - if (root["game"].isMember(installer+GlobalConstants::LANGUAGES[j].code)) - { - gameFileInfo installerInfo; - installerInfo.jsonNode = root["game"][installer+GlobalConstants::LANGUAGES[j].code]; - installerInfo.platform = GlobalConstants::PLATFORMS[i].id; - installerInfo.language = GlobalConstants::LANGUAGES[j].id; - installers.push_back(installerInfo); - } - } - } - } - } - - for ( unsigned int i = 0; i < installers.size(); ++i ) - { - for ( unsigned int index = 0; index < installers[i].jsonNode.size(); ++index ) - { - Json::Value installer = installers[i].jsonNode[index]; - unsigned int language = installers[i].language; - std::string path = installer["link"].asString(); - path = (std::string)curl_easy_unescape(curlhandle, path.c_str(), path.size(), NULL); - - // Check for duplicate installers in different languages and add languageId of duplicate installer to the original installer - // https://secure.gog.com/forum/general/introducing_the_beta_release_of_the_new_gogcom_downloader/post1483 - if (useDuplicateHandler) - { - bool bDuplicate = false; - for (unsigned int j = 0; j < game.installers.size(); ++j) - { - if (game.installers[j].path == path) - { - game.installers[j].language |= language; // Add language code to installer - bDuplicate = true; - break; - } - } - if (bDuplicate) - continue; - } - - gameFile gf; - gf.type = GFTYPE_INSTALLER; - gf.gamename = game.gamename; - gf.updated = installer["notificated"].isInt() ? installer["notificated"].asInt() : std::stoi(installer["notificated"].asString()); - gf.id = installer["id"].isInt() ? std::to_string(installer["id"].asInt()) : installer["id"].asString(); - gf.name = installer["name"].asString(); - gf.path = path; - gf.size = installer["size"].asString(); - gf.language = language; - gf.platform = installers[i].platform; - gf.silent = installer["silent"].isInt() ? installer["silent"].asInt() : std::stoi(installer["silent"].asString()); - - game.installers.push_back(gf); - } - } - - // Extra details - const Json::Value extras = root["game"]["extras"]; - for ( unsigned int index = 0; index < extras.size(); ++index ) - { - Json::Value extra = extras[index]; - - gameFile gf; - gf.type = GFTYPE_EXTRA; - gf.gamename = game.gamename; - gf.updated = false; // extras don't have "updated" flag - gf.id = extra["id"].isInt() ? std::to_string(extra["id"].asInt()) : extra["id"].asString(); - gf.name = extra["name"].asString(); - gf.path = extra["link"].asString(); - gf.path = (std::string)curl_easy_unescape(curlhandle, gf.path.c_str(), gf.path.size(), NULL); - gf.size = extra["size_mb"].asString(); - - game.extras.push_back(gf); - } - - // Patch details - for (unsigned int i = 0; i < GlobalConstants::LANGUAGES.size(); ++i) - { // Check against the specified languages - if (lang & GlobalConstants::LANGUAGES[i].id) - { - // Try to find a patch - _regex_namespace_::regex re(GlobalConstants::LANGUAGES[i].code + "\\d+patch\\d+", _regex_namespace_::regex_constants::icase); // regex for patch node names - std::vector patches; - for (unsigned int j = 0; j < membernames.size(); ++j) - { - if (_regex_namespace_::regex_match(membernames[j], re)) - { // Regex matches, we have a patch node - gameFileInfo patchInfo; - patchInfo.jsonNode = root["game"][membernames[j]]; - patchInfo.language = GlobalConstants::LANGUAGES[i].id; - if (patchInfo.jsonNode["link"].asString().find("/mac/") != std::string::npos) - patchInfo.platform = GlobalConstants::PLATFORM_MAC; - else if (patchInfo.jsonNode["link"].asString().find("/linux/") != std::string::npos) - patchInfo.platform = GlobalConstants::PLATFORM_LINUX; - else - patchInfo.platform = GlobalConstants::PLATFORM_WINDOWS; - - if (platform & patchInfo.platform) - patches.push_back(patchInfo); - } - } - - if (!patches.empty()) // found at least one patch - { - for (unsigned int j = 0; j < patches.size(); ++j) - { - Json::Value patchnode = patches[j].jsonNode; - if (patchnode.isArray()) // Patch has multiple files - { - for ( unsigned int index = 0; index < patchnode.size(); ++index ) - { - Json::Value patch = patchnode[index]; - std::string path = patch["link"].asString(); - path = (std::string)curl_easy_unescape(curlhandle, path.c_str(), path.size(), NULL); - - // Check for duplicate patches in different languages and add languageId of duplicate patch to the original patch - if (useDuplicateHandler) - { - bool bDuplicate = false; - for (unsigned int j = 0; j < game.patches.size(); ++j) - { - if (game.patches[j].path == path) - { - game.patches[j].language |= GlobalConstants::LANGUAGES[i].id; // Add language code to patch - bDuplicate = true; - break; - } - } - if (bDuplicate) - continue; - } - - gameFile gf; - gf.type = GFTYPE_PATCH; - gf.gamename = game.gamename; - gf.updated = patch["notificated"].isInt() ? patch["notificated"].asInt() : std::stoi(patch["notificated"].asString()); - gf.id = patch["id"].isInt() ? std::to_string(patch["id"].asInt()) : patch["id"].asString(); - gf.name = patch["name"].asString(); - gf.path = path; - gf.size = patch["size"].asString(); - gf.language = GlobalConstants::LANGUAGES[i].id; - gf.platform = patches[j].platform; - - game.patches.push_back(gf); - } - } - else // Patch is a single file - { - std::string path = patchnode["link"].asString(); - path = (std::string)curl_easy_unescape(curlhandle, path.c_str(), path.size(), NULL); - - // Check for duplicate patches in different languages and add languageId of duplicate patch to the original patch - if (useDuplicateHandler) - { - bool bDuplicate = false; - for (unsigned int k = 0; k < game.patches.size(); ++k) - { - if (game.patches[k].path == path) - { - game.patches[k].language |= GlobalConstants::LANGUAGES[i].id; // Add language code to patch - bDuplicate = true; - break; - } - } - if (bDuplicate) - continue; - } - - gameFile gf; - gf.type = GFTYPE_PATCH; - gf.gamename = game.gamename; - gf.updated = patchnode["notificated"].isInt() ? patchnode["notificated"].asInt() : std::stoi(patchnode["notificated"].asString()); - gf.id = patchnode["id"].isInt() ? std::to_string(patchnode["id"].asInt()) : patchnode["id"].asString(); - gf.name = patchnode["name"].asString(); - gf.path = path; - gf.size = patchnode["size"].asString(); - gf.language = GlobalConstants::LANGUAGES[i].id; - gf.platform = patches[j].platform; - - game.patches.push_back(gf); - } - } - } - } - } - - // Language pack details - for (unsigned int i = 0; i < GlobalConstants::LANGUAGES.size(); ++i) - { // Check against the specified languages - if (lang & GlobalConstants::LANGUAGES[i].id) - { - // Try to find a language pack - _regex_namespace_::regex re(GlobalConstants::LANGUAGES[i].code + "\\d+langpack\\d+", _regex_namespace_::regex_constants::icase); // regex for language pack node names - std::vector langpacknames; - for (unsigned int j = 0; j < membernames.size(); ++j) - { - if (_regex_namespace_::regex_match(membernames[j], re)) - langpacknames.push_back(membernames[j]); - } - - if (!langpacknames.empty()) // found at least one language pack - { - for (unsigned int j = 0; j < langpacknames.size(); ++j) - { - Json::Value langpack = root["game"][langpacknames[j]]; - - gameFile gf; - gf.type = GFTYPE_LANGPACK; - gf.gamename = game.gamename; - gf.updated = false; // language packs don't have "updated" flag - gf.id = langpack["id"].isInt() ? std::to_string(langpack["id"].asInt()) : langpack["id"].asString(); - gf.name = langpack["name"].asString(); - gf.path = langpack["link"].asString(); - gf.path = (std::string)curl_easy_unescape(curlhandle, gf.path.c_str(), gf.path.size(), NULL); - gf.size = langpack["size"].asString(); - gf.language = GlobalConstants::LANGUAGES[i].id; - - game.languagepacks.push_back(gf); - } - } - } - } - - return game; -} - - -std::string API::getInstallerLink(const std::string& game_name, const std::string& id) -{ - std::string url, link; - url = this->config.get_installer_link + game_name + "/" + id + "/"; - std::string json = this->getResponseOAuth(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return link; - } - - Json::Value root; - std::istringstream json_stream(json); - - try { - json_stream >> root; - } catch (const Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getInstallerLink)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - return link; - } - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getInstallerLink)" << std::endl << root << std::endl; - #endif - int available = root["file"]["available"].isInt() ? root["file"]["available"].asInt() : std::stoi(root["file"]["available"].asString()); - if (available) - link = root["file"]["link"].asString(); - - return link; -} - -std::string API::getExtraLink(const std::string& game_name, const std::string& id) -{ - std::string url, link; - url = this->config.get_extra_link + game_name + "/" + id + "/"; - std::string json = this->getResponseOAuth(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return link; - } - - Json::Value root; - std::istringstream json_stream(json); - - try { - json_stream >> root; - } catch (const Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getExtraLink)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - return link; - } - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getExtraLink)" << std::endl << root << std::endl; - #endif - int available = root["file"]["available"].isInt() ? root["file"]["available"].asInt() : std::stoi(root["file"]["available"].asString()); - if (available) - link = root["file"]["link"].asString(); - - return link; -} - -std::string API::getPatchLink(const std::string& game_name, const std::string& id) -{ - return this->getInstallerLink(game_name, id); -} - -std::string API::getLanguagePackLink(const std::string& game_name, const std::string& id) -{ - return this->getInstallerLink(game_name, id); -} - -std::string API::getXML(const std::string& game_name, const std::string& id) -{ - std::string url, XML; - url = this->config.get_installer_link + game_name + "/" + id + "/crc/"; - std::string json = this->getResponseOAuth(url); - - if (json.empty()) { - this->setError("Found nothing in " + url); - return XML; - } - - try { - std::istringstream iss(json); - Json::Value root; - iss >> root; - - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getXML)" << std::endl << root << std::endl; - #endif - int available = root["file"]["available"].isInt() ? root["file"]["available"].asInt() : std::stoi(root["file"]["available"].asString()); - if (available) - { - url = root["file"]["link"].asString(); - XML = this->getResponse(url); - } - } catch (const Json::Exception& exc) { - #ifdef DEBUG - std::cerr << "DEBUG INFO (API::getXML)" << std::endl << json << std::endl; - #endif - this->setError(exc.what()); - } - - return XML; -} - -void API::clearError() -{ - this->error = false; - this->error_message = ""; -} - -void API::setError(const std::string& err) -{ - this->error = true; - if (this->error_message.empty()) - this->error_message = err; - else - this->error_message += "\n" + err; -} - -API::~API() -{ - curl_easy_cleanup(curlhandle); -} diff --git a/src/blacklist.cpp b/src/blacklist.cpp index 0b0b2b7..07cb4c4 100644 --- a/src/blacklist.cpp +++ b/src/blacklist.cpp @@ -6,7 +6,6 @@ #include "blacklist.h" #include "config.h" -#include "api.h" #include "util.h" #include diff --git a/src/downloader.cpp b/src/downloader.cpp index 15355c6..9f9532a 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -71,7 +71,7 @@ static curl_off_t WriteChunkMemoryCallback(void *contents, curl_off_t size, curl Downloader::Downloader() { - if (Globals::globalConfig.bLoginHTTP) + if (Globals::globalConfig.bLogin) { if (boost::filesystem::exists(Globals::globalConfig.curlConf.sCookiePath)) if (!boost::filesystem::remove(Globals::globalConfig.curlConf.sCookiePath)) @@ -110,16 +110,6 @@ Downloader::Downloader() // Create new GOG website handle gogWebsite = new Website(); - // Create new API handle and set curl options for the API - gogAPI = new API(Globals::globalConfig.apiConf.sToken, Globals::globalConfig.apiConf.sSecret); - gogAPI->curlSetOpt(CURLOPT_VERBOSE, Globals::globalConfig.curlConf.bVerbose); - gogAPI->curlSetOpt(CURLOPT_SSL_VERIFYPEER, Globals::globalConfig.curlConf.bVerifyPeer); - gogAPI->curlSetOpt(CURLOPT_CONNECTTIMEOUT, Globals::globalConfig.curlConf.iTimeout); - if (!Globals::globalConfig.curlConf.sCACertPath.empty()) - gogAPI->curlSetOpt(CURLOPT_CAINFO, Globals::globalConfig.curlConf.sCACertPath.c_str()); - - gogAPI->init(); - progressbar = new ProgressBar(Globals::globalConfig.bUnicode, Globals::globalConfig.bColor); if (boost::filesystem::exists(Globals::galaxyConf.getFilepath())) @@ -159,7 +149,6 @@ Downloader::~Downloader() delete progressbar; delete gogGalaxy; - delete gogAPI; delete gogWebsite; curl_easy_cleanup(curlhandle); // Make sure that cookie file is only readable/writable by owner @@ -176,12 +165,11 @@ Downloader::~Downloader() bool Downloader::isLoggedIn() { bool bIsLoggedIn = false; - Globals::globalConfig.bLoginAPI = false; - Globals::globalConfig.bLoginHTTP = false; + Globals::globalConfig.bLogin= false; bool bWebsiteIsLoggedIn = gogWebsite->IsLoggedIn(); if (!bWebsiteIsLoggedIn) - Globals::globalConfig.bLoginHTTP = true; + Globals::globalConfig.bLogin = true; bool bGalaxyIsLoggedIn = !gogGalaxy->isTokenExpired(); if (!bGalaxyIsLoggedIn) @@ -189,17 +177,9 @@ bool Downloader::isLoggedIn() if (gogGalaxy->refreshLogin()) bGalaxyIsLoggedIn = true; else - Globals::globalConfig.bLoginHTTP = true; + Globals::globalConfig.bLogin = true; } - bool bIsLoggedInAPI = gogAPI->isLoggedIn(); - if (!bIsLoggedInAPI) - Globals::globalConfig.bLoginAPI = true; - - /* Check that website and Galaxy API are logged in. - Allows users to use most of the functionality without having valid API login credentials. - Globals::globalConfig.bLoginAPI can still be set to true at this point which means that if website is not logged in we still try to login to API. - */ if (bWebsiteIsLoggedIn && bGalaxyIsLoggedIn) bIsLoggedIn = true; @@ -299,8 +279,8 @@ int Downloader::login() } else { - // Login to website - if (Globals::globalConfig.bLoginHTTP) + // Login to website and Galaxy API + if (Globals::globalConfig.bLogin) { // Delete old cookies if (boost::filesystem::exists(Globals::globalConfig.curlConf.sCookiePath)) @@ -331,25 +311,6 @@ int Downloader::login() { this->saveGalaxyJSON(); } - - if (!Globals::globalConfig.bLoginAPI) - return 1; - } - } - // Login to API - if (Globals::globalConfig.bLoginAPI) - { - if (!gogAPI->login(email, password)) - { - std::cerr << "API: Login failed (--download-file option will not work)" << std::endl; - return 0; - } - else - { - std::cerr << "API: Login successful" << std::endl; - Globals::globalConfig.apiConf.sToken = gogAPI->getToken(); - Globals::globalConfig.apiConf.sSecret = gogAPI->getSecret(); - return 1; } } } @@ -1690,91 +1651,6 @@ uintmax_t Downloader::getResumePosition() return this->resume_position; } -std::vector Downloader::getExtrasFromJSON(const Json::Value& json, const std::string& gamename, const Config& config) -{ - std::vector extras; - - // Create new API handle and set curl options for the API - API* api = new API(config.apiConf.sToken, config.apiConf.sSecret); - api->curlSetOpt(CURLOPT_VERBOSE, config.curlConf.bVerbose); - api->curlSetOpt(CURLOPT_SSL_VERIFYPEER, config.curlConf.bVerifyPeer); - api->curlSetOpt(CURLOPT_CONNECTTIMEOUT, config.curlConf.iTimeout); - if (!config.curlConf.sCACertPath.empty()) - api->curlSetOpt(CURLOPT_CAINFO, config.curlConf.sCACertPath.c_str()); - - if (!api->init()) - { - delete api; - return extras; - } - - for (unsigned int i = 0; i < json["extras"].size(); ++i) - { - std::string id, name, path, downloaderUrl; - name = json["extras"][i]["name"].asString(); - downloaderUrl = json["extras"][i]["downloaderUrl"].asString(); - id.assign(downloaderUrl.begin()+downloaderUrl.find_last_of("/")+1, downloaderUrl.end()); - - // Get path from download link - std::string url = api->getExtraLink(gamename, id); - if (api->getError()) - { - api->clearError(); - continue; - } - url = htmlcxx::Uri::decode(url); - if (url.find("/extras/") != std::string::npos) - { - path.assign(url.begin()+url.find("/extras/"), url.begin()+url.find_first_of("?")); - path = "/" + gamename + path; - } - else - { - path.assign(url.begin()+url.find_last_of("/")+1, url.begin()+url.find_first_of("?")); - path = "/" + gamename + "/extras/" + path; - } - - // Get filename - std::string filename; - filename.assign(path.begin()+path.find_last_of("/")+1,path.end()); - - // Use filename if name was not specified - if (name.empty()) - name = filename; - - if (name.empty()) - { - #ifdef DEBUG - std::cerr << "DEBUG INFO (getExtrasFromJSON)" << std::endl; - std::cerr << "Skipped file without a name (game: " << gamename << ", fileid: " << id << ")" << std::endl; - #endif - continue; - } - - if (filename.empty()) - { - #ifdef DEBUG - std::cerr << "DEBUG INFO (getExtrasFromJSON)" << std::endl; - std::cerr << "Skipped file without a filename (game: " << gamename << ", fileid: " << id << ", name: " << name << ")" << std::endl; - #endif - continue; - } - - gameFile gf; - gf.type = GFTYPE_EXTRA; - gf.gamename = gamename; - gf.updated = false; - gf.id = id; - gf.name = name; - gf.path = path; - - extras.push_back(gf); - } - delete api; - - return extras; -} - std::string Downloader::getSerialsFromJSON(const Json::Value& json) { std::ostringstream serials; diff --git a/src/ziputil.cpp b/src/ziputil.cpp index adede30..6beb81a 100644 --- a/src/ziputil.cpp +++ b/src/ziputil.cpp @@ -578,7 +578,6 @@ int ZipUtil::extractStream(std::istream* input_stream, std::ostream* output_stre if (cd.compression_method == boost::iostreams::zlib::deflated) in.push(boost::iostreams::zlib_decompressor(p)); - //in.push(compressed); in.push(*input_stream); try {