aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/cloud/dropbox/dropboxstorage.cpp110
-rw-r--r--backends/cloud/dropbox/dropboxstorage.h39
-rw-r--r--backends/cloud/manager.cpp15
-rw-r--r--backends/cloud/manager.h2
-rw-r--r--backends/cloud/storage.h6
-rw-r--r--backends/networking/curl/connectionmanager.cpp4
-rw-r--r--backends/networking/curl/connectionmanager.h3
-rw-r--r--backends/networking/curl/curljsonrequest.cpp16
-rw-r--r--backends/networking/curl/curljsonrequest.h8
-rw-r--r--backends/networking/curl/networkreadstream.cpp7
-rw-r--r--backends/networking/curl/networkreadstream.h3
-rw-r--r--base/main.cpp1
-rw-r--r--common/cloudmanager.h12
-rw-r--r--common/config-manager.cpp26
-rw-r--r--common/config-manager.h9
15 files changed, 239 insertions, 22 deletions
diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp
index 729283bcfa..add6bff54c 100644
--- a/backends/cloud/dropbox/dropboxstorage.cpp
+++ b/backends/cloud/dropbox/dropboxstorage.cpp
@@ -23,6 +23,7 @@
#include "backends/cloud/dropbox/dropboxstorage.h"
#include "backends/networking/curl/curljsonrequest.h"
+#include "common/config-manager.h"
#include "common/debug.h"
#include "common/json.h"
#include <curl/curl.h>
@@ -30,18 +31,44 @@
namespace Cloud {
namespace Dropbox {
-static void curlJsonCallback(void *ptr) {
+Common::String DropboxStorage::KEY; //can't use ConfMan there yet, loading it on instance creation/auth
+Common::String DropboxStorage::SECRET; //TODO: hide these secrets somehow
+
+static void printJsonCallback(void *ptr) {
+ Common::JSONValue *json = (Common::JSONValue *)ptr;
+ if (json) {
+ debug("printJsonCallback:");
+ debug("%s", json->stringify(true).c_str());
+ delete json;
+ } else {
+ debug("printJsonCallback: got NULL instead of JSON!");
+ }
+}
+
+static void saveAccessTokenCallback(void *ptr) {
Common::JSONValue *json = (Common::JSONValue *)ptr;
if (json) {
- debug("curlJsonCallback:");
+ debug("saveAccessTokenCallback:");
debug("%s", json->stringify(true).c_str());
+
+ Common::JSONObject result = json->asObject();
+ if (!result.contains("access_token") || !result.contains("uid")) {
+ warning("Bad response, no token/uid passed");
+ } else {
+ ConfMan.set("current_storage_type", "Dropbox", "cloud");
+ ConfMan.set("current_storage_access_token", result.getVal("access_token")->asString(), "cloud");
+ ConfMan.set("current_storage_user_id", result.getVal("uid")->asString(), "cloud");
+ ConfMan.removeKey("dropbox_code", "cloud");
+ debug("Now please restart ScummVM to apply the changes.");
+ }
+
delete json;
} else {
- debug("curlJsonCallback: got NULL instead of JSON!");
+ debug("saveAccessTokenCallback: got NULL instead of JSON!");
}
}
-DropboxStorage::DropboxStorage() {
+DropboxStorage::DropboxStorage(Common::String accessToken, Common::String userId): _token(accessToken), _uid(userId) {
curl_global_init(CURL_GLOBAL_ALL);
}
@@ -54,9 +81,78 @@ void DropboxStorage::listDirectory(Common::String path) {
}
void DropboxStorage::syncSaves() {
- //not so Dropbox, just testing JSON requesting & parsing:
- addRequest(new Networking::CurlJsonRequest(curlJsonCallback, "https://api.vk.com/method/users.get?v=5.50&user_ids=205387401"));
- addRequest(new Networking::CurlJsonRequest(curlJsonCallback, "https://api.vk.com/method/users.get?v=5.50&user_ids=28870501"));
+ //not syncing, but already something:
+ printInfo();
+}
+
+void DropboxStorage::printInfo() {
+ Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(printJsonCallback, "https://api.dropboxapi.com/1/account/info");
+ request->addHeader("Authorization: Bearer " + _token);
+ addRequest(request);
+}
+
+DropboxStorage *DropboxStorage::loadFromConfig() {
+ KEY = ConfMan.get("DROPBOX_KEY", "cloud");
+ SECRET = ConfMan.get("DROPBOX_SECRET", "cloud");
+
+ if (!ConfMan.hasKey("current_storage_access_token", "cloud")) {
+ warning("No access_token found");
+ return 0;
+ }
+
+ if (!ConfMan.hasKey("current_storage_user_id", "cloud")) {
+ warning("No user_id found");
+ return 0;
+ }
+
+ Common::String accessToken = ConfMan.get("current_storage_access_token", "cloud");
+ Common::String userId = ConfMan.get("current_storage_user_id", "cloud");
+ return new DropboxStorage(accessToken, userId);
+}
+
+Common::String DropboxStorage::getAuthLink() {
+ Common::String url = "https://www.dropbox.com/1/oauth2/authorize";
+ url += "?response_type=code";
+ url += "&redirect_uri=http://localhost:12345/"; //that's for copy-pasting
+ //url += "&redirect_uri=http%3A%2F%2Flocalhost%3A12345%2F"; //that's "http://localhost:12345/" for automatic opening
+ url += "&client_id=" + KEY;
+ return url;
+}
+
+DropboxStorage *DropboxStorage::authThroughConsole() {
+ if (!ConfMan.hasKey("DROPBOX_KEY", "cloud") || !ConfMan.hasKey("DROPBOX_SECRET", "cloud")) {
+ warning("No Dropbox keys available, cannot do auth");
+ return 0;
+ }
+
+ KEY = ConfMan.get("DROPBOX_KEY", "cloud");
+ SECRET = ConfMan.get("DROPBOX_SECRET", "cloud");
+
+ if (ConfMan.hasKey("dropbox_code", "cloud")) {
+ //phase 2: get access_token using specified code
+ return getAccessToken(ConfMan.get("dropbox_code", "cloud"));
+ }
+
+ debug("Navigate to this URL and press \"Allow\":");
+ debug("%s\n", getAuthLink().c_str());
+ debug("Then, add dropbox_code key in [cloud] section of configuration file. You should copy the <code> value from URL and put it as value for that key.\n");
+ debug("Navigate to this URL to get more information on ScummVM's configuration files:");
+ debug("http://wiki.scummvm.org/index.php/User_Manual/Configuring_ScummVM#Using_the_configuration_file_to_configure_ScummVM\n");
+ return 0;
+}
+
+DropboxStorage *DropboxStorage::getAccessToken(Common::String code) {
+ Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(saveAccessTokenCallback, "https://api.dropboxapi.com/1/oauth2/token");
+ request->addPostField("code=" + code);
+ request->addPostField("grant_type=authorization_code");
+ request->addPostField("client_id=" + KEY);
+ request->addPostField("client_secret=" + SECRET);
+ request->addPostField("&redirect_uri=http%3A%2F%2Flocalhost%3A12345%2F");
+
+ //OK, that's not how I imagined that...
+ DropboxStorage *storage = new DropboxStorage("", "");
+ storage->addRequest(request);
+ return storage;
}
} //end of namespace Dropbox
diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h
index a0229438be..f2281f146f 100644
--- a/backends/cloud/dropbox/dropboxstorage.h
+++ b/backends/cloud/dropbox/dropboxstorage.h
@@ -24,18 +24,47 @@
#define BACKENDS_CLOUD_DROPBOX_STORAGE_H
#include "backends/cloud/storage.h"
+#include "../manager.h"
-namespace Cloud { namespace Dropbox {
+namespace Cloud {
+namespace Dropbox {
-class DropboxStorage: public Cloud::Storage {
-public:
- DropboxStorage();
+class DropboxStorage: public Cloud::Storage {
+ static Common::String KEY, SECRET;
+
+ Common::String _token, _uid;
+
+ /** This private constructor is called from loadFromConfig(). */
+ DropboxStorage(Common::String token, Common::String uid);
+
+ static DropboxStorage *getAccessToken(Common::String code);
+
+public:
virtual ~DropboxStorage();
virtual void listDirectory(Common::String path);
virtual void syncSaves();
+ virtual void printInfo();
+ /**
+ * Load token and user id from configs and return DropboxStorage for those.
+ * @return pointer to the newly created DropboxStorage or 0 if some problem occured.
+ */
+ static DropboxStorage *loadFromConfig();
+
+ /**
+ * Returns Dropbox auth link.
+ */
+ static Common::String DropboxStorage::getAuthLink();
+
+ /**
+ * Show message with Dropbox auth instructions. (Temporary)
+ * Returns temporary DropboxStorage, which does network requests
+ * to get access token.
+ */
+ static DropboxStorage *authThroughConsole();
};
-} } //end of namespace Cloud::Dropbox
+} //end of namespace Dropbox
+} //end of namespace Cloud
#endif
diff --git a/backends/cloud/manager.cpp b/backends/cloud/manager.cpp
index 58bb0ce83f..08340e9288 100644
--- a/backends/cloud/manager.cpp
+++ b/backends/cloud/manager.cpp
@@ -22,13 +22,26 @@
#include "backends/cloud/manager.h"
#include "backends/cloud/dropbox/dropboxstorage.h"
+#include "common/config-manager.h"
namespace Cloud {
-Manager::Manager(): _currentStorage(new Dropbox::DropboxStorage()) {}
+Manager::Manager(): _currentStorage(0) {}
Manager::~Manager() { delete _currentStorage; }
+void Manager::init() {
+ if (ConfMan.hasKey("current_storage_type", "cloud")) {
+ Common::String storageType = ConfMan.get("current_storage_type", "cloud");
+ if (storageType == "Dropbox") _currentStorage = Dropbox::DropboxStorage::loadFromConfig();
+ else warning("Unknown cloud storage type '%s' passed", storageType.c_str());
+ }
+ else {
+ //this is temporary console offer to auth with Dropbox (because there is no other storage type yet anyway)
+ Dropbox::DropboxStorage::authThroughConsole();
+ }
+}
+
Storage* Manager::getCurrentStorage() {
return _currentStorage;
}
diff --git a/backends/cloud/manager.h b/backends/cloud/manager.h
index 11cc595da4..a1f046d71d 100644
--- a/backends/cloud/manager.h
+++ b/backends/cloud/manager.h
@@ -35,6 +35,8 @@ public:
Manager();
virtual ~Manager();
+ virtual void init();
+
virtual Storage* getCurrentStorage();
virtual void syncSaves();
};
diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h
index 84b6157a22..a5d048d3af 100644
--- a/backends/cloud/storage.h
+++ b/backends/cloud/storage.h
@@ -63,6 +63,12 @@ public:
*/
virtual void syncSaves() = 0;
+
+ /**
+ * Prints user info on console. (Temporary)
+ */
+
+ virtual void printInfo() = 0;
};
} //end of namespace Cloud
diff --git a/backends/networking/curl/connectionmanager.cpp b/backends/networking/curl/connectionmanager.cpp
index 8c718e019b..d34eab23e8 100644
--- a/backends/networking/curl/connectionmanager.cpp
+++ b/backends/networking/curl/connectionmanager.cpp
@@ -39,8 +39,8 @@ ConnectionManager::~ConnectionManager() {
curl_global_cleanup();
}
-NetworkReadStream *ConnectionManager::makeRequest(const char *url) {
- NetworkReadStream *stream = new NetworkReadStream(url);
+NetworkReadStream *ConnectionManager::makeRequest(const char *url, curl_slist *headersList, Common::String postFields) {
+ NetworkReadStream *stream = new NetworkReadStream(url, headersList, postFields);
curl_multi_add_handle(_multi, stream->getEasyHandle());
return stream;
}
diff --git a/backends/networking/curl/connectionmanager.h b/backends/networking/curl/connectionmanager.h
index fadcdf1372..b83de6191a 100644
--- a/backends/networking/curl/connectionmanager.h
+++ b/backends/networking/curl/connectionmanager.h
@@ -26,6 +26,7 @@
#include "common/str.h"
typedef void CURLM;
+struct curl_slist;
namespace Networking {
@@ -38,7 +39,7 @@ public:
ConnectionManager();
virtual ~ConnectionManager();
- NetworkReadStream *makeRequest(const char *url);
+ NetworkReadStream *makeRequest(const char *url, curl_slist *headersList, Common::String postFields);
void handle();
};
diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp
index f5a7a7c8d0..0c6363467a 100644
--- a/backends/networking/curl/curljsonrequest.cpp
+++ b/backends/networking/curl/curljsonrequest.cpp
@@ -30,7 +30,7 @@
namespace Networking {
-CurlJsonRequest::CurlJsonRequest(Callback cb, const char *url) : Request(cb), _stream(0), _contentsStream(DisposeAfterUse::YES) {
+CurlJsonRequest::CurlJsonRequest(Callback cb, const char *url) : Request(cb), _stream(0), _headersList(0), _contentsStream(DisposeAfterUse::YES) {
_url = url;
}
@@ -57,7 +57,7 @@ char *CurlJsonRequest::getPreparedContents() {
}
bool CurlJsonRequest::handle(ConnectionManager &manager) {
- if (!_stream) _stream = manager.makeRequest(_url);
+ if (!_stream) _stream = manager.makeRequest(_url, _headersList, _postFields);
if (_stream) {
const int kBufSize = 16*1024;
@@ -83,4 +83,16 @@ bool CurlJsonRequest::handle(ConnectionManager &manager) {
return false;
}
+void CurlJsonRequest::addHeader(Common::String header) {
+ _headersList = curl_slist_append(_headersList, header.c_str());
+}
+
+void CurlJsonRequest::addPostField(Common::String keyValuePair) {
+ if (_postFields == "")
+ _postFields = keyValuePair;
+ else
+ _postFields += "&" + keyValuePair;
+}
+
+
} //end of namespace Networking
diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h
index e9634393dc..17df9693f2 100644
--- a/backends/networking/curl/curljsonrequest.h
+++ b/backends/networking/curl/curljsonrequest.h
@@ -26,6 +26,8 @@
#include "backends/cloud/request.h"
#include "common/memstream.h"
+struct curl_slist;
+
namespace Networking {
class NetworkReadStream;
@@ -33,6 +35,8 @@ class NetworkReadStream;
class CurlJsonRequest : public Cloud::Request {
const char *_url;
NetworkReadStream *_stream;
+ curl_slist *_headersList;
+ Common::String _postFields;
Common::MemoryWriteStreamDynamic _contentsStream;
/** Prepares raw bytes from _contentsStream to be parsed with Common::JSON::parse(). */
@@ -43,6 +47,10 @@ public:
virtual ~CurlJsonRequest();
virtual bool handle(ConnectionManager &manager);
+
+ void addHeader(Common::String header);
+
+ void addPostField(Common::String header);
};
} //end of namespace Networking
diff --git a/backends/networking/curl/networkreadstream.cpp b/backends/networking/curl/networkreadstream.cpp
index b8cb81aca2..f2af4fd50c 100644
--- a/backends/networking/curl/networkreadstream.cpp
+++ b/backends/networking/curl/networkreadstream.cpp
@@ -34,7 +34,9 @@ static size_t curlDataCallback(char *d, size_t n, size_t l, void *p) {
return 0;
}
-NetworkReadStream::NetworkReadStream(const char *url): _easy(0), _eos(false), _requestComplete(false) {
+NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields):
+ _easy(0), _eos(false), _requestComplete(false)
+{
_easy = curl_easy_init();
curl_easy_setopt(_easy, CURLOPT_WRITEFUNCTION, curlDataCallback);
curl_easy_setopt(_easy, CURLOPT_WRITEDATA, this); //so callback can call us
@@ -42,6 +44,9 @@ NetworkReadStream::NetworkReadStream(const char *url): _easy(0), _eos(false), _r
curl_easy_setopt(_easy, CURLOPT_HEADER, 0L);
curl_easy_setopt(_easy, CURLOPT_URL, url);
curl_easy_setopt(_easy, CURLOPT_VERBOSE, 0L);
+ curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList);
+ curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, postFields.size());
+ curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, postFields.c_str());
}
NetworkReadStream::~NetworkReadStream() {
diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h
index 0333e4fb16..bc4b761ba7 100644
--- a/backends/networking/curl/networkreadstream.h
+++ b/backends/networking/curl/networkreadstream.h
@@ -28,6 +28,7 @@
#include "common/str.h"
typedef void CURL;
+struct curl_slist;
namespace Networking {
@@ -36,7 +37,7 @@ class NetworkReadStream: public Common::MemoryReadWriteStream {
bool _eos, _requestComplete;
public:
- NetworkReadStream(const char *url);
+ NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields);
virtual ~NetworkReadStream();
CURL *getEasyHandle() const { return _easy; }
diff --git a/base/main.cpp b/base/main.cpp
index ac24376e37..f629eb98d8 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -478,6 +478,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
#endif
#ifdef USE_CLOUD
+ system.getCloudManager()->init();
system.getCloudManager()->syncSaves();
#endif
diff --git a/common/cloudmanager.h b/common/cloudmanager.h
index 6b5768280a..8a10a1a3c7 100644
--- a/common/cloudmanager.h
+++ b/common/cloudmanager.h
@@ -29,8 +29,16 @@ namespace Common {
class CloudManager {
public:
- CloudManager() {};
- virtual ~CloudManager() {};
+ CloudManager() {}
+ virtual ~CloudManager() {}
+
+ /**
+ * Loads all information from configs and creates current Storage instance.
+ *
+ * @note It's called once on startup in scummvm_main().
+ */
+
+ virtual void init() = 0;
/**
* Returns active Storage, which could be used to interact
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index 24c877a4e9..40d8aca219 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -45,6 +45,10 @@ char const *const ConfigManager::kTransientDomain = "__TRANSIENT";
char const *const ConfigManager::kKeymapperDomain = "keymapper";
#endif
+#ifdef USE_CLOUD
+char const *const ConfigManager::kCloudDomain = "cloud";
+#endif
+
#pragma mark -
@@ -67,6 +71,9 @@ void ConfigManager::copyFrom(ConfigManager &source) {
#ifdef ENABLE_KEYMAPPER
_keymapperDomain = source._keymapperDomain;
#endif
+#ifdef USE_CLOUD
+ _cloudDomain = source._cloudDomain;
+#endif
_domainSaveOrder = source._domainSaveOrder;
_activeDomainName = source._activeDomainName;
_activeDomain = &_gameDomains[_activeDomainName];
@@ -121,6 +128,10 @@ void ConfigManager::addDomain(const String &domainName, const ConfigManager::Dom
} else if (domainName == kKeymapperDomain) {
_keymapperDomain = domain;
#endif
+#ifdef USE_CLOUD
+ } else if (domainName == kCloudDomain) {
+ _cloudDomain = domain;
+#endif
} else if (domain.contains("gameid")) {
// If the domain contains "gameid" we assume it's a game domain
if (_gameDomains.contains(domainName))
@@ -160,6 +171,9 @@ void ConfigManager::loadFromStream(SeekableReadStream &stream) {
#ifdef ENABLE_KEYMAPPER
_keymapperDomain.clear();
#endif
+#ifdef USE_CLOUD
+ _cloudDomain.clear();
+#endif
// TODO: Detect if a domain occurs multiple times (or likewise, if
// a key occurs multiple times inside one domain).
@@ -272,6 +286,10 @@ void ConfigManager::flushToDisk() {
// Write the keymapper domain
writeDomain(*stream, kKeymapperDomain, _keymapperDomain);
#endif
+#ifdef USE_CLOUD
+ // Write the cloud domain
+ writeDomain(*stream, kCloudDomain, _cloudDomain);
+#endif
DomainMap::const_iterator d;
@@ -359,6 +377,10 @@ const ConfigManager::Domain *ConfigManager::getDomain(const String &domName) con
if (domName == kKeymapperDomain)
return &_keymapperDomain;
#endif
+#ifdef USE_CLOUD
+ if (domName == kCloudDomain)
+ return &_cloudDomain;
+#endif
if (_gameDomains.contains(domName))
return &_gameDomains[domName];
if (_miscDomains.contains(domName))
@@ -379,6 +401,10 @@ ConfigManager::Domain *ConfigManager::getDomain(const String &domName) {
if (domName == kKeymapperDomain)
return &_keymapperDomain;
#endif
+#ifdef USE_CLOUD
+ if (domName == kCloudDomain)
+ return &_cloudDomain;
+#endif
if (_gameDomains.contains(domName))
return &_gameDomains[domName];
if (_miscDomains.contains(domName))
diff --git a/common/config-manager.h b/common/config-manager.h
index 14f911f69d..669faaaf88 100644
--- a/common/config-manager.h
+++ b/common/config-manager.h
@@ -94,6 +94,11 @@ public:
static char const *const kKeymapperDomain;
#endif
+#ifdef USE_CLOUD
+ /** The name of cloud domain used to store user's tokens */
+ static char const *const kCloudDomain;
+#endif
+
void loadDefaultConfigFile();
void loadConfigFile(const String &filename);
@@ -188,6 +193,10 @@ private:
Domain _keymapperDomain;
#endif
+#ifdef USE_CLOUD
+ Domain _cloudDomain;
+#endif
+
Array<String> _domainSaveOrder;
String _activeDomainName;