Compare commits
8 Commits
experiment
...
1.11
| Author | SHA1 | Date | |
|---|---|---|---|
| df6a068bd3 | |||
| c1307d4221 | |||
| 832c60862b | |||
| 529d88af06 | |||
| d26baf817e | |||
| 01f2f44942 | |||
| e28e562a10 | |||
| 83661c7fcb |
+14
-1
@@ -40,6 +40,14 @@ add_executable(ezremote_client
|
||||
source/clients/smbclient.cpp
|
||||
source/clients/webdavclient.cpp
|
||||
source/clients/sftpclient.cpp
|
||||
source/clients/rclone.cpp
|
||||
source/filehost/alldebrid.cpp
|
||||
source/filehost/directhost.cpp
|
||||
source/filehost/gdrive.cpp
|
||||
source/filehost/filehost.cpp
|
||||
source/filehost/1fichier.cpp
|
||||
source/filehost/mediafire.cpp
|
||||
source/filehost/pixeldrain.cpp
|
||||
source/server/http_server.cpp
|
||||
source/actions.cpp
|
||||
source/config.cpp
|
||||
@@ -62,7 +70,7 @@ add_executable(ezremote_client
|
||||
|
||||
add_self(ezremote_client)
|
||||
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.10" 32 0)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.11" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
c
|
||||
@@ -85,6 +93,11 @@ target_link_libraries(ezremote_client
|
||||
minizip
|
||||
un7zip
|
||||
unrar
|
||||
bz2
|
||||
b2
|
||||
lzma
|
||||
lz4
|
||||
archive
|
||||
json-c
|
||||
ssh2
|
||||
kernel
|
||||
|
||||
@@ -114,6 +114,7 @@ Remote Package Installation with all Remote Server, even if they are password pr
|
||||
- Upload files to the PS4
|
||||
- Download files from the PS4
|
||||
- Install packages on the PS4
|
||||
- Install packages from shared links from mediafire, google and pixeldrain. For other filehost, they can installed via AllDebrid (See AllDebrid website for supported filehost).
|
||||
|
||||
## How to access the Web Interface ##
|
||||
You need to launch the "ezRemote Client" app on the PS4. Then on any device(laptop, tablet, phone etc..) with web browser goto to http://<ip_address_of_ps4>:8080 . That's all.
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
permissionsUrl: '/__local__/permission',
|
||||
installUrl: '/__local__/install',
|
||||
uploadResumeSizeUrl: '__local__/uploadResumeSize',
|
||||
installUrlUrl: '/__local__/install_url',
|
||||
multipleDownloadFileName: 'ezremote-client.zip',
|
||||
isExtractableFilePattern: /\.(7z|rar|zip)$/i,
|
||||
pickCallback: function (item) {
|
||||
|
||||
@@ -82,7 +82,7 @@ STR_ONETIME_URL=One Time Url
|
||||
STR_NOT_A_VALID_PACKAGE=Not a valid Package
|
||||
STR_WAIT_FOR_INSTALL_MSG=Waiting for Package to finish installing
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Failed to install pkg file. Please delete the tmp pkg manually
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain google download URL
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain download URL
|
||||
STR_AUTO_DELETE_TMP_PKG=Auto delete temporary downloaded pkg file after install
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protocol not supported
|
||||
STR_COULD_NOT_RESOLVE_HOST=Could not resolve hostname
|
||||
@@ -150,3 +150,9 @@ STR_WEB_SERVER=Web Server
|
||||
STR_ENABLE=Enable
|
||||
STR_COMPRESSED_FILE_PATH=Compressed Files Location
|
||||
STR_COMPRESSED_FILE_PATH_MSG=Location of where compressed files are stored on the web server
|
||||
STR_ALLDEBRID=AllDebrid
|
||||
STR_API_KEY=API Key
|
||||
STR_CANT_EXTRACT_URL_MSG=Couldn't extract download url
|
||||
STR_FAIL_INSTALL_FROM_URL_MSG=Failed to install from URL
|
||||
STR_INVALID_URL=InValid URL
|
||||
STR_ALLDEBRID_API_KEY_MISSING_MSG=To use this function, an API Key needs to be configured in the ezRemote Client settings
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+19
-84
@@ -14,7 +14,9 @@
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/rclone.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "filehost/filehost.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "config.h"
|
||||
@@ -26,6 +28,7 @@
|
||||
#include "web/request.hpp"
|
||||
#include "web/urn.hpp"
|
||||
#include "system.h"
|
||||
#include "sfo.h"
|
||||
#include "zip_util.h"
|
||||
|
||||
namespace Actions
|
||||
@@ -706,7 +709,10 @@ namespace Actions
|
||||
}
|
||||
else
|
||||
{
|
||||
if (INSTALLER::InstallRemotePkg(it->path, &header) == 0)
|
||||
std::string url = INSTALLER::getRemoteUrl(it->path, true);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
|
||||
|
||||
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
|
||||
failed++;
|
||||
else
|
||||
success++;
|
||||
@@ -918,87 +924,6 @@ namespace Actions
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetGoogleDownloadUrl(std::string &url)
|
||||
{
|
||||
size_t scheme_pos = url.find_first_of("://");
|
||||
size_t path_pos = url.find_first_of("/", scheme_pos + 3);
|
||||
std::string host = url.substr(0, path_pos);
|
||||
std::string path = url.substr(path_pos);
|
||||
|
||||
std::string first_download_path;
|
||||
size_t file_id_start_pos = path.find("/file/d/");
|
||||
if (file_id_start_pos != std::string::npos)
|
||||
{
|
||||
file_id_start_pos = file_id_start_pos + 8;
|
||||
std::string file_id = path.substr(file_id_start_pos);
|
||||
size_t file_id_end_pos = file_id.find_first_of("/");
|
||||
file_id = file_id.substr(0, file_id_end_pos);
|
||||
first_download_path = "/uc?export=download&id=" + file_id;
|
||||
}
|
||||
else if (path.find("/uc?export=download") != std::string::npos)
|
||||
{
|
||||
first_download_path = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
WebDAV::WebDavClient tmp_client;
|
||||
tmp_client.Connect(host.c_str(), "", "", false);
|
||||
WebDAV::dict_t headers;
|
||||
tmp_client.GetHeaders(first_download_path.c_str(), &headers);
|
||||
|
||||
std::string content_type = WebDAV::get(headers, "content-type");
|
||||
if (content_type.find("application/octet-stream") != std::string::npos)
|
||||
{
|
||||
return first_download_path;
|
||||
}
|
||||
else if (content_type.find("text/html") == std::string::npos)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
char *buffer_ptr = nullptr;
|
||||
unsigned long long buffer_size = 0;
|
||||
tmp_client.GetClient()->download_to(first_download_path, buffer_ptr, buffer_size);
|
||||
|
||||
lxb_status_t status;
|
||||
lxb_dom_element_t *element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *collection;
|
||||
lxb_dom_attr_t *attr;
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)buffer_ptr, buffer_size);
|
||||
if (status != LXB_STATUS_OK)
|
||||
return "";
|
||||
collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (collection == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
collection, (const lxb_char_t *)"form", 4);
|
||||
if (status != LXB_STATUS_OK)
|
||||
return "";
|
||||
std::string download_url;
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
|
||||
{
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
|
||||
if (form_id == "download-form")
|
||||
{
|
||||
size_t value_len;
|
||||
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
|
||||
download_url = std::string((char *)value, value_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
|
||||
return download_url;
|
||||
}
|
||||
|
||||
void *InstallUrlPkgThread(void *argp)
|
||||
{
|
||||
bytes_transfered = 0;
|
||||
@@ -1012,8 +937,16 @@ namespace Actions
|
||||
sprintf(filename, "%s/%lu.pkg", DATA_PATH, tick.mytick);
|
||||
|
||||
std::string full_url = std::string(install_pkg_url.url);
|
||||
if (full_url.find("https://drive.google.com") != std::string::npos)
|
||||
full_url = GetGoogleDownloadUrl(full_url);
|
||||
FileHost *filehost = FileHost::getFileHost(full_url);
|
||||
if (!filehost->IsValidUrl())
|
||||
{
|
||||
sprintf(status_message, "%s", lang_strings[STR_FAIL_TO_OBTAIN_GG_DL_MSG]);
|
||||
activity_inprogess = false;
|
||||
Windows::SetModalMode(false);
|
||||
return NULL;
|
||||
}
|
||||
full_url = filehost->GetDownloadUrl();
|
||||
delete(filehost);
|
||||
|
||||
if (full_url.empty())
|
||||
{
|
||||
@@ -1133,6 +1066,8 @@ namespace Actions
|
||||
remoteclient = new NginxClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
|
||||
remoteclient = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
remoteclient = new RCloneClient();
|
||||
}
|
||||
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
|
||||
{
|
||||
|
||||
+6
-2
@@ -6,7 +6,7 @@
|
||||
class Base64
|
||||
{
|
||||
public:
|
||||
static int Encode(const std::string &input, std::string &out)
|
||||
static int Encode(unsigned char *input, size_t in_len, std::string &out)
|
||||
{
|
||||
static constexpr char sEncodingTable[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
@@ -18,7 +18,6 @@ public:
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'};
|
||||
|
||||
size_t in_len = input.size();
|
||||
size_t out_len = 4 * ((in_len + 2) / 3);
|
||||
out.resize(out_len);
|
||||
size_t i;
|
||||
@@ -50,6 +49,11 @@ public:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Encode(const std::string &input, std::string &out)
|
||||
{
|
||||
return Encode((unsigned char*)input.data(), input.size(), out);
|
||||
}
|
||||
|
||||
static int Decode(const std::string &input, std::string &out)
|
||||
{
|
||||
static constexpr unsigned char kDecodingTable[] = {
|
||||
|
||||
@@ -12,26 +12,6 @@ using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
lxb_dom_node_t *nextChildElement(lxb_dom_element_t *element)
|
||||
{
|
||||
lxb_dom_node_t *node = element->node.first_child;
|
||||
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
lxb_dom_node_t *nextElement(lxb_dom_node_t *node)
|
||||
{
|
||||
lxb_dom_node_t *next = node->next;
|
||||
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
|
||||
{
|
||||
next = next->next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
@@ -101,7 +81,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
node = nextChildElement(element);
|
||||
node = NextChildElement(element);
|
||||
if (node == nullptr) continue;
|
||||
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
|
||||
@@ -114,7 +94,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
if (tmp_string.compare("td") == 0)
|
||||
{
|
||||
// get the child img element
|
||||
lxb_dom_node_t *img = nextChildElement(lxb_dom_interface_element(node));
|
||||
lxb_dom_node_t *img = NextChildElement(lxb_dom_interface_element(node));
|
||||
if (img == nullptr) continue;
|
||||
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(img), &value_len);
|
||||
@@ -142,7 +122,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
else continue; // invalid record
|
||||
|
||||
// file/folder name
|
||||
node = nextElement(node);
|
||||
node = NextElement(node);
|
||||
if (node == nullptr) continue;
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
@@ -165,7 +145,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
else continue; // not valid record
|
||||
|
||||
// datetime
|
||||
node = nextElement(node);
|
||||
node = NextElement(node);
|
||||
if (node == nullptr) continue;
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
@@ -195,7 +175,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
else continue; // invalid record
|
||||
|
||||
// filesize
|
||||
node = nextElement(node);
|
||||
node = NextElement(node);
|
||||
if (node == nullptr) continue;
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include <curl/curl.h>
|
||||
#include "common.h"
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "http/httplib.h"
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include "common.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/rclone.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
#include "dbglogger.h"
|
||||
|
||||
using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path)+"/");
|
||||
if (auto res = client->Get(encoded_path))
|
||||
{
|
||||
lxb_status_t status;
|
||||
lxb_dom_attr_t *attr;
|
||||
lxb_dom_element_t *tbody_element, *tr_element, *td_element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *tbody_collection;
|
||||
lxb_dom_collection_t *tr_collection;
|
||||
lxb_dom_collection_t *td_collection;
|
||||
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
tbody_collection = lxb_dom_collection_make(&document->dom_document, 1);
|
||||
if (tbody_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
tr_collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (tbody_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
tbody_collection, (const lxb_char_t *)"tbody", 5);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (lxb_dom_collection_length(tbody_collection) < 1)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// Get the first tbody which should only be 1
|
||||
tbody_element = lxb_dom_collection_element(tbody_collection, 0);
|
||||
status = lxb_dom_elements_by_tag_name(tbody_element,
|
||||
tr_collection, (const lxb_char_t *)"tr", 2);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// skip row 0 , since it has the previous folder header
|
||||
for (size_t i = 1; i < lxb_dom_collection_length(tr_collection); i++)
|
||||
{
|
||||
DirEntry entry;
|
||||
std::string title, aclass;
|
||||
memset(&entry.modified, 0, sizeof(DateTime));
|
||||
const lxb_char_t *value;
|
||||
size_t value_len;
|
||||
std::string tmp_string;
|
||||
|
||||
tr_element = lxb_dom_collection_element(tr_collection, i);
|
||||
|
||||
td_collection = lxb_dom_collection_make(&document->dom_document, 5);
|
||||
status = lxb_dom_elements_by_tag_name(tr_element,
|
||||
td_collection, (const lxb_char_t *)"td", 2);
|
||||
if (status != LXB_STATUS_OK || lxb_dom_collection_length(td_collection) < 0)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// td 0 is empty, td 1 is file or folder
|
||||
td_element = lxb_dom_collection_element(td_collection, 1);
|
||||
lxb_dom_node_t *use_node = NextChildElement(lxb_dom_interface_element(NextChildElement(td_element)));
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(use_node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("use") != 0)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(use_node), (const lxb_char_t *)"xlink:href", 10, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("#folder") == 0)
|
||||
{
|
||||
entry.isDir = true;
|
||||
entry.selectable = true;
|
||||
entry.file_size = 0;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.isDir = false;
|
||||
entry.selectable = true;
|
||||
}
|
||||
|
||||
// <a> element contains the file/folder name
|
||||
lxb_dom_node_t *a_node = NextChildElement(lxb_dom_interface_element(NextElement(NextChildElement(td_element))));
|
||||
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(a_node), (const lxb_char_t *)"href", 4, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string[tmp_string.length()-1] == '/')
|
||||
tmp_string = tmp_string.substr(0, tmp_string.length()-1);
|
||||
tmp_string = BaseClient::DecodeUrl(tmp_string);
|
||||
sprintf(entry.name, "%s", tmp_string.c_str());
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
if (path.length() > 0 && path[path.length() - 1] == '/')
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
|
||||
}
|
||||
|
||||
// td 3 - filesize
|
||||
if (!entry.isDir)
|
||||
{
|
||||
td_element = lxb_dom_collection_element(td_collection, 2);
|
||||
lxb_dom_node_t *size_node = NextChildElement(td_element);
|
||||
value = lxb_dom_node_text_content(size_node->first_child, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
entry.file_size = atoi(tmp_string.c_str());
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
}
|
||||
|
||||
// td 4 - datetime
|
||||
td_element = lxb_dom_collection_element(td_collection, 3);
|
||||
lxb_dom_node_t *date_node = NextChildElement(td_element);
|
||||
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(date_node), (const lxb_char_t *)"datetime", 8, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
std::vector<std::string> date_time = Util::Split(tmp_string, " ");
|
||||
|
||||
OrbisDateTime gmt;
|
||||
OrbisDateTime lt;
|
||||
|
||||
if (date_time.size() > 1)
|
||||
{
|
||||
std::vector<std::string> adate = Util::Split(date_time[0], "-");
|
||||
if (adate.size() == 3)
|
||||
{
|
||||
gmt.year = atoi(adate[0].c_str());
|
||||
gmt.month = atoi(adate[1].c_str());
|
||||
gmt.day = atoi(adate[2].c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> atime = Util::Split(date_time[1], ":");
|
||||
if (atime.size() == 3)
|
||||
{
|
||||
gmt.hour = atoi(atime[0].c_str());
|
||||
gmt.minute = atoi(atime[1].c_str());
|
||||
|
||||
std::vector<std::string> sec_msec = Util::Split(atime[2], ".");
|
||||
if (sec_msec.size() > 0)
|
||||
{
|
||||
gmt.second = atoi(sec_msec[0].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
convertUtcToLocalTime(&gmt, <);
|
||||
entry.modified.day = lt.day;
|
||||
entry.modified.month = lt.month;
|
||||
entry.modified.year = lt.year;
|
||||
entry.modified.hours = lt.hour;
|
||||
entry.modified.minutes = lt.minute;
|
||||
entry.modified.seconds = lt.second;
|
||||
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
out.push_back(entry);
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(tbody_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
return out;
|
||||
}
|
||||
|
||||
finish:
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef RCLONE_H
|
||||
#define RCLONE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
|
||||
class RCloneClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -34,7 +34,14 @@ int SmbClient::Connect(const std::string &url, const std::string &user, const st
|
||||
sprintf(response, "Failed to init SMB context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
smb_url = smb2_parse_url(smb2, url.c_str());
|
||||
if (smb_url == NULL || smb_url->share == NULL || strlen(smb_url->share) == 0)
|
||||
{
|
||||
sprintf(response, "Invalid SMB Url");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pass.length() > 0)
|
||||
smb2_set_password(smb2, pass.c_str());
|
||||
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
|
||||
#define HTTP_SUCCESS(x) (x >= 200 && x < 300)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
@@ -86,4 +88,44 @@ struct DirEntry
|
||||
}
|
||||
};
|
||||
|
||||
static lxb_dom_node_t *NextChildElement(lxb_dom_element_t *element)
|
||||
{
|
||||
lxb_dom_node_t *node = element->node.first_child;
|
||||
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static lxb_dom_node_t *NextElement(lxb_dom_node_t *node)
|
||||
{
|
||||
lxb_dom_node_t *next = node->next;
|
||||
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
|
||||
{
|
||||
next = next->next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
static lxb_dom_node_t *NextChildTextNode(lxb_dom_element_t *element)
|
||||
{
|
||||
lxb_dom_node_t *node = element->node.first_child;
|
||||
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_TEXT)
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static lxb_dom_node_t *NextTextNode(lxb_dom_node_t *node)
|
||||
{
|
||||
lxb_dom_node_t *next = node->next;
|
||||
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_TEXT)
|
||||
{
|
||||
next = next->next;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
#endif
|
||||
+26
-1
@@ -37,6 +37,7 @@ bool auto_delete_tmp_pkg;
|
||||
int max_edit_file_size;
|
||||
GoogleAppInfo gg_app;
|
||||
bool show_hidden_files;
|
||||
char alldebrid_api_key[32];
|
||||
|
||||
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
|
||||
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
|
||||
@@ -151,7 +152,7 @@ namespace CONFIG
|
||||
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
|
||||
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
|
||||
|
||||
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE};
|
||||
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE};
|
||||
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
|
||||
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
|
||||
|
||||
@@ -181,6 +182,22 @@ namespace CONFIG
|
||||
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
|
||||
|
||||
// alldebrid api key
|
||||
char tmp_api_key[512];
|
||||
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, ""));
|
||||
std::string encrypted_api_key;
|
||||
if (strlen(tmp_api_key) > 0)
|
||||
{
|
||||
std::string decrypted__api_key;
|
||||
int ret = Decrypt(tmp_api_key, decrypted__api_key);
|
||||
if (ret == 0)
|
||||
sprintf(alldebrid_api_key, "%s", tmp_api_key);
|
||||
else
|
||||
sprintf(alldebrid_api_key, "%s", decrypted__api_key.c_str());
|
||||
Encrypt(alldebrid_api_key, encrypted_api_key);
|
||||
}
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
|
||||
|
||||
// Load Google Account Info
|
||||
sprintf(gg_app.client_id, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, ""));
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
|
||||
@@ -355,9 +372,17 @@ namespace CONFIG
|
||||
Encrypt(gg_app.client_secret, encrypted_secret);
|
||||
else
|
||||
encrypted_secret = std::string(gg_app.client_secret);
|
||||
|
||||
std::string encrypted_api_key;
|
||||
if (strlen(alldebrid_api_key) > 0)
|
||||
Encrypt(alldebrid_api_key, encrypted_api_key);
|
||||
else
|
||||
encrypted_api_key = std::string(alldebrid_api_key);
|
||||
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str());
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
|
||||
WriteInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, http_server_port);
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
#define CONFIG_REMOTE_HTTP_SERVER_TYPE "remote_server_http_server_type"
|
||||
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
|
||||
|
||||
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
|
||||
|
||||
#define CONFIG_VERSION "config_version"
|
||||
#define CONFIG_VERSION_NUM 1
|
||||
|
||||
@@ -75,6 +77,7 @@
|
||||
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
|
||||
#define HTTP_SERVER_NGINX "Nginx"
|
||||
#define HTTP_SERVER_NPX_SERVE "Serve"
|
||||
#define HTTP_SERVER_RCLONE "RClone"
|
||||
|
||||
#define MAX_EDIT_FILE_SIZE 32768
|
||||
|
||||
@@ -134,6 +137,7 @@ extern unsigned char cipher_key[32];
|
||||
extern unsigned char cipher_iv[16];
|
||||
extern GoogleAppInfo gg_app;
|
||||
extern bool show_hidden_files;
|
||||
extern char alldebrid_api_key[32];
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "1fichier.h"
|
||||
|
||||
#define VALIDATION_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
|
||||
|
||||
FichierHost::FichierHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool FichierHost::IsValidUrl()
|
||||
{
|
||||
std::regex regex(VALIDATION_REGEX);
|
||||
|
||||
if (std::regex_match(url, regex))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string FichierHost::GetDownloadUrl()
|
||||
{
|
||||
std::regex re("https:\\/\\/1fichier\\.com");
|
||||
std::string path = std::regex_replace(url, re, "");
|
||||
|
||||
httplib::Client tmp_client("https://1fichier.com");
|
||||
tmp_client.set_keep_alive(true);
|
||||
tmp_client.set_follow_location(true);
|
||||
tmp_client.set_connection_timeout(30);
|
||||
tmp_client.set_read_timeout(30);
|
||||
tmp_client.enable_server_certificate_verification(false);
|
||||
|
||||
auto res = tmp_client.Get(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
lxb_status_t status;
|
||||
lxb_dom_element_t *element;
|
||||
lxb_dom_node_t *node;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *collection;
|
||||
lxb_dom_attr_t *attr;
|
||||
const lxb_char_t *value;
|
||||
size_t value_len;
|
||||
std::string download_url = "";
|
||||
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
|
||||
if (status != LXB_STATUS_OK)
|
||||
return "";
|
||||
collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
collection, (const lxb_char_t *)"input", 5);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string post_data;
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
|
||||
{
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"name", 4, &value_len);
|
||||
if (value != nullptr)
|
||||
{
|
||||
std::string name_attr((char *)value, value_len);
|
||||
if (name_attr == "adz")
|
||||
{
|
||||
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"value", 5, &value_len);
|
||||
std::string adz_value((char *)value, value_len);
|
||||
post_data = std::string("adz=") + adz_value + "&did=0&dl_no_ssl=off&dlinline=on";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
|
||||
if (auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
|
||||
if (status != LXB_STATUS_OK)
|
||||
return "";
|
||||
|
||||
collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
collection, (const lxb_char_t *)"a", 1);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
|
||||
{
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"class", 5, &value_len);
|
||||
if (value != nullptr)
|
||||
{
|
||||
std::string class_value((char*) value, value_len);
|
||||
if (class_value == "ok btn-general btn-orange")
|
||||
{
|
||||
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
|
||||
if (value != nullptr)
|
||||
{
|
||||
download_url = std::string((char*) value, value_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
}
|
||||
}
|
||||
|
||||
return download_url;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef FICHIER_HOST_H
|
||||
#define FICHIER_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class FichierHost : public FileHost
|
||||
{
|
||||
public:
|
||||
FichierHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <http/httplib.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "alldebrid.h"
|
||||
|
||||
AllDebridHost::AllDebridHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool AllDebridHost::IsValidUrl()
|
||||
{
|
||||
httplib::Client tmp_client("https://api.alldebrid.com");
|
||||
tmp_client.set_keep_alive(true);
|
||||
tmp_client.set_follow_location(true);
|
||||
tmp_client.set_connection_timeout(30);
|
||||
tmp_client.set_read_timeout(30);
|
||||
tmp_client.enable_server_certificate_verification(false);
|
||||
|
||||
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
|
||||
auto res = tmp_client.Get(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
|
||||
|
||||
if (strcmp(status, "success") == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string AllDebridHost::GetDownloadUrl()
|
||||
{
|
||||
httplib::Client tmp_client("https://api.alldebrid.com");
|
||||
tmp_client.set_keep_alive(true);
|
||||
tmp_client.set_follow_location(true);
|
||||
tmp_client.set_connection_timeout(30);
|
||||
tmp_client.set_read_timeout(30);
|
||||
tmp_client.enable_server_certificate_verification(false);
|
||||
|
||||
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
|
||||
auto res = tmp_client.Get(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
|
||||
|
||||
if (status != nullptr && strcmp(status, "success") == 0)
|
||||
{
|
||||
json_object *data = json_object_object_get(jobj, "data");
|
||||
const char *link = json_object_get_string(json_object_object_get(data, "link"));
|
||||
return std::string(link);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef ALLDEBRID_HOST_H
|
||||
#define ALLDEBRID_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class AllDebridHost : public FileHost
|
||||
{
|
||||
public:
|
||||
AllDebridHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "directhost.h"
|
||||
|
||||
|
||||
#define VALIDATION_REGEX "(.*)"
|
||||
|
||||
DirectHost::DirectHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectHost::IsValidUrl()
|
||||
{
|
||||
std::regex regex_1(VALIDATION_REGEX);
|
||||
|
||||
if (std::regex_match(url, regex_1))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string DirectHost::GetDownloadUrl()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef DIRECT_HOST_H
|
||||
#define DIRECT_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class DirectHost : public FileHost
|
||||
{
|
||||
public:
|
||||
DirectHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "openssl/md5.h"
|
||||
|
||||
#include "filehost.h"
|
||||
#include "1fichier.h"
|
||||
#include "filehost/alldebrid.h"
|
||||
#include "filehost/directhost.h"
|
||||
#include "filehost/gdrive.h"
|
||||
#include "filehost/mediafire.h"
|
||||
#include "filehost/pixeldrain.h"
|
||||
#include "config.h"
|
||||
#include "base64.h"
|
||||
#include "util.h"
|
||||
|
||||
#define GDRIVE_REGEX "https:\\/\\/drive\\.google\\.com\\/(.*)"
|
||||
#define MEDIAFIRE_REGEX "https:\\/\\/www\\.mediafire\\.com\\/(.*)"
|
||||
#define PIXELDRAIN_REGEX "https:\\/\\/pixeldrain\\.com\\/(.*)"
|
||||
#define FICHIER_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
|
||||
|
||||
static std::map<std::string, std::string> cache_downloal_urls;
|
||||
|
||||
std::string FileHost::Hash()
|
||||
{
|
||||
std::vector<unsigned char> res(16);
|
||||
MD5((const unsigned char *)this->url.c_str(), this->url.length(), res.data());
|
||||
|
||||
std::string out;
|
||||
Base64::Encode(res.data(), res.size(), out);
|
||||
Util::ReplaceAll(out, "=", "_");
|
||||
Util::ReplaceAll(out, "+", "_");
|
||||
out = out + ".pkg";
|
||||
return out;
|
||||
}
|
||||
|
||||
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
|
||||
{
|
||||
std::regex google_re(GDRIVE_REGEX);
|
||||
std::regex mediafire_re(MEDIAFIRE_REGEX);
|
||||
std::regex pixeldrain_re(PIXELDRAIN_REGEX);
|
||||
std::regex fichier_re(FICHIER_REGEX);
|
||||
|
||||
if (use_alldebrid)
|
||||
return new AllDebridHost(url);
|
||||
else if (std::regex_match(url, google_re))
|
||||
return new GDriveHost(url);
|
||||
else if (std::regex_match(url, mediafire_re))
|
||||
return new MediaFireHost(url);
|
||||
else if (std::regex_match(url, pixeldrain_re))
|
||||
return new PixelDrainHost(url);
|
||||
else
|
||||
return new DirectHost(url);
|
||||
}
|
||||
|
||||
std::string FileHost::GetCachedDownloadUrl(std::string &hash)
|
||||
{
|
||||
return cache_downloal_urls[hash];
|
||||
}
|
||||
|
||||
void FileHost::AddCacheDownloadUrl(std::string &hash, std::string &url)
|
||||
{
|
||||
std::pair<std::string, std::string> pair = std::make_pair(hash, url);
|
||||
cache_downloal_urls.erase(hash);
|
||||
cache_downloal_urls.insert(pair);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef FILEHOST_H
|
||||
#define FILEHOST_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class FileHost
|
||||
{
|
||||
public:
|
||||
FileHost(const std::string &url) { this->url = url; };
|
||||
virtual ~FileHost(){};
|
||||
virtual bool IsValidUrl() = 0;
|
||||
virtual std::string GetDownloadUrl() = 0;
|
||||
|
||||
std::string Hash();
|
||||
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false);
|
||||
static std::string GetCachedDownloadUrl(std::string &hash);
|
||||
static void AddCacheDownloadUrl(std::string &hash, std::string &url);
|
||||
|
||||
protected:
|
||||
std::string url;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "gdrive.h"
|
||||
|
||||
#define VALIDATION_REGEX_1 "https:\\/\\/drive\\.google\\.com\\/file\\/d\\/(.*)\\/(edit|view)\\?usp=(.*)"
|
||||
#define VALIDATION_REGEX_2 "https:\\/\\/drive\\.google\\.com\\/(.*)uc\\?(id=|export=)(.*)&(id=|export=)(.*)"
|
||||
|
||||
GDriveHost::GDriveHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool GDriveHost::IsValidUrl()
|
||||
{
|
||||
std::regex regex_1(VALIDATION_REGEX_1);
|
||||
std::regex regex_2(VALIDATION_REGEX_2);
|
||||
|
||||
if (std::regex_match(url, regex_1) || std::regex_match(url, regex_2))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GDriveHost::GetDownloadUrl()
|
||||
{
|
||||
std::regex regex_1(VALIDATION_REGEX_1);
|
||||
std::smatch matches;
|
||||
|
||||
std::string path;
|
||||
if(std::regex_search(url, matches, regex_1))
|
||||
{
|
||||
path = std::string("/uc?export=download&id=") + matches[1].str();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::regex re("https:\\/\\/drive\\.google\\.com");
|
||||
path = std::regex_replace(url, re, "");
|
||||
}
|
||||
|
||||
httplib::Client tmp_client("https://drive.google.com");
|
||||
tmp_client.set_keep_alive(true);
|
||||
tmp_client.set_follow_location(true);
|
||||
tmp_client.set_connection_timeout(30);
|
||||
tmp_client.set_read_timeout(30);
|
||||
tmp_client.enable_server_certificate_verification(false);
|
||||
|
||||
auto res = tmp_client.Head(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
std::string content_type = res->get_header_value("Content-Type");
|
||||
if (content_type == "application/octet-stream")
|
||||
return url;
|
||||
else if (content_type.find("text/html") == std::string::npos)
|
||||
return "";
|
||||
}
|
||||
else
|
||||
return "";
|
||||
|
||||
res = tmp_client.Get(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
lxb_status_t status;
|
||||
lxb_dom_element_t *element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *collection;
|
||||
lxb_dom_attr_t *attr;
|
||||
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
collection, (const lxb_char_t *)"form", 4);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string download_url;
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
|
||||
{
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
if (element->attr_id != nullptr)
|
||||
{
|
||||
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
|
||||
if (form_id == "download-form")
|
||||
{
|
||||
size_t value_len;
|
||||
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
|
||||
download_url = std::string((char *)value, value_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
|
||||
return download_url;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef GDRIVE_HOST_H
|
||||
#define GDRIVE_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class GDriveHost : public FileHost
|
||||
{
|
||||
public:
|
||||
GDriveHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mediafire.h"
|
||||
|
||||
#define VALIDATION_REGEX "https:\\/\\/www\\.mediafire\\.com\\/file\\/(.*)\\/(.*)\\/file"
|
||||
|
||||
MediaFireHost::MediaFireHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool MediaFireHost::IsValidUrl()
|
||||
{
|
||||
std::regex regex(VALIDATION_REGEX);
|
||||
|
||||
if (std::regex_match(url, regex))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string MediaFireHost::GetDownloadUrl()
|
||||
{
|
||||
std::regex re("https:\\/\\/www\\.mediafire\\.com");
|
||||
std::string path = std::regex_replace(url, re, "");
|
||||
|
||||
httplib::Client tmp_client("https://www.mediafire.com");
|
||||
tmp_client.set_keep_alive(true);
|
||||
tmp_client.set_follow_location(true);
|
||||
tmp_client.set_connection_timeout(30);
|
||||
tmp_client.set_read_timeout(30);
|
||||
tmp_client.enable_server_certificate_verification(false);
|
||||
|
||||
auto res = tmp_client.Get(path);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
lxb_status_t status;
|
||||
lxb_dom_element_t *element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *collection;
|
||||
lxb_dom_attr_t *attr;
|
||||
|
||||
document = lxb_html_document_create();
|
||||
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
|
||||
if (status != LXB_STATUS_OK)
|
||||
return "";
|
||||
collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
collection, (const lxb_char_t *)"a", 1);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string download_url;
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
|
||||
{
|
||||
element = lxb_dom_collection_element(collection, i);
|
||||
if (element->attr_id != nullptr)
|
||||
{
|
||||
std::string a_id((char *)element->attr_id->value->data, element->attr_id->value->length);
|
||||
|
||||
if (a_id == "downloadButton")
|
||||
{
|
||||
size_t value_len;
|
||||
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
|
||||
download_url = std::string((char *)value, value_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lxb_dom_collection_destroy(collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
|
||||
return download_url;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef MEDIAFIRE_HOST_H
|
||||
#define MEDIAFIRE_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class MediaFireHost : public FileHost
|
||||
{
|
||||
public:
|
||||
MediaFireHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "pixeldrain.h"
|
||||
|
||||
|
||||
#define VALIDATION_REGEX "https:\\/\\/pixeldrain\\.com\\/u\\/(.*)"
|
||||
|
||||
PixelDrainHost::PixelDrainHost(const std::string &url) : FileHost(url)
|
||||
{
|
||||
}
|
||||
|
||||
bool PixelDrainHost::IsValidUrl()
|
||||
{
|
||||
std::regex re(VALIDATION_REGEX);
|
||||
|
||||
if (std::regex_match(url, re))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string PixelDrainHost::GetDownloadUrl()
|
||||
{
|
||||
std::regex re(VALIDATION_REGEX);
|
||||
std::smatch matches;
|
||||
|
||||
if(std::regex_search(url, matches, re))
|
||||
{
|
||||
if (matches.size() > 1)
|
||||
{
|
||||
return std::string("https://pixeldrain.com/api/file/") + matches[1].str() + "?download=";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef PIXELDRAIN_HOST_H
|
||||
#define PIXELDRAIN_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
class PixelDrainHost : public FileHost
|
||||
{
|
||||
public:
|
||||
PixelDrainHost(const std::string &url);
|
||||
bool IsValidUrl();
|
||||
std::string GetDownloadUrl();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1900,6 +1900,7 @@ namespace detail {
|
||||
|
||||
std::string encode_query_param(const std::string &value);
|
||||
|
||||
std::string encode_url(const std::string &s);
|
||||
std::string decode_url(const std::string &s, bool convert_plus_to_space);
|
||||
|
||||
void read_file(const std::string &path, std::string &out);
|
||||
|
||||
+145
-33
@@ -21,7 +21,9 @@
|
||||
#include "lang.h"
|
||||
#include "system.h"
|
||||
#include "fs.h"
|
||||
#include "sfo.h"
|
||||
#include "clients/webdavclient.h"
|
||||
#include "clients/remote_client.h"
|
||||
|
||||
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
||||
|
||||
@@ -99,6 +101,96 @@ namespace INSTALLER
|
||||
s_bgft_initialized = false;
|
||||
}
|
||||
|
||||
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header)
|
||||
{
|
||||
size_t entry_count = BE32(header->pkg_entry_count);
|
||||
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
|
||||
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
|
||||
void *entry_table_data = malloc(entry_table_size);
|
||||
|
||||
int ret = client->GetRange(path, entry_table_data, entry_table_size, entry_table_offset);
|
||||
if (ret == 0)
|
||||
{
|
||||
free(entry_table_data);
|
||||
return "";
|
||||
}
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = nullptr;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
for (size_t i = 0; i < entry_count; ++i)
|
||||
{
|
||||
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
|
||||
{
|
||||
param_sfo_offset = BE32(entries[i].offset);
|
||||
param_sfo_size = BE32(entries[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(entry_table_data);
|
||||
|
||||
std::string title;
|
||||
if (param_sfo_offset > 0 && param_sfo_size > 0)
|
||||
{
|
||||
param_sfo_data = malloc(param_sfo_size);
|
||||
int ret = client->GetRange(path, param_sfo_data, param_sfo_size, param_sfo_offset);
|
||||
if (ret)
|
||||
{
|
||||
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
|
||||
if (tmp_title != nullptr)
|
||||
title = std::string(tmp_title);
|
||||
}
|
||||
free(param_sfo_data);
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header)
|
||||
{
|
||||
size_t entry_count = BE32(header->pkg_entry_count);
|
||||
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
|
||||
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
|
||||
void *entry_table_data = malloc(entry_table_size);
|
||||
|
||||
FILE *fd = FS::OpenRead(path);
|
||||
FS::Seek(fd, entry_table_offset);
|
||||
FS::Read(fd, entry_table_data, entry_table_size);
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
uint32_t icon0_png_offset = 0;
|
||||
uint32_t icon0_png_size = 0;
|
||||
for (size_t i = 0; i < entry_count; ++i)
|
||||
{
|
||||
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
|
||||
{
|
||||
param_sfo_offset = BE32(entries[i].offset);
|
||||
param_sfo_size = BE32(entries[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(entry_table_data);
|
||||
|
||||
std::string title;
|
||||
if (param_sfo_offset > 0 && param_sfo_size > 0)
|
||||
{
|
||||
param_sfo_data = malloc(param_sfo_size);
|
||||
FS::Seek(fd, param_sfo_offset);
|
||||
FS::Read(fd, param_sfo_data, param_sfo_size);
|
||||
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
|
||||
if (tmp_title != nullptr)
|
||||
title = std::string(tmp_title);
|
||||
free(param_sfo_data);
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
std::string getRemoteUrl(const std::string path, bool encodeUrl)
|
||||
{
|
||||
if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 &&
|
||||
@@ -125,11 +217,14 @@ namespace INSTALLER
|
||||
else
|
||||
{
|
||||
std::string encoded_path = path;
|
||||
std::string encoded_site_name = remote_settings->site_name;
|
||||
Web::Urn::Path uri(encoded_path);
|
||||
Web::Urn::Path site_name(encoded_site_name);
|
||||
CURL *curl = curl_easy_init();
|
||||
encoded_path = uri.quote(curl);
|
||||
encoded_site_name = site_name.quote(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_path;
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path;
|
||||
|
||||
return full_url;
|
||||
}
|
||||
@@ -142,17 +237,15 @@ namespace INSTALLER
|
||||
return true;
|
||||
}
|
||||
|
||||
int InstallRemotePkg(const std::string &path, pkg_header *header)
|
||||
int InstallRemotePkg(const std::string &url, pkg_header *header, std::string title, bool prompt)
|
||||
{
|
||||
std::string url = getRemoteUrl(path, true);
|
||||
|
||||
if (url.empty())
|
||||
return 0;
|
||||
|
||||
int ret;
|
||||
std::string filename = path.substr(path.find_last_of("/")+1);
|
||||
std::string cid = std::string((char *)header->pkg_content_id);
|
||||
cid = cid.substr(cid.find_first_of("-") + 1, 9);
|
||||
std::string display_title = title.length() > 0 ? title : cid;
|
||||
int user_id;
|
||||
ret = sceUserServiceGetForegroundUser(&user_id);
|
||||
const char *package_type;
|
||||
@@ -196,7 +289,7 @@ namespace INSTALLER
|
||||
params.entitlementType = 5;
|
||||
params.id = (char *)header->pkg_content_id;
|
||||
params.contentUrl = url.c_str();
|
||||
params.contentName = filename.c_str();
|
||||
params.contentName = display_title.c_str();
|
||||
params.iconPath = "";
|
||||
params.playgoScenarioId = "0";
|
||||
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
|
||||
@@ -213,18 +306,28 @@ namespace INSTALLER
|
||||
ret = sceBgftServiceIntDebugDownloadRegisterPkg(¶ms, &task_id);
|
||||
if (ret == 0x80990088 || ret == 0x80990015)
|
||||
{
|
||||
sprintf(confirm_message, "%s - %s?", path.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
while (confirm_state == CONFIRM_WAIT)
|
||||
if (prompt)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
while (confirm_state == CONFIRM_WAIT)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
@@ -241,19 +344,22 @@ namespace INSTALLER
|
||||
goto err;
|
||||
}
|
||||
|
||||
Util::Notify("%s queued", filename.c_str());
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_transfered = 0;
|
||||
while (bytes_transfered < 99)
|
||||
if (prompt)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
|
||||
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
|
||||
return 0;
|
||||
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
|
||||
sceSystemServicePowerTick();
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_transfered = 0;
|
||||
while (bytes_transfered < 99)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
|
||||
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
|
||||
return 0;
|
||||
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
|
||||
sceSystemServicePowerTick();
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -286,6 +392,9 @@ namespace INSTALLER
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string title = GetLocalPkgTitle(path, &header);
|
||||
std::string display_title = title.length() > 0 ? title : std::string(titleId);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
OrbisBgftDownloadParamEx download_params;
|
||||
memset(&download_params, 0, sizeof(download_params));
|
||||
@@ -293,7 +402,7 @@ namespace INSTALLER
|
||||
download_params.params.entitlementType = 5;
|
||||
download_params.params.id = (char *)header.pkg_content_id;
|
||||
download_params.params.contentUrl = filepath;
|
||||
download_params.params.contentName = path.c_str();
|
||||
download_params.params.contentName = display_title.c_str();
|
||||
;
|
||||
download_params.params.iconPath = "";
|
||||
download_params.params.playgoScenarioId = "0";
|
||||
@@ -318,7 +427,7 @@ namespace INSTALLER
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
Util::Notify("%s queued", path.c_str());
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
@@ -360,6 +469,9 @@ namespace INSTALLER
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string title = GetLocalPkgTitle(path, header);
|
||||
std::string display_title = title.length() > 0 ? title : std::string(titleId);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
int prog = 0;
|
||||
OrbisBgftDownloadParamEx download_params;
|
||||
@@ -368,7 +480,7 @@ namespace INSTALLER
|
||||
download_params.params.entitlementType = 5;
|
||||
download_params.params.id = (char *)header->pkg_content_id;
|
||||
download_params.params.contentUrl = filepath;
|
||||
download_params.params.contentName = filename.c_str();
|
||||
download_params.params.contentName = display_title.c_str();
|
||||
;
|
||||
download_params.params.iconPath = "";
|
||||
download_params.params.playgoScenarioId = "0";
|
||||
@@ -381,7 +493,7 @@ namespace INSTALLER
|
||||
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
|
||||
if (ret == 0x80990088 || ret == 0x80990015)
|
||||
{
|
||||
sprintf(confirm_message, "%s - %s?", path.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
@@ -416,7 +528,7 @@ namespace INSTALLER
|
||||
|
||||
if (!remove_after_install)
|
||||
{
|
||||
Util::Notify("%s queued", filename.c_str());
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -587,4 +699,4 @@ namespace INSTALLER
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "clients/remote_client.h"
|
||||
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
|
||||
(((uint16_t)(x)&UINT16_C(0xFF00)) >> 8)))
|
||||
@@ -121,9 +123,11 @@ namespace INSTALLER
|
||||
|
||||
bool canInstallRemotePkg(const std::string &url);
|
||||
std::string getRemoteUrl(const std::string path, bool encodeUrl = false);
|
||||
int InstallRemotePkg(const std::string &path, pkg_header *header);
|
||||
int InstallRemotePkg(const std::string &path, pkg_header *header, std::string title, bool prompt = false);
|
||||
int InstallLocalPkg(const std::string &path);
|
||||
int InstallLocalPkg(const std::string &path, pkg_header *header, bool remove_after_install = false);
|
||||
bool ExtractLocalPkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
|
||||
bool ExtractRemotePkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
|
||||
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header);
|
||||
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header);
|
||||
}
|
||||
+7
-1
@@ -94,7 +94,7 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Not a valid Package", // STR_NOT_A_VALID_PACKAGE
|
||||
"Waiting for Package to finish installing", // STR_WAIT_FOR_INSTALL_MSG
|
||||
"Failed to install pkg file. Please delete the tmp pkg manually", // STR_FAIL_INSTALL_TMP_PKG_MSG
|
||||
"Failed to obtain google download URL", // STR_FAIL_TO_OBTAIN_GG_DL_MSG
|
||||
"Failed to obtain download URL", // STR_FAIL_TO_OBTAIN_GG_DL_MSG
|
||||
"Auto delete temporary downloaded pkg file after install", // STR_AUTO_DELETE_TMP_PKG
|
||||
"Protocol not supported", // STR_PROTOCOL_NOT_SUPPORTED
|
||||
"Could not resolve hostname", // STR_COULD_NOT_RESOLVE_HOST
|
||||
@@ -162,6 +162,12 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Enable", // STR_ENABLE
|
||||
"Compressed Files Location", // STR_COMPRESSED_FILE_PATH
|
||||
"Location of where compressed files are stored on the web server", // STR_COMPRESSED_FILE_PATH_MSG
|
||||
"AllDebrid", // STR_ALLDEBRID
|
||||
"API Key", // STR_API_KEY
|
||||
"Couldn't extract download url", // STR_CANT_EXTRACT_URL_MSG
|
||||
"Failed to install from URL", // STR_FAIL_INSTALL_FROM_URL_MSG
|
||||
"InValid URL", // STR_INVALID_URL
|
||||
"To use this function, an API Key needs to be configured in the ezRemote Client settings", // STR_ALLDEBRID_API_KEY_MISSING_MSG
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
|
||||
+9
-3
@@ -153,9 +153,15 @@
|
||||
FUNC(STR_FAIL_INIT_NFS_CONTEXT) \
|
||||
FUNC(STR_FAIL_MOUNT_NFS_MSG) \
|
||||
FUNC(STR_WEB_SERVER) \
|
||||
FUNC(STR_ENABLE) \
|
||||
FUNC(STR_ENABLE) \
|
||||
FUNC(STR_COMPRESSED_FILE_PATH) \
|
||||
FUNC(STR_COMPRESSED_FILE_PATH_MSG)
|
||||
FUNC(STR_COMPRESSED_FILE_PATH_MSG) \
|
||||
FUNC(STR_ALLDEBRID) \
|
||||
FUNC(STR_API_KEY) \
|
||||
FUNC(STR_CANT_EXTRACT_URL_MSG) \
|
||||
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
|
||||
FUNC(STR_INVALID_URL) \
|
||||
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG)
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -165,7 +171,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 152
|
||||
#define LANG_STRINGS_NUM 158
|
||||
#define LANG_ID_SIZE 64
|
||||
#define LANG_STR_SIZE 384
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
|
||||
@@ -2,9 +2,70 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <libjbc.h>
|
||||
|
||||
#define SYSCALL(nr, fn) __attribute__((naked)) fn\
|
||||
{\
|
||||
asm volatile("mov $" #nr ", %rax\nmov %rcx, %r10\nsyscall\nret");\
|
||||
}
|
||||
|
||||
SYSCALL(22, static int unmount(const char* path, int flags))
|
||||
SYSCALL(378, static int nmount(struct iovec* iov, unsigned int niov, int flags))
|
||||
|
||||
static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const void* val, size_t len) {
|
||||
int i;
|
||||
|
||||
if (*iovlen < 0)
|
||||
return;
|
||||
|
||||
i = *iovlen;
|
||||
*iov = (struct iovec*)realloc(*iov, sizeof **iov * (i + 2));
|
||||
if (*iov == NULL) {
|
||||
*iovlen = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
(*iov)[i].iov_base = strdup(name);
|
||||
(*iov)[i].iov_len = strlen(name) + 1;
|
||||
++i;
|
||||
|
||||
(*iov)[i].iov_base = (void*)val;
|
||||
if (len == (size_t)-1) {
|
||||
if (val != NULL)
|
||||
len = strlen((const char*)val) + 1;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
(*iov)[i].iov_len = (int)len;
|
||||
|
||||
*iovlen = ++i;
|
||||
}
|
||||
|
||||
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags)
|
||||
{
|
||||
struct iovec* iov = NULL;
|
||||
int iovlen = 0;
|
||||
|
||||
unmount(mountpoint, 0);
|
||||
|
||||
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
|
||||
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
|
||||
build_iovec(&iov, &iovlen, "from", device, -1);
|
||||
build_iovec(&iov, &iovlen, "large", "yes", -1);
|
||||
build_iovec(&iov, &iovlen, "timezone", "static", -1);
|
||||
build_iovec(&iov, &iovlen, "async", "", -1);
|
||||
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
|
||||
|
||||
if (mode) {
|
||||
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
|
||||
build_iovec(&iov, &iovlen, "mask", mode, -1);
|
||||
}
|
||||
|
||||
return nmount(iov, iovlen, flags);
|
||||
}
|
||||
|
||||
// Variables for (un)jailbreaking
|
||||
jbc_cred g_Cred;
|
||||
jbc_cred g_RootCreds;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#ifndef __ORBIS_JBC_H__
|
||||
#define __ORBIS_JBC_H__
|
||||
|
||||
#define MNT_UPDATE 0x0000000000010000ULL
|
||||
|
||||
int initialize_jbc();
|
||||
void terminate_jbc();
|
||||
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags);
|
||||
|
||||
#endif
|
||||
|
||||
+122
-27
@@ -8,6 +8,7 @@
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "filehost/filehost.h"
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "windows.h"
|
||||
@@ -920,34 +921,55 @@ namespace HttpServer
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
});
|
||||
|
||||
svr->Get("/rmt_inst/(.*)", [&](const Request & req, Response & res)
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
auto path = std::string("/") + std::string(req.matches[1]);
|
||||
RemoteSettings *tmp_settings;
|
||||
auto site_idx = std::stoi(req.matches[1])-1;
|
||||
std::string path;
|
||||
|
||||
if (remote_settings->type == CLIENT_TYPE_SFTP)
|
||||
if (site_idx != 98)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
|
||||
}
|
||||
else if (remote_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
|
||||
}
|
||||
else if (remote_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
|
||||
}
|
||||
else if (remote_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
|
||||
path = std::string("/") + std::string(req.matches[3]);
|
||||
|
||||
tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
if (tmp_settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_client = remoteclient;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_client = remoteclient;
|
||||
std::string hash = std::string(req.matches[3]);
|
||||
std::string url = FileHost::GetCachedDownloadUrl(hash);
|
||||
size_t scheme_pos = url.find("://");
|
||||
size_t root_pos = url.find("/", scheme_pos + 3);
|
||||
std::string host = url.substr(0, root_pos);
|
||||
path = url.substr(root_pos);
|
||||
|
||||
tmp_client = new BaseClient();
|
||||
tmp_client->Connect(host, "", "");
|
||||
}
|
||||
|
||||
if (tmp_client == nullptr || !tmp_client->IsConnected())
|
||||
@@ -983,11 +1005,12 @@ namespace HttpServer
|
||||
int ret = tmp_client->GetRange(path, sink, length, offset);
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, path](bool success) {
|
||||
[tmp_client, path, site_idx](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS))
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
@@ -1011,11 +1034,12 @@ namespace HttpServer
|
||||
int ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, path, range, range_len](bool success) {
|
||||
[tmp_client, site_idx, path, range, range_len](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS))
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
@@ -1024,6 +1048,77 @@ namespace HttpServer
|
||||
}
|
||||
});
|
||||
|
||||
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
|
||||
{
|
||||
std::string url;
|
||||
const char *url_param;
|
||||
bool use_alldebrid;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
|
||||
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
|
||||
if (url_param == nullptr)
|
||||
{
|
||||
bad_request(res, "Required url_param, use_alldebrid parameter missing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_request(res, "Invalid payload");
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_alldebrid && strlen(alldebrid_api_key) == 0)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ALLDEBRID_API_KEY_MISSING_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
url = std::string(url_param);
|
||||
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid);
|
||||
|
||||
if (!filehost->IsValidUrl())
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_INVALID_URL]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string hash = filehost->Hash();
|
||||
std::string download_url = filehost->GetDownloadUrl();
|
||||
if (download_url.empty())
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
FileHost::AddCacheDownloadUrl(hash, download_url);
|
||||
delete(filehost);
|
||||
|
||||
size_t scheme_pos = download_url.find("://");
|
||||
size_t root_pos = download_url.find("/", scheme_pos + 3);
|
||||
std::string host = download_url.substr(0, root_pos);
|
||||
std::string path = download_url.substr(root_pos);
|
||||
pkg_header header;
|
||||
|
||||
BaseClient *baseclient = new BaseClient();
|
||||
baseclient->Connect(host, "", "");
|
||||
baseclient->Head(path, &header, sizeof(pkg_header));
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
|
||||
delete(baseclient);
|
||||
|
||||
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
|
||||
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
|
||||
if (rc == 0)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
success(res);
|
||||
});
|
||||
|
||||
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
|
||||
{
|
||||
svr->stop();
|
||||
@@ -1043,7 +1138,7 @@ namespace HttpServer
|
||||
dbglogger_log("%s", log(req, res).c_str());
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
svr->set_payload_max_length(1024 * 1024 * 12);
|
||||
svr->set_tcp_nodelay(true);
|
||||
svr->set_mount_point("/", "/");
|
||||
@@ -1072,4 +1167,4 @@ namespace HttpServer
|
||||
if (svr != nullptr)
|
||||
svr->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-3
@@ -1062,7 +1062,7 @@ namespace Windows
|
||||
ime_after_update = AfterExtractFolderCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
file_transfering = true;
|
||||
file_transfering = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
@@ -1605,7 +1605,7 @@ namespace Windows
|
||||
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(1050, 80));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 500), NULL, NULL);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 650), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
|
||||
@@ -1674,6 +1674,34 @@ namespace Windows
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
// Google settings
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
|
||||
ImGui::Separator();
|
||||
|
||||
field_size = ImGui::CalcTextSize(lang_strings[STR_API_KEY]);
|
||||
width = field_size.x + 45;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_API_KEY]);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
|
||||
|
||||
if (strlen(alldebrid_api_key) > 0)
|
||||
sprintf(id, "%s", "*********************************************##alldebrid_api_key");
|
||||
else
|
||||
sprintf(id, "%s", "##client_secret_input");
|
||||
if (ImGui::Button(id, ImVec2(835-width, 0)))
|
||||
{
|
||||
ResetImeCallbacks();
|
||||
ime_single_field = alldebrid_api_key;
|
||||
ime_field_size = 31;
|
||||
ime_callback = SingleValueImeCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 31, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
// Google settings
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GOOGLE]);
|
||||
ImGui::Separator();
|
||||
@@ -1972,7 +2000,7 @@ namespace Windows
|
||||
activity_inprogess = true;
|
||||
sprintf(activity_message, "%s", "");
|
||||
stop_activity = false;
|
||||
file_transfering = true;
|
||||
file_transfering = false;
|
||||
selected_action = ACTION_NONE;
|
||||
Actions::ExtractLocalZips();
|
||||
break;
|
||||
|
||||
+222
-117
@@ -9,18 +9,23 @@
|
||||
#include <minizip/zip.h>
|
||||
#include <un7zip.h>
|
||||
#include <unrar.h>
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "ime_dialog.h"
|
||||
#include "lang.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
#include "zip_util.h"
|
||||
|
||||
#define TRANSFER_SIZE (128 * 1024)
|
||||
#define TRANSFER_SIZE (16 * 1024)
|
||||
|
||||
namespace ZipUtil
|
||||
{
|
||||
static char filename_extracted[256];
|
||||
static char password[128];
|
||||
|
||||
void callback_7zip(const char *fileName, unsigned long fileSize, unsigned fileNum, unsigned numFiles)
|
||||
{
|
||||
@@ -217,153 +222,253 @@ namespace ZipUtil
|
||||
return 1;
|
||||
}
|
||||
|
||||
CompressFileType getCompressFileType(const std::string &file)
|
||||
/* duplicate a path name, possibly converting to lower case */
|
||||
static char *pathdup(const char *path)
|
||||
{
|
||||
char buf[8];
|
||||
char *str;
|
||||
size_t i, len;
|
||||
|
||||
memset(buf, 0, 8);
|
||||
int ret = FS::Head(file, buf, 8);
|
||||
if (ret == 0)
|
||||
return COMPRESS_FILE_TYPE_UNKNOWN;
|
||||
if (path == NULL || path[0] == '\0')
|
||||
return (NULL);
|
||||
|
||||
if (strncmp(buf, (const char *)MAGIC_7Z_1, 6) == 0)
|
||||
return COMPRESS_FILE_TYPE_7Z;
|
||||
else if (strncmp(buf, (const char *)MAGIC_RAR_1, 7) == 0 || strncmp(buf, (const char *)MAGIC_RAR_2, 8) == 0)
|
||||
return COMPRESS_FILE_TYPE_RAR;
|
||||
else if (strncmp(buf, (const char *)MAGIC_ZIP_1, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_2, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_3, 4) == 0)
|
||||
return COMPRESS_FILE_TYPE_ZIP;
|
||||
len = strlen(path);
|
||||
while (len && path[len - 1] == '/')
|
||||
len--;
|
||||
if ((str = (char*) malloc(len + 1)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
memcpy(str, path, len);
|
||||
|
||||
return COMPRESS_FILE_TYPE_UNKNOWN;
|
||||
str[len] = '\0';
|
||||
|
||||
return (str);
|
||||
}
|
||||
|
||||
int ExtractZip(const DirEntry &file, const std::string &dir)
|
||||
/* concatenate two path names */
|
||||
static char *pathcat(const char *prefix, const char *path)
|
||||
{
|
||||
file_transfering = true;
|
||||
unz_global_info global_info;
|
||||
unz_file_info file_info;
|
||||
unzFile zipfile = unzOpen(file.path);
|
||||
std::string dest_dir = std::string(dir);
|
||||
if (dest_dir[dest_dir.length() - 1] != '/')
|
||||
{
|
||||
dest_dir = dest_dir + "/";
|
||||
}
|
||||
if (zipfile == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unzGetGlobalInfo(zipfile, &global_info);
|
||||
unzGoToFirstFile(zipfile);
|
||||
uint64_t curr_extracted_bytes = 0;
|
||||
uint64_t curr_file_bytes = 0;
|
||||
int num_files = global_info.number_entry;
|
||||
char fname[512];
|
||||
char ext_fname[512];
|
||||
char read_buffer[TRANSFER_SIZE];
|
||||
char *str;
|
||||
size_t prelen, len;
|
||||
|
||||
for (int zip_idx = 0; zip_idx < num_files; ++zip_idx)
|
||||
{
|
||||
if (stop_activity)
|
||||
break;
|
||||
unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0);
|
||||
sprintf(ext_fname, "%s%s", dest_dir.c_str(), fname);
|
||||
const size_t filename_length = strlen(ext_fname);
|
||||
bytes_transfered = 0;
|
||||
bytes_to_download = file_info.uncompressed_size;
|
||||
if (ext_fname[filename_length - 1] != '/')
|
||||
{
|
||||
snprintf(activity_message, 255, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, fname);
|
||||
curr_file_bytes = 0;
|
||||
unzOpenCurrentFile(zipfile);
|
||||
FS::MkDirs(ext_fname, true);
|
||||
FILE *f = fopen(ext_fname, "wb");
|
||||
while (curr_file_bytes < file_info.uncompressed_size)
|
||||
{
|
||||
int rbytes = unzReadCurrentFile(zipfile, read_buffer, TRANSFER_SIZE);
|
||||
if (rbytes > 0)
|
||||
{
|
||||
fwrite(read_buffer, 1, rbytes, f);
|
||||
curr_extracted_bytes += rbytes;
|
||||
curr_file_bytes += rbytes;
|
||||
bytes_transfered = curr_file_bytes;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
unzCloseCurrentFile(zipfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
FS::MkDirs(ext_fname, true);
|
||||
}
|
||||
if ((zip_idx + 1) < num_files)
|
||||
{
|
||||
unzGoToNextFile(zipfile);
|
||||
}
|
||||
prelen = prefix ? strlen(prefix) + 1 : 0;
|
||||
len = strlen(path) + 1;
|
||||
if ((str = (char*) malloc(prelen + len)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
unzClose(zipfile);
|
||||
return 1;
|
||||
if (prefix) {
|
||||
memcpy(str, prefix, prelen); /* includes zero */
|
||||
str[prelen - 1] = '/'; /* splat zero */
|
||||
}
|
||||
memcpy(str + prelen, path, len); /* includes zero */
|
||||
|
||||
return (str);
|
||||
}
|
||||
|
||||
int Extract7Zip(const DirEntry &file, const std::string &dir)
|
||||
/*
|
||||
* Extract a directory.
|
||||
*/
|
||||
static void extract_dir(struct archive *a, struct archive_entry *e, const std::string &path)
|
||||
{
|
||||
file_transfering = false;
|
||||
FS::MkDirs(dir, true);
|
||||
sprintf(filename_extracted, "%s", file.name);
|
||||
int res = Extract7zFileEx(file.path, dir.c_str(), callback_7zip, DEFAULT_IN_BUF_SIZE);
|
||||
return res == 0;
|
||||
int mode;
|
||||
|
||||
if (path[0] == '\0')
|
||||
return;
|
||||
|
||||
FS::MkDirs(path);
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
|
||||
int ExtractRar(const DirEntry &file, const std::string &dir)
|
||||
/*
|
||||
* Extract to a file descriptor
|
||||
*/
|
||||
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
|
||||
{
|
||||
file_transfering = false;
|
||||
HANDLE hArcData; // Archive Handle
|
||||
struct RAROpenArchiveDataEx rarOpenArchiveData;
|
||||
struct RARHeaderDataEx rarHeaderData;
|
||||
char destPath[256];
|
||||
ssize_t len;
|
||||
unsigned char buffer[TRANSFER_SIZE];
|
||||
|
||||
memset(&rarOpenArchiveData, 0, sizeof(rarOpenArchiveData));
|
||||
memset(&rarHeaderData, 0, sizeof(rarHeaderData));
|
||||
/* loop over file contents and write to fd */
|
||||
for (int n = 0; ; n++) {
|
||||
len = archive_read_data(a, buffer, sizeof buffer);
|
||||
|
||||
sprintf(destPath, "%s", dir.c_str());
|
||||
rarOpenArchiveData.ArcName = (char *)file.path;
|
||||
rarOpenArchiveData.CmtBuf = NULL;
|
||||
rarOpenArchiveData.CmtBufSize = 0;
|
||||
rarOpenArchiveData.OpenMode = RAR_OM_EXTRACT;
|
||||
hArcData = RAROpenArchiveEx(&rarOpenArchiveData);
|
||||
if (len == 0)
|
||||
return 1;
|
||||
|
||||
if (rarOpenArchiveData.OpenResult != ERAR_SUCCESS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (RARReadHeaderEx(hArcData, &rarHeaderData) == ERAR_SUCCESS)
|
||||
{
|
||||
sprintf(activity_message, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, rarHeaderData.FileName);
|
||||
if (RARProcessFile(hArcData, RAR_EXTRACT, destPath, NULL) != ERAR_SUCCESS)
|
||||
if (len < 0)
|
||||
{
|
||||
RARCloseArchive(hArcData);
|
||||
sprintf(status_message, "error archive_read_data('%s')", pathname.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (write(fd, buffer, len) != len)
|
||||
{
|
||||
sprintf(status_message, "error write('%s')", pathname.c_str());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RARCloseArchive(hArcData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Extract(const DirEntry &file, const std::string &dir)
|
||||
/*
|
||||
* Extract a regular file.
|
||||
*/
|
||||
static void extract_file(struct archive *a, struct archive_entry *e, const std::string &path)
|
||||
{
|
||||
CompressFileType fileType = getCompressFileType(file.path);
|
||||
struct stat sb;
|
||||
int fd;
|
||||
const char *linkname;
|
||||
|
||||
if (fileType == COMPRESS_FILE_TYPE_ZIP)
|
||||
return ExtractZip(file, dir);
|
||||
else if (fileType == COMPRESS_FILE_TYPE_7Z)
|
||||
return Extract7Zip(file, dir);
|
||||
else if (fileType == COMPRESS_FILE_TYPE_RAR)
|
||||
return ExtractRar(file, dir);
|
||||
/* look for existing file of same name */
|
||||
recheck:
|
||||
if (lstat(path.c_str(), &sb) == 0) {
|
||||
(void)unlink(path.c_str());
|
||||
}
|
||||
|
||||
/* process symlinks */
|
||||
linkname = archive_entry_symlink(e);
|
||||
if (linkname != NULL) {
|
||||
if (symlink(linkname, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(status_message, "error symlink('%s')", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
/* set access and modification time */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((fd = open(path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0777)) < 0)
|
||||
{
|
||||
sprintf(status_message, "error open('%s')", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
extract2fd(a, path, fd);
|
||||
|
||||
/* set access and modification time */
|
||||
if (close(fd) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void extract(struct archive *a, struct archive_entry *e, const std::string &base_dir)
|
||||
{
|
||||
char *pathname, *realpathname;
|
||||
mode_t filetype;
|
||||
char *p, *q;
|
||||
|
||||
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
|
||||
archive_read_data_skip(a);
|
||||
return;
|
||||
}
|
||||
filetype = archive_entry_filetype(e);
|
||||
|
||||
/* sanity checks */
|
||||
if (pathname[0] == '/' ||
|
||||
strncmp(pathname, "../", 3) == 0 ||
|
||||
strstr(pathname, "/../") != NULL) {
|
||||
archive_read_data_skip(a);
|
||||
free(pathname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* I don't think this can happen in a zipfile.. */
|
||||
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) {
|
||||
archive_read_data_skip(a);
|
||||
free(pathname);
|
||||
return;
|
||||
}
|
||||
|
||||
realpathname = pathcat(base_dir.c_str(), pathname);
|
||||
|
||||
/* ensure that parent directory exists */
|
||||
FS::MkDirs(realpathname, true);
|
||||
|
||||
if (S_ISDIR(filetype))
|
||||
extract_dir(a, e, realpathname);
|
||||
else
|
||||
{
|
||||
sprintf(status_message, "%s - %s", file.name, lang_strings[STR_UNSUPPORTED_FILE_FORMAT]);
|
||||
return -1;
|
||||
snprintf(activity_message, 255, "%s: %s", lang_strings[STR_EXTRACTING], pathname);
|
||||
extract_file(a, e, realpathname);
|
||||
}
|
||||
|
||||
free(realpathname);
|
||||
free(pathname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for reading passphrase.
|
||||
* Originally from cpio.c and passphrase.c, libarchive.
|
||||
*/
|
||||
static const char *passphrase_callback(struct archive *a, void *_client_data)
|
||||
{
|
||||
Dialog::initImeDialog(lang_strings[STR_PASSWORD], password, 127, ORBIS_TYPE_DEFAULT, 560, 200);
|
||||
int ime_result = Dialog::updateImeDialog();
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED || ime_result == IME_DIALOG_RESULT_CANCELED)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
{
|
||||
snprintf(password, 127, "%s", (char *)Dialog::getImeDialogInputText());
|
||||
return password;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(password, 0, sizeof(password));
|
||||
}
|
||||
}
|
||||
|
||||
memset(password, 0, sizeof(password));
|
||||
return password;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop: open the zipfile, iterate over its contents and decide what
|
||||
* to do with each entry.
|
||||
*/
|
||||
int Extract(const DirEntry &file, const std::string &basepath)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *e;
|
||||
int ret;
|
||||
uintmax_t total_size, file_count, error_count;
|
||||
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
sprintf(status_message, "%s", "archive_read_new failed");
|
||||
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
archive_read_set_passphrase_callback(a, NULL, &passphrase_callback);
|
||||
|
||||
ret = archive_read_open_filename(a, file.path, TRANSFER_SIZE);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "%s", "archive_read_open_filename failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (stop_activity)
|
||||
break;
|
||||
|
||||
ret = archive_read_next_header(a, &e);
|
||||
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "%s", "archive_read_next_header failed");
|
||||
archive_read_free(a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret == ARCHIVE_EOF)
|
||||
break;
|
||||
|
||||
extract(a, e, basepath);
|
||||
}
|
||||
|
||||
archive_read_free(a);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user