void BoxStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("BoxStorage: got NULL instead of JSON"); if (callback) (*callback)(BoolResponse(nullptr, false)); delete callback; return; } if (!Networking::CurlJsonRequest::jsonIsObject(json, "BoxStorage")) { if (callback) (*callback)(BoolResponse(nullptr, false)); delete json; delete callback; return; } Common::JSONObject result = json->asObject(); if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "BoxStorage") || !Networking::CurlJsonRequest::jsonContainsString(result, "refresh_token", "BoxStorage")) { warning("BoxStorage: bad response, no token passed"); debug(9, "%s", json->stringify().c_str()); if (callback) (*callback)(BoolResponse(nullptr, false)); } else { _token = result.getVal("access_token")->asString(); _refreshToken = result.getVal("refresh_token")->asString(); CloudMan.save(); //ask CloudManager to save our new refreshToken if (callback) (*callback)(BoolResponse(nullptr, true)); } delete json; delete callback; }
void DropboxStorage::codeFlowComplete(Networking::JsonResponse response) { Common::JSONValue *json = (Common::JSONValue *)response.value; if (json == nullptr) { debug(9, "DropboxStorage::codeFlowComplete: got NULL instead of JSON!"); CloudMan.removeStorage(this); return; } if (!json->isObject()) { debug(9, "DropboxStorage::codeFlowComplete: Passed JSON is not an object!"); CloudMan.removeStorage(this); delete json; return; } Common::JSONObject result = json->asObject(); if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "DropboxStorage::codeFlowComplete") || !Networking::CurlJsonRequest::jsonContainsString(result, "uid", "DropboxStorage::codeFlowComplete")) { warning("DropboxStorage: bad response, no token/uid passed"); debug(9, "%s", json->stringify(true).c_str()); CloudMan.removeStorage(this); } else { _token = result.getVal("access_token")->asString(); _uid = result.getVal("uid")->asString(); ConfMan.removeKey("dropbox_code", ConfMan.kCloudDomain); CloudMan.replaceStorage(this, kStorageDropboxId); ConfMan.flushToDisk(); } delete json; }
void OneDriveUploadRequest::partUploadedCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::ErrorResponse error(this, false, true, "", -1); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); Common::JSONValue *json = response.value; if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (json->isObject()) { Common::JSONObject object = json->asObject(); if (object.contains("error")) { warning("OneDriveUploadRequest: error: %s", json->stringify(true).c_str()); error.response = json->stringify(true); finishError(error); delete json; return; } if (Networking::CurlJsonRequest::jsonContainsString(object, "id", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "name", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsIntegerNumber(object, "size", "OneDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "lastModifiedDateTime", "OneDriveUploadRequest")) { //finished Common::String path = _savePath; uint32 size = object.getVal("size")->asIntegerNumber(); uint32 timestamp = ISO8601::convertToTimestamp(object.getVal("lastModifiedDateTime")->asString()); finishUpload(StorageFile(path, size, timestamp, false)); return; } if (_uploadUrl == "") { if (Networking::CurlJsonRequest::jsonContainsString(object, "uploadUrl", "OneDriveUploadRequest")) _uploadUrl = object.getVal("uploadUrl")->asString(); } } if (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1) { warning("OneDriveUploadRequest: no file info to return"); finishUpload(StorageFile(_savePath, 0, 0, false)); } else { uploadNextPart(); } delete json; }
void SavesSyncRequest::directoryListedErrorCallback(Networking::ErrorResponse error) { _workingRequest = nullptr; if (_ignoreCallback) return; bool irrecoverable = error.interrupted || error.failed; if (error.failed) { Common::JSONValue *value = Common::JSON::parse(error.response.c_str()); if (value) { if (value->isObject()) { Common::JSONObject object = value->asObject(); //Dropbox-related error: if (object.contains("error_summary") && object.getVal("error_summary")->isString()) { Common::String summary = object.getVal("error_summary")->asString(); if (summary.contains("not_found")) { irrecoverable = false; } } //OneDrive-related error: if (object.contains("error") && object.getVal("error")->isObject()) { Common::JSONObject errorNode = object.getVal("error")->asObject(); if (Networking::CurlJsonRequest::jsonContainsString(errorNode, "code", "SavesSyncRequest")) { Common::String code = errorNode.getVal("code")->asString(); if (code == "itemNotFound") { irrecoverable = false; } } } } delete value; } //Google Drive and Box-related ScummVM-based error if (error.response.contains("subdirectory not found")) { irrecoverable = false; //base "/ScummVM/" folder not found } else if (error.response.contains("no such file found in its parent directory")) { irrecoverable = false; //"Saves" folder within "/ScummVM/" not found } } if (irrecoverable) { finishError(error); return; } //we're lucky - user just lacks his "/cloud/" folder - let's create one Common::String dir = _storage->savesDirectoryPath(); if (dir.lastChar() == '/') dir.deleteLastChar(); debug(9, "SavesSyncRequest: creating %s", dir.c_str()); _workingRequest = _storage->createDirectory( dir, new Common::Callback<SavesSyncRequest, Storage::BoolResponse>(this, &SavesSyncRequest::directoryCreatedCallback), new Common::Callback<SavesSyncRequest, Networking::ErrorResponse>(this, &SavesSyncRequest::directoryCreatedErrorCallback) ); if (!_workingRequest) finishError(Networking::ErrorResponse(this)); }
Networking::Request *DropboxStorage::streamFileById(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) { Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("path", new Common::JSONValue(path)); Common::JSONValue value(jsonRequestParameters); Networking::CurlRequest *request = new Networking::CurlRequest(nullptr, nullptr, DROPBOX_API_FILES_DOWNLOAD); //TODO: is it OK to pass no callbacks? request->addHeader("Authorization: Bearer " + _token); request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value)); request->addHeader("Content-Type: "); //required to be empty (as we do POST, it's usually app/form-url-encoded) Networking::NetworkReadStreamResponse response = request->execute(); if (callback) (*callback)(response); return response.request; // no leak here, response.request == request }
void BoxStorage::createDirectoryInnerCallback(BoolCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("BoxStorage::createDirectoryInnerCallback: NULL passed instead of JSON"); delete outerCallback; return; } if (outerCallback) { if (Networking::CurlJsonRequest::jsonIsObject(json, "BoxStorage::createDirectoryInnerCallback")) { Common::JSONObject info = json->asObject(); (*outerCallback)(BoolResponse(nullptr, info.contains("id"))); } else { (*outerCallback)(BoolResponse(nullptr, false)); } delete outerCallback; } delete json; }
Networking::Request *BoxStorage::createDirectoryWithParentId(Common::String parentId, Common::String name, BoolCallback callback, Networking::ErrorCallback errorCallback) { if (!errorCallback) errorCallback = getErrorPrintingCallback(); Common::String url = BOX_API_FOLDERS; Networking::JsonCallback innerCallback = new Common::CallbackBridge<BoxStorage, BoolResponse, Networking::JsonResponse>(this, &BoxStorage::createDirectoryInnerCallback, callback); Networking::CurlJsonRequest *request = new BoxTokenRefresher(this, innerCallback, errorCallback, url.c_str()); request->addHeader("Authorization: Bearer " + accessToken()); request->addHeader("Content-Type: application/json"); Common::JSONObject parentObject; parentObject.setVal("id", new Common::JSONValue(parentId)); Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("name", new Common::JSONValue(name)); jsonRequestParameters.setVal("parent", new Common::JSONValue(parentObject)); Common::JSONValue value(jsonRequestParameters); request->addPostField(Common::JSON::stringify(&value)); return addRequest(request); }
void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("OneDriveStorage::fileInfoCallback: NULL passed instead of JSON"); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); delete outerCallback; return; } if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage::fileInfoCallback")) { if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); delete json; delete outerCallback; return; } Common::JSONObject result = response.value->asObject(); if (!Networking::CurlJsonRequest::jsonContainsString(result, "@content.downloadUrl", "OneDriveStorage::fileInfoCallback")) { warning("OneDriveStorage: downloadUrl not found in passed JSON"); debug(9, "%s", response.value->stringify().c_str()); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(response.request, nullptr)); delete json; delete outerCallback; return; } const char *url = result.getVal("@content.downloadUrl")->asString().c_str(); if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse( response.request, new Networking::NetworkReadStream(url, nullptr, "") )); delete json; delete outerCallback; }
void OneDriveStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("OneDriveStorage::infoInnerCallback: NULL passed instead of JSON"); delete outerCallback; return; } if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage::infoInnerCallback")) { delete json; delete outerCallback; return; } Common::JSONObject jsonInfo = json->asObject(); Common::String uid, displayName, email; uint64 quotaUsed = 0, quotaAllocated = 26843545600LL; // 25 GB, because I actually don't know any way to find out the real one if (Networking::CurlJsonRequest::jsonContainsObject(jsonInfo, "createdBy", "OneDriveStorage::infoInnerCallback")) { Common::JSONObject createdBy = jsonInfo.getVal("createdBy")->asObject(); if (Networking::CurlJsonRequest::jsonContainsObject(createdBy, "user", "OneDriveStorage::infoInnerCallback")) { Common::JSONObject user = createdBy.getVal("user")->asObject(); if (Networking::CurlJsonRequest::jsonContainsString(user, "id", "OneDriveStorage::infoInnerCallback")) uid = user.getVal("id")->asString(); if (Networking::CurlJsonRequest::jsonContainsString(user, "displayName", "OneDriveStorage::infoInnerCallback")) displayName = user.getVal("displayName")->asString(); } } if (Networking::CurlJsonRequest::jsonContainsIntegerNumber(jsonInfo, "size", "OneDriveStorage::infoInnerCallback")) { quotaUsed = jsonInfo.getVal("size")->asIntegerNumber(); } Common::String username = email; if (username == "") username = displayName; if (username == "") username = uid; CloudMan.setStorageUsername(kStorageOneDriveId, username); if (outerCallback) { (*outerCallback)(StorageInfoResponse(nullptr, StorageInfo(uid, displayName, email, quotaUsed, quotaAllocated))); delete outerCallback; } delete json; }
Networking::Request *GoogleDriveStorage::createDirectoryWithParentId(Common::String parentId, Common::String name, BoolCallback callback, Networking::ErrorCallback errorCallback) { if (!errorCallback) errorCallback = getErrorPrintingCallback(); Common::String url = GOOGLEDRIVE_API_FILES; Networking::JsonCallback innerCallback = new Common::CallbackBridge<GoogleDriveStorage, BoolResponse, Networking::JsonResponse>(this, &GoogleDriveStorage::createDirectoryInnerCallback, callback); Networking::CurlJsonRequest *request = new GoogleDriveTokenRefresher(this, innerCallback, errorCallback, url.c_str()); request->addHeader("Authorization: Bearer " + accessToken()); request->addHeader("Content-Type: application/json"); Common::JSONArray parentsArray; parentsArray.push_back(new Common::JSONValue(parentId)); Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("mimeType", new Common::JSONValue("application/vnd.google-apps.folder")); jsonRequestParameters.setVal("name", new Common::JSONValue(name)); jsonRequestParameters.setVal("parents", new Common::JSONValue(parentsArray)); Common::JSONValue value(jsonRequestParameters); request->addPostField(Common::JSON::stringify(&value)); return addRequest(request); }
void GoogleDriveUploadRequest::startUpload() { Common::String name = _savePath; for (uint32 i = name.size(); i > 0; --i) { if (name[i - 1] == '/' || name[i - 1] == '\\') { name.erase(0, i); break; } } Common::String url = GOOGLEDRIVE_API_FILES; if (_resolvedId != "") url += "/" + ConnMan.urlEncode(_resolvedId); url += "?uploadType=resumable&fields=id,mimeType,modifiedTime,name,size"; Networking::JsonCallback callback = new Common::Callback<GoogleDriveUploadRequest, Networking::JsonResponse>(this, &GoogleDriveUploadRequest::startUploadCallback); Networking::ErrorCallback failureCallback = new Common::Callback<GoogleDriveUploadRequest, Networking::ErrorResponse>(this, &GoogleDriveUploadRequest::startUploadErrorCallback); Networking::CurlJsonRequest *request = new GoogleDriveTokenRefresher(_storage, callback, failureCallback, url.c_str()); request->addHeader("Authorization: Bearer " + _storage->accessToken()); request->addHeader("Content-Type: application/json"); if (_resolvedId != "") request->usePatch(); Common::JSONObject jsonRequestParameters; if (_resolvedId != "") { jsonRequestParameters.setVal("id", new Common::JSONValue(_resolvedId)); } else { Common::JSONArray parentsArray; parentsArray.push_back(new Common::JSONValue(_parentId)); jsonRequestParameters.setVal("parents", new Common::JSONValue(parentsArray)); } jsonRequestParameters.setVal("name", new Common::JSONValue(name)); Common::JSONValue value(jsonRequestParameters); request->addPostField(Common::JSON::stringify(&value)); _workingRequest = ConnMan.addRequest(request); }
void BoxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("BoxStorage::infoInnerCallback: NULL passed instead of JSON"); delete outerCallback; return; } if (!Networking::CurlJsonRequest::jsonIsObject(json, "BoxStorage::infoInnerCallback")) { delete json; delete outerCallback; return; } Common::JSONObject info = json->asObject(); Common::String uid, name, email; uint64 quotaUsed = 0, quotaAllocated = 0; // can check that "type": "user" // there is also "max_upload_size", "phone" and "avatar_url" if (Networking::CurlJsonRequest::jsonContainsString(info, "id", "BoxStorage::infoInnerCallback")) uid = info.getVal("id")->asString(); if (Networking::CurlJsonRequest::jsonContainsString(info, "name", "BoxStorage::infoInnerCallback")) name = info.getVal("name")->asString(); if (Networking::CurlJsonRequest::jsonContainsString(info, "login", "BoxStorage::infoInnerCallback")) email = info.getVal("login")->asString(); if (Networking::CurlJsonRequest::jsonContainsIntegerNumber(info, "space_amount", "BoxStorage::infoInnerCallback")) quotaAllocated = info.getVal("space_amount")->asIntegerNumber(); if (Networking::CurlJsonRequest::jsonContainsIntegerNumber(info, "space_used", "BoxStorage::infoInnerCallback")) quotaUsed = info.getVal("space_used")->asIntegerNumber(); Common::String username = email; if (username == "") username = name; if (username == "") username = uid; CloudMan.setStorageUsername(kStorageBoxId, username); if (outerCallback) { (*outerCallback)(StorageInfoResponse(nullptr, StorageInfo(uid, name, email, quotaUsed, quotaAllocated))); delete outerCallback; } delete json; }
void OneDriveListDirectoryRequest::listedDirectoryCallback(Networking::JsonResponse response) { _workingRequest = nullptr; Common::JSONValue *json = response.value; if (_ignoreCallback) { delete json; return; } if (response.request) _date = response.request->date(); Networking::ErrorResponse error(this); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq && rq->getNetworkReadStream()) error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (!json->isObject()) { error.response = "Passed JSON is not an object!"; finishError(error); delete json; return; } Common::JSONObject object = json->asObject(); //check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults if (!Networking::CurlJsonRequest::jsonContainsArray(object, "value", "OneDriveListDirectoryRequest")) { error.response = "\"value\" not found or that's not an array!"; finishError(error); delete json; return; } Common::JSONArray items = object.getVal("value")->asArray(); for (uint32 i = 0; i < items.size(); ++i) { if (!Networking::CurlJsonRequest::jsonIsObject(items[i], "OneDriveListDirectoryRequest")) continue; Common::JSONObject item = items[i]->asObject(); if (!Networking::CurlJsonRequest::jsonContainsAttribute(item, "folder", "OneDriveListDirectoryRequest", true)) continue; if (!Networking::CurlJsonRequest::jsonContainsString(item, "name", "OneDriveListDirectoryRequest")) continue; if (!Networking::CurlJsonRequest::jsonContainsIntegerNumber(item, "size", "OneDriveListDirectoryRequest")) continue; if (!Networking::CurlJsonRequest::jsonContainsString(item, "lastModifiedDateTime", "OneDriveListDirectoryRequest")) continue; Common::String path = _currentDirectory + item.getVal("name")->asString(); bool isDirectory = item.contains("folder"); uint32 size = item.getVal("size")->asIntegerNumber(); uint32 timestamp = ISO8601::convertToTimestamp(item.getVal("lastModifiedDateTime")->asString()); StorageFile file(path, size, timestamp, isDirectory); _files.push_back(file); if (_requestedRecursive && file.isDirectory()) { _directoriesQueue.push_back(file.path()); } } bool hasMore = object.contains("@odata.nextLink"); if (hasMore) { if (!Networking::CurlJsonRequest::jsonContainsString(object, "@odata.nextLink", "OneDriveListDirectoryRequest")) { error.response = "\"@odata.nextLink\" is not a string!"; finishError(error); delete json; return; } makeRequest(object.getVal("@odata.nextLink")->asString()); } else { listNextDirectory(); } delete json; }
void GoogleDriveStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse response) { Common::JSONValue *json = response.value; if (!json) { warning("GoogleDriveStorage::infoInnerCallback: NULL passed instead of JSON"); delete outerCallback; return; } if (!Networking::CurlJsonRequest::jsonIsObject(json, "GoogleDriveStorage::infoInnerCallback")) { delete json; delete outerCallback; return; } Common::JSONObject info = json->asObject(); Common::String uid, name, email; uint64 quotaUsed = 0, quotaAllocated = 0; if (Networking::CurlJsonRequest::jsonContainsAttribute(info, "user", "GoogleDriveStorage::infoInnerCallback") && Networking::CurlJsonRequest::jsonIsObject(info.getVal("user"), "GoogleDriveStorage::infoInnerCallback")) { //"me":true, "kind":"drive#user","photoLink": "", //"displayName":"Alexander Tkachev","emailAddress":"*****@*****.**","permissionId":"" Common::JSONObject user = info.getVal("user")->asObject(); if (Networking::CurlJsonRequest::jsonContainsString(user, "permissionId", "GoogleDriveStorage::infoInnerCallback")) uid = user.getVal("permissionId")->asString(); //not sure it's user's id, but who cares anyway? if (Networking::CurlJsonRequest::jsonContainsString(user, "displayName", "GoogleDriveStorage::infoInnerCallback")) name = user.getVal("displayName")->asString(); if (Networking::CurlJsonRequest::jsonContainsString(user, "emailAddress", "GoogleDriveStorage::infoInnerCallback")) email = user.getVal("emailAddress")->asString(); } if (Networking::CurlJsonRequest::jsonContainsAttribute(info, "storageQuota", "GoogleDriveStorage::infoInnerCallback") && Networking::CurlJsonRequest::jsonIsObject(info.getVal("storageQuota"), "GoogleDriveStorage::infoInnerCallback")) { //"usageInDrive":"6332462","limit":"18253611008","usage":"6332462","usageInDriveTrash":"0" Common::JSONObject storageQuota = info.getVal("storageQuota")->asObject(); if (Networking::CurlJsonRequest::jsonContainsString(storageQuota, "usage", "GoogleDriveStorage::infoInnerCallback")) { Common::String usage = storageQuota.getVal("usage")->asString(); quotaUsed = usage.asUint64(); } if (Networking::CurlJsonRequest::jsonContainsString(storageQuota, "limit", "GoogleDriveStorage::infoInnerCallback")) { Common::String limit = storageQuota.getVal("limit")->asString(); quotaAllocated = limit.asUint64(); } } CloudMan.setStorageUsername(kStorageGoogleDriveId, email); if (outerCallback) { (*outerCallback)(StorageInfoResponse(nullptr, StorageInfo(uid, name, email, quotaUsed, quotaAllocated))); delete outerCallback; } delete json; }
void GoogleDriveUploadRequest::partUploadedCallback(Networking::JsonResponse response) { _workingRequest = nullptr; if (_ignoreCallback) return; Networking::ErrorResponse error(this, false, true, "", -1); Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; if (rq) { const Networking::NetworkReadStream *stream = rq->getNetworkReadStream(); if (stream) { long code = stream->httpResponseCode(); error.httpResponseCode = code; if (code == 308 && handleHttp308(stream)) { delete (Common::JSONValue *)response.value; return; } } } Common::JSONValue *json = response.value; if (json == nullptr) { error.response = "Failed to parse JSON, null passed!"; finishError(error); return; } if (json->isObject()) { Common::JSONObject object = json->asObject(); if (object.contains("error")) { warning("GoogleDrive returned error: %s", json->stringify(true).c_str()); error.response = json->stringify(true); finishError(error); delete json; return; } if (Networking::CurlJsonRequest::jsonContainsString(object, "id", "GoogleDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "name", "GoogleDriveUploadRequest") && Networking::CurlJsonRequest::jsonContainsString(object, "mimeType", "GoogleDriveUploadRequest")) { //finished Common::String id = object.getVal("id")->asString(); Common::String name = object.getVal("name")->asString(); bool isDirectory = (object.getVal("mimeType")->asString() == "application/vnd.google-apps.folder"); uint32 size = 0, timestamp = 0; if (Networking::CurlJsonRequest::jsonContainsString(object, "size", "GoogleDriveUploadRequest", true)) size = object.getVal("size")->asString().asUint64(); if (Networking::CurlJsonRequest::jsonContainsString(object, "modifiedTime", "GoogleDriveUploadRequest", true)) timestamp = ISO8601::convertToTimestamp(object.getVal("modifiedTime")->asString()); finishUpload(StorageFile(id, _savePath, name, size, timestamp, isDirectory)); return; } } if (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1) { warning("GoogleDriveUploadRequest: no file info to return"); finishUpload(StorageFile(_savePath, 0, 0, false)); } else { uploadNextPart(); } delete json; }