mirror of
https://github.com/hax4dazy/TinWoo.git
synced 2025-02-09 19:25:05 +01:00
Add files via upload
This commit is contained in:
parent
efe355b29a
commit
d05cf71f13
315
source/ThemeInstall.cpp
Normal file
315
source/ThemeInstall.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
Copyright (c) 2017-2018 Adubbz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <sys/errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
#include <curl/curl.h>
|
||||
#include <thread>
|
||||
#include <switch.h>
|
||||
#include "ThemeInstall.hpp"
|
||||
#include "util/error.hpp"
|
||||
#include "util/config.hpp"
|
||||
#include "util/util.hpp"
|
||||
#include "util/curl.hpp"
|
||||
#include "util/lang.hpp"
|
||||
#include "ui/MainApplication.hpp"
|
||||
|
||||
bool netConnected2 = false;
|
||||
|
||||
namespace inst::ui {
|
||||
extern MainApplication* mainApp;
|
||||
}
|
||||
|
||||
namespace ThemeInstStuff {
|
||||
|
||||
//Strip the filename from the url we are trying to download - ie list.txt, index.html etc...
|
||||
std::string stripfilename(const std::string& s) {
|
||||
|
||||
int pos = 0;
|
||||
std::string mystr = s;
|
||||
pos = mystr.find_last_of('/');
|
||||
|
||||
//if the url doesn't contain "/" after "http://" don't bother stripping as we won't need to.
|
||||
if (pos > 7) {
|
||||
mystr = mystr.substr(0, pos);
|
||||
}
|
||||
|
||||
return mystr;
|
||||
}
|
||||
|
||||
//Find Case Insensitive Sub String in a given substring
|
||||
size_t findCaseInsensitive(std::string data, std::string toSearch, size_t pos = 0)
|
||||
{
|
||||
// Convert complete given String to lower case
|
||||
std::transform(data.begin(), data.end(), data.begin(), ::tolower);
|
||||
// Convert complete given Sub String to lower case
|
||||
std::transform(toSearch.begin(), toSearch.end(), toSearch.begin(), ::tolower);
|
||||
// Find sub string in given string
|
||||
return data.find(toSearch, pos);
|
||||
}
|
||||
|
||||
std::string urlencode(std::string str)
|
||||
{
|
||||
std::string new_str = "";
|
||||
char c;
|
||||
int ic;
|
||||
const char* chars = str.c_str();
|
||||
char bufHex[10];
|
||||
int len = strlen(chars);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
c = chars[i];
|
||||
ic = c;
|
||||
// bodge code needed to prevernt encoded url changing forward slash to %2F
|
||||
if (c == '/') new_str += '/';
|
||||
else if (c == '.') new_str += '.';
|
||||
else if (c == ':') new_str += ':';
|
||||
else if (c == '\\') new_str += '/'; //windows paths break urls - change the path mod..
|
||||
else if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') new_str += c;
|
||||
else {
|
||||
sprintf(bufHex, "%X", c);
|
||||
if (ic < 16)
|
||||
new_str += "%0";
|
||||
else
|
||||
new_str += "%";
|
||||
new_str += bufHex;
|
||||
}
|
||||
}
|
||||
return new_str;
|
||||
}
|
||||
|
||||
std::string url_decode(const std::string& encoded)
|
||||
{
|
||||
int output_length;
|
||||
const auto decoded_value = curl_easy_unescape(nullptr, encoded.c_str(), static_cast<int>(encoded.length()), &output_length);
|
||||
std::string result(decoded_value, output_length);
|
||||
curl_free(decoded_value);
|
||||
return result;
|
||||
}
|
||||
|
||||
void OnUnwound()
|
||||
{
|
||||
LOG_DEBUG("unwinding view\n");
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
std::vector<std::string> OnSelected()
|
||||
{
|
||||
padConfigureInput(8, HidNpadStyleSet_NpadStandard);
|
||||
PadState pad;
|
||||
padInitializeAny(&pad);
|
||||
u64 freq = armGetSystemTickFreq();
|
||||
u64 startTime = armGetSystemTick();
|
||||
OnUnwound();
|
||||
|
||||
try {
|
||||
ASSERT_OK(curl_global_init(CURL_GLOBAL_ALL), "Curl failed to initialized");
|
||||
|
||||
std::string ourIPAddress = inst::util::getIPAddress();
|
||||
inst::ui::mainApp->ThemeinstPage->pageInfoText->SetText("inst.net.top_info1"_lang + ourIPAddress);
|
||||
inst::ui::mainApp->CallForRender();
|
||||
netConnected2 = false;
|
||||
LOG_DEBUG("%s %s\n", "Switch IP is ", ourIPAddress.c_str());
|
||||
LOG_DEBUG("%s\n", "Waiting for network");
|
||||
LOG_DEBUG("%s\n", "B to cancel");
|
||||
std::vector<std::string> urls;
|
||||
std::vector<std::string> tmp_array;
|
||||
|
||||
while (true) {
|
||||
padUpdate(&pad);
|
||||
|
||||
// If we don't update the UI occasionally the Switch basically crashes on this screen if you press the home button
|
||||
u64 newTime = armGetSystemTick();
|
||||
|
||||
if (newTime - startTime >= freq * 0.25) {
|
||||
startTime = newTime;
|
||||
inst::ui::mainApp->CallForRender();
|
||||
}
|
||||
|
||||
u64 kDown = padGetButtonsDown(&pad);
|
||||
if (kDown & HidNpadButton_B)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::remove("temp.html");
|
||||
std::string url;
|
||||
unsigned short maxlist = 50;
|
||||
unsigned short nowlist = 0;
|
||||
|
||||
if (inst::config::httpkeyboard) {
|
||||
url = inst::util::softwareKeyboard("inst.net.url.hint_theme"_lang, inst::config::httplastUrl2, 500);
|
||||
inst::config::httplastUrl2 = url;
|
||||
inst::config::setConfig();
|
||||
//refresh options page
|
||||
inst::ui::mainApp->optionspage->setMenuText();
|
||||
}
|
||||
else {
|
||||
url = inst::config::httplastUrl2;
|
||||
}
|
||||
|
||||
if (url == "") {
|
||||
url = ("http://127.0.0.1");
|
||||
inst::ui::mainApp->CreateShowDialog("options.menu_items.theme_fail"_lang, "inst.net.help.blank"_lang, { "common.ok"_lang }, true, "romfs:/images/icons/information.png");
|
||||
inst::config::httplastUrl2 = url;
|
||||
inst::config::setConfig();
|
||||
//refresh options page
|
||||
inst::ui::mainApp->optionspage->setMenuText();
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
std::string response;
|
||||
if (inst::util::formatUrlString(url) == "" || url == "https://" || url == "http://" || url == "HTTP://" || url == "HTTPS://") {
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.url.invalid"_lang, "", { "common.ok"_lang }, false, "romfs:/images/icons/fail.png");
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (url[url.size() - 1] != '/') //does this line even do anything?
|
||||
|
||||
//First try and stream the links
|
||||
response = inst::curl::downloadToBuffer(url);
|
||||
|
||||
//If the above fails we probably have an html page - try to download it instead.
|
||||
if (response.empty()) {
|
||||
response = inst::curl::html_to_buffer(url);
|
||||
if (response.empty()) {
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.theme_error"_lang, "inst.net.theme_error_info"_lang, { "common.ok"_lang }, true, "romfs:/images/icons/fail.png");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.empty()) {
|
||||
if (response[0] == '*') {
|
||||
try {
|
||||
nlohmann::json j = nlohmann::json::parse(response);
|
||||
for (const auto& file : j["files"]) {
|
||||
urls.push_back(file["url"]);
|
||||
}
|
||||
|
||||
return urls;
|
||||
response.clear();
|
||||
}
|
||||
catch (const nlohmann::detail::exception& ex) {
|
||||
LOG_DEBUG("Failed to parse JSON\n");
|
||||
}
|
||||
}
|
||||
else if (!response.empty()) {
|
||||
std::size_t index = 0;
|
||||
if (!inst::config::listoveride) {
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.url.listwait"_lang + std::to_string(maxlist) + "inst.net.url.listwait2"_lang, "", { "common.ok"_lang }, false, "romfs:/images/icons/wait.png");
|
||||
}
|
||||
while (index < response.size()) {
|
||||
std::string link;
|
||||
auto found = findCaseInsensitive(response, "href=\"", index);
|
||||
if (found == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
index = found + 6;
|
||||
while (index < response.size()) {
|
||||
if (response[index] == '"') {
|
||||
if (findCaseInsensitive(link, ".zip") != std::string::npos) {
|
||||
/*
|
||||
Try to see if the href links contain http - if not add the own url
|
||||
defined in the settings page
|
||||
*/
|
||||
if (!inst::config::listoveride && nowlist >= maxlist) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (link.find("http") == std::string::npos) {
|
||||
std::string before_strip = stripfilename(url);
|
||||
if (link[0] == '/') {
|
||||
tmp_array.push_back(before_strip + link);
|
||||
nowlist++;
|
||||
}
|
||||
else {
|
||||
tmp_array.push_back(before_strip + "/" + link);
|
||||
nowlist++;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmp_array.push_back(link);
|
||||
nowlist++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break; //don't remove this or the net install screen will crash
|
||||
}
|
||||
link += response[index++];
|
||||
}
|
||||
}
|
||||
if (tmp_array.size() > 0) {
|
||||
|
||||
//code to decode the url (if it's encoded), if not then (re)encode all urls.
|
||||
for (unsigned long int i = 0; i < tmp_array.size(); i++) {
|
||||
std::string debug = tmp_array[i];
|
||||
std::string decoded = url_decode(debug);
|
||||
debug = urlencode(decoded);
|
||||
urls.push_back(debug);
|
||||
}
|
||||
|
||||
tmp_array.clear(); //we may as well clear this now as it's done it's job..
|
||||
std::sort(urls.begin(), urls.end(), inst::util::ignoreCaseCompare);
|
||||
return urls;
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.url.no_themes"_lang, "", { "common.ok"_lang }, false, "romfs:/images/icons/fail.png");
|
||||
LOG_DEBUG("Failed to parse themes from HTML\n");
|
||||
break;
|
||||
}
|
||||
response.clear();
|
||||
}
|
||||
|
||||
else {
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.theme_error"_lang, "inst.net.theme_error_info"_lang, { "common.ok"_lang }, true, "romfs:/images/icons/fail.png");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
LOG_DEBUG("Failed to fetch theme list\n");
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.theme_error"_lang, "inst.net.theme_error_info"_lang, { "common.ok"_lang }, true, "romfs:/images/icons/fail.png");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
catch (std::runtime_error& e) {
|
||||
LOG_DEBUG("Failed to perform remote install!\n");
|
||||
LOG_DEBUG("%s", e.what());
|
||||
fprintf(stdout, "%s", e.what());
|
||||
inst::ui::mainApp->CreateShowDialog("inst.net.failed"_lang, (std::string)e.what(), { "common.ok"_lang }, true, "romfs:/images/icons/fail.png");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user