Major refactor to networking, including a fix for an incorrect error message on cancelling the swkbd for downloads
This commit is contained in:
@@ -52,6 +52,6 @@
|
|||||||
#define CACHE_PATH_FORMAT "/3ds/" APP_TITLE "/cache/%" JSON_INTEGER_FORMAT
|
#define CACHE_PATH_FORMAT "/3ds/" APP_TITLE "/cache/%" JSON_INTEGER_FORMAT
|
||||||
|
|
||||||
bool themeplaza_browser(EntryMode mode);
|
bool themeplaza_browser(EntryMode mode);
|
||||||
u32 http_get(const char *url, char ** filename, char ** buf, InstallType install_type, const char *mime_type);
|
Result http_get(const char *url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -332,7 +332,19 @@ bool init_qr(void)
|
|||||||
draw_install(INSTALL_DOWNLOAD);
|
draw_install(INSTALL_DOWNLOAD);
|
||||||
char * zip_buf = NULL;
|
char * zip_buf = NULL;
|
||||||
char * filename = NULL;
|
char * filename = NULL;
|
||||||
u32 zip_size = http_get((char*)scan_data->payload, &filename, &zip_buf, INSTALL_DOWNLOAD, "application/zip");
|
u32 zip_size;
|
||||||
|
Result res = http_get((char*)scan_data->payload, &filename, &zip_buf, &zip_size, INSTALL_DOWNLOAD, "application/zip");
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(filename);
|
||||||
|
free(zip_buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (R_DESCRIPTION(res) == RD_CANCEL_REQUESTED)
|
||||||
|
{
|
||||||
|
free(filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if(zip_size != 0)
|
if(zip_size != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
224
source/remote.c
224
source/remote.c
@@ -128,7 +128,12 @@ static C2D_Image * load_remote_smdh(Entry_s * entry, bool ignore_cache)
|
|||||||
smdh_buf = NULL;
|
smdh_buf = NULL;
|
||||||
char * api_url = NULL;
|
char * api_url = NULL;
|
||||||
asprintf(&api_url, THEMEPLAZA_SMDH_FORMAT, entry->tp_download_id);
|
asprintf(&api_url, THEMEPLAZA_SMDH_FORMAT, entry->tp_download_id);
|
||||||
smdh_size = http_get(api_url, NULL, &smdh_buf, INSTALL_NONE, "application/octet-stream");
|
Result res = http_get(api_url, NULL, &smdh_buf, &smdh_size, INSTALL_NONE, "application/octet-stream");
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(smdh_buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
free(api_url);
|
free(api_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,8 +210,14 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod
|
|||||||
char * page_json = NULL;
|
char * page_json = NULL;
|
||||||
char * api_url = NULL;
|
char * api_url = NULL;
|
||||||
asprintf(&api_url, THEMEPLAZA_PAGE_FORMAT, page, mode + 1, list->tp_search);
|
asprintf(&api_url, THEMEPLAZA_PAGE_FORMAT, page, mode + 1, list->tp_search);
|
||||||
u32 json_len = http_get(api_url, NULL, &page_json, INSTALL_NONE, "application/json");
|
u32 json_len;
|
||||||
|
Result res = http_get(api_url, NULL, &page_json, &json_len, INSTALL_NONE, "application/json");
|
||||||
free(api_url);
|
free(api_url);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(page_json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (json_len)
|
if (json_len)
|
||||||
{
|
{
|
||||||
@@ -266,9 +277,13 @@ static bool load_remote_preview(Entry_s * entry, C2D_Image * preview_image, int
|
|||||||
asprintf(&preview_url, THEMEPLAZA_PREVIEW_FORMAT, entry->tp_download_id);
|
asprintf(&preview_url, THEMEPLAZA_PREVIEW_FORMAT, entry->tp_download_id);
|
||||||
|
|
||||||
draw_install(INSTALL_LOADING_REMOTE_PREVIEW);
|
draw_install(INSTALL_LOADING_REMOTE_PREVIEW);
|
||||||
|
Result res = http_get(preview_url, NULL, &preview_png, &preview_size, INSTALL_LOADING_REMOTE_PREVIEW, "image/png");
|
||||||
preview_size = http_get(preview_url, NULL, &preview_png, INSTALL_LOADING_REMOTE_PREVIEW, "image/png");
|
|
||||||
free(preview_url);
|
free(preview_url);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(preview_png);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preview_size)
|
if (!preview_size)
|
||||||
@@ -312,8 +327,13 @@ static void load_remote_bgm(Entry_s * entry)
|
|||||||
|
|
||||||
draw_install(INSTALL_LOADING_REMOTE_BGM);
|
draw_install(INSTALL_LOADING_REMOTE_BGM);
|
||||||
|
|
||||||
bgm_size = http_get(bgm_url, NULL, &bgm_ogg, INSTALL_LOADING_REMOTE_BGM, "application/ogg, audio/ogg");
|
Result res = http_get(bgm_url, NULL, &bgm_ogg, &bgm_size, INSTALL_LOADING_REMOTE_BGM, "application/ogg, audio/ogg");
|
||||||
free(bgm_url);
|
free(bgm_url);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
free(bgm_ogg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
u16 path[0x107] = { 0 };
|
u16 path[0x107] = { 0 };
|
||||||
strucat(path, entry->path);
|
strucat(path, entry->path);
|
||||||
@@ -335,7 +355,13 @@ static void download_remote_entry(Entry_s * entry, EntryMode mode)
|
|||||||
char * zip_buf = NULL;
|
char * zip_buf = NULL;
|
||||||
char * filename = NULL;
|
char * filename = NULL;
|
||||||
draw_install(INSTALL_DOWNLOAD);
|
draw_install(INSTALL_DOWNLOAD);
|
||||||
u32 zip_size = http_get(download_url, &filename, &zip_buf, INSTALL_DOWNLOAD, "application/zip");
|
u32 zip_size;
|
||||||
|
if(R_FAILED(http_get(download_url, &filename, &zip_buf, &zip_size, INSTALL_DOWNLOAD, "application/zip")))
|
||||||
|
{
|
||||||
|
free(download_url);
|
||||||
|
free(filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
free(download_url);
|
free(download_url);
|
||||||
|
|
||||||
char path_to_file[0x107] = { 0 };
|
char path_to_file[0x107] = { 0 };
|
||||||
@@ -346,7 +372,7 @@ static void download_remote_entry(Entry_s * entry, EntryMode mode)
|
|||||||
if (extension == NULL || strcmp(extension, ".zip"))
|
if (extension == NULL || strcmp(extension, ".zip"))
|
||||||
strcat(path_to_file, ".zip");
|
strcat(path_to_file, ".zip");
|
||||||
|
|
||||||
DEBUG("Saving to sd: %s\n", path_to_file);
|
DEBUG("Saving to SD: %s\n", path_to_file);
|
||||||
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
|
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
|
||||||
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
|
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
|
||||||
free(zip_buf);
|
free(zip_buf);
|
||||||
@@ -412,10 +438,10 @@ static void search_menu(Entry_List_s * list)
|
|||||||
|
|
||||||
SwkbdState swkbd;
|
SwkbdState swkbd;
|
||||||
|
|
||||||
swkbdInit(&swkbd, SWKBD_TYPE_WESTERN, 2, max_chars);
|
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 2, max_chars);
|
||||||
swkbdSetHintText(&swkbd, "Which tags do you want to search for?");
|
swkbdSetHintText(&swkbd, "Which tags do you want to search for?");
|
||||||
|
|
||||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cance", false);
|
swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false);
|
||||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Search", true);
|
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Search", true);
|
||||||
swkbdSetValidation(&swkbd, SWKBD_NOTBLANK, 0, max_chars);
|
swkbdSetValidation(&swkbd, SWKBD_NOTBLANK, 0, max_chars);
|
||||||
|
|
||||||
@@ -728,8 +754,9 @@ bool themeplaza_browser(EntryMode mode)
|
|||||||
|
|
||||||
typedef struct header
|
typedef struct header
|
||||||
{
|
{
|
||||||
char * filename; // allocated in parse_header; if NULL, this is user-provided
|
char ** filename; // pointer to location for filename; if NULL, no filename is parsed
|
||||||
u32 file_size; // if == 0, fall back to chunked read
|
u32 file_size; // if == 0, fall back to chunked read
|
||||||
|
Result result_code;
|
||||||
} header;
|
} header;
|
||||||
|
|
||||||
typedef enum ParseResult
|
typedef enum ParseResult
|
||||||
@@ -737,8 +764,8 @@ typedef enum ParseResult
|
|||||||
SUCCESS, // 200/203 (203 indicates a successful request with a transformation applied by a proxy)
|
SUCCESS, // 200/203 (203 indicates a successful request with a transformation applied by a proxy)
|
||||||
REDIRECT, // 301/302/303/307/308
|
REDIRECT, // 301/302/303/307/308
|
||||||
HTTPC_ERROR,
|
HTTPC_ERROR,
|
||||||
|
ABORTED,
|
||||||
SERVER_IS_MISBEHAVING,
|
SERVER_IS_MISBEHAVING,
|
||||||
NO_FILENAME, // provisional
|
|
||||||
HTTP_UNAUTHORIZED = 401,
|
HTTP_UNAUTHORIZED = 401,
|
||||||
HTTP_FORBIDDEN = 403,
|
HTTP_FORBIDDEN = 403,
|
||||||
HTTP_NOT_FOUND = 404,
|
HTTP_NOT_FOUND = 404,
|
||||||
@@ -755,14 +782,29 @@ typedef enum ParseResult
|
|||||||
HTTP_GATEWAY_TIMEOUT = 504,
|
HTTP_GATEWAY_TIMEOUT = 504,
|
||||||
} ParseResult;
|
} ParseResult;
|
||||||
|
|
||||||
// the good paths for this function return SUCCESS or REDIRECT;
|
static SwkbdCallbackResult fat32filter(void *user, const char **ppMessage, const char *text, size_t textlen)
|
||||||
|
{
|
||||||
|
(void)textlen;
|
||||||
|
(void)user;
|
||||||
|
*ppMessage = "Input must not contain:\n><\"?;:/\\+,.|[=]";
|
||||||
|
if(strpbrk(text, "><\"?;:/\\+,.|[=]"))
|
||||||
|
{
|
||||||
|
DEBUG("illegal filename: %s\n", text);
|
||||||
|
return SWKBD_CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SWKBD_CALLBACK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the good paths for this function return SUCCESS, ABORTED, or REDIRECT;
|
||||||
// all other paths are failures
|
// all other paths are failures
|
||||||
static ParseResult parse_header(struct header * out, httpcContext * context, bool get_filename, const char * mime)
|
static ParseResult parse_header(struct header * out, httpcContext * context, const char * mime)
|
||||||
{
|
{
|
||||||
// status code
|
// status code
|
||||||
u32 status_code;
|
u32 status_code;
|
||||||
|
|
||||||
if (httpcGetResponseStatusCode(context, &status_code))
|
out->result_code = httpcGetResponseStatusCode(context, &status_code);
|
||||||
|
if (R_FAILED(out->result_code))
|
||||||
{
|
{
|
||||||
DEBUG("httpcGetResponseStatusCode\n");
|
DEBUG("httpcGetResponseStatusCode\n");
|
||||||
return HTTPC_ERROR;
|
return HTTPC_ERROR;
|
||||||
@@ -783,23 +825,28 @@ static ParseResult parse_header(struct header * out, httpcContext * context, boo
|
|||||||
return (ParseResult)status_code;
|
return (ParseResult)status_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * content_buf = calloc(1024, sizeof(char));
|
char content_buf[1024] = {0};
|
||||||
|
|
||||||
// Content-Type
|
// Content-Type
|
||||||
|
|
||||||
if (mime)
|
if (mime)
|
||||||
{
|
{
|
||||||
httpcGetResponseHeader(context, "Content-Type", content_buf, 1024);
|
out->result_code = httpcGetResponseHeader(context, "Content-Type", content_buf, 1024);
|
||||||
|
if (R_FAILED(out->result_code))
|
||||||
|
{
|
||||||
|
return HTTPC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strstr(mime, content_buf))
|
if (!strstr(mime, content_buf))
|
||||||
{
|
{
|
||||||
free(content_buf);
|
|
||||||
return SERVER_IS_MISBEHAVING;
|
return SERVER_IS_MISBEHAVING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content-Length
|
// Content-Length
|
||||||
|
|
||||||
if (httpcGetDownloadSizeState(context, NULL, &out->file_size))
|
out->result_code = httpcGetDownloadSizeState(context, NULL, &out->file_size);
|
||||||
|
if (R_FAILED(out->result_code))
|
||||||
{
|
{
|
||||||
DEBUG("httpcGetDownloadSizeState\n");
|
DEBUG("httpcGetDownloadSizeState\n");
|
||||||
return HTTPC_ERROR; // no need to free, program dies anyway
|
return HTTPC_ERROR; // no need to free, program dies anyway
|
||||||
@@ -807,11 +854,11 @@ static ParseResult parse_header(struct header * out, httpcContext * context, boo
|
|||||||
|
|
||||||
// Content-Disposition
|
// Content-Disposition
|
||||||
|
|
||||||
if (get_filename)
|
if (out->filename)
|
||||||
{
|
{
|
||||||
if (httpcGetResponseHeader(context, "Content-Disposition", content_buf, 1024))
|
out->result_code = httpcGetResponseHeader(context, "Content-Disposition", content_buf, 1024);
|
||||||
|
if (R_FAILED(out->result_code))
|
||||||
{
|
{
|
||||||
free(content_buf);
|
|
||||||
DEBUG("httpcGetResponseHeader\n");
|
DEBUG("httpcGetResponseHeader\n");
|
||||||
return HTTPC_ERROR;
|
return HTTPC_ERROR;
|
||||||
}
|
}
|
||||||
@@ -821,8 +868,31 @@ static ParseResult parse_header(struct header * out, httpcContext * context, boo
|
|||||||
char * filename = strstr(content_buf, "filename="); // filename=<filename>;? ...
|
char * filename = strstr(content_buf, "filename="); // filename=<filename>;? ...
|
||||||
if (!filename)
|
if (!filename)
|
||||||
{
|
{
|
||||||
free(content_buf);
|
const int max_chars = 250;
|
||||||
return NO_FILENAME;
|
// needs to be heap allocated only because the call site is expected to free it
|
||||||
|
*out->filename = malloc(max_chars + 5); // + .zip and the null term
|
||||||
|
|
||||||
|
SwkbdState swkbd;
|
||||||
|
|
||||||
|
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 2, max_chars / 2);
|
||||||
|
swkbdSetHintText(&swkbd, "Choose a filename");
|
||||||
|
swkbdSetFeatures(&swkbd, SWKBD_PREDICTIVE_INPUT | SWKBD_DARKEN_TOP_SCREEN);
|
||||||
|
|
||||||
|
swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false);
|
||||||
|
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Download", true);
|
||||||
|
swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, SWKBD_FILTER_CALLBACK, -1);
|
||||||
|
swkbdSetFilterCallback(&swkbd, &fat32filter, NULL);
|
||||||
|
|
||||||
|
SwkbdButton button = swkbdInputText(&swkbd, *out->filename, max_chars);
|
||||||
|
|
||||||
|
if (button != SWKBD_BUTTON_CONFIRM)
|
||||||
|
{
|
||||||
|
out->result_code = swkbdGetResult(&swkbd);
|
||||||
|
return ABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(*out->filename, ".zip");
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = strpbrk(filename, "=") + 1; // <filename>;?
|
filename = strpbrk(filename, "=") + 1; // <filename>;?
|
||||||
@@ -842,50 +912,35 @@ static ParseResult parse_header(struct header * out, httpcContext * context, boo
|
|||||||
while ((illegal_char = strpbrk(filename, "><\"?;:/\\+,.|[=]")))
|
while ((illegal_char = strpbrk(filename, "><\"?;:/\\+,.|[=]")))
|
||||||
*illegal_char = '-';
|
*illegal_char = '-';
|
||||||
|
|
||||||
out->filename = malloc(strlen(filename) + 1);
|
*out->filename = malloc(strlen(filename) + 1);
|
||||||
strcpy(out->filename, filename);
|
strcpy(*out->filename, filename);
|
||||||
DEBUG("%s\n", out->filename);
|
|
||||||
}
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SwkbdCallbackResult fat32filter(void *user, const char **ppMessage, const char *text, size_t textlen)
|
|
||||||
{
|
|
||||||
(void)textlen;
|
|
||||||
(void)user;
|
|
||||||
*ppMessage = "Input must not contain:\n><\"?;:/\\+,.|[=]";
|
|
||||||
if(strpbrk(text, "><\"?;:/\\+,.|[=]"))
|
|
||||||
{
|
|
||||||
DEBUG("illegal filename: %s\n", text);
|
|
||||||
return SWKBD_CALLBACK_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SWKBD_CALLBACK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ZIP_NOT_AVAILABLE "ZIP not found at this URL\nIf you believe this is an error, please\ncontact the site administrator"
|
#define ZIP_NOT_AVAILABLE "ZIP not found at this URL\nIf you believe this is an error, please\ncontact the site administrator"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call example: written = http_get("url", &filename, &buffer_to_download_to, INSTALL_DOWNLOAD, "application/json");
|
* call example: written = http_get("url", &filename, &buffer_to_download_to, &filesize, INSTALL_DOWNLOAD, "application/json");
|
||||||
*/
|
*/
|
||||||
u32 http_get(const char * url, char ** filename, char ** buf, InstallType install_type, const char * acceptable_mime_types)
|
Result http_get(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types)
|
||||||
{
|
{
|
||||||
Result ret;
|
Result ret;
|
||||||
httpcContext context;
|
httpcContext context;
|
||||||
char redirect_url[0x824] = {0};
|
char redirect_url[0x824] = {0};
|
||||||
char new_url[0x824] = {0};
|
char new_url[0x824] = {0};
|
||||||
|
|
||||||
struct header _header = {};
|
struct header _header = { .filename = filename };
|
||||||
|
|
||||||
DEBUG("Original URL: %s\n", url);
|
DEBUG("Original URL: %s\n", url);
|
||||||
|
|
||||||
redirect: // goto here if we need to redirect
|
redirect: // goto here if we need to redirect
|
||||||
ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);
|
ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);
|
||||||
if (ret != 0)
|
if (R_FAILED(ret))
|
||||||
{
|
{
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
DEBUG("httpcOpenContext %.8lx\n", ret);
|
DEBUG("httpcOpenContext %.8lx\n", ret);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); // should let us do https
|
httpcSetSSLOpt(&context, SSLCOPT_DisableVerify); // should let us do https
|
||||||
@@ -896,20 +951,24 @@ redirect: // goto here if we need to redirect
|
|||||||
httpcAddRequestHeaderField(&context, "Accept", acceptable_mime_types);
|
httpcAddRequestHeaderField(&context, "Accept", acceptable_mime_types);
|
||||||
|
|
||||||
ret = httpcBeginRequest(&context);
|
ret = httpcBeginRequest(&context);
|
||||||
if (ret != 0)
|
if (R_FAILED(ret))
|
||||||
{
|
{
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
DEBUG("httpcBeginRequest %.8lx\n", ret);
|
DEBUG("httpcBeginRequest %.8lx\n", ret);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseResult parse = parse_header(&_header, &context, (bool)filename, acceptable_mime_types);
|
char err_buf[0x69];
|
||||||
|
ParseResult parse = parse_header(&_header, &context, acceptable_mime_types);
|
||||||
switch (parse)
|
switch (parse)
|
||||||
{
|
{
|
||||||
char err_buf[0x69];
|
|
||||||
case NO_FILENAME:
|
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
break;
|
break;
|
||||||
|
case ABORTED:
|
||||||
|
ret = httpcCloseContext(&context);
|
||||||
|
if(R_FAILED(ret))
|
||||||
|
return ret;
|
||||||
|
return MAKERESULT(RL_SUCCESS, RS_CANCELED, RM_APPLICATION, RD_CANCEL_REQUESTED);
|
||||||
case REDIRECT:
|
case REDIRECT:
|
||||||
httpcGetResponseHeader(&context, "Location", redirect_url, 0x824);
|
httpcGetResponseHeader(&context, "Location", redirect_url, 0x824);
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
@@ -939,7 +998,8 @@ redirect: // goto here if we need to redirect
|
|||||||
DEBUG("httpc error\n");
|
DEBUG("httpc error\n");
|
||||||
throw_error("Error in HTTPC sysmodule.\nIf you are seeing this, please contact an Anemone developer\non the ThemePlaza Discord.", ERROR_LEVEL_ERROR);
|
throw_error("Error in HTTPC sysmodule.\nIf you are seeing this, please contact an Anemone developer\non the ThemePlaza Discord.", ERROR_LEVEL_ERROR);
|
||||||
quit = true;
|
quit = true;
|
||||||
return httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
|
return _header.result_code;
|
||||||
case HTTP_NOT_FOUND:
|
case HTTP_NOT_FOUND:
|
||||||
case HTTP_GONE: ;
|
case HTTP_GONE: ;
|
||||||
// TODO: check if we're looking at a TP URL, if we are, suggest that it might be missing
|
// TODO: check if we're looking at a TP URL, if we are, suggest that it might be missing
|
||||||
@@ -998,36 +1058,6 @@ redirect: // goto here if we need to redirect
|
|||||||
return httpcCloseContext(&context);
|
return httpcCloseContext(&context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename)
|
|
||||||
{
|
|
||||||
if (parse != NO_FILENAME)
|
|
||||||
*filename = _header.filename;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const int max_chars = 250;
|
|
||||||
// needs to be heap allocated only because the call site is expected to free it
|
|
||||||
*filename = malloc(max_chars + 5); // + .zip and the null term
|
|
||||||
|
|
||||||
SwkbdState swkbd;
|
|
||||||
|
|
||||||
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 2, max_chars / 2);
|
|
||||||
swkbdSetHintText(&swkbd, "Choose a filename.");
|
|
||||||
swkbdSetFeatures(&swkbd, SWKBD_PREDICTIVE_INPUT | SWKBD_DARKEN_TOP_SCREEN);
|
|
||||||
|
|
||||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false);
|
|
||||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Download", true);
|
|
||||||
swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, SWKBD_FILTER_CALLBACK, -1);
|
|
||||||
swkbdSetFilterCallback(&swkbd, &fat32filter, NULL);
|
|
||||||
|
|
||||||
SwkbdButton button = swkbdInputText(&swkbd, *filename, max_chars);
|
|
||||||
|
|
||||||
if (button != SWKBD_BUTTON_CONFIRM)
|
|
||||||
return httpcCloseContext(&context);
|
|
||||||
|
|
||||||
strcat(*filename, ".zip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 chunk_size;
|
u32 chunk_size;
|
||||||
if (_header.file_size)
|
if (_header.file_size)
|
||||||
// the only reason we chunk this at all is for the download bar;
|
// the only reason we chunk this at all is for the download bar;
|
||||||
@@ -1039,42 +1069,52 @@ redirect: // goto here if we need to redirect
|
|||||||
|
|
||||||
*buf = NULL;
|
*buf = NULL;
|
||||||
char * new_buf;
|
char * new_buf;
|
||||||
u32 size = 0;
|
*size = 0;
|
||||||
u32 read_size = 0;
|
u32 read_size = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
new_buf = realloc(*buf, size + chunk_size);
|
new_buf = realloc(*buf, *size + chunk_size);
|
||||||
if (new_buf == NULL)
|
if (new_buf == NULL)
|
||||||
{
|
{
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
free(*buf);
|
free(*buf);
|
||||||
DEBUG("realloc failed in http_get - file possibly too large?\n"); // TODO: report this?
|
DEBUG("realloc failed in http_get - file possibly too large?\n"); // TODO: report this?
|
||||||
return 0;
|
return MAKERESULT(RL_FATAL, RS_INTERNAL, RM_KERNEL, RD_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
*buf = new_buf;
|
*buf = new_buf;
|
||||||
|
|
||||||
// download exactly chunk_size bytes and toss them into buf.
|
// download exactly chunk_size bytes and toss them into buf.
|
||||||
// size contains the current offset into buf.
|
// size contains the current offset into buf.
|
||||||
ret = httpcDownloadData(&context, (u8*)(*buf) + size, chunk_size, &read_size);
|
ret = httpcDownloadData(&context, (u8*)(*buf) + *size, chunk_size, &read_size);
|
||||||
size += read_size;
|
/* FIXME: I have no idea why this doesn't work, but it causes problems. Look into it later
|
||||||
|
if (R_FAILED(ret))
|
||||||
|
{
|
||||||
|
httpcCloseContext(&context);
|
||||||
|
free(*buf);
|
||||||
|
DEBUG("download failed in http_get\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
*size += read_size;
|
||||||
|
|
||||||
if (_header.file_size && install_type != INSTALL_NONE)
|
if (_header.file_size && install_type != INSTALL_NONE)
|
||||||
draw_loading_bar(size, _header.file_size, install_type);
|
draw_loading_bar(*size, _header.file_size, install_type);
|
||||||
} while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING);
|
} while (ret == (Result)HTTPC_RESULTCODE_DOWNLOADPENDING);
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
|
|
||||||
// shrink to size
|
// shrink to size
|
||||||
new_buf = realloc(*buf, size);
|
new_buf = realloc(*buf, *size);
|
||||||
if (new_buf == NULL)
|
if (new_buf == NULL)
|
||||||
{
|
{
|
||||||
httpcCloseContext(&context);
|
httpcCloseContext(&context);
|
||||||
free(*buf);
|
free(*buf);
|
||||||
DEBUG("shrinking realloc failed\n"); // 何?
|
DEBUG("shrinking realloc failed\n"); // 何?
|
||||||
return 0;
|
return MAKERESULT(RL_FATAL, RS_INTERNAL, RM_KERNEL, RD_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
*buf = new_buf;
|
*buf = new_buf;
|
||||||
|
|
||||||
DEBUG("size: %lu\n", size);
|
DEBUG("size: %lu\n", *size);
|
||||||
return size;
|
if (filename) { DEBUG("filename: %s\n", *filename); }
|
||||||
|
return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user