mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
Cloud Sync (#15548)
* cloud sync - algorithm and abstract cloud storage API * WebDAV cloud sync driver, and associated net_http improvements * Cloud sync settings menu
This commit is contained in:
parent
45af11efe9
commit
893b0d142e
@ -1490,6 +1490,7 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
|
|||||||
SETTING_ARRAY("bluetooth_driver", settings->arrays.bluetooth_driver, false, NULL, true);
|
SETTING_ARRAY("bluetooth_driver", settings->arrays.bluetooth_driver, false, NULL, true);
|
||||||
SETTING_ARRAY("wifi_driver", settings->arrays.wifi_driver, false, NULL, true);
|
SETTING_ARRAY("wifi_driver", settings->arrays.wifi_driver, false, NULL, true);
|
||||||
SETTING_ARRAY("location_driver", settings->arrays.location_driver,false, NULL, true);
|
SETTING_ARRAY("location_driver", settings->arrays.location_driver,false, NULL, true);
|
||||||
|
SETTING_ARRAY("cloud_sync_driver", settings->arrays.cloud_sync_driver, false, NULL, true);
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
SETTING_ARRAY("menu_driver", settings->arrays.menu_driver, false, NULL, true);
|
SETTING_ARRAY("menu_driver", settings->arrays.menu_driver, false, NULL, true);
|
||||||
#endif
|
#endif
|
||||||
@ -1516,6 +1517,9 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
|
|||||||
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);
|
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);
|
||||||
SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, DEFAULT_MIDI_INPUT, true);
|
SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, DEFAULT_MIDI_INPUT, true);
|
||||||
SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, DEFAULT_MIDI_OUTPUT, true);
|
SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, DEFAULT_MIDI_OUTPUT, true);
|
||||||
|
SETTING_ARRAY("webdav_url", settings->arrays.webdav_url, false, NULL, true);
|
||||||
|
SETTING_ARRAY("webdav_username", settings->arrays.webdav_username, false, NULL, true);
|
||||||
|
SETTING_ARRAY("webdav_password", settings->arrays.webdav_password, false, NULL, true);
|
||||||
SETTING_ARRAY("youtube_stream_key", settings->arrays.youtube_stream_key, true, NULL, true);
|
SETTING_ARRAY("youtube_stream_key", settings->arrays.youtube_stream_key, true, NULL, true);
|
||||||
SETTING_ARRAY("twitch_stream_key", settings->arrays.twitch_stream_key, true, NULL, true);
|
SETTING_ARRAY("twitch_stream_key", settings->arrays.twitch_stream_key, true, NULL, true);
|
||||||
SETTING_ARRAY("facebook_stream_key", settings->arrays.facebook_stream_key, true, NULL, true);
|
SETTING_ARRAY("facebook_stream_key", settings->arrays.facebook_stream_key, true, NULL, true);
|
||||||
@ -1848,6 +1852,8 @@ static struct config_bool_setting *populate_settings_bool(
|
|||||||
SETTING_BOOL("core_updater_show_experimental_cores", &settings->bools.network_buildbot_show_experimental_cores, true, DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES, false);
|
SETTING_BOOL("core_updater_show_experimental_cores", &settings->bools.network_buildbot_show_experimental_cores, true, DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES, false);
|
||||||
SETTING_BOOL("core_updater_auto_backup", &settings->bools.core_updater_auto_backup, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP, false);
|
SETTING_BOOL("core_updater_auto_backup", &settings->bools.core_updater_auto_backup, true, DEFAULT_CORE_UPDATER_AUTO_BACKUP, false);
|
||||||
SETTING_BOOL("camera_allow", &settings->bools.camera_allow, true, false, false);
|
SETTING_BOOL("camera_allow", &settings->bools.camera_allow, true, false, false);
|
||||||
|
SETTING_BOOL("cloud_sync_enable", &settings->bools.cloud_sync_enable, true, false, false);
|
||||||
|
SETTING_BOOL("cloud_sync_destructive", &settings->bools.cloud_sync_destructive, true, false, false);
|
||||||
SETTING_BOOL("discord_allow", &settings->bools.discord_enable, true, false, false);
|
SETTING_BOOL("discord_allow", &settings->bools.discord_enable, true, false, false);
|
||||||
#if defined(VITA)
|
#if defined(VITA)
|
||||||
SETTING_BOOL("input_backtouch_enable", &settings->bools.input_backtouch_enable, false, DEFAULT_INPUT_BACKTOUCH_ENABLE, false);
|
SETTING_BOOL("input_backtouch_enable", &settings->bools.input_backtouch_enable, false, DEFAULT_INPUT_BACKTOUCH_ENABLE, false);
|
||||||
|
@ -427,6 +427,7 @@ typedef struct settings
|
|||||||
char wifi_driver[32];
|
char wifi_driver[32];
|
||||||
char led_driver[32];
|
char led_driver[32];
|
||||||
char location_driver[32];
|
char location_driver[32];
|
||||||
|
char cloud_sync_driver[32];
|
||||||
char menu_driver[32];
|
char menu_driver[32];
|
||||||
char cheevos_username[32];
|
char cheevos_username[32];
|
||||||
char cheevos_password[256];
|
char cheevos_password[256];
|
||||||
@ -460,6 +461,10 @@ typedef struct settings
|
|||||||
|
|
||||||
char translation_service_url[2048];
|
char translation_service_url[2048];
|
||||||
|
|
||||||
|
char webdav_url[255];
|
||||||
|
char webdav_username[255];
|
||||||
|
char webdav_password[255];
|
||||||
|
|
||||||
char youtube_stream_key[PATH_MAX_LENGTH];
|
char youtube_stream_key[PATH_MAX_LENGTH];
|
||||||
char twitch_stream_key[PATH_MAX_LENGTH];
|
char twitch_stream_key[PATH_MAX_LENGTH];
|
||||||
char facebook_stream_key[PATH_MAX_LENGTH];
|
char facebook_stream_key[PATH_MAX_LENGTH];
|
||||||
@ -899,6 +904,10 @@ typedef struct settings
|
|||||||
bool steam_rich_presence_enable;
|
bool steam_rich_presence_enable;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Cloud Sync */
|
||||||
|
bool cloud_sync_enable;
|
||||||
|
bool cloud_sync_destructive;
|
||||||
|
|
||||||
/* Misc. */
|
/* Misc. */
|
||||||
bool discord_enable;
|
bool discord_enable;
|
||||||
bool threaded_data_runloop_enable;
|
bool threaded_data_runloop_enable;
|
||||||
|
@ -1621,3 +1621,12 @@ STEAM INTEGRATION USING MIST
|
|||||||
#ifdef HAVE_PRESENCE
|
#ifdef HAVE_PRESENCE
|
||||||
#include "../network/presence.c"
|
#include "../network/presence.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*============================================================
|
||||||
|
CLOUD SYNC
|
||||||
|
============================================================ */
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
#include "../tasks/task_cloudsync.c"
|
||||||
|
#include "../network/cloud_sync_driver.c"
|
||||||
|
#include "../network/cloud_sync/webdav.c"
|
||||||
|
#endif
|
||||||
|
@ -1409,6 +1409,10 @@ MSG_HASH(
|
|||||||
MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST,
|
||||||
"deferred_saving_settings_list"
|
"deferred_saving_settings_list"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST,
|
||||||
|
"deferred_cloud_sync_settings_list"
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST,
|
MENU_ENUM_LABEL_DEFERRED_THUMBNAILS_UPDATER_LIST,
|
||||||
"deferred_thumbnails_updater_list"
|
"deferred_thumbnails_updater_list"
|
||||||
@ -3483,6 +3487,34 @@ MSG_HASH(
|
|||||||
MENU_ENUM_LABEL_SAVING_SETTINGS,
|
MENU_ENUM_LABEL_SAVING_SETTINGS,
|
||||||
"saving_settings"
|
"saving_settings"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS,
|
||||||
|
"cloud_sync_settings"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_ENABLE,
|
||||||
|
"cloud_sync_enable"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_DESTRUCTIVE,
|
||||||
|
"cloud_sync_destructive"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_DRIVER,
|
||||||
|
"cloud_sync_driver"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_URL,
|
||||||
|
"cloud_sync_url"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME,
|
||||||
|
"cloud_sync_username"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD,
|
||||||
|
"cloud_sync_password"
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_SCAN_DIRECTORY,
|
MENU_ENUM_LABEL_SCAN_DIRECTORY,
|
||||||
"scan_directory"
|
"scan_directory"
|
||||||
|
@ -1204,6 +1204,62 @@ MSG_HASH(
|
|||||||
MENU_ENUM_SUBLABEL_SAVING_SETTINGS,
|
MENU_ENUM_SUBLABEL_SAVING_SETTINGS,
|
||||||
"Change saving settings."
|
"Change saving settings."
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS,
|
||||||
|
"Cloud Sync"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS,
|
||||||
|
"Change cloud sync settings."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE,
|
||||||
|
"Enable Cloud Sync"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE,
|
||||||
|
"Attempt to sync configs, sram, and states to a cloud storage provider."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DESTRUCTIVE,
|
||||||
|
"Destructive Cloud Sync"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_DESTRUCTIVE,
|
||||||
|
"When disabled, files are moved to a backup folder before being overwritten or deleted."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER,
|
||||||
|
"Cloud Sync Backend"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER,
|
||||||
|
"Which cloud storage network protocol to use."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_URL,
|
||||||
|
"Cloud Storage URL"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_URL,
|
||||||
|
"The URL for the API entry point to the cloud storage service."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_USERNAME,
|
||||||
|
"Username"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_USERNAME,
|
||||||
|
"Your username for your cloud storage account."
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD,
|
||||||
|
"Password"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD,
|
||||||
|
"Your password for your cloud storage account."
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS,
|
MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS,
|
||||||
"Logging"
|
"Logging"
|
||||||
|
@ -51,6 +51,9 @@ void net_http_connection_set_user_agent(struct http_connection_t *conn, const ch
|
|||||||
|
|
||||||
void net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);
|
void net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);
|
||||||
|
|
||||||
|
void net_http_connection_set_content(struct http_connection_t *conn, const char *content_type,
|
||||||
|
size_t content_length, const void *content);
|
||||||
|
|
||||||
const char *net_http_connection_url(struct http_connection_t *conn);
|
const char *net_http_connection_url(struct http_connection_t *conn);
|
||||||
|
|
||||||
const char* net_http_connection_method(struct http_connection_t* conn);
|
const char* net_http_connection_method(struct http_connection_t* conn);
|
||||||
@ -93,6 +96,17 @@ int net_http_status(struct http_t *state);
|
|||||||
**/
|
**/
|
||||||
bool net_http_error(struct http_t *state);
|
bool net_http_error(struct http_t *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* net_http_headers:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* @return the response headers. The returned buffer is owned by the
|
||||||
|
* caller of net_http_new; it is not freed by net_http_delete.
|
||||||
|
* If the status is not 20x and accept_error is false, it returns NULL.
|
||||||
|
**/
|
||||||
|
struct string_list *net_http_headers(struct http_t *state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* net_http_data:
|
* net_http_data:
|
||||||
*
|
*
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <lists/string_list.h>
|
||||||
#include <retro_common_api.h>
|
#include <retro_common_api.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ struct http_socket_state_t
|
|||||||
struct http_t
|
struct http_t
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
|
struct string_list *headers;
|
||||||
struct http_socket_state_t sock_state; /* ptr alignment */
|
struct http_socket_state_t sock_state; /* ptr alignment */
|
||||||
size_t pos;
|
size_t pos;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -81,10 +83,11 @@ struct http_connection_t
|
|||||||
char *scan;
|
char *scan;
|
||||||
char *methodcopy;
|
char *methodcopy;
|
||||||
char *contenttypecopy;
|
char *contenttypecopy;
|
||||||
char *postdatacopy;
|
void *postdatacopy;
|
||||||
char *useragentcopy;
|
char *useragentcopy;
|
||||||
char *headerscopy;
|
char *headerscopy;
|
||||||
struct http_socket_state_t sock_state; /* ptr alignment */
|
struct http_socket_state_t sock_state; /* ptr alignment */
|
||||||
|
size_t contentlength;
|
||||||
int port;
|
int port;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -530,7 +533,10 @@ struct http_connection_t *net_http_connection_new(const char *url,
|
|||||||
conn->methodcopy = strdup(method);
|
conn->methodcopy = strdup(method);
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
|
{
|
||||||
conn->postdatacopy = strdup(data);
|
conn->postdatacopy = strdup(data);
|
||||||
|
conn->contentlength = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(conn->urlcopy = strdup(url)))
|
if (!(conn->urlcopy = strdup(url)))
|
||||||
goto error;
|
goto error;
|
||||||
@ -703,6 +709,25 @@ void net_http_connection_set_headers(
|
|||||||
conn->headerscopy = headers ? strdup(headers) : NULL;
|
conn->headerscopy = headers ? strdup(headers) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void net_http_connection_set_content(
|
||||||
|
struct http_connection_t *conn, const char *content_type,
|
||||||
|
size_t content_length, const void *content)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (conn->contenttypecopy)
|
||||||
|
free(conn->contenttypecopy);
|
||||||
|
if (conn->postdatacopy)
|
||||||
|
free(conn->postdatacopy);
|
||||||
|
|
||||||
|
conn->contenttypecopy = content_type ? strdup(content_type) : NULL;
|
||||||
|
conn->contentlength = content_length;
|
||||||
|
if (content_length)
|
||||||
|
{
|
||||||
|
conn->postdatacopy = malloc(content_length);
|
||||||
|
memcpy(conn->postdatacopy, content, content_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *net_http_connection_url(struct http_connection_t *conn)
|
const char *net_http_connection_url(struct http_connection_t *conn)
|
||||||
{
|
{
|
||||||
return conn->urlcopy;
|
return conn->urlcopy;
|
||||||
@ -767,8 +792,7 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||||||
if (conn->headerscopy)
|
if (conn->headerscopy)
|
||||||
net_http_send_str(&conn->sock_state, &error, conn->headerscopy,
|
net_http_send_str(&conn->sock_state, &error, conn->headerscopy,
|
||||||
strlen(conn->headerscopy));
|
strlen(conn->headerscopy));
|
||||||
/* This is not being set anywhere yet */
|
if (conn->contenttypecopy)
|
||||||
else if (conn->contenttypecopy)
|
|
||||||
{
|
{
|
||||||
net_http_send_str(&conn->sock_state, &error, "Content-Type: ",
|
net_http_send_str(&conn->sock_state, &error, "Content-Type: ",
|
||||||
STRLEN_CONST("Content-Type: "));
|
STRLEN_CONST("Content-Type: "));
|
||||||
@ -778,12 +802,12 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||||||
STRLEN_CONST("\r\n"));
|
STRLEN_CONST("\r\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
|
if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST") || string_is_equal(conn->methodcopy, "PUT")))
|
||||||
{
|
{
|
||||||
size_t post_len, len;
|
size_t post_len, len;
|
||||||
char *len_str = NULL;
|
char *len_str = NULL;
|
||||||
|
|
||||||
if (!conn->postdatacopy)
|
if (!conn->postdatacopy && !string_is_equal(conn->methodcopy, "PUT"))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!conn->headerscopy)
|
if (!conn->headerscopy)
|
||||||
@ -799,7 +823,7 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||||||
net_http_send_str(&conn->sock_state, &error, "Content-Length: ",
|
net_http_send_str(&conn->sock_state, &error, "Content-Length: ",
|
||||||
STRLEN_CONST("Content-Length: "));
|
STRLEN_CONST("Content-Length: "));
|
||||||
|
|
||||||
post_len = strlen(conn->postdatacopy);
|
post_len = conn->contentlength;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
len = snprintf(NULL, 0, "%" PRIuPTR, post_len);
|
len = snprintf(NULL, 0, "%" PRIuPTR, post_len);
|
||||||
len_str = (char*)malloc(len + 1);
|
len_str = (char*)malloc(len + 1);
|
||||||
@ -836,9 +860,9 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||||||
net_http_send_str(&conn->sock_state, &error, "\r\n",
|
net_http_send_str(&conn->sock_state, &error, "\r\n",
|
||||||
STRLEN_CONST("\r\n"));
|
STRLEN_CONST("\r\n"));
|
||||||
|
|
||||||
if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
|
if (conn->postdatacopy && conn->contentlength)
|
||||||
net_http_send_str(&conn->sock_state, &error, conn->postdatacopy,
|
net_http_send_str(&conn->sock_state, &error, conn->postdatacopy,
|
||||||
strlen(conn->postdatacopy));
|
conn->contentlength);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
{
|
{
|
||||||
@ -854,7 +878,12 @@ struct http_t *net_http_new(struct http_connection_t *conn)
|
|||||||
state->buflen = 512;
|
state->buflen = 512;
|
||||||
|
|
||||||
if ((state->data = (char*)malloc(state->buflen)))
|
if ((state->data = (char*)malloc(state->buflen)))
|
||||||
|
{
|
||||||
|
if ((state->headers = string_list_new()) &&
|
||||||
|
string_list_initialize(state->headers))
|
||||||
return state;
|
return state;
|
||||||
|
string_list_free(state->headers);
|
||||||
|
}
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,6 +894,8 @@ err:
|
|||||||
free(conn->methodcopy);
|
free(conn->methodcopy);
|
||||||
if (conn->contenttypecopy)
|
if (conn->contenttypecopy)
|
||||||
free(conn->contenttypecopy);
|
free(conn->contenttypecopy);
|
||||||
|
if (conn->postdatacopy)
|
||||||
|
free(conn->postdatacopy);
|
||||||
conn->methodcopy = NULL;
|
conn->methodcopy = NULL;
|
||||||
conn->contenttypecopy = NULL;
|
conn->contenttypecopy = NULL;
|
||||||
conn->postdatacopy = NULL;
|
conn->postdatacopy = NULL;
|
||||||
@ -981,14 +1012,26 @@ bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
|
|||||||
if (string_is_equal_case_insensitive(state->data, "Transfer-Encoding: chunked"))
|
if (string_is_equal_case_insensitive(state->data, "Transfer-Encoding: chunked"))
|
||||||
state->bodytype = T_CHUNK;
|
state->bodytype = T_CHUNK;
|
||||||
|
|
||||||
/* TODO: save headers somewhere */
|
|
||||||
if (state->data[0]=='\0')
|
if (state->data[0]=='\0')
|
||||||
|
{
|
||||||
|
if (state->status == 100)
|
||||||
|
{
|
||||||
|
state->part = P_HEADER_TOP;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
state->part = P_BODY;
|
state->part = P_BODY;
|
||||||
if (state->bodytype == T_CHUNK)
|
if (state->bodytype == T_CHUNK)
|
||||||
state->part = P_BODY_CHUNKLEN;
|
state->part = P_BODY_CHUNKLEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
attr.i = 0;
|
||||||
|
string_list_append(state->headers, state->data, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
memmove(state->data, lineend + 1, dataend-(lineend+1));
|
||||||
state->pos = (dataend-(lineend + 1));
|
state->pos = (dataend-(lineend + 1));
|
||||||
@ -1007,7 +1050,7 @@ bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
|
|||||||
{
|
{
|
||||||
if (state->error)
|
if (state->error)
|
||||||
newlen = -1;
|
newlen = -1;
|
||||||
else
|
else if (state->len)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SSL
|
#ifdef HAVE_SSL
|
||||||
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
if (state->sock_state.ssl && state->sock_state.ssl_ctx)
|
||||||
@ -1158,6 +1201,26 @@ int net_http_status(struct http_t *state)
|
|||||||
return state->status;
|
return state->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* net_http_headers:
|
||||||
|
*
|
||||||
|
* Leaf function.
|
||||||
|
*
|
||||||
|
* @return the response headers. The returned buffer is owned by the
|
||||||
|
* caller of net_http_new; it is not freed by net_http_delete().
|
||||||
|
* If the status is not 20x and accept_error is false, it returns NULL.
|
||||||
|
**/
|
||||||
|
struct string_list *net_http_headers(struct http_t *state)
|
||||||
|
{
|
||||||
|
if (!state)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (state->error)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return state->headers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* net_http_data:
|
* net_http_data:
|
||||||
*
|
*
|
||||||
|
@ -234,12 +234,25 @@ int ssl_socket_send_all_blocking(void *state_data,
|
|||||||
|
|
||||||
mbedtls_net_set_block(&state->net_ctx);
|
mbedtls_net_set_block(&state->net_ctx);
|
||||||
|
|
||||||
while ((ret = mbedtls_ssl_write(&state->ctx, data, size)) <= 0)
|
while (size)
|
||||||
|
{
|
||||||
|
ret = mbedtls_ssl_write(&state->ctx, data, size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
if ( ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
if ( ret != MBEDTLS_ERR_SSL_WANT_READ &&
|
||||||
ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data += ret;
|
||||||
|
size -= ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ enum string_list_type
|
|||||||
STRING_LIST_INPUT_JOYPAD_DRIVERS,
|
STRING_LIST_INPUT_JOYPAD_DRIVERS,
|
||||||
STRING_LIST_INPUT_HID_DRIVERS,
|
STRING_LIST_INPUT_HID_DRIVERS,
|
||||||
STRING_LIST_RECORD_DRIVERS,
|
STRING_LIST_RECORD_DRIVERS,
|
||||||
|
STRING_LIST_CLOUD_SYNC_DRIVERS,
|
||||||
#ifdef HAVE_LAKKA
|
#ifdef HAVE_LAKKA
|
||||||
STRING_LIST_TIMEZONES,
|
STRING_LIST_TIMEZONES,
|
||||||
#endif
|
#endif
|
||||||
|
@ -176,6 +176,7 @@ GENERIC_DEFERRED_PUSH(deferred_push_video_hdr_settings_list, DISPLAYLIST_
|
|||||||
GENERIC_DEFERRED_PUSH(deferred_push_crt_switchres_settings_list, DISPLAYLIST_CRT_SWITCHRES_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_crt_switchres_settings_list, DISPLAYLIST_CRT_SWITCHRES_SETTINGS_LIST)
|
||||||
GENERIC_DEFERRED_PUSH(deferred_push_configuration_settings_list, DISPLAYLIST_CONFIGURATION_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_configuration_settings_list, DISPLAYLIST_CONFIGURATION_SETTINGS_LIST)
|
||||||
GENERIC_DEFERRED_PUSH(deferred_push_saving_settings_list, DISPLAYLIST_SAVING_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_saving_settings_list, DISPLAYLIST_SAVING_SETTINGS_LIST)
|
||||||
|
GENERIC_DEFERRED_PUSH(deferred_push_cloud_sync_settings_list, DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST)
|
||||||
GENERIC_DEFERRED_PUSH(deferred_push_mixer_stream_settings_list, DISPLAYLIST_MIXER_STREAM_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_mixer_stream_settings_list, DISPLAYLIST_MIXER_STREAM_SETTINGS_LIST)
|
||||||
GENERIC_DEFERRED_PUSH(deferred_push_logging_settings_list, DISPLAYLIST_LOGGING_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_logging_settings_list, DISPLAYLIST_LOGGING_SETTINGS_LIST)
|
||||||
GENERIC_DEFERRED_PUSH(deferred_push_frame_throttle_settings_list, DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST)
|
GENERIC_DEFERRED_PUSH(deferred_push_frame_throttle_settings_list, DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST)
|
||||||
@ -702,6 +703,7 @@ static int menu_cbs_init_bind_deferred_push_compare_label(
|
|||||||
{MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST, deferred_push_core_information_list},
|
{MENU_ENUM_LABEL_DEFERRED_CORE_INFORMATION_LIST, deferred_push_core_information_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST, deferred_push_configuration_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST, deferred_push_configuration_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST, deferred_push_saving_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST, deferred_push_saving_settings_list},
|
||||||
|
{MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST, deferred_push_cloud_sync_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST, deferred_push_mixer_stream_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST, deferred_push_mixer_stream_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST, deferred_push_logging_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST, deferred_push_logging_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST, deferred_push_frame_throttle_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST, deferred_push_frame_throttle_settings_list},
|
||||||
@ -1262,8 +1264,11 @@ static int menu_cbs_init_bind_deferred_push_compare_label(
|
|||||||
case MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST:
|
case MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST:
|
||||||
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_saving_settings_list);
|
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_saving_settings_list);
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
|
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_cloud_sync_settings_list);
|
||||||
|
break;
|
||||||
case MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST:
|
case MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST:
|
||||||
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_saving_settings_list);
|
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_logging_settings_list);
|
||||||
break;
|
break;
|
||||||
case MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST:
|
case MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST:
|
||||||
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_frame_throttle_settings_list);
|
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_frame_throttle_settings_list);
|
||||||
|
@ -366,6 +366,8 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl)
|
|||||||
return MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST;
|
return MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST;
|
||||||
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
|
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
|
||||||
return MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST;
|
return MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST;
|
||||||
|
case ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
|
return MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST;
|
||||||
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
|
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
|
||||||
return MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST;
|
return MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST;
|
||||||
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
|
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
|
||||||
@ -1672,6 +1674,7 @@ int generic_action_ok_displaylist_push(
|
|||||||
case ACTION_OK_DL_CRT_SWITCHRES_SETTINGS_LIST:
|
case ACTION_OK_DL_CRT_SWITCHRES_SETTINGS_LIST:
|
||||||
case ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST:
|
case ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST:
|
||||||
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
|
case ACTION_OK_DL_SAVING_SETTINGS_LIST:
|
||||||
|
case ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
|
case ACTION_OK_DL_LOGGING_SETTINGS_LIST:
|
||||||
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
|
case ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST:
|
||||||
case ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST:
|
case ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST:
|
||||||
@ -5924,6 +5927,7 @@ STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_parent_directory_push, ACTION_OK_DL_PARE
|
|||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_directory_push, ACTION_OK_DL_DIRECTORY_PUSH)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_directory_push, ACTION_OK_DL_DIRECTORY_PUSH)
|
||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_configurations_list, ACTION_OK_DL_CONFIGURATIONS_LIST)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_configurations_list, ACTION_OK_DL_CONFIGURATIONS_LIST)
|
||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_saving_list, ACTION_OK_DL_SAVING_SETTINGS_LIST)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_saving_list, ACTION_OK_DL_SAVING_SETTINGS_LIST)
|
||||||
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_cloud_sync_list, ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST)
|
||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_list, ACTION_OK_DL_NETWORK_SETTINGS_LIST)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_list, ACTION_OK_DL_NETWORK_SETTINGS_LIST)
|
||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_hosting_list, ACTION_OK_DL_NETWORK_HOSTING_SETTINGS_LIST)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_network_hosting_list, ACTION_OK_DL_NETWORK_HOSTING_SETTINGS_LIST)
|
||||||
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_kick_list, ACTION_OK_DL_NETPLAY_KICK_LIST)
|
STATIC_DEFAULT_ACTION_OK_FUNC(action_ok_netplay_kick_list, ACTION_OK_DL_NETPLAY_KICK_LIST)
|
||||||
@ -8568,6 +8572,7 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs,
|
|||||||
{MENU_ENUM_LABEL_SUBSYSTEM_LOAD, action_ok_subsystem_add_load},
|
{MENU_ENUM_LABEL_SUBSYSTEM_LOAD, action_ok_subsystem_add_load},
|
||||||
{MENU_ENUM_LABEL_CONFIGURATIONS, action_ok_configurations_list},
|
{MENU_ENUM_LABEL_CONFIGURATIONS, action_ok_configurations_list},
|
||||||
{MENU_ENUM_LABEL_SAVING_SETTINGS, action_ok_saving_list},
|
{MENU_ENUM_LABEL_SAVING_SETTINGS, action_ok_saving_list},
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS, action_ok_cloud_sync_list},
|
||||||
{MENU_ENUM_LABEL_LOGGING_SETTINGS, action_ok_logging_list},
|
{MENU_ENUM_LABEL_LOGGING_SETTINGS, action_ok_logging_list},
|
||||||
{MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS, action_ok_frame_throttle_list},
|
{MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS, action_ok_frame_throttle_list},
|
||||||
{MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, action_ok_frame_time_counter_list},
|
{MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, action_ok_frame_time_counter_list},
|
||||||
|
@ -252,6 +252,13 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_crt_switchres_hires_menu, MENU
|
|||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_driver_settings_list, MENU_ENUM_SUBLABEL_DRIVER_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_driver_settings_list, MENU_ENUM_SUBLABEL_DRIVER_SETTINGS)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_retro_achievements_settings_list, MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_retro_achievements_settings_list, MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_saving_settings_list, MENU_ENUM_SUBLABEL_SAVING_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_saving_settings_list, MENU_ENUM_SUBLABEL_SAVING_SETTINGS)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_settings_list, MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_enable, MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_destructive, MENU_ENUM_SUBLABEL_CLOUD_SYNC_DESTRUCTIVE)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_driver, MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_url, MENU_ENUM_SUBLABEL_CLOUD_SYNC_URL)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_username, MENU_ENUM_SUBLABEL_CLOUD_SYNC_USERNAME)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_cloud_sync_password, MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_logging_settings_list, MENU_ENUM_SUBLABEL_LOGGING_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_logging_settings_list, MENU_ENUM_SUBLABEL_LOGGING_SETTINGS)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_user_interface_settings_list, MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_user_interface_settings_list, MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_ai_service_settings_list, MENU_ENUM_SUBLABEL_AI_SERVICE_SETTINGS)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_ai_service_settings_list, MENU_ENUM_SUBLABEL_AI_SERVICE_SETTINGS)
|
||||||
@ -4784,6 +4791,27 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
|
|||||||
case MENU_ENUM_LABEL_SAVING_SETTINGS:
|
case MENU_ENUM_LABEL_SAVING_SETTINGS:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_saving_settings_list);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_saving_settings_list);
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_settings_list);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_ENABLE:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_enable);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_DESTRUCTIVE:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_destructive);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_DRIVER:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_driver);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_URL:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_url);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_username);
|
||||||
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_cloud_sync_password);
|
||||||
|
break;
|
||||||
case MENU_ENUM_LABEL_LOGGING_SETTINGS:
|
case MENU_ENUM_LABEL_LOGGING_SETTINGS:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_logging_settings_list);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_logging_settings_list);
|
||||||
break;
|
break;
|
||||||
|
@ -629,6 +629,7 @@ DEFAULT_TITLE_MACRO(action_get_dump_disc_list, MENU_ENUM_LABEL_
|
|||||||
DEFAULT_TITLE_MACRO(action_get_eject_disc, MENU_ENUM_LABEL_VALUE_EJECT_DISC)
|
DEFAULT_TITLE_MACRO(action_get_eject_disc, MENU_ENUM_LABEL_VALUE_EJECT_DISC)
|
||||||
#endif
|
#endif
|
||||||
DEFAULT_TITLE_MACRO(action_get_saving_settings_list, MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS)
|
DEFAULT_TITLE_MACRO(action_get_saving_settings_list, MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS)
|
||||||
|
DEFAULT_TITLE_MACRO(action_get_cloud_sync_settings_list, MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS)
|
||||||
DEFAULT_TITLE_MACRO(action_get_logging_settings_list, MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS)
|
DEFAULT_TITLE_MACRO(action_get_logging_settings_list, MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS)
|
||||||
DEFAULT_TITLE_MACRO(action_get_frame_throttle_settings_list, MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS)
|
DEFAULT_TITLE_MACRO(action_get_frame_throttle_settings_list, MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS)
|
||||||
DEFAULT_TITLE_MACRO(action_get_frame_time_counter_settings_list, MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_SETTINGS)
|
DEFAULT_TITLE_MACRO(action_get_frame_time_counter_settings_list, MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_SETTINGS)
|
||||||
@ -989,6 +990,7 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs,
|
|||||||
{MENU_ENUM_LABEL_DEFERRED_LOAD_DISC_LIST, action_get_load_disc_list},
|
{MENU_ENUM_LABEL_DEFERRED_LOAD_DISC_LIST, action_get_load_disc_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST, action_get_configuration_settings_list },
|
{MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST, action_get_configuration_settings_list },
|
||||||
{MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST, action_get_saving_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST, action_get_saving_settings_list},
|
||||||
|
{MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST, action_get_cloud_sync_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST, action_get_logging_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST, action_get_logging_settings_list},
|
||||||
{MENU_ENUM_LABEL_DEFERRED_FRAME_TIME_COUNTER_SETTINGS_LIST, action_get_frame_time_counter_settings_list },
|
{MENU_ENUM_LABEL_DEFERRED_FRAME_TIME_COUNTER_SETTINGS_LIST, action_get_frame_time_counter_settings_list },
|
||||||
{MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST, action_get_frame_throttle_settings_list},
|
{MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST, action_get_frame_throttle_settings_list},
|
||||||
@ -1597,6 +1599,9 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs,
|
|||||||
case MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST:
|
case MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST:
|
||||||
BIND_ACTION_GET_TITLE(cbs, action_get_saving_settings_list);
|
BIND_ACTION_GET_TITLE(cbs, action_get_saving_settings_list);
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
|
BIND_ACTION_GET_TITLE(cbs, action_get_cloud_sync_settings_list);
|
||||||
|
break;
|
||||||
case MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST:
|
case MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST:
|
||||||
BIND_ACTION_GET_TITLE(cbs, action_get_frame_throttle_settings_list);
|
BIND_ACTION_GET_TITLE(cbs, action_get_frame_throttle_settings_list);
|
||||||
break;
|
break;
|
||||||
|
@ -10860,6 +10860,7 @@ static void materialui_list_insert(
|
|||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SIDELOAD_CORE_LIST))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SIDELOAD_CORE_LIST))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CRT_SWITCHRES_SETTINGS))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CRT_SWITCHRES_SETTINGS))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVING_SETTINGS))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVING_SETTINGS))
|
||||||
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOGGING_SETTINGS))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOGGING_SETTINGS))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RECORDING_SETTINGS))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RECORDING_SETTINGS))
|
||||||
|
@ -2125,6 +2125,7 @@ static uintptr_t ozone_entries_icon_get_texture(
|
|||||||
case MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS:
|
case MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS:
|
||||||
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST:
|
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST:
|
||||||
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST:
|
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST:
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS:
|
||||||
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD];
|
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RELOAD];
|
||||||
case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE:
|
case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE:
|
||||||
/* Only show icon in Throttle settings */
|
/* Only show icon in Throttle settings */
|
||||||
|
@ -2956,6 +2956,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
|
|||||||
case MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS:
|
case MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS:
|
||||||
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST:
|
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST:
|
||||||
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST:
|
case MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST:
|
||||||
|
case MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS:
|
||||||
return xmb->textures.list[XMB_TEXTURE_RELOAD];
|
return xmb->textures.list[XMB_TEXTURE_RELOAD];
|
||||||
case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE:
|
case MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE:
|
||||||
/* Only show icon in Throttle settings */
|
/* Only show icon in Throttle settings */
|
||||||
|
@ -120,6 +120,7 @@ enum
|
|||||||
ACTION_OK_DL_LATENCY_SETTINGS_LIST,
|
ACTION_OK_DL_LATENCY_SETTINGS_LIST,
|
||||||
ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST,
|
ACTION_OK_DL_CONFIGURATION_SETTINGS_LIST,
|
||||||
ACTION_OK_DL_SAVING_SETTINGS_LIST,
|
ACTION_OK_DL_SAVING_SETTINGS_LIST,
|
||||||
|
ACTION_OK_DL_CLOUD_SYNC_SETTINGS_LIST,
|
||||||
ACTION_OK_DL_LOGGING_SETTINGS_LIST,
|
ACTION_OK_DL_LOGGING_SETTINGS_LIST,
|
||||||
ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST,
|
ACTION_OK_DL_FRAME_THROTTLE_SETTINGS_LIST,
|
||||||
ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
ACTION_OK_DL_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
||||||
|
@ -10142,6 +10142,9 @@ unsigned menu_displaylist_build_list(
|
|||||||
{MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
|
{MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
|
||||||
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, true},
|
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, true},
|
||||||
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, PARSE_ONLY_BOOL, true},
|
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, PARSE_ONLY_BOOL, true},
|
||||||
|
#if HAVE_CLOUDSYNC
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS, PARSE_ACTION, true},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(build_list); i++)
|
for (i = 0; i < ARRAY_SIZE(build_list); i++)
|
||||||
@ -10169,6 +10172,26 @@ unsigned menu_displaylist_build_list(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
|
{
|
||||||
|
menu_displaylist_build_info_t build_list[] = {
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_ENABLE, PARSE_ONLY_BOOL },
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_DESTRUCTIVE, PARSE_ONLY_BOOL },
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_DRIVER, PARSE_ONLY_STRING_OPTIONS },
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_URL, PARSE_ONLY_STRING },
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME, PARSE_ONLY_STRING },
|
||||||
|
{MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD, PARSE_ONLY_STRING },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(build_list); i++)
|
||||||
|
{
|
||||||
|
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
|
||||||
|
build_list[i].enum_idx, build_list[i].parse_type,
|
||||||
|
false) == 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef HAVE_MIST
|
#ifdef HAVE_MIST
|
||||||
case DISPLAYLIST_STEAM_SETTINGS_LIST:
|
case DISPLAYLIST_STEAM_SETTINGS_LIST:
|
||||||
{
|
{
|
||||||
@ -13637,6 +13660,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case DISPLAYLIST_SAVING_SETTINGS_LIST:
|
case DISPLAYLIST_SAVING_SETTINGS_LIST:
|
||||||
|
case DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST:
|
||||||
case DISPLAYLIST_DRIVER_SETTINGS_LIST:
|
case DISPLAYLIST_DRIVER_SETTINGS_LIST:
|
||||||
case DISPLAYLIST_LOGGING_SETTINGS_LIST:
|
case DISPLAYLIST_LOGGING_SETTINGS_LIST:
|
||||||
case DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST:
|
case DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST:
|
||||||
|
@ -181,6 +181,7 @@ enum menu_displaylist_ctl_state
|
|||||||
DISPLAYLIST_VIDEO_SETTINGS_LIST,
|
DISPLAYLIST_VIDEO_SETTINGS_LIST,
|
||||||
DISPLAYLIST_CONFIGURATION_SETTINGS_LIST,
|
DISPLAYLIST_CONFIGURATION_SETTINGS_LIST,
|
||||||
DISPLAYLIST_SAVING_SETTINGS_LIST,
|
DISPLAYLIST_SAVING_SETTINGS_LIST,
|
||||||
|
DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST,
|
||||||
DISPLAYLIST_LOGGING_SETTINGS_LIST,
|
DISPLAYLIST_LOGGING_SETTINGS_LIST,
|
||||||
DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST,
|
DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST,
|
||||||
DISPLAYLIST_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
DISPLAYLIST_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "../midi_driver.h"
|
#include "../midi_driver.h"
|
||||||
#include "../location_driver.h"
|
#include "../location_driver.h"
|
||||||
|
#include "../network/cloud_sync_driver.h"
|
||||||
#include "../record/record_driver.h"
|
#include "../record/record_driver.h"
|
||||||
#include "../tasks/tasks_internal.h"
|
#include "../tasks/tasks_internal.h"
|
||||||
#include "../config.def.h"
|
#include "../config.def.h"
|
||||||
@ -275,6 +276,7 @@ enum settings_list_type
|
|||||||
SETTINGS_LIST_CONFIGURATION,
|
SETTINGS_LIST_CONFIGURATION,
|
||||||
SETTINGS_LIST_LOGGING,
|
SETTINGS_LIST_LOGGING,
|
||||||
SETTINGS_LIST_SAVING,
|
SETTINGS_LIST_SAVING,
|
||||||
|
SETTINGS_LIST_CLOUD_SYNC,
|
||||||
SETTINGS_LIST_REWIND,
|
SETTINGS_LIST_REWIND,
|
||||||
SETTINGS_LIST_CHEAT_DETAILS,
|
SETTINGS_LIST_CHEAT_DETAILS,
|
||||||
SETTINGS_LIST_CHEAT_SEARCH,
|
SETTINGS_LIST_CHEAT_SEARCH,
|
||||||
@ -2936,8 +2938,8 @@ static void setting_get_string_representation_max_users(rarch_setting_t *setting
|
|||||||
snprintf(s, len, "%d", *setting->value.target.unsigned_integer);
|
snprintf(s, len, "%d", *setting->value.target.unsigned_integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CHEEVOS
|
#if defined(HAVE_CHEEVOS) || defined(HAVE_CLOUDSYNC)
|
||||||
static void setting_get_string_representation_cheevos_password(
|
static void setting_get_string_representation_password(
|
||||||
rarch_setting_t *setting,
|
rarch_setting_t *setting,
|
||||||
char *s, size_t len)
|
char *s, size_t len)
|
||||||
{
|
{
|
||||||
@ -11099,10 +11101,128 @@ static bool setting_append_list(
|
|||||||
general_read_handler,
|
general_read_handler,
|
||||||
SD_FLAG_NONE);
|
SD_FLAG_NONE);
|
||||||
|
|
||||||
|
CONFIG_ACTION(
|
||||||
|
list, list_info,
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group);
|
||||||
|
|
||||||
END_SUB_GROUP(list, list_info, parent_group);
|
END_SUB_GROUP(list, list_info, parent_group);
|
||||||
END_GROUP(list, list_info, parent_group);
|
END_GROUP(list, list_info, parent_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SETTINGS_LIST_CLOUD_SYNC:
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
START_GROUP(list, list_info, &group_info,
|
||||||
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS),
|
||||||
|
parent_group);
|
||||||
|
parent_group = msg_hash_to_str(MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS);
|
||||||
|
START_SUB_GROUP(list, list_info, "State", &group_info, &subgroup_info, parent_group);
|
||||||
|
|
||||||
|
CONFIG_BOOL(
|
||||||
|
list, list_info,
|
||||||
|
&settings->bools.cloud_sync_enable,
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_ENABLE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE,
|
||||||
|
false,
|
||||||
|
MENU_ENUM_LABEL_VALUE_OFF,
|
||||||
|
MENU_ENUM_LABEL_VALUE_ON,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler,
|
||||||
|
SD_FLAG_NONE);
|
||||||
|
|
||||||
|
CONFIG_BOOL(
|
||||||
|
list, list_info,
|
||||||
|
&settings->bools.cloud_sync_destructive,
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_DESTRUCTIVE,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DESTRUCTIVE,
|
||||||
|
false,
|
||||||
|
MENU_ENUM_LABEL_VALUE_OFF,
|
||||||
|
MENU_ENUM_LABEL_VALUE_ON,
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler,
|
||||||
|
SD_FLAG_NONE);
|
||||||
|
|
||||||
|
CONFIG_STRING_OPTIONS(
|
||||||
|
list, list_info,
|
||||||
|
settings->arrays.cloud_sync_driver,
|
||||||
|
sizeof(settings->arrays.cloud_sync_driver),
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_DRIVER,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER,
|
||||||
|
"null",
|
||||||
|
config_get_cloud_sync_driver_options(),
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_read_handler,
|
||||||
|
general_write_handler);
|
||||||
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_IS_DRIVER);
|
||||||
|
(*list)[list_info->index - 1].action_ok = setting_action_ok_uint;
|
||||||
|
(*list)[list_info->index - 1].action_left = setting_string_action_left_driver;
|
||||||
|
(*list)[list_info->index - 1].action_right = setting_string_action_right_driver;
|
||||||
|
|
||||||
|
CONFIG_STRING(
|
||||||
|
list, list_info,
|
||||||
|
settings->arrays.webdav_url,
|
||||||
|
sizeof(settings->arrays.webdav_url),
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_URL,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_URL,
|
||||||
|
"",
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler);
|
||||||
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
||||||
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_STRING_LINE_EDIT;
|
||||||
|
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
||||||
|
|
||||||
|
CONFIG_STRING(
|
||||||
|
list, list_info,
|
||||||
|
settings->arrays.webdav_username,
|
||||||
|
sizeof(settings->arrays.webdav_username),
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_USERNAME,
|
||||||
|
"",
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler);
|
||||||
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
||||||
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_STRING_LINE_EDIT;
|
||||||
|
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
||||||
|
|
||||||
|
CONFIG_STRING(
|
||||||
|
list, list_info,
|
||||||
|
settings->arrays.webdav_password,
|
||||||
|
sizeof(settings->arrays.webdav_password),
|
||||||
|
MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD,
|
||||||
|
MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD,
|
||||||
|
"",
|
||||||
|
&group_info,
|
||||||
|
&subgroup_info,
|
||||||
|
parent_group,
|
||||||
|
general_write_handler,
|
||||||
|
general_read_handler);
|
||||||
|
(*list)[list_info->index - 1].get_string_representation =
|
||||||
|
&setting_get_string_representation_password;
|
||||||
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
||||||
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_PASSWORD_LINE_EDIT;
|
||||||
|
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
||||||
|
|
||||||
|
END_SUB_GROUP(list, list_info, parent_group);
|
||||||
|
END_GROUP(list, list_info, parent_group);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SETTINGS_LIST_FRAME_TIME_COUNTER:
|
case SETTINGS_LIST_FRAME_TIME_COUNTER:
|
||||||
START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_SETTINGS), parent_group);
|
START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FRAME_TIME_COUNTER_SETTINGS), parent_group);
|
||||||
@ -21994,7 +22114,7 @@ static bool setting_append_list(
|
|||||||
general_write_handler,
|
general_write_handler,
|
||||||
general_read_handler);
|
general_read_handler);
|
||||||
(*list)[list_info->index - 1].get_string_representation =
|
(*list)[list_info->index - 1].get_string_representation =
|
||||||
&setting_get_string_representation_cheevos_password;
|
&setting_get_string_representation_password;
|
||||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
||||||
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_PASSWORD_LINE_EDIT;
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_PASSWORD_LINE_EDIT;
|
||||||
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
||||||
@ -22917,6 +23037,7 @@ static rarch_setting_t *menu_setting_new_internal(rarch_setting_info_t *list_inf
|
|||||||
SETTINGS_LIST_CONFIGURATION,
|
SETTINGS_LIST_CONFIGURATION,
|
||||||
SETTINGS_LIST_LOGGING,
|
SETTINGS_LIST_LOGGING,
|
||||||
SETTINGS_LIST_SAVING,
|
SETTINGS_LIST_SAVING,
|
||||||
|
SETTINGS_LIST_CLOUD_SYNC,
|
||||||
SETTINGS_LIST_REWIND,
|
SETTINGS_LIST_REWIND,
|
||||||
SETTINGS_LIST_CHEAT_DETAILS,
|
SETTINGS_LIST_CHEAT_DETAILS,
|
||||||
SETTINGS_LIST_CHEAT_SEARCH,
|
SETTINGS_LIST_CHEAT_SEARCH,
|
||||||
|
@ -1920,6 +1920,7 @@ enum msg_hash_enums
|
|||||||
MENU_ENUM_LABEL_DEFERRED_CRT_SWITCHRES_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_CRT_SWITCHRES_SETTINGS_LIST,
|
||||||
MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST,
|
||||||
MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_SAVING_SETTINGS_LIST,
|
||||||
|
MENU_ENUM_LABEL_DEFERRED_CLOUD_SYNC_SETTINGS_LIST,
|
||||||
MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_FRAME_THROTTLE_SETTINGS_LIST,
|
||||||
MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_REWIND_SETTINGS_LIST,
|
||||||
MENU_ENUM_LABEL_DEFERRED_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
MENU_ENUM_LABEL_DEFERRED_FRAME_TIME_COUNTER_SETTINGS_LIST,
|
||||||
@ -3062,6 +3063,13 @@ enum msg_hash_enums
|
|||||||
MENU_LABEL(CONFIGURATION_SETTINGS),
|
MENU_LABEL(CONFIGURATION_SETTINGS),
|
||||||
MENU_LABEL(LOGGING_SETTINGS),
|
MENU_LABEL(LOGGING_SETTINGS),
|
||||||
MENU_LABEL(SAVING_SETTINGS),
|
MENU_LABEL(SAVING_SETTINGS),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_SETTINGS),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_ENABLE),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_DESTRUCTIVE),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_DRIVER),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_URL),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_USERNAME),
|
||||||
|
MENU_LABEL(CLOUD_SYNC_PASSWORD),
|
||||||
MENU_LABEL(RECORDING_SETTINGS),
|
MENU_LABEL(RECORDING_SETTINGS),
|
||||||
MENU_LABEL(OVERLAY_SETTINGS),
|
MENU_LABEL(OVERLAY_SETTINGS),
|
||||||
MENU_LABEL(REWIND_SETTINGS),
|
MENU_LABEL(REWIND_SETTINGS),
|
||||||
|
803
network/cloud_sync/webdav.c
Normal file
803
network/cloud_sync/webdav.c
Normal file
@ -0,0 +1,803 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <encodings/base64.h>
|
||||||
|
#include <lrc_hash.h>
|
||||||
|
#include <net/net_http.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <time/rtime.h>
|
||||||
|
|
||||||
|
#include "../cloud_sync_driver.h"
|
||||||
|
#include "../../retroarch.h"
|
||||||
|
#include "../../tasks/tasks_internal.h"
|
||||||
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char path[PATH_MAX_LENGTH];
|
||||||
|
char file[PATH_MAX_LENGTH];
|
||||||
|
cloud_sync_complete_handler_t cb;
|
||||||
|
void *user_data;
|
||||||
|
RFILE *rfile;
|
||||||
|
} webdav_cb_state_t;
|
||||||
|
|
||||||
|
typedef void (*webdav_mkdir_cb_t)(bool success, webdav_cb_state_t *state);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
char *last_slash;
|
||||||
|
webdav_mkdir_cb_t cb;
|
||||||
|
webdav_cb_state_t *cb_st;
|
||||||
|
} webdav_mkdir_state_t;
|
||||||
|
|
||||||
|
// TODO: all of this HTTP auth stuff should probably live in libretro-common/net?
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
bool basic;
|
||||||
|
char *basic_auth_header;
|
||||||
|
|
||||||
|
char *username;
|
||||||
|
char *ha1hash;
|
||||||
|
char *realm;
|
||||||
|
char *nonce;
|
||||||
|
char *algo;
|
||||||
|
char *opaque;
|
||||||
|
char *cnonce;
|
||||||
|
bool qop_auth;
|
||||||
|
unsigned nc;
|
||||||
|
char *digest_auth_header;
|
||||||
|
} webdav_state_t;
|
||||||
|
|
||||||
|
static webdav_state_t webdav_driver_st = {0};
|
||||||
|
|
||||||
|
webdav_state_t *webdav_state_get_ptr(void)
|
||||||
|
{
|
||||||
|
return &webdav_driver_st;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_basic_auth(void)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
size_t len = 0;
|
||||||
|
char userpass[512];
|
||||||
|
char *base64auth;
|
||||||
|
int flen;
|
||||||
|
|
||||||
|
if (!string_is_empty(settings->arrays.webdav_username))
|
||||||
|
len += strlcpy(userpass + len, settings->arrays.webdav_username, sizeof(userpass) - len);
|
||||||
|
userpass[len++] = ':';
|
||||||
|
if (!string_is_empty(settings->arrays.webdav_password))
|
||||||
|
len += strlcpy(userpass + len, settings->arrays.webdav_password, sizeof(userpass) - len);
|
||||||
|
userpass[len] = '\0';
|
||||||
|
base64auth = base64(userpass, (int)len, &flen);
|
||||||
|
len = strlcpy(userpass, "Authorization: Basic ", sizeof(userpass));
|
||||||
|
len += strlcpy(userpass + len, base64auth, sizeof(userpass) - len);
|
||||||
|
free(base64auth);
|
||||||
|
userpass[len++] = '\r';
|
||||||
|
userpass[len++] = '\n';
|
||||||
|
userpass[len ] = '\0';
|
||||||
|
|
||||||
|
return strdup(userpass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_cleanup_digest(void)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
|
||||||
|
if (webdav_st->ha1hash)
|
||||||
|
free(webdav_st->ha1hash);
|
||||||
|
webdav_st->ha1hash = NULL;
|
||||||
|
|
||||||
|
if (webdav_st->realm)
|
||||||
|
free(webdav_st->realm);
|
||||||
|
webdav_st->realm = NULL;
|
||||||
|
|
||||||
|
if (webdav_st->nonce)
|
||||||
|
free(webdav_st->nonce);
|
||||||
|
webdav_st->nonce = NULL;
|
||||||
|
|
||||||
|
if (webdav_st->algo)
|
||||||
|
free(webdav_st->algo);
|
||||||
|
webdav_st->algo = NULL;
|
||||||
|
|
||||||
|
if (webdav_st->opaque)
|
||||||
|
free(webdav_st->opaque);
|
||||||
|
webdav_st->opaque = NULL;
|
||||||
|
|
||||||
|
webdav_st->qop_auth = false;
|
||||||
|
webdav_st->nc = 1;
|
||||||
|
|
||||||
|
if (webdav_st->digest_auth_header)
|
||||||
|
free(webdav_st->digest_auth_header);
|
||||||
|
webdav_st->digest_auth_header = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_ha1_hash(char *user, char *realm, char *pass)
|
||||||
|
{
|
||||||
|
char *hash = malloc(33);
|
||||||
|
MD5_CTX md5;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
MD5_Init(&md5);
|
||||||
|
MD5_Update(&md5, user, strlen(user));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, realm, strlen(realm));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, pass, strlen(pass));
|
||||||
|
MD5_Final(digest, &md5);
|
||||||
|
|
||||||
|
snprintf(hash, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||||
|
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
||||||
|
);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_create_digest_auth(char *digest)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
char *ptr = digest + strlen("WWW-Authenticate: Digest ");
|
||||||
|
char *end = ptr + strlen(ptr);
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
if (string_is_empty(settings->arrays.webdav_username) &&
|
||||||
|
string_is_empty(settings->arrays.webdav_password))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
webdav_cleanup_digest();
|
||||||
|
|
||||||
|
webdav_st->username = settings->arrays.webdav_username;
|
||||||
|
|
||||||
|
while (ptr < end)
|
||||||
|
{
|
||||||
|
while (ISSPACE(*ptr))
|
||||||
|
++ptr;
|
||||||
|
|
||||||
|
if (!*ptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (string_starts_with(ptr, "realm=\""))
|
||||||
|
{
|
||||||
|
ptr += strlen("realm=\"");
|
||||||
|
sz = strchr(ptr, '"') + 1 - ptr;
|
||||||
|
webdav_st->realm = malloc(sz);
|
||||||
|
strlcpy(webdav_st->realm, ptr, sz);
|
||||||
|
ptr += sz;
|
||||||
|
|
||||||
|
webdav_st->ha1hash = webdav_create_ha1_hash(webdav_st->username, webdav_st->realm, settings->arrays.webdav_password);
|
||||||
|
}
|
||||||
|
else if (string_starts_with(ptr, "qop=\""))
|
||||||
|
{
|
||||||
|
char *tail;
|
||||||
|
ptr += strlen("qop=\"");
|
||||||
|
tail = strchr(ptr, '"');
|
||||||
|
while (ptr < tail)
|
||||||
|
{
|
||||||
|
if (string_starts_with(ptr, "auth") &&
|
||||||
|
(ptr[4] == ',' || ptr[4] == '"'))
|
||||||
|
{
|
||||||
|
webdav_st->qop_auth = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (*ptr != ',' && *ptr != '"' && *ptr != '\0')
|
||||||
|
ptr++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
/* not even going to try for auth-int, sorry */
|
||||||
|
if (!webdav_st->qop_auth)
|
||||||
|
return false;
|
||||||
|
while (*ptr != ',' && *ptr != '"' && *ptr != '\0')
|
||||||
|
ptr++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else if (string_starts_with(ptr, "nonce=\""))
|
||||||
|
{
|
||||||
|
ptr += strlen("nonce=\"");
|
||||||
|
sz = strchr(ptr, '"') + 1 - ptr;
|
||||||
|
webdav_st->nonce = malloc(sz);
|
||||||
|
strlcpy(webdav_st->nonce, ptr, sz);
|
||||||
|
ptr += sz;
|
||||||
|
}
|
||||||
|
else if (string_starts_with(ptr, "algorithm="))
|
||||||
|
{
|
||||||
|
ptr += strlen("algorithm=");
|
||||||
|
sz = strchr(ptr, ',') + 1 - ptr;
|
||||||
|
webdav_st->algo = malloc(sz);
|
||||||
|
strlcpy(webdav_st->algo, ptr, sz);
|
||||||
|
ptr += sz;
|
||||||
|
}
|
||||||
|
else if (string_starts_with(ptr, "opaque=\""))
|
||||||
|
{
|
||||||
|
ptr += strlen("opaque=\"");
|
||||||
|
sz = strchr(ptr, '"') + 1 - ptr;
|
||||||
|
webdav_st->opaque = malloc(sz);
|
||||||
|
strlcpy(webdav_st->opaque, ptr, sz);
|
||||||
|
ptr += sz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (*ptr != '=' && *ptr != '\0')
|
||||||
|
ptr++;
|
||||||
|
ptr++;
|
||||||
|
if (*ptr == '"')
|
||||||
|
{
|
||||||
|
ptr++;
|
||||||
|
while (*ptr != '"' && *ptr != '\0')
|
||||||
|
ptr++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (*ptr != ',' && *ptr != ',')
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ISSPACE(*ptr))
|
||||||
|
++ptr;
|
||||||
|
if (*ptr == ',')
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!webdav_st->ha1hash || !webdav_st->nonce)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
webdav_st->cnonce = "1a2b3c4f";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_ha1(void)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char *hash;
|
||||||
|
MD5_CTX md5;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
if (!string_is_equal(webdav_st->algo, "MD5-sess"))
|
||||||
|
return strdup(webdav_st->ha1hash);
|
||||||
|
|
||||||
|
hash = malloc(33);
|
||||||
|
|
||||||
|
MD5_Init(&md5);
|
||||||
|
MD5_Update(&md5, webdav_st->ha1hash, 32);
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, webdav_st->nonce, strlen(webdav_st->nonce));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, webdav_st->cnonce, strlen(webdav_st->cnonce));
|
||||||
|
MD5_Final(digest, &md5);
|
||||||
|
|
||||||
|
snprintf(hash, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||||
|
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
||||||
|
);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_ha2(const char *method, const char *path)
|
||||||
|
{
|
||||||
|
/* no attempt at supporting auth-int, everything else uses this */
|
||||||
|
char *hash = malloc(33);
|
||||||
|
MD5_CTX md5;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
MD5_Init(&md5);
|
||||||
|
MD5_Update(&md5, method, strlen(method));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, path, strlen(path));
|
||||||
|
MD5_Final(digest, &md5);
|
||||||
|
|
||||||
|
snprintf(hash, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||||
|
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
||||||
|
);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_digest_response(const char *method, const char *path)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char *ha1 = webdav_create_ha1();
|
||||||
|
char *ha2 = webdav_create_ha2(method, path);
|
||||||
|
char *hash = malloc(33);
|
||||||
|
MD5_CTX md5;
|
||||||
|
unsigned char digest[16];
|
||||||
|
|
||||||
|
MD5_Init(&md5);
|
||||||
|
MD5_Update(&md5, ha1, 32);
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, webdav_st->nonce, strlen(webdav_st->nonce));
|
||||||
|
if (webdav_st->qop_auth)
|
||||||
|
{
|
||||||
|
char nonceCount[10];
|
||||||
|
snprintf(nonceCount, sizeof(nonceCount), "%08x", webdav_st->nc);
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, nonceCount, strlen(nonceCount));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, webdav_st->cnonce, strlen(webdav_st->cnonce));
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, "auth", strlen("auth"));
|
||||||
|
}
|
||||||
|
MD5_Update(&md5, ":", 1);
|
||||||
|
MD5_Update(&md5, ha2, 32);
|
||||||
|
MD5_Final(digest, &md5);
|
||||||
|
|
||||||
|
snprintf(hash, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||||
|
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
||||||
|
);
|
||||||
|
|
||||||
|
free(ha1);
|
||||||
|
free(ha2);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_create_digest_auth_header(const char *method, const char *url)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char *header;
|
||||||
|
char *response;
|
||||||
|
char nonceCount[10];
|
||||||
|
const char *path = url;
|
||||||
|
int count = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
size_t total = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
path++;
|
||||||
|
path = strchr(path, '/');
|
||||||
|
count++;
|
||||||
|
} while (count < 3 && *path != '\0');
|
||||||
|
|
||||||
|
response = webdav_create_digest_response(method, path);
|
||||||
|
snprintf(nonceCount, sizeof(nonceCount), "%08x", webdav_st->nc);
|
||||||
|
|
||||||
|
len = strlen("Authorization: Digest ");
|
||||||
|
len += strlen("username=\"") + strlen(webdav_st->username) + strlen("\", ");
|
||||||
|
len += strlen("realm=\"") + strlen(webdav_st->realm) + strlen("\", ");
|
||||||
|
len += strlen("nonce=\"") + strlen(webdav_st->nonce) + strlen("\", ");
|
||||||
|
len += strlen("uri=\"") + strlen(path) + strlen("\", ");
|
||||||
|
len += strlen("nc=\"") + strlen(nonceCount) + strlen("\", ");
|
||||||
|
len += strlen("cnonce=\"") + strlen(webdav_st->cnonce) + strlen("\", ");
|
||||||
|
if (webdav_st->qop_auth)
|
||||||
|
len += strlen("qop=\"auth\", ");
|
||||||
|
if (webdav_st->opaque)
|
||||||
|
len += strlen("opaque=\"") + strlen(webdav_st->opaque) + strlen("\", ");
|
||||||
|
len += strlen("response=\"") + strlen(response) + strlen("\"\r\n");
|
||||||
|
len += 1;
|
||||||
|
|
||||||
|
total = len;
|
||||||
|
len = 0;
|
||||||
|
header = malloc(total);
|
||||||
|
len = strlcpy(header, "Authorization: Digest username=\"", total - len);
|
||||||
|
len += strlcpy(header + len, webdav_st->username, total - len);
|
||||||
|
len += strlcpy(header + len, "\", realm=\"", total - len);
|
||||||
|
len += strlcpy(header + len, webdav_st->realm, total - len);
|
||||||
|
len += strlcpy(header + len, "\", nonce=\"", total - len);
|
||||||
|
len += strlcpy(header + len, webdav_st->nonce, total - len);
|
||||||
|
len += strlcpy(header + len, "\", uri=\"", total - len);
|
||||||
|
len += strlcpy(header + len, path, total - len);
|
||||||
|
len += strlcpy(header + len, "\", nc=\"", total - len);
|
||||||
|
len += strlcpy(header + len, nonceCount, total - len);
|
||||||
|
len += strlcpy(header + len, "\", cnonce=\"", total - len);
|
||||||
|
len += strlcpy(header + len, webdav_st->cnonce, total - len);
|
||||||
|
if (webdav_st->qop_auth)
|
||||||
|
len += strlcpy(header + len, "\", qop=\"auth", total - len);
|
||||||
|
if (webdav_st->opaque)
|
||||||
|
{
|
||||||
|
len += strlcpy(header + len, "\", opaque=\"", total - len);
|
||||||
|
len += strlcpy(header + len, webdav_st->opaque, total - len);
|
||||||
|
}
|
||||||
|
len += strlcpy(header + len, "\", response=\"", total - len);
|
||||||
|
len += strlcpy(header + len, response, total - len);
|
||||||
|
len += strlcpy(header + len, "\"\r\n", total - len);
|
||||||
|
|
||||||
|
free(response);
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *webdav_get_auth_header(const char *method, const char *url)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
if (string_is_empty(settings->arrays.webdav_username) &&
|
||||||
|
string_is_empty(settings->arrays.webdav_password))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (webdav_st->basic)
|
||||||
|
{
|
||||||
|
if (!webdav_st->basic_auth_header)
|
||||||
|
webdav_st->basic_auth_header = webdav_create_basic_auth();
|
||||||
|
return webdav_st->basic_auth_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webdav_st->digest_auth_header)
|
||||||
|
free(webdav_st->digest_auth_header);
|
||||||
|
webdav_st->digest_auth_header = webdav_create_digest_auth_header(method, url);
|
||||||
|
return webdav_st->digest_auth_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_stat_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
bool success = (data && data->status >= 200 && data->status < 300);
|
||||||
|
|
||||||
|
if (!webdav_cb_st)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (data && data->status == 401 && data->headers && webdav_st->basic == true)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
webdav_st->basic = false;
|
||||||
|
for (i = 0; i < data->headers->size; i++)
|
||||||
|
{
|
||||||
|
if (!string_starts_with(data->headers->elems[i].data, "WWW-Authenticate: Digest "))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (webdav_create_digest_auth(data->headers->elems[i].data))
|
||||||
|
{
|
||||||
|
task_push_webdav_stat(webdav_st->url, true,
|
||||||
|
webdav_get_auth_header("OPTIONS", webdav_st->url),
|
||||||
|
webdav_stat_cb, webdav_cb_st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, NULL, success, NULL);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_sync_begin(cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
const char *url = settings->arrays.webdav_url;
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
const char *auth_header;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// TODO: LOCK?
|
||||||
|
|
||||||
|
strlcpy(webdav_st->url, url, sizeof(webdav_st->url));
|
||||||
|
fill_pathname_slash(webdav_st->url, sizeof(webdav_st->url));
|
||||||
|
|
||||||
|
/* url/username/password may have changed, redo auth check */
|
||||||
|
webdav_st->basic = true;
|
||||||
|
auth_header = webdav_get_auth_header(NULL, NULL);
|
||||||
|
|
||||||
|
if (auth_header)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t*)calloc(1, sizeof(webdav_cb_state_t));
|
||||||
|
webdav_cb_st->cb = cb;
|
||||||
|
webdav_cb_st->user_data = user_data;
|
||||||
|
task_push_webdav_stat(webdav_st->url, true, auth_header, webdav_stat_cb, webdav_cb_st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cb(user_data, NULL, true, NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_sync_end(cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
|
||||||
|
// TODO: UNLOCK?
|
||||||
|
|
||||||
|
if (webdav_st->basic_auth_header)
|
||||||
|
free(webdav_st->basic_auth_header);
|
||||||
|
webdav_st->basic_auth_header = NULL;
|
||||||
|
|
||||||
|
webdav_cleanup_digest();
|
||||||
|
|
||||||
|
cb(user_data, NULL, true, NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_read_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
RFILE *file = NULL;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
success = (data &&
|
||||||
|
((data->status >= 200 && data->status < 300) || data->status == 404));
|
||||||
|
|
||||||
|
// TODO: it's possible we get a 401 here and need to redo the auth check with this request
|
||||||
|
if (data && data->data && webdav_cb_st)
|
||||||
|
{
|
||||||
|
// TODO: it would be better if writing to the file happened during the network reads
|
||||||
|
file = filestream_open(webdav_cb_st->file,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
filestream_write(file, data->data, data->len);
|
||||||
|
filestream_seek(file, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, file);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_read(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t*)calloc(1, sizeof(webdav_cb_state_t));
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
char url_encoded[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, path, sizeof(url));
|
||||||
|
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||||
|
|
||||||
|
webdav_cb_st->cb = cb;
|
||||||
|
webdav_cb_st->user_data = user_data;
|
||||||
|
strlcpy(webdav_cb_st->path, path, sizeof(webdav_cb_st->path));
|
||||||
|
strlcpy(webdav_cb_st->file, file, sizeof(webdav_cb_st->file));
|
||||||
|
|
||||||
|
task_push_http_transfer_with_headers(url_encoded, true, NULL,
|
||||||
|
webdav_get_auth_header("GET", url_encoded),
|
||||||
|
webdav_read_cb, webdav_cb_st);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_mkdir_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_mkdir_state_t *webdav_mkdir_st = (webdav_mkdir_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
|
||||||
|
if (!webdav_mkdir_st)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: it's possible we get a 401 here and need to redo the auth check with this request
|
||||||
|
if (!data || data->status < 200 || data->status >= 400)
|
||||||
|
{
|
||||||
|
webdav_mkdir_st->cb(false, webdav_mkdir_st->cb_st);
|
||||||
|
free(webdav_mkdir_st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*webdav_mkdir_st->last_slash++ = '/';
|
||||||
|
webdav_mkdir_st->last_slash = strchr(webdav_mkdir_st->last_slash, '/');
|
||||||
|
if (webdav_mkdir_st->last_slash)
|
||||||
|
{
|
||||||
|
*webdav_mkdir_st->last_slash = '\0';
|
||||||
|
task_push_webdav_mkdir(webdav_mkdir_st->url, true,
|
||||||
|
webdav_get_auth_header("MVCOL", webdav_mkdir_st->url),
|
||||||
|
webdav_mkdir_cb, webdav_mkdir_st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
webdav_mkdir_st->cb(true, webdav_mkdir_st->cb_st);
|
||||||
|
free(webdav_mkdir_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_ensure_dir(const char *dir, webdav_mkdir_cb_t cb, webdav_cb_state_t *webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
webdav_mkdir_state_t *webdav_mkdir_st = (webdav_mkdir_state_t *)malloc(sizeof(webdav_mkdir_state_t));
|
||||||
|
http_transfer_data_t data;
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, dir, sizeof(url));
|
||||||
|
net_http_urlencode_full(webdav_mkdir_st->url, url, sizeof(webdav_mkdir_st->url));
|
||||||
|
webdav_mkdir_st->last_slash = strchr(webdav_mkdir_st->url + strlen(webdav_st->url) - 1, '/');
|
||||||
|
webdav_mkdir_st->cb = cb;
|
||||||
|
webdav_mkdir_st->cb_st = webdav_cb_st;
|
||||||
|
|
||||||
|
/* this is a recursive callback, set it up so it looks like it's still proceeding */
|
||||||
|
data.status = 200;
|
||||||
|
webdav_mkdir_cb(NULL, &data, webdav_mkdir_st, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_update_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
bool success = (data && data->status >= 200 && data->status < 300);
|
||||||
|
|
||||||
|
// TODO: it's possible we get a 401 here and need to redo the auth check with this request
|
||||||
|
if (webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, webdav_cb_st->rfile);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_do_update(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char url_encoded[PATH_MAX_LENGTH];
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
void *buf;
|
||||||
|
int64_t len;
|
||||||
|
|
||||||
|
if (!webdav_cb_st)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, false, webdav_cb_st->rfile);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: would be better to read file as it's being written to wire, this is very inefficient
|
||||||
|
len = filestream_get_size(webdav_cb_st->rfile);
|
||||||
|
buf = malloc((size_t)(len + 1));
|
||||||
|
filestream_read(webdav_cb_st->rfile, buf, len);
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, webdav_cb_st->path, sizeof(url));
|
||||||
|
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||||
|
|
||||||
|
task_push_webdav_put(url_encoded, buf, len, true,
|
||||||
|
webdav_get_auth_header("PUT", url_encoded),
|
||||||
|
webdav_update_cb, webdav_cb_st);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_update(const char *path, RFILE *rfile, cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t*)calloc(1, sizeof(webdav_cb_state_t));
|
||||||
|
char dir[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
// TODO: if !settings->bools.cloud_sync_destructive, should move to deleted/ first
|
||||||
|
|
||||||
|
webdav_cb_st->cb = cb;
|
||||||
|
webdav_cb_st->user_data = user_data;
|
||||||
|
strlcpy(webdav_cb_st->path, path, sizeof(webdav_cb_st->path));
|
||||||
|
webdav_cb_st->rfile = rfile;
|
||||||
|
|
||||||
|
if (strchr(path, '/'))
|
||||||
|
{
|
||||||
|
fill_pathname_basedir(dir, path, sizeof(dir));
|
||||||
|
webdav_ensure_dir(dir, webdav_do_update, webdav_cb_st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
webdav_do_update(true, webdav_cb_st);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_delete_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
bool success = (data != NULL && data->status >= 200 && data->status < 300);
|
||||||
|
|
||||||
|
// TODO: it's possible we get a 401 here and need to redo the auth check with this request
|
||||||
|
if (webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, NULL);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_backup_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
bool success = (data != NULL && data->status >= 200 && data->status < 300);
|
||||||
|
|
||||||
|
// TODO: it's possible we get a 401 here and need to redo the auth check with this request
|
||||||
|
if (webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, NULL);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void webdav_do_backup(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char dest_encoded[PATH_MAX_LENGTH];
|
||||||
|
char dest[PATH_MAX_LENGTH];
|
||||||
|
char url_encoded[PATH_MAX_LENGTH];
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
size_t len;
|
||||||
|
struct tm tm_;
|
||||||
|
time_t cur_time = time(NULL);
|
||||||
|
|
||||||
|
if (!webdav_cb_st)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, false, NULL);
|
||||||
|
free(webdav_cb_st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, webdav_cb_st->path, sizeof(url));
|
||||||
|
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, "deleted/", sizeof(url));
|
||||||
|
len = fill_pathname_join_special(dest, url, webdav_cb_st->path, sizeof(dest));
|
||||||
|
rtime_localtime(&cur_time, &tm_);
|
||||||
|
strftime(dest + len, sizeof(dest) - len, "-%y%m%d-%H%M%S", &tm_);
|
||||||
|
net_http_urlencode_full(dest_encoded, dest, sizeof(dest_encoded));
|
||||||
|
|
||||||
|
task_push_webdav_move(url_encoded, dest_encoded, true,
|
||||||
|
webdav_get_auth_header("MOVE", url_encoded),
|
||||||
|
webdav_backup_cb, webdav_cb_st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool webdav_delete(const char *path, cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t*)calloc(1, sizeof(webdav_cb_state_t));
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
webdav_cb_st->cb = cb;
|
||||||
|
webdav_cb_st->user_data = user_data;
|
||||||
|
strlcpy(webdav_cb_st->path, path, sizeof(webdav_cb_st->path));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should all cloud_sync_destructive handling be done in task_cloudsync? I
|
||||||
|
* think not because it gives each driver a chance to do a move rather than a
|
||||||
|
* delete/update. Or we could add a cloud_sync_move() API to the driver.
|
||||||
|
*/
|
||||||
|
if (settings->bools.cloud_sync_destructive)
|
||||||
|
{
|
||||||
|
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||||
|
char url_encoded[PATH_MAX_LENGTH];
|
||||||
|
char url[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
fill_pathname_join_special(url, webdav_st->url, path, sizeof(url));
|
||||||
|
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||||
|
|
||||||
|
task_push_webdav_delete(url_encoded, true,
|
||||||
|
webdav_get_auth_header("DELETE", url_encoded),
|
||||||
|
webdav_delete_cb, webdav_cb_st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char dir[PATH_MAX_LENGTH] = {0};
|
||||||
|
size_t _len;
|
||||||
|
_len = strlcat(dir, "deleted/", sizeof(dir));
|
||||||
|
fill_pathname_basedir(dir + _len, path, sizeof(dir) - _len);
|
||||||
|
webdav_ensure_dir(dir, webdav_do_backup, webdav_cb_st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cloud_sync_driver_t cloud_sync_webdav = {
|
||||||
|
webdav_sync_begin,
|
||||||
|
webdav_sync_end,
|
||||||
|
webdav_read,
|
||||||
|
webdav_update,
|
||||||
|
webdav_delete,
|
||||||
|
"webdav" /* ident */
|
||||||
|
};
|
126
network/cloud_sync_driver.c
Normal file
126
network/cloud_sync_driver.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cloud_sync_driver.h"
|
||||||
|
#include "../list_special.h"
|
||||||
|
#include "../retroarch.h"
|
||||||
|
#include "../verbosity.h"
|
||||||
|
|
||||||
|
static cloud_sync_driver_t cloud_sync_null = {
|
||||||
|
NULL, /* sync_begin */
|
||||||
|
NULL, /* sync_end */
|
||||||
|
NULL, /* read */
|
||||||
|
NULL, /* update */
|
||||||
|
NULL, /* delete */
|
||||||
|
"null" /* ident */
|
||||||
|
};
|
||||||
|
|
||||||
|
const cloud_sync_driver_t *cloud_sync_drivers[] = {
|
||||||
|
&cloud_sync_webdav,
|
||||||
|
&cloud_sync_null,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static cloud_sync_driver_state_t cloud_sync_driver_st = {0};
|
||||||
|
|
||||||
|
cloud_sync_driver_state_t *cloud_sync_state_get_ptr(void)
|
||||||
|
{
|
||||||
|
return &cloud_sync_driver_st;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config_get_cloud_sync_driver_options:
|
||||||
|
*
|
||||||
|
* Get an enumerated list of all cloud sync driver names, separated by '|'.
|
||||||
|
*
|
||||||
|
* @return string listing of all cloud sync driver names, separated by '|'.
|
||||||
|
**/
|
||||||
|
const char* config_get_cloud_sync_driver_options(void)
|
||||||
|
{
|
||||||
|
return char_list_new_special(STRING_LIST_CLOUD_SYNC_DRIVERS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cloud_sync_find_driver(
|
||||||
|
settings_t *settings,
|
||||||
|
const char *prefix,
|
||||||
|
bool verbosity_enabled)
|
||||||
|
{
|
||||||
|
cloud_sync_driver_state_t
|
||||||
|
*cloud_sync_st = &cloud_sync_driver_st;
|
||||||
|
int i = (int)driver_find_index(
|
||||||
|
"cloud_sync_driver",
|
||||||
|
settings->arrays.cloud_sync_driver);
|
||||||
|
|
||||||
|
if (i >= 0)
|
||||||
|
cloud_sync_st->driver = (const cloud_sync_driver_t*)
|
||||||
|
cloud_sync_drivers[i];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbosity_enabled)
|
||||||
|
{
|
||||||
|
unsigned d;
|
||||||
|
RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
|
||||||
|
settings->arrays.cloud_sync_driver);
|
||||||
|
|
||||||
|
RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
|
||||||
|
for (d = 0; cloud_sync_drivers[d]; d++)
|
||||||
|
RARCH_LOG_OUTPUT("\t%s\n", cloud_sync_drivers[d]->ident);
|
||||||
|
|
||||||
|
RARCH_WARN("Going to default to first %s...\n", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
cloud_sync_st->driver = (const cloud_sync_driver_t*)cloud_sync_drivers[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cloud_sync_begin(cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver = cloud_sync_state_get_ptr()->driver;
|
||||||
|
if (driver && driver->sync_begin)
|
||||||
|
return driver->sync_begin(cb, user_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cloud_sync_end(cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver = cloud_sync_state_get_ptr()->driver;
|
||||||
|
if (driver && driver->sync_end)
|
||||||
|
return driver->sync_end(cb, user_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cloud_sync_read(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver = cloud_sync_state_get_ptr()->driver;
|
||||||
|
if (driver && driver->read)
|
||||||
|
return driver->read(path, file, cb, user_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cloud_sync_update(const char *path, RFILE *file,
|
||||||
|
cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver = cloud_sync_state_get_ptr()->driver;
|
||||||
|
if (driver && driver->update)
|
||||||
|
return driver->update(path, file, cb, user_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cloud_sync_delete(const char *path, cloud_sync_complete_handler_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver = cloud_sync_state_get_ptr()->driver;
|
||||||
|
if (driver && driver->delete)
|
||||||
|
return driver->delete(path, cb, user_data);
|
||||||
|
return false;
|
||||||
|
}
|
77
network/cloud_sync_driver.h
Normal file
77
network/cloud_sync_driver.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CLOUD_SYNC_DRIVER__H
|
||||||
|
#define __CLOUD_SYNC_DRIVER__H
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
|
||||||
|
#include "../configuration.h"
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a read, `success' indicates whether we successfully communicated with the
|
||||||
|
* server. We may ask to read a file that doesn't exist; in that case, `success'
|
||||||
|
* is true and `file' is NULL. `file' is expected to be close()'d by the handler
|
||||||
|
* if non-NULL.
|
||||||
|
*/
|
||||||
|
typedef void (*cloud_sync_complete_handler_t)(void *user_data, const char *path, bool success, RFILE *file);
|
||||||
|
|
||||||
|
typedef struct cloud_sync_driver
|
||||||
|
{
|
||||||
|
bool (*sync_begin)(cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool (*sync_end)(cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
|
||||||
|
bool (*read)(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool (*update)(const char *path, RFILE *file, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool (*delete)(const char *path, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
|
||||||
|
const char *ident;
|
||||||
|
} cloud_sync_driver_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const cloud_sync_driver_t *driver;
|
||||||
|
} cloud_sync_driver_state_t;
|
||||||
|
|
||||||
|
cloud_sync_driver_state_t *cloud_sync_state_get_ptr(void);
|
||||||
|
|
||||||
|
extern cloud_sync_driver_t cloud_sync_webdav;
|
||||||
|
|
||||||
|
extern const cloud_sync_driver_t *cloud_sync_drivers[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config_get_cloud_sync_driver_options:
|
||||||
|
*
|
||||||
|
* Get an enumerated list of all cloud_sync driver names, separated by '|'.
|
||||||
|
*
|
||||||
|
* Returns: string listing of all cloud_sync driver names, separated by '|'.
|
||||||
|
**/
|
||||||
|
const char* config_get_cloud_sync_driver_options(void);
|
||||||
|
|
||||||
|
void cloud_sync_find_driver(settings_t *settings, const char *prefix, bool verbosity_enabled);
|
||||||
|
|
||||||
|
bool cloud_sync_begin(cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool cloud_sync_end(cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
|
||||||
|
bool cloud_sync_read(const char *path, const char *file, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool cloud_sync_update(const char *path, RFILE *file, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
bool cloud_sync_delete(const char *path, cloud_sync_complete_handler_t cb, void *user_data);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
@ -18,6 +18,7 @@ OTHER_CFLAGS = $(inherited) -DHAVE_CC_RESAMPLER
|
|||||||
OTHER_CFLAGS = $(inherited) -DHAVE_CHD
|
OTHER_CFLAGS = $(inherited) -DHAVE_CHD
|
||||||
OTHER_CFLAGS = $(inherited) -DHAVE_CHEATS
|
OTHER_CFLAGS = $(inherited) -DHAVE_CHEATS
|
||||||
OTHER_CFLAGS = $(inherited) -DHAVE_CHEEVOS
|
OTHER_CFLAGS = $(inherited) -DHAVE_CHEEVOS
|
||||||
|
OTHER_CFLAGS = $(inherited) -DHAVE_CLOUDSYNC
|
||||||
OTHER_CFLAGS = $(inherited) -DHAVE_COCOA_METAL
|
OTHER_CFLAGS = $(inherited) -DHAVE_COCOA_METAL
|
||||||
OTHER_CFLAGS = $(inherited) -DHAVE_COMMAND
|
OTHER_CFLAGS = $(inherited) -DHAVE_COMMAND
|
||||||
OTHER_CFLAGS = $(inherited) -DHAVE_CONFIGFILE
|
OTHER_CFLAGS = $(inherited) -DHAVE_CONFIGFILE
|
||||||
|
@ -1596,6 +1596,7 @@
|
|||||||
"-DHAVE_CC_RESAMPLER",
|
"-DHAVE_CC_RESAMPLER",
|
||||||
"-DHAVE_CHEATS",
|
"-DHAVE_CHEATS",
|
||||||
"-DHAVE_CHEEVOS",
|
"-DHAVE_CHEEVOS",
|
||||||
|
"-DHAVE_CLOUDSYNC",
|
||||||
"-DHAVE_COCOATOUCH",
|
"-DHAVE_COCOATOUCH",
|
||||||
"-DHAVE_COCOA_METAL",
|
"-DHAVE_COCOA_METAL",
|
||||||
"-DHAVE_CONFIGFILE",
|
"-DHAVE_CONFIGFILE",
|
||||||
@ -1743,6 +1744,7 @@
|
|||||||
"-DHAVE_CC_RESAMPLER",
|
"-DHAVE_CC_RESAMPLER",
|
||||||
"-DHAVE_CHEATS",
|
"-DHAVE_CHEATS",
|
||||||
"-DHAVE_CHEEVOS",
|
"-DHAVE_CHEEVOS",
|
||||||
|
"-DHAVE_CLOUDSYNC",
|
||||||
"-DHAVE_COCOATOUCH",
|
"-DHAVE_COCOATOUCH",
|
||||||
"-DHAVE_COCOA_METAL",
|
"-DHAVE_COCOA_METAL",
|
||||||
"-DHAVE_CONFIGFILE",
|
"-DHAVE_CONFIGFILE",
|
||||||
@ -1918,6 +1920,7 @@
|
|||||||
"-DHAVE_CC_RESAMPLER",
|
"-DHAVE_CC_RESAMPLER",
|
||||||
"-DHAVE_CHEATS",
|
"-DHAVE_CHEATS",
|
||||||
"-DHAVE_CHEEVOS",
|
"-DHAVE_CHEEVOS",
|
||||||
|
"-DHAVE_CLOUDSYNC",
|
||||||
"-DHAVE_COCOATOUCH",
|
"-DHAVE_COCOATOUCH",
|
||||||
"-DHAVE_COCOA_METAL",
|
"-DHAVE_COCOA_METAL",
|
||||||
"-DHAVE_CONFIGFILE",
|
"-DHAVE_CONFIGFILE",
|
||||||
@ -2082,6 +2085,7 @@
|
|||||||
"-DHAVE_CC_RESAMPLER",
|
"-DHAVE_CC_RESAMPLER",
|
||||||
"-DHAVE_CHEATS",
|
"-DHAVE_CHEATS",
|
||||||
"-DHAVE_CHEEVOS",
|
"-DHAVE_CHEEVOS",
|
||||||
|
"-DHAVE_CLOUDSYNC",
|
||||||
"-DHAVE_COCOATOUCH",
|
"-DHAVE_COCOATOUCH",
|
||||||
"-DHAVE_COCOA_METAL",
|
"-DHAVE_COCOA_METAL",
|
||||||
"-DHAVE_CONFIGFILE",
|
"-DHAVE_CONFIGFILE",
|
||||||
|
36
retroarch.c
36
retroarch.c
@ -164,6 +164,9 @@
|
|||||||
#ifdef HAVE_WIFI
|
#ifdef HAVE_WIFI
|
||||||
#include "network/wifi_driver.h"
|
#include "network/wifi_driver.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
#include "network/cloud_sync_driver.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
@ -498,6 +501,18 @@ static const void *find_driver_nonempty(
|
|||||||
return wifi_drivers[i];
|
return wifi_drivers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
else if (string_is_equal(label, "cloud_sync_driver"))
|
||||||
|
{
|
||||||
|
if (cloud_sync_drivers[i])
|
||||||
|
{
|
||||||
|
const char *ident = cloud_sync_drivers[i]->ident;
|
||||||
|
|
||||||
|
strlcpy(s, ident, len);
|
||||||
|
return cloud_sync_drivers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1606,6 +1621,17 @@ struct string_list *string_list_new_special(enum string_list_type type,
|
|||||||
string_list_append(s, opt, attr);
|
string_list_append(s, opt, attr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case STRING_LIST_CLOUD_SYNC_DRIVERS:
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
for (i = 0; cloud_sync_drivers[i]; i++)
|
||||||
|
{
|
||||||
|
const char *opt = cloud_sync_drivers[i]->ident;
|
||||||
|
*len += STRLEN_CONST(cloud_sync_drivers[i]->ident) + 1;
|
||||||
|
|
||||||
|
string_list_append(s, opt, attr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
#ifdef HAVE_LAKKA
|
#ifdef HAVE_LAKKA
|
||||||
case STRING_LIST_TIMEZONES:
|
case STRING_LIST_TIMEZONES:
|
||||||
{
|
{
|
||||||
@ -2796,6 +2822,9 @@ bool command_event(enum event_command cmd, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
task_push_cloud_sync();
|
||||||
|
#endif
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
runloop_st->runtime_shader_preset_path[0] = '\0';
|
runloop_st->runtime_shader_preset_path[0] = '\0';
|
||||||
#endif
|
#endif
|
||||||
@ -4883,6 +4912,9 @@ int rarch_main(int argc, char *argv[], void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui_companion_driver_init_first();
|
ui_companion_driver_init_first();
|
||||||
|
#if HAVE_CLOUDSYNC
|
||||||
|
task_push_cloud_sync();
|
||||||
|
#endif
|
||||||
#if !defined(HAVE_MAIN) || defined(HAVE_QT)
|
#if !defined(HAVE_MAIN) || defined(HAVE_QT)
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -6519,6 +6551,10 @@ bool retroarch_main_init(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_WIFI
|
#ifdef HAVE_WIFI
|
||||||
wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
|
wifi_driver_ctl(RARCH_WIFI_CTL_FIND_DRIVER, NULL);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_CLOUDSYNC
|
||||||
|
cloud_sync_find_driver(settings,
|
||||||
|
"cloud sync driver", verbosity_enabled);
|
||||||
#endif
|
#endif
|
||||||
location_driver_find_driver(settings,
|
location_driver_find_driver(settings,
|
||||||
"location driver", verbosity_enabled);
|
"location driver", verbosity_enabled);
|
||||||
|
1064
tasks/task_cloudsync.c
Normal file
1064
tasks/task_cloudsync.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -177,6 +177,7 @@ task_finished:
|
|||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char *tmp = (char*)net_http_data(http->handle, &len, false);
|
char *tmp = (char*)net_http_data(http->handle, &len, false);
|
||||||
|
struct string_list *headers = net_http_headers(http->handle);
|
||||||
|
|
||||||
if (tmp && http->cb)
|
if (tmp && http->cb)
|
||||||
http->cb(tmp, len);
|
http->cb(tmp, len);
|
||||||
@ -188,6 +189,7 @@ task_finished:
|
|||||||
{
|
{
|
||||||
if (tmp)
|
if (tmp)
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
string_list_free(headers);
|
||||||
|
|
||||||
task_set_error(task,
|
task_set_error(task,
|
||||||
strldup("Task cancelled.", sizeof("Task cancelled.")));
|
strldup("Task cancelled.", sizeof("Task cancelled.")));
|
||||||
@ -196,6 +198,7 @@ task_finished:
|
|||||||
{
|
{
|
||||||
data = (http_transfer_data_t*)malloc(sizeof(*data));
|
data = (http_transfer_data_t*)malloc(sizeof(*data));
|
||||||
data->data = tmp;
|
data->data = tmp;
|
||||||
|
data->headers = headers;
|
||||||
data->len = len;
|
data->len = len;
|
||||||
data->status = net_http_status(http->handle);
|
data->status = net_http_status(http->handle);
|
||||||
|
|
||||||
@ -219,6 +222,7 @@ static void task_http_transfer_cleanup(retro_task_t *task)
|
|||||||
http_transfer_data_t* data = (http_transfer_data_t*)task_get_data(task);
|
http_transfer_data_t* data = (http_transfer_data_t*)task_get_data(task);
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
|
string_list_free(data->headers);
|
||||||
if (data->data)
|
if (data->data)
|
||||||
free(data->data);
|
free(data->data);
|
||||||
free(data);
|
free(data);
|
||||||
@ -346,6 +350,112 @@ void* task_push_http_transfer(const char *url, bool mute,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *task_push_webdav_stat(const char *url, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct http_connection_t *conn;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(conn = net_http_connection_new(url, "OPTIONS", NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (headers)
|
||||||
|
net_http_connection_set_headers(conn, headers);
|
||||||
|
|
||||||
|
return task_push_http_transfer_generic(conn, url, mute, NULL, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* task_push_webdav_mkdir(const char *url, bool mute,
|
||||||
|
const char *headers,
|
||||||
|
retro_task_callback_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct http_connection_t *conn;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(conn = net_http_connection_new(url, "MKCOL", NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (headers)
|
||||||
|
net_http_connection_set_headers(conn, headers);
|
||||||
|
|
||||||
|
return task_push_http_transfer_generic(conn, url, mute, NULL, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* task_push_webdav_put(const char *url,
|
||||||
|
const void *put_data, size_t len, bool mute,
|
||||||
|
const char *headers, retro_task_callback_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct http_connection_t *conn;
|
||||||
|
char expect[1024];
|
||||||
|
size_t _len;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(conn = net_http_connection_new(url, "PUT", NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
_len = strlcpy(expect, "Expect: 100-continue\r\n", sizeof(expect));
|
||||||
|
if (headers)
|
||||||
|
{
|
||||||
|
strlcpy(expect + _len, headers, sizeof(expect) - _len);
|
||||||
|
net_http_connection_set_headers(conn, expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (put_data)
|
||||||
|
net_http_connection_set_content(conn, NULL, len, put_data);
|
||||||
|
|
||||||
|
return task_push_http_transfer_generic(conn, url, mute, NULL, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* task_push_webdav_delete(const char *url, bool mute,
|
||||||
|
const char *headers,
|
||||||
|
retro_task_callback_t cb, void *user_data)
|
||||||
|
{
|
||||||
|
struct http_connection_t *conn;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(conn = net_http_connection_new(url, "DELETE", NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (headers)
|
||||||
|
net_http_connection_set_headers(conn, headers);
|
||||||
|
|
||||||
|
return task_push_http_transfer_generic(conn, url, mute, NULL, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *task_push_webdav_move(const char *url,
|
||||||
|
const char *dest, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata)
|
||||||
|
{
|
||||||
|
struct http_connection_t *conn;
|
||||||
|
char dest_header[PATH_MAX_LENGTH + 512];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (string_is_empty(url))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(conn = net_http_connection_new(url, "MOVE", NULL)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = strlcpy(dest_header, "Destination: ", sizeof(dest_header));
|
||||||
|
len += strlcpy(dest_header + len, dest, sizeof(dest_header) - len);
|
||||||
|
len += strlcpy(dest_header + len, "\r\n", sizeof(dest_header) - len);
|
||||||
|
|
||||||
|
if (headers)
|
||||||
|
strlcpy(dest_header + len, headers, sizeof(dest_header) - len);
|
||||||
|
|
||||||
|
net_http_connection_set_headers(conn, dest_header);
|
||||||
|
|
||||||
|
return task_push_http_transfer_generic(conn, url, mute, NULL, cb, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
void* task_push_http_transfer_file(const char* url, bool mute,
|
void* task_push_http_transfer_file(const char* url, bool mute,
|
||||||
const char* type,
|
const char* type,
|
||||||
retro_task_callback_t cb, file_transfer_t* transfer_data)
|
retro_task_callback_t cb, file_transfer_t* transfer_data)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_common_api.h>
|
#include <retro_common_api.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <lists/string_list.h>
|
||||||
|
|
||||||
#include <queues/task_queue.h>
|
#include <queues/task_queue.h>
|
||||||
#include <gfx/scaler/scaler.h>
|
#include <gfx/scaler/scaler.h>
|
||||||
@ -85,6 +86,7 @@ struct screenshot_task_state
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
|
struct string_list *headers;
|
||||||
size_t len;
|
size_t len;
|
||||||
int status;
|
int status;
|
||||||
} http_transfer_data_t;
|
} http_transfer_data_t;
|
||||||
@ -109,6 +111,17 @@ void *task_push_http_post_transfer_with_headers(const char *url, const char *pos
|
|||||||
|
|
||||||
task_retriever_info_t *http_task_get_transfer_list(void);
|
task_retriever_info_t *http_task_get_transfer_list(void);
|
||||||
|
|
||||||
|
void *task_push_webdav_stat(const char *url, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata);
|
||||||
|
void *task_push_webdav_mkdir(const char *url, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata);
|
||||||
|
void *task_push_webdav_put(const char *url, const void *put_data, size_t len, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata);
|
||||||
|
void *task_push_webdav_delete(const char *url, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata);
|
||||||
|
void *task_push_webdav_move(const char *url, const char *dest, bool mute, const char *headers,
|
||||||
|
retro_task_callback_t cb, void *userdata);
|
||||||
|
|
||||||
bool task_push_bluetooth_scan(retro_task_callback_t cb);
|
bool task_push_bluetooth_scan(retro_task_callback_t cb);
|
||||||
|
|
||||||
bool task_push_wifi_scan(retro_task_callback_t cb);
|
bool task_push_wifi_scan(retro_task_callback_t cb);
|
||||||
@ -292,6 +305,9 @@ void menu_explore_wait_for_init_task(void);
|
|||||||
|
|
||||||
extern const char* const input_builtin_autoconfs[];
|
extern const char* const input_builtin_autoconfs[];
|
||||||
|
|
||||||
|
/* cloud sync tasks */
|
||||||
|
void task_push_cloud_sync(void);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user