2016-05-11 13:45:10 +06:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
2016-05-15 00:31:02 +06:00
# define FORBIDDEN_SYMBOL_ALLOW_ALL
2016-05-11 13:45:10 +06:00
2016-05-11 20:24:53 +06:00
# include "backends/cloud/dropbox/dropboxstorage.h"
2016-05-24 00:14:24 +06:00
# include "backends/cloud/dropbox/dropboxlistdirectoryrequest.h"
2016-05-24 11:57:49 +06:00
# include "backends/cloud/downloadrequest.h"
2016-05-18 15:21:09 +06:00
# include "backends/networking/curl/connectionmanager.h"
2016-05-17 01:19:49 +06:00
# include "backends/networking/curl/curljsonrequest.h"
2016-05-18 14:08:05 +06:00
# include "common/config-manager.h"
2016-05-11 13:45:10 +06:00
# include "common/debug.h"
2016-05-17 01:19:49 +06:00
# include "common/json.h"
2016-05-15 00:31:02 +06:00
# include <curl/curl.h>
2016-05-24 12:31:27 +06:00
# include <common/file.h>
2016-05-11 01:10:37 +06:00
2016-05-12 18:52:57 +06:00
namespace Cloud {
namespace Dropbox {
2016-05-11 01:10:37 +06:00
2016-05-18 14:08:05 +06:00
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
2016-05-21 21:30:25 +06:00
static void saveAccessTokenCallback ( void * ptr ) {
2016-05-17 01:19:49 +06:00
Common : : JSONValue * json = ( Common : : JSONValue * ) ptr ;
if ( json ) {
2016-05-18 14:08:05 +06:00
debug ( " saveAccessTokenCallback: " ) ;
2016-05-17 01:19:49 +06:00
debug ( " %s " , json - > stringify ( true ) . c_str ( ) ) ;
2016-05-18 14:08:05 +06:00
Common : : JSONObject result = json - > asObject ( ) ;
if ( ! result . contains ( " access_token " ) | | ! result . contains ( " uid " ) ) {
warning ( " Bad response, no token/uid passed " ) ;
} else {
2016-05-23 11:23:33 +06:00
//we suppose that's the first storage
ConfMan . set ( " storages_number " , " 1 " , " cloud " ) ;
ConfMan . set ( " current_storage " , " 1 " , " cloud " ) ;
ConfMan . set ( " storage1_type " , " Dropbox " , " cloud " ) ;
ConfMan . set ( " storage1_access_token " , result . getVal ( " access_token " ) - > asString ( ) , " cloud " ) ;
ConfMan . set ( " storage1_user_id " , result . getVal ( " uid " ) - > asString ( ) , " cloud " ) ;
2016-05-18 14:08:05 +06:00
ConfMan . removeKey ( " dropbox_code " , " cloud " ) ;
debug ( " Now please restart ScummVM to apply the changes. " ) ;
}
2016-05-17 01:19:49 +06:00
delete json ;
} else {
2016-05-18 14:08:05 +06:00
debug ( " saveAccessTokenCallback: got NULL instead of JSON! " ) ;
2016-05-17 01:19:49 +06:00
}
2016-05-15 00:31:02 +06:00
}
2016-05-18 14:08:05 +06:00
DropboxStorage : : DropboxStorage ( Common : : String accessToken , Common : : String userId ) : _token ( accessToken ) , _uid ( userId ) {
2016-05-15 00:31:02 +06:00
curl_global_init ( CURL_GLOBAL_ALL ) ;
}
DropboxStorage : : ~ DropboxStorage ( ) {
curl_global_cleanup ( ) ;
2016-05-11 01:10:37 +06:00
}
2016-05-23 11:23:33 +06:00
void DropboxStorage : : saveConfig ( Common : : String keyPrefix ) {
ConfMan . set ( keyPrefix + " type " , " Dropbox " , " cloud " ) ;
ConfMan . set ( keyPrefix + " access_token " , _token , " cloud " ) ;
ConfMan . set ( keyPrefix + " user_id " , _uid , " cloud " ) ;
}
2016-05-24 00:14:24 +06:00
void DropboxStorage : : printFiles ( Common : : Array < StorageFile > files ) {
debug ( " files: " ) ;
for ( uint32 i = 0 ; i < files . size ( ) ; + + i )
debug ( " \t %s " , files [ i ] . name ( ) . c_str ( ) ) ;
2016-05-23 12:21:45 +06:00
}
void DropboxStorage : : listDirectory ( Common : : String path , FileArrayCallback outerCallback , bool recursive ) {
2016-05-24 00:14:24 +06:00
ConnMan . addRequest ( new DropboxListDirectoryRequest ( _token , path , outerCallback , recursive ) ) ;
2016-05-23 12:21:45 +06:00
}
2016-05-24 11:57:49 +06:00
Networking : : NetworkReadStream * DropboxStorage : : streamFile ( Common : : String path ) {
Common : : JSONObject jsonRequestParameters ;
jsonRequestParameters . setVal ( " path " , new Common : : JSONValue ( path ) ) ;
Common : : JSONValue value ( jsonRequestParameters ) ;
Networking : : CurlRequest * request = new Networking : : CurlRequest ( 0 , " https://content.dropboxapi.com/2/files/download " ) ;
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)
return request - > execute ( ) ;
}
2016-05-24 12:31:27 +06:00
void DropboxStorage : : download ( Common : : String remotePath , Common : : String localPath , BoolCallback callback ) {
Common : : DumpFile * f = new Common : : DumpFile ( ) ;
if ( ! f - > open ( localPath ) ) {
warning ( " DropboxStorage: unable to open file to download into " ) ;
if ( callback ) ( * callback ) ( false ) ;
delete f ;
return ;
}
ConnMan . addRequest ( new DownloadRequest ( callback , streamFile ( remotePath ) , f ) ) ;
2016-05-24 11:57:49 +06:00
}
2016-05-22 00:04:00 +06:00
void DropboxStorage : : syncSaves ( BoolCallback callback ) {
2016-05-23 12:21:45 +06:00
//this is not the real syncSaves() implementation
2016-05-24 00:14:24 +06:00
//"" is root in Dropbox, not "/"
2016-05-24 11:57:49 +06:00
//listDirectory("", new Common::Callback<DropboxStorage, Common::Array<StorageFile> >(this, &DropboxStorage::printFiles), true);
2016-05-24 12:31:27 +06:00
download ( " /remote/test.jpg " , " local/test.jpg " , 0 ) ;
2016-05-21 14:06:50 +06:00
}
2016-05-22 00:04:00 +06:00
void DropboxStorage : : info ( StorageInfoCallback outerCallback ) {
2016-05-21 23:21:42 +06:00
Common : : BaseCallback < > * innerCallback = new Common : : CallbackBridge < DropboxStorage , StorageInfo > ( this , & DropboxStorage : : infoInnerCallback , outerCallback ) ;
Networking : : CurlJsonRequest * request = new Networking : : CurlJsonRequest ( innerCallback , " https://api.dropboxapi.com/1/account/info " ) ;
2016-05-18 14:08:05 +06:00
request - > addHeader ( " Authorization: Bearer " + _token ) ;
2016-05-18 15:21:09 +06:00
ConnMan . addRequest ( request ) ;
2016-05-21 23:21:42 +06:00
//that callback bridge wraps the outerCallback (passed in arguments from user) into innerCallback
//so, when CurlJsonRequest is finished, it calls the innerCallback
//innerCallback (which is DropboxStorage::infoInnerCallback in this case) processes the void *ptr
//and then calls the outerCallback (which wants to receive StorageInfo, not void *)
2016-05-18 14:08:05 +06:00
}
2016-05-22 00:04:00 +06:00
void DropboxStorage : : infoInnerCallback ( StorageInfoCallback outerCallback , void * jsonPointer ) {
Common : : JSONValue * json = ( Common : : JSONValue * ) jsonPointer ;
2016-05-21 23:21:42 +06:00
if ( ! json ) {
warning ( " NULL passed instead of JSON " ) ;
delete outerCallback ;
return ;
}
2016-05-23 12:00:12 +06:00
if ( outerCallback ) {
//Dropbox documentation states there is no errors for this API method
Common : : JSONObject info = json - > asObject ( ) ;
Common : : String uid = Common : : String : : format ( " %d " , info . getVal ( " uid " ) - > asNumber ( ) ) ;
Common : : String name = info . getVal ( " display_name " ) - > asString ( ) ;
Common : : String email = info . getVal ( " email " ) - > asString ( ) ;
Common : : JSONObject quota = info . getVal ( " quota_info " ) - > asObject ( ) ;
uint32 quotaNormal = quota . getVal ( " normal " ) - > asNumber ( ) ;
uint32 quotaShared = quota . getVal ( " shared " ) - > asNumber ( ) ;
uint32 quotaAllocated = quota . getVal ( " quota " ) - > asNumber ( ) ;
( * outerCallback ) ( StorageInfo ( uid , name , email , quotaNormal + quotaShared , quotaAllocated ) ) ;
2016-05-21 23:21:42 +06:00
delete outerCallback ;
}
delete json ;
2016-05-21 21:30:25 +06:00
}
2016-05-21 23:21:42 +06:00
void DropboxStorage : : infoMethodCallback ( StorageInfo storageInfo ) {
2016-05-23 12:00:12 +06:00
debug ( " \n Storage info: " ) ;
debug ( " User name: %s " , storageInfo . name ( ) . c_str ( ) ) ;
debug ( " Email: %s " , storageInfo . email ( ) . c_str ( ) ) ;
debug ( " Disk usage: %u/%u " , storageInfo . used ( ) , storageInfo . available ( ) ) ;
2016-05-21 14:06:50 +06:00
}
2016-05-23 11:23:33 +06:00
DropboxStorage * DropboxStorage : : loadFromConfig ( Common : : String keyPrefix ) {
2016-05-18 14:08:05 +06:00
KEY = ConfMan . get ( " DROPBOX_KEY " , " cloud " ) ;
SECRET = ConfMan . get ( " DROPBOX_SECRET " , " cloud " ) ;
2016-05-23 11:23:33 +06:00
if ( ! ConfMan . hasKey ( keyPrefix + " access_token " , " cloud " ) ) {
2016-05-18 14:08:05 +06:00
warning ( " No access_token found " ) ;
return 0 ;
}
2016-05-23 11:23:33 +06:00
if ( ! ConfMan . hasKey ( keyPrefix + " user_id " , " cloud " ) ) {
2016-05-18 14:08:05 +06:00
warning ( " No user_id found " ) ;
return 0 ;
}
2016-05-23 11:23:33 +06:00
Common : : String accessToken = ConfMan . get ( keyPrefix + " access_token " , " cloud " ) ;
Common : : String userId = ConfMan . get ( keyPrefix + " user_id " , " cloud " ) ;
2016-05-18 14:08:05 +06:00
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 ;
}
2016-05-18 15:21:09 +06:00
void DropboxStorage : : authThroughConsole ( ) {
2016-05-18 14:08:05 +06:00
if ( ! ConfMan . hasKey ( " DROPBOX_KEY " , " cloud " ) | | ! ConfMan . hasKey ( " DROPBOX_SECRET " , " cloud " ) ) {
warning ( " No Dropbox keys available, cannot do auth " ) ;
2016-05-18 15:21:09 +06:00
return ;
2016-05-18 14:08:05 +06:00
}
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
2016-05-18 15:21:09 +06:00
getAccessToken ( ConfMan . get ( " dropbox_code " , " cloud " ) ) ;
return ;
2016-05-18 14:08:05 +06:00
}
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: " ) ;
2016-05-18 15:21:09 +06:00
debug ( " http://wiki.scummvm.org/index.php/User_Manual/Configuring_ScummVM#Using_the_configuration_file_to_configure_ScummVM \n " ) ;
2016-05-18 14:08:05 +06:00
}
2016-05-18 15:21:09 +06:00
void DropboxStorage : : getAccessToken ( Common : : String code ) {
2016-05-21 23:21:42 +06:00
Common : : BaseCallback < > * callback = new Common : : GlobalFunctionCallback ( saveAccessTokenCallback ) ;
2016-05-21 21:30:25 +06:00
Networking : : CurlJsonRequest * request = new Networking : : CurlJsonRequest ( callback , " https://api.dropboxapi.com/1/oauth2/token " ) ;
2016-05-18 14:08:05 +06:00
request - > addPostField ( " code= " + code ) ;
request - > addPostField ( " grant_type=authorization_code " ) ;
request - > addPostField ( " client_id= " + KEY ) ;
request - > addPostField ( " client_secret= " + SECRET ) ;
2016-05-18 15:21:09 +06:00
request - > addPostField ( " &redirect_uri=http%3A%2F%2Flocalhost%3A12345%2F " ) ;
ConnMan . addRequest ( request ) ;
2016-05-11 15:15:23 +06:00
}
2016-05-12 18:52:57 +06:00
} //end of namespace Dropbox
} //end of namespace Cloud