diff --git a/Makefile b/Makefile index 362f337..f79d6f5 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ INCLUDES := inc inc/ui inc/fs EXEFS_SRC := exefs_src APP_TITLE := JKSV APP_AUTHOR := JK -APP_VERSION := 11.28.2021 +APP_VERSION := 12.15.2021 ROMFS := romfs ICON := icon.jpg diff --git a/inc/cfg.h b/inc/cfg.h index c743fcc..4ca3fc8 100644 --- a/inc/cfg.h +++ b/inc/cfg.h @@ -34,5 +34,5 @@ namespace cfg extern std::vector blacklist; extern std::vector favorites; extern uint8_t sortType; - extern std::string driveClientID, driveClientSecret, driveRefreshToken, driveAuthCode; + extern std::string driveClientID, driveClientSecret, driveRefreshToken; } diff --git a/inc/data.h b/inc/data.h index 3aaba21..de84e28 100644 --- a/inc/data.h +++ b/inc/data.h @@ -7,8 +7,8 @@ #include "gfx.h" -#define BLD_MON 11 -#define BLD_DAY 28 +#define BLD_MON 12 +#define BLD_DAY 15 #define BLD_YEAR 2021 namespace data diff --git a/inc/fs/drive.h b/inc/fs/drive.h index f155214..3e736ad 100644 --- a/inc/fs/drive.h +++ b/inc/fs/drive.h @@ -2,9 +2,14 @@ #include "../gd.h" +#define JKSV_DRIVE_FOLDER "JKSV" + namespace fs { extern drive::gd *gDrive; + extern std::string jksvDriveID; + void driveInit(); void driveExit(); + std::string driveSignInGetAuthCode(); } \ No newline at end of file diff --git a/inc/gd.h b/inc/gd.h index f4b269a..31cc249 100644 --- a/inc/gd.h +++ b/inc/gd.h @@ -18,38 +18,36 @@ namespace drive { typedef struct { - std::string name, id, mimeType; + std::string name, id, parent; + bool isDir = false; unsigned int size; - std::vector parents; - } gdDirItem; + } gdItem; class gd { public: - gd(const std::string& _clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken); + void setClientID(const std::string& _clientID) { clientID = _clientID; } + void setClientSecret(const std::string& _clientSecret) { secretID = _clientSecret; } + void setRefreshToken(const std::string& _refreshToken) { rToken = _refreshToken; } - void exhangeAuthCode(const std::string& _authCode); + bool exhangeAuthCode(const std::string& _authCode); bool hasToken() { return token.empty() == false; } - void refreshToken(); + bool refreshToken(); bool tokenIsValid(); - //Drive query parameters are appened to the default - void loadDriveList(const std::string& _qParams); - + + void clearDriveList() { driveList.clear(); } + void driveListInit(const std::string& _q); + void driveListAppend(const std::string& _q); + void getListWithParent(const std::string& _parent, std::vector& _out); void debugWriteList(); - bool createDir(const std::string& _dirName); + bool createDir(const std::string& _dirName, const std::string& _parent); bool dirExists(const std::string& _dirName); - void setRootDir(const std::string& _dirID) - { - rootDir = _dirID; - parentDir = _dirID; - loadDriveList(""); - } - void returnToRoot(){ parentDir = rootDir; loadDriveList(""); } - void chDir(const std::string& _dirID) { parentDir = _dirID; loadDriveList(""); } + bool dirExists(const std::string& _dirName, const std::string& _parent); bool fileExists(const std::string& _filename); - void uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload); + bool fileExists(const std::string& _filename, const std::string& _parent); + void uploadFile(const std::string& _filename, const std::string& _parent, curlFuncs::curlUpArgs *_upload); void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload); void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download); void deleteFile(const std::string& _fileID); @@ -57,14 +55,16 @@ namespace drive std::string getClientID() const { return clientID; } std::string getClientSecret() const { return secretID; } std::string getRefreshToken() const { return rToken; } - std::string getFileID(const std::string& name); + std::string getFileID(const std::string& _name); + std::string getFileID(const std::string& _name, const std::string& _parent); + std::string getDirID(const std::string& _name); + std::string getDirID(const std::string& _name, const std::string& _parent); size_t getDriveListCount() const { return driveList.size(); } - drive::gdDirItem *getDirItemAt(unsigned int _ind) { return &driveList[_ind]; } + drive::gdItem *getItemAt(unsigned int _ind) { return &driveList[_ind]; } private: - std::vector driveList; + std::vector driveList; std::string clientID, secretID, token, rToken; - std::string rootDir = "", parentDir = ""; }; } \ No newline at end of file diff --git a/inc/ui/fld.h b/inc/ui/fld.h index a1947ab..aed957f 100644 --- a/inc/ui/fld.h +++ b/inc/ui/fld.h @@ -15,5 +15,5 @@ namespace ui //Populate to open menu, refresh for updating after actions void fldPopulateMenu(); - void fldRefreshMenu(bool _updateDrive); + void fldRefreshMenu(); } \ No newline at end of file diff --git a/src/cfg.cpp b/src/cfg.cpp index 9b301fb..1b0643c 100644 --- a/src/cfg.cpp +++ b/src/cfg.cpp @@ -14,7 +14,7 @@ std::vector cfg::blacklist; std::vector cfg::favorites; static std::unordered_map pathDefs; uint8_t cfg::sortType; -std::string cfg::driveClientID, cfg::driveClientSecret, cfg::driveRefreshToken, cfg::driveAuthCode; +std::string cfg::driveClientID, cfg::driveClientSecret, cfg::driveRefreshToken; const char *cfgPath = "sdmc:/config/JKSV/JKSV.cfg", *titleDefPath = "sdmc:/config/JKSV/titleDefs.txt", *workDirLegacy = "sdmc:/switch/jksv_dir.txt"; static std::unordered_map cfgStrings = @@ -417,7 +417,7 @@ void cfg::loadConfig() break; case 22: - cfg::driveAuthCode = cfgRead.getNextValueStr(); + //cfg::driveAuthCode = cfgRead.getNextValueStr(); break; default: diff --git a/src/fs.cpp b/src/fs.cpp index 69552ce..bda4025 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -431,7 +431,7 @@ void fs::createNewBackup(void *a) path += "/"; fs::copyDirToDirThreaded("sv:/", path); } - ui::fldRefreshMenu(false); + ui::fldRefreshMenu(); } } @@ -537,7 +537,7 @@ void fs::restoreBackup(void *a) } } if(cfg::config["autoBack"]) - ui::fldRefreshMenu(false); + ui::fldRefreshMenu(); delete restore; t->finished = true; @@ -572,7 +572,7 @@ void fs::deleteBackup(void *a) fs::delfile(*deletePath); ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str()); } - ui::fldRefreshMenu(false); + ui::fldRefreshMenu(); delete deletePath; t->finished = true; } diff --git a/src/fs/drive.cpp b/src/fs/drive.cpp index ab6cade..a61e65a 100644 --- a/src/fs/drive.cpp +++ b/src/fs/drive.cpp @@ -1,47 +1,87 @@ +#include "fs.h" #include "drive.h" #include "cfg.h" #include "ui.h" drive::gd *fs::gDrive = NULL; +std::string fs::jksvDriveID; void fs::driveInit() { - if(!cfg::driveClientID.empty() && !cfg::driveClientSecret.empty()) + if(cfg::driveClientID.empty() || cfg::driveClientSecret.empty()) + return; + + bool refreshed = false, exchanged = false; + fs::gDrive = new drive::gd; + fs::gDrive->setClientID(cfg::driveClientID); + fs::gDrive->setClientSecret(cfg::driveClientSecret); + if(!cfg::driveRefreshToken.empty()) { - fs::gDrive = new drive::gd(cfg::driveClientID, cfg::driveClientSecret, cfg::driveAuthCode, cfg::driveRefreshToken); - if(!fs::gDrive->hasToken()) + fs::gDrive->setRefreshToken(cfg::driveRefreshToken); + refreshed = fs::gDrive->refreshToken(); + } + + if(!refreshed) + { + std::string authCode = driveSignInGetAuthCode(); + exchanged = fs::gDrive->exhangeAuthCode(authCode); + } + + if(fs::gDrive->hasToken()) + { + if(exchanged) { - delete fs::gDrive; - fs::gDrive = NULL; - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveFailed", 0)); + cfg::driveRefreshToken = fs::gDrive->getRefreshToken(); + cfg::saveConfig(); } - else - { - if(!cfg::driveAuthCode.empty() && fs::gDrive->hasToken()) - { - cfg::driveRefreshToken = fs::gDrive->getRefreshToken(); - cfg::saveConfig(); - } - fs::gDrive->loadDriveList("name = 'JKSV'"); + fs::gDrive->driveListInit(""); - if(!fs::gDrive->dirExists("JKSV")) - fs::gDrive->createDir("JKSV"); + if(!fs::gDrive->dirExists(JKSV_DRIVE_FOLDER)) + fs::gDrive->createDir(JKSV_DRIVE_FOLDER, ""); - std::string jksvID = fs::gDrive->getFileID("JKSV"); - fs::gDrive->setRootDir(jksvID); + jksvDriveID = fs::gDrive->getDirID(JKSV_DRIVE_FOLDER); - ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveStarted", 0)); - } + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveStarted", 0)); + } + else + { + delete fs::gDrive; + fs::gDrive = NULL; + ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveFailed", 0)); } } void fs::driveExit() { if(fs::gDrive) - { - //Need to save for config if first run - cfg::driveRefreshToken = fs::gDrive->getRefreshToken(); delete gDrive; - } +} + +std::string fs::driveSignInGetAuthCode() +{ + std::string url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=" + cfg::driveClientID + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto&response_type=code&scope=https://www.googleapis.com/auth/drive"; + std::string replyURL; + WebCommonConfig webCfg; + WebCommonReply webReply; + webPageCreate(&webCfg, url.c_str()); + webConfigSetCallbackUrl(&webCfg, "https://accounts.google.com/o/oauth2/approval/"); + webConfigShow(&webCfg, &webReply); + + size_t rLength = 0; + char replyURLCstr[0x1000]; + webReplyGetLastUrl(&webReply, replyURLCstr, 0x1000, &rLength); + replyURL.assign(replyURLCstr); + + int unescLength = 0; + size_t codeBegin = replyURL.find("approvalCode") + 13, codeEnd = replyURL.find_last_of('#'); + size_t codeLength = codeEnd - codeBegin; + replyURL = replyURL.substr(codeBegin, codeLength); + + char *urlUnesc = curl_easy_unescape(NULL, replyURL.c_str(), replyURL.length(), &unescLength); + replyURL = urlUnesc; + curl_free(urlUnesc); + + //Finally + return replyURL; } \ No newline at end of file diff --git a/src/gd.cpp b/src/gd.cpp index 607f18f..b37995b 100644 --- a/src/gd.cpp +++ b/src/gd.cpp @@ -18,6 +18,7 @@ Still major WIP #define DRIVE_UPLOAD_BUFFER_SIZE 0x8000 #define DRIVE_DOWNLOAD_BUFFER_SIZE 0xA00000 +#define DRIVE_DEFAULT_PARAMS_AND_QUERY "?fields=files(name,id,mimeType,size,parents)&pageSize=1000&q=trashed=false\%20and\%20\%27me\%27\%20in\%20owners" #define tokenURL "https://oauth2.googleapis.com/token" #define tokenCheckURL "https://oauth2.googleapis.com/tokeninfo" @@ -95,22 +96,10 @@ static size_t writeDataBufferThreaded(uint8_t *buff, size_t sz, size_t cnt, void return sz * cnt; } -drive::gd::gd(const std::string &_clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken) +bool drive::gd::exhangeAuthCode(const std::string& _authCode) { - clientID = _clientID; - secretID = _secretID; - rToken = _rToken; + bool ret = false; - if(!_authCode.empty()) - exhangeAuthCode(_authCode); - else if(!rToken.empty()) - refreshToken(); - else - writeDriveError("gd::gd", "Missing data needed to init Google Drive.\n"); -} - -void drive::gd::exhangeAuthCode(const std::string& _authCode) -{ // Header curl_slist *postHeader = NULL; postHeader = curl_slist_append(postHeader, HEADER_CONTENT_TYPE_APP_JSON); @@ -120,7 +109,7 @@ void drive::gd::exhangeAuthCode(const std::string& _authCode) json_object *clientIDString = json_object_new_string(clientID.c_str()); json_object *secretIDString = json_object_new_string(secretID.c_str()); json_object *authCodeString = json_object_new_string(_authCode.c_str()); - json_object *redirectUriString = json_object_new_string("urn:ietf:wg:oauth:2.0:oob"); + json_object *redirectUriString = json_object_new_string("urn:ietf:wg:oauth:2.0:oob:auto"); json_object *grantTypeString = json_object_new_string("authorization_code"); json_object_object_add(post, "client_id", clientIDString); json_object_object_add(post, "client_secret", secretIDString); @@ -151,9 +140,10 @@ void drive::gd::exhangeAuthCode(const std::string& _authCode) { token = json_object_get_string(accessToken); rToken = json_object_get_string(refreshToken); + ret = true; } else - writeDriveError("exchangeAuthCode", "Error exchanging code for token."); + writeDriveError("exchangeAuthCode", jsonResp->c_str()); } else writeCurlError("exchangeAuthCode", error); @@ -163,10 +153,14 @@ void drive::gd::exhangeAuthCode(const std::string& _authCode) json_object_put(respParse); curl_slist_free_all(postHeader); curl_easy_cleanup(curl); + + return true; } -void drive::gd::refreshToken() +bool drive::gd::refreshToken() { + bool ret = false; + // Header curl_slist *header = NULL; header = curl_slist_append(header, HEADER_CONTENT_TYPE_APP_JSON); @@ -202,9 +196,12 @@ void drive::gd::refreshToken() json_object_object_get_ex(parse, "error", &error); if(accessToken) + { token = json_object_get_string(accessToken); + ret = true; + } else if(error) - writeDriveError("refreshToken", json_object_get_string(error)); + writeDriveError("refreshToken", jsonResp->c_str()); } delete jsonResp; @@ -212,6 +209,8 @@ void drive::gd::refreshToken() json_object_put(parse); curl_slist_free_all(header); curl_easy_cleanup(curl); + + return ret; } bool drive::gd::tokenIsValid() @@ -245,105 +244,139 @@ bool drive::gd::tokenIsValid() return ret; } -void drive::gd::loadDriveList(const std::string& _qParams) +static int requestList(const std::string& _url, const std::string& _token, std::string *_respOut) +{ + int ret = 0; + + // Headers needed + curl_slist *postHeaders = NULL; + postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + _token).c_str()); + + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); + curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders); + curl_easy_setopt(curl, CURLOPT_URL, _url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, _respOut); + ret = curl_easy_perform(curl); + + + curl_slist_free_all(postHeaders); + curl_easy_cleanup(curl); + + return ret; +} + +static void processList(const std::string& _json, std::vector& _drvl, bool _clear) +{ + if(_clear) + _drvl.clear(); + + json_object *parse = json_tokener_parse(_json.c_str()), *fileArray; + json_object_object_get_ex(parse, "files", &fileArray); + if(fileArray) + { + size_t arrayLength = json_object_array_length(fileArray); + _drvl.reserve(_drvl.size() + arrayLength); + for(unsigned i = 0; i < arrayLength; i++) + { + json_object *idString, *nameString, *mimeTypeString, *size, *parentArray; + json_object *curFile = json_object_array_get_idx(fileArray, i); + json_object_object_get_ex(curFile, "id", &idString); + json_object_object_get_ex(curFile, "name", &nameString); + json_object_object_get_ex(curFile, "mimeType", &mimeTypeString); + json_object_object_get_ex(curFile, "size", &size); + json_object_object_get_ex(curFile, "parents", &parentArray); + + drive::gdItem newDirItem; + newDirItem.name = json_object_get_string(nameString); + newDirItem.id = json_object_get_string(idString); + newDirItem.size = json_object_get_int(size); + if(strcmp(json_object_get_string(mimeTypeString), MIMETYPE_FOLDER) == 0) + newDirItem.isDir = true; + + if (parentArray) + { + size_t parentCount = json_object_array_length(parentArray); + //There can only be 1 parent, but it's held in an array... + for (unsigned j = 0; j < parentCount; j++) + { + json_object *parent = json_object_array_get_idx(parentArray, j); + newDirItem.parent = json_object_get_string(parent); + } + } + _drvl.push_back(newDirItem); + } + } + json_object_put(parse); +} + +void drive::gd::driveListInit(const std::string& _q) { if(!tokenIsValid()) refreshToken(); // Request url with specific fields needed. - std::string url = driveURL, queryParams = "trashed=false and 'me' in owners "; - //These are always used - url.append("?fields=files(name,id,mimeType,size,parents)&q="); - if(!parentDir.empty()) - queryParams.append("and '" + parentDir + "' in parents "); - if(!_qParams.empty()) - queryParams.append("and " + _qParams); - - // Headers needed - curl_slist *postHeaders = NULL; - postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str()); - - // Curl request - std::string *jsonResp = new std::string; - CURL *curl = curl_easy_init(); - - //I don't understand why this needs a CURL handle... - char *urlAppend = curl_easy_escape(curl, queryParams.c_str(), queryParams.length()); - url.append(urlAppend); - curl_free(urlAppend); - - curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); - curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp); - - int error = curl_easy_perform(curl); - - json_object *parse = json_tokener_parse(jsonResp->c_str()); - if (error == CURLE_OK) + std::string url = std::string(driveURL) + std::string(DRIVE_DEFAULT_PARAMS_AND_QUERY); + if(!_q.empty()) { - driveList.clear(); - json_object *fileArray; - json_object_object_get_ex(parse, "files", &fileArray); - if(fileArray) - { - size_t count = json_object_array_length(fileArray); - driveList.reserve(count); - for (unsigned i = 0; i < count; i++) - { - json_object *idString, *nameString, *mimeTypeString, *size, *parentArray; - json_object *curFile = json_object_array_get_idx(fileArray, i); - json_object_object_get_ex(curFile, "id", &idString); - json_object_object_get_ex(curFile, "name", &nameString); - json_object_object_get_ex(curFile, "mimeType", &mimeTypeString); - json_object_object_get_ex(curFile, "size", &size); - json_object_object_get_ex(curFile, "parents", &parentArray); - - drive::gdDirItem newDirItem; - newDirItem.name = json_object_get_string(nameString); - newDirItem.id = json_object_get_string(idString); - newDirItem.mimeType = json_object_get_string(mimeTypeString); - newDirItem.size = json_object_get_int(size); - - if (parentArray) - { - size_t parentCount = json_object_array_length(parentArray); - for (unsigned j = 0; j < parentCount; j++) - { - json_object *parent = json_object_array_get_idx(parentArray, j); - newDirItem.parents.push_back(json_object_get_string(parent)); - } - } - driveList.push_back(newDirItem); - } - } - else - writeDriveError("updateList", "Error obtaining drive listing."); + char *qEsc = curl_easy_escape(NULL, _q.c_str(), _q.length()); + url.append(std::string("\%20and\%20") + std::string(qEsc)); + curl_free(qEsc); } + + std::string jsonResp; + int error = requestList(url, token, &jsonResp); + if(error == CURLE_OK) + processList(jsonResp, driveList, true); else - writeCurlError("updateList", error); + writeCurlError("driveListInit", error); +} - delete jsonResp; - json_object_put(parse); - curl_slist_free_all(postHeaders); - curl_easy_cleanup(curl); +void drive::gd::driveListAppend(const std::string& _q) +{ + if(!tokenIsValid()) + refreshToken(); + + std::string url = std::string(driveURL) + std::string(DRIVE_DEFAULT_PARAMS_AND_QUERY); + if(!_q.empty()) + { + char *qEsc = curl_easy_escape(NULL, _q.c_str(), _q.length()); + url.append(std::string("\%20and\%20") + std::string(qEsc)); + curl_free(qEsc); + } + + std::string jsonResp; + int error = requestList(url, token, &jsonResp); + if(error == CURLE_OK) + processList(jsonResp, driveList, false); + else + writeCurlError("driveListAppend", error); +} + +void drive::gd::getListWithParent(const std::string& _parent, std::vector& _out) +{ + _out.clear(); + for(unsigned i = 0; i < driveList.size(); i++) + { + if(driveList[i].parent == _parent) + _out.push_back(&driveList[i]); + } } void drive::gd::debugWriteList() { - fs::logWrite("Parent: %s\n", parentDir.c_str()); for(auto& di : driveList) { fs::logWrite("%s\n\t%s\n", di.name.c_str(), di.id.c_str()); - if(!di.parents.empty()) - fs::logWrite("\t%s\n", di.parents[0].c_str()); + if(!di.parent.empty()) + fs::logWrite("\t%s\n", di.parent.c_str()); } } -bool drive::gd::createDir(const std::string& _dirName) +bool drive::gd::createDir(const std::string& _dirName, const std::string& _parent) { if(!tokenIsValid()) refreshToken(); @@ -361,10 +394,10 @@ bool drive::gd::createDir(const std::string& _dirName) json_object *mimeTypeString = json_object_new_string(MIMETYPE_FOLDER); json_object_object_add(post, "name", nameString); json_object_object_add(post, "mimeType", mimeTypeString); - if (!parentDir.empty()) + if (!_parent.empty()) { json_object *parentsArray = json_object_new_array(); - json_object *parentString = json_object_new_string(parentDir.c_str()); + json_object *parentString = json_object_new_string(_parent.c_str()); json_object_array_add(parentsArray, parentString); json_object_object_add(post, "parents", parentsArray); } @@ -389,11 +422,12 @@ bool drive::gd::createDir(const std::string& _dirName) json_object *id; json_object_object_get_ex(respParse, "id", &id); - drive::gdDirItem newDir; + drive::gdItem newDir; newDir.name = _dirName; newDir.id = json_object_get_string(id); - newDir.mimeType = MIMETYPE_FOLDER; + newDir.isDir = true; newDir.size = 0; + newDir.parent = _parent; driveList.push_back(newDir); } else @@ -409,37 +443,45 @@ bool drive::gd::createDir(const std::string& _dirName) bool drive::gd::dirExists(const std::string& _dirName) { - bool ret = false; - for(unsigned i = 0; i < driveList.size(); i++) { - if(driveList[i].name == _dirName && driveList[i].mimeType == MIMETYPE_FOLDER) - { - ret = true; - break; - } + if(driveList[i].isDir && driveList[i].name == _dirName) + return true; } + return false; +} - return ret; +bool drive::gd::dirExists(const std::string& _dirName, const std::string& _parent) +{ + for(unsigned i = 0; i < driveList.size(); i++) + { + if(driveList[i].isDir && driveList[i].name == _dirName && driveList[i].parent == _parent) + return true; + } + return false; } bool drive::gd::fileExists(const std::string& _filename) { - bool ret = false; - for(unsigned i = 0; i < driveList.size(); i++) { - if(driveList[i].name == _filename && driveList[i].mimeType != MIMETYPE_FOLDER) - { - ret = true; - break; - } + if(!driveList[i].isDir && driveList[i].name == _filename) + return true; } - - return ret; + return false; } -void drive::gd::uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload) +bool drive::gd::fileExists(const std::string& _filename, const std::string& _parent) +{ + for(unsigned i = 0; i < driveList.size(); i++) + { + if(!driveList[i].isDir && driveList[i].name == _filename && driveList[i].parent == _parent) + return true; + } + return false; +} + +void drive::gd::uploadFile(const std::string& _filename, const std::string& _parent, curlFuncs::curlUpArgs *_upload) { if(!tokenIsValid()) refreshToken(); @@ -456,10 +498,10 @@ void drive::gd::uploadFile(const std::string& _filename, curlFuncs::curlUpArgs * json_object *post = json_object_new_object(); json_object *nameString = json_object_new_string(_filename.c_str()); json_object_object_add(post, "name", nameString); - if (!parentDir.empty()) + if (!_parent.empty()) { json_object *parentArray = json_object_new_array(); - json_object *parentString = json_object_new_string(parentDir.c_str()); + json_object *parentString = json_object_new_string(_parent.c_str()); json_object_array_add(parentArray, parentString); json_object_object_add(post, "parents", parentArray); } @@ -499,14 +541,15 @@ void drive::gd::uploadFile(const std::string& _filename, curlFuncs::curlUpArgs * if(name && id && mimeType) { - drive::gdDirItem uploadData; + drive::gdItem uploadData; uploadData.id = json_object_get_string(id); uploadData.name = json_object_get_string(name); - uploadData.mimeType = json_object_get_string(mimeType); + uploadData.isDir = false; uploadData.size = *_upload->o;//should be safe to use - uploadData.parents.push_back(parentDir); + uploadData.parent = _parent; driveList.push_back(uploadData); } + json_object_put(parse); } else writeCurlError("uploadFile", error); @@ -633,7 +676,37 @@ std::string drive::gd::getFileID(const std::string& _name) { for(unsigned i = 0; i < driveList.size(); i++) { - if(driveList[i].name == _name) + if(!driveList[i].isDir && driveList[i].name == _name) + return driveList[i].id; + } + return ""; +} + +std::string drive::gd::getFileID(const std::string& _name, const std::string& _parent) +{ + for(unsigned i = 0; i < driveList.size(); i++) + { + if(!driveList[i].isDir && driveList[i].name == _name && driveList[i].parent == _parent) + return driveList[i].id; + } + return ""; +} + +std::string drive::gd::getDirID(const std::string& _name) +{ + for(unsigned i = 0; i < driveList.size(); i++) + { + if(driveList[i].isDir && driveList[i].name == _name) + return driveList[i].id; + } + return ""; +} + +std::string drive::gd::getDirID(const std::string& _name, const std::string& _parent) +{ + for(unsigned i = 0; i < driveList.size(); i++) + { + if(driveList[i].isDir && driveList[i].name == _name && driveList[i].parent == _parent) return driveList[i].id; } return ""; diff --git a/src/ui/fld.cpp b/src/ui/fld.cpp index 180d7a2..3e0c15f 100644 --- a/src/ui/fld.cpp +++ b/src/ui/fld.cpp @@ -11,15 +11,14 @@ static fs::dirList *fldList = NULL; static SDL_Texture *fldBuffer; static unsigned int fldGuideWidth = 0; static Mutex fldLock = 0; +static std::string driveParent; +static std::vector driveFldList; static void fldMenuCallback(void *a) { switch(ui::padKeysDown()) { case HidNpadButton_B: - if(fs::gDrive) - fs::gDrive->returnToRoot(); - fs::unmountSave(); fs::freePathFilters(); fldMenu->setActive(false); @@ -134,7 +133,7 @@ static void fldFuncUpload_t(void *a) fs::gDrive->updateFile(id, &upload); } else - fs::gDrive->uploadFile(filename, &upload); + fs::gDrive->uploadFile(filename, driveParent, &upload); fclose(upload.f); @@ -147,7 +146,7 @@ static void fldFuncUpload_t(void *a) if(cfg::config["ovrClk"]) util::sysNormal(); - ui::fldRefreshMenu(false); + ui::fldRefreshMenu(); t->finished = true; } @@ -163,7 +162,7 @@ static void fldFuncUpload(void *a) static void fldFuncDownload_t(void *a) { threadInfo *t = (threadInfo *)a; - drive::gdDirItem *in = (drive::gdDirItem *)t->argPtr; + drive::gdItem *in = (drive::gdItem *)t->argPtr; data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid); std::string targetPath = util::generatePathByTID(utinfo->tid) + in->name; @@ -198,14 +197,14 @@ static void fldFuncDownload_t(void *a) if(cfg::config["ovrClk"]) util::sysNormal(); - ui::fldRefreshMenu(false); + ui::fldRefreshMenu(); t->finished = true; } static void fldFuncDownload(void *a) { - drive::gdDirItem *in = (drive::gdDirItem *)a; + drive::gdItem *in = (drive::gdItem *)a; data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid); std::string testPath = util::generatePathByTID(utinfo->tid) + in->name; @@ -222,25 +221,24 @@ static void fldFuncDownload(void *a) static void fldFuncDriveDelete_t(void *a) { threadInfo *t = (threadInfo *)a; - drive::gdDirItem *gdi = (drive::gdDirItem *)t->argPtr; + drive::gdItem *gdi = (drive::gdItem *)t->argPtr; t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0)); fs::gDrive->deleteFile(gdi->id); - ui::fldRefreshMenu(true); + ui::fldRefreshMenu(); t->finished = true; } static void fldFuncDriveDelete(void *a) { - drive::gdDirItem *in = (drive::gdDirItem *)a; + drive::gdItem *in = (drive::gdItem *)a; ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fldFuncDriveDelete_t, NULL, a, ui::getUICString("confirmDelete", 0), in->name.c_str()); ui::confirm(conf); } -//TODO static void fldFuncDriveRestore_t(void *a) { threadInfo *t = (threadInfo *)a; - drive::gdDirItem *gdi = (drive::gdDirItem *)t->argPtr; + drive::gdItem *gdi = (drive::gdItem *)t->argPtr; t->status->setStatus(ui::getUICString("threadStatusDownloadingFile", 0), gdi->name.c_str()); fs::copyArgs *cpy = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0); @@ -270,7 +268,7 @@ static void fldFuncDriveRestore_t(void *a) static void fldFuncDriveRestore(void *a) { - drive::gdDirItem *in = (drive::gdDirItem *)a; + drive::gdItem *in = (drive::gdItem *)a; ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fldFuncDriveRestore_t, NULL, a, ui::getUICString("confirmRestore", 0), in->name.c_str()); ui::confirm(conf); } @@ -315,31 +313,27 @@ void ui::fldPopulateMenu() std::string targetDir = util::generatePathByTID(d->tid); fldList->reassign(targetDir); - if(fs::gDrive) - { - if(!fs::gDrive->dirExists(t->title)) - fs::gDrive->createDir(t->title); - - std::string dirID = fs::gDrive->getFileID(t->title); - fs::gDrive->chDir(dirID); - } - fs::loadPathFilters(d->tid); fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0)); fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL); unsigned fldInd = 1; - if(fs::gDrive && fs::gDrive->getDriveListCount() > 0) + if(fs::gDrive) { - for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++) - { - drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i); - fldMenu->addOpt(NULL, "[GD] " + gdi->name); + if(!fs::gDrive->dirExists(t->title, fs::jksvDriveID)) + fs::gDrive->createDir(t->title, fs::jksvDriveID); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, gdi); + driveParent = fs::gDrive->getDirID(t->title, fs::jksvDriveID); + + fs::gDrive->getListWithParent(driveParent, driveFldList); + for(unsigned i = 0; i < driveFldList.size(); i++, fldInd++) + { + fldMenu->addOpt(NULL, "[GD] " + driveFldList[i]->name); + + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, driveFldList[i]); + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, driveFldList[i]); + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, driveFldList[i]); } } @@ -359,7 +353,7 @@ void ui::fldPopulateMenu() mutexUnlock(&fldLock); } -void ui::fldRefreshMenu(bool _updateDrive) +void ui::fldRefreshMenu() { mutexLock(&fldLock); @@ -369,23 +363,21 @@ void ui::fldRefreshMenu(bool _updateDrive) std::string targetDir = util::generatePathByTID(utinfo->tid); fldList->reassign(targetDir); - if(_updateDrive && fs::gDrive) - fs::gDrive->loadDriveList(""); - fldMenu->addOpt(NULL, ui::getUIString("folderMenuNew", 0)); fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL); unsigned fldInd = 1; - if(fs::gDrive && fs::gDrive->getDriveListCount() > 0) + if(fs::gDrive) { - for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++) - { - drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i); - fldMenu->addOpt(NULL, "[GD] " + gdi->name); + fs::gDrive->getListWithParent(driveParent, driveFldList); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi); - fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, gdi); + for(unsigned i = 0; i < driveFldList.size(); i++, fldInd++) + { + fldMenu->addOpt(NULL, "[GD] " + driveFldList[i]->name); + + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, driveFldList[i]); + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, driveFldList[i]); + fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, driveFldList[i]); } }