Compare commits

...

24 Commits

Author SHA1 Message Date
Chee Yee c328b26480 fix google login 2024-02-26 00:25:41 -08:00
Chee Yee 1e702aa0e2 refactor webdav client 2024-02-22 20:30:18 -08:00
Chee Yee d35b311946 make settings dialog bigger to fix content 2024-02-17 18:40:57 -08:00
Chee Yee f02944e596 dont need WebUI install dialog to wait 2024-02-16 19:26:16 -08:00
Chee Yee 338eacfd3f more places where modal mode needs to be disabled 2024-02-16 14:08:45 -08:00
Chee Yee 0bd0a0f273 disable modal dialog mode 2024-02-16 02:19:45 -08:00
Chee Yee bf3f4330c0 add progress meter for file extraction and pkg install 2024-02-16 02:11:05 -08:00
Chee Yee f16850fed9 more bug fixes for install patch/dlc from remote 2024-02-16 01:19:27 -08:00
cy33hc a30a20f6db Update README.md 2024-02-15 21:47:57 -08:00
cy33hc 54b9a80410 Update README.md 2024-02-15 10:53:22 -08:00
Chee Yee fe55ddeb8a fix install of some patch/dlc pkg 2024-02-15 04:01:42 -08:00
Chee Yee a5a5f8d611 fix 2024-02-12 16:03:21 -08:00
Chee Yee 9854437c94 add support for realdebrid 2024-02-10 23:57:52 -08:00
Chee Yee 7a908ebf1b improve speed of installing from compress file by increase read buffer 2024-02-10 00:27:18 -08:00
Chee Yee f83629d107 add ability to install pkg in compress file on public shares like mediafire, gdrive, pixeldrain and alldebrid 2024-02-09 21:31:59 -08:00
Chee Yee f0c0213940 fix file list navigration jumping to top of list when last item is selected 2024-02-07 23:54:25 -08:00
Chee Yee 9baf6c18fa enable extracting compress files from http servers 2024-02-07 07:38:54 -08:00
Chee Yee 263822ef66 update to install all pkgs inside compress file 2024-02-07 02:28:44 -08:00
Chee Yee 487e288635 fix rclone filesize display 2024-02-06 23:40:17 -08:00
Chee Yee 267551c979 add ability to install pkg inside compress files 2024-02-03 18:58:42 -08:00
Chee Yee b761596fe3 set extract folder to current local directory on multi select 2024-01-31 02:16:54 -08:00
Chee Yee 99568b9990 update logic for selecting default extract folder 2024-01-31 02:13:32 -08:00
Chee Yee 414a8a4b50 add ability to extract files from remote server 2024-01-31 01:47:51 -08:00
Chee Yee 628312360c clear multi selection after uploading files 2024-01-24 23:19:55 -08:00
50 changed files with 2050 additions and 3306 deletions
+4 -8
View File
@@ -22,12 +22,6 @@ add_executable(ezremote_client
source/imgui/imgui_widgets.cpp
source/imgui/imgui.cpp
source/pugixml/pugixml.cpp
source/web/callback.cpp
source/web/fsinfo.cpp
source/web/header.cpp
source/web/request.cpp
source/web/urn.cpp
source/webdav/client.cpp
source/http/httplib.cpp
source/clients/baseclient.cpp
source/clients/apache.cpp
@@ -38,10 +32,11 @@ add_executable(ezremote_client
source/clients/npxserve.cpp
source/clients/nfsclient.cpp
source/clients/smbclient.cpp
source/clients/webdavclient.cpp
source/clients/sftpclient.cpp
source/clients/rclone.cpp
source/clients/webdav.cpp
source/filehost/alldebrid.cpp
source/filehost/realdebrid.cpp
source/filehost/directhost.cpp
source/filehost/gdrive.cpp
source/filehost/filehost.cpp
@@ -66,11 +61,12 @@ add_executable(ezremote_client
source/textures.cpp
source/windows.cpp
source/zip_util.cpp
source/split_file.cpp
)
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.13" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.21" 32 0)
target_link_libraries(ezremote_client
c
+3 -3
View File
@@ -1,6 +1,6 @@
# ezRemote Client
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB, NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB(Windows Share), NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
**New:** As of version 1.0.8, ezRemote Client has a Web Interface that can be access from any modern browser to manage the PS4 files.
@@ -27,7 +27,7 @@ To distinguish between FTP, SMB, NFS, WebDAV or HTTP, the URL must be prefix wit
then in the password field enter file:///data/ezremote-client
```
- The url format for SMB is
- The url format for SMB(Windows Share) is
```
smb://hostname[:port]/sharename
@@ -114,7 +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).
- Install packages from shared links from mediafire, google and pixeldrain. For other filehost, they can installed via AllDebrid/RealDebrid (See respective websites 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.
+4 -1
View File
@@ -156,4 +156,7 @@ 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
STR_LANGUAGE=Language
STR_LANGUAGE=Language
STR_TEMP_DIRECTORY=Temp Directory
STR_REALDEBRID=Real-Debrid
STR_BACKGROUND_INSTALL_INPROGRESS=Package install is running in the background. Don't close the app while install is in progress
File diff suppressed because one or more lines are too long
+151 -16
View File
@@ -8,7 +8,7 @@
#include "clients/gdrive.h"
#include "clients/ftpclient.h"
#include "clients/smbclient.h"
#include "clients/webdavclient.h"
#include "clients/webdav.h"
#include "clients/apache.h"
#include "clients/nginx.h"
#include "clients/npxserve.h"
@@ -25,8 +25,6 @@
#include "lang.h"
#include "actions.h"
#include "installer.h"
#include "web/request.hpp"
#include "web/urn.hpp"
#include "system.h"
#include "sfo.h"
#include "zip_util.h"
@@ -465,6 +463,7 @@ namespace Actions
}
activity_inprogess = false;
file_transfering = false;
multi_selected_local_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_REMOTE_FILES;
return NULL;
@@ -722,6 +721,37 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz"))
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path, remoteclient);
if (entry != nullptr)
{
while (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
ArchiveEntry *previos = entry;
entry = ZipUtil::GetNextPackageEntry(entry);
free(previos);
}
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -746,11 +776,47 @@ namespace Actions
if (res != 0)
{
activity_inprogess = false;
file_transfering = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
}
}
void *ExtractArchivePkg(void *argp)
{
ssize_t len;
char *buffer = (char*) malloc(ARCHIVE_TRANSFER_SIZE);
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) argp;
SplitFile *sp = install_data->split_file;
/* loop over file contents and write to fd */
sp->Open();
while (!install_data->stop_write_thread)
{
len = archive_read_data(install_data->archive_entry->archive, buffer, ARCHIVE_TRANSFER_SIZE);
if (len == 0)
break;
if (len < 0)
{
sprintf(status_message, "error archive_read_data('%s')", install_data->archive_entry->filename.c_str());
break;
}
if (sp->Write(buffer, len) != len)
{
sprintf(status_message, "error write('%s')", install_data->archive_entry->filename.c_str());
break;;
}
}
sp->Close();
free(buffer);
return NULL;
}
void *InstallLocalPkgsThread(void *argp)
{
int failed = 0;
@@ -774,7 +840,7 @@ namespace Actions
{
std::string path = std::string(it->path);
path = Util::ToLower(path);
if (path.size() > 4 && path.substr(path.size() - 4) == ".pkg")
if (Util::EndsWith(path,".pkg"))
{
pkg_header header;
memset(&header, 0, sizeof(header));
@@ -805,6 +871,37 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") || Util::EndsWith(path,".7z") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz") || Util::EndsWith(path,".tar.bz2") )
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path);
if (entry != nullptr)
{
while (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
ArchiveEntry *previous = entry;
entry = ZipUtil::GetNextPackageEntry(entry);
free(previous);
}
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -876,6 +973,49 @@ namespace Actions
}
}
void *ExtractRemoteZipThread(void *argp)
{
FS::MkDirs(extract_zip_folder);
std::vector<DirEntry> files;
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
{
if (stop_activity)
break;
if (!it->isDir)
{
int ret = ZipUtil::Extract(*it, extract_zip_folder, remoteclient);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAILED_TO_EXTRACT], it->name);
sceKernelUsleep(100000);
}
}
}
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_LOCAL_FILES;
return NULL;
}
void ExtractRemoteZips()
{
sprintf(status_message, "%s", "");
int res = pthread_create(&bk_activity_thid, NULL, ExtractRemoteZipThread, NULL);
if (res != 0)
{
file_transfering = false;
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
}
}
void *MakeZipThread(void *argp)
{
zipFile zf = zipOpen64(zip_file_path, APPEND_STATUS_CREATE);
@@ -960,14 +1100,14 @@ namespace Actions
std::string host = full_url.substr(0, path_pos);
std::string path = full_url.substr(path_pos);
WebDAV::WebDavClient tmp_client;
tmp_client.Connect(host.c_str(), install_pkg_url.username, install_pkg_url.password, false);
WebDAVClient tmp_client;
tmp_client.Connect(host.c_str(), install_pkg_url.username, install_pkg_url.password);
sprintf(activity_message, "%s URL to %s", lang_strings[STR_DOWNLOADING], filename);
int s = sizeof(pkg_header);
memset(&header, 0, s);
WebDAV::dict_t response_headers{};
int ret = tmp_client.GetHeaders(path.c_str(), &response_headers);
int ret = tmp_client.Size(path, &bytes_to_download);
if (!ret)
{
sprintf(status_message, "%s - %s", lang_strings[STR_FAILED], lang_strings[STR_CANNOT_READ_PKG_HDR_MSG]);
@@ -977,13 +1117,8 @@ namespace Actions
return NULL;
}
auto content_length = WebDAV::get(response_headers, "content-length");
if (content_length.length() > 0)
bytes_to_download = std::stol(content_length);
else
bytes_to_download = 1;
file_transfering = 1;
int is_performed = tmp_client.Get(filename, path.c_str());
int is_performed = tmp_client.Get(path, filename);
if (is_performed == 0)
{
@@ -1071,7 +1206,7 @@ namespace Actions
}
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
{
remoteclient = new WebDAV::WebDavClient();
remoteclient = new WebDAVClient();
}
else if (strncmp(remote_settings->server, "smb://", 6) == 0)
{
@@ -1586,7 +1721,7 @@ namespace Actions
OrbisTick tick;
sceRtcGetCurrentClockLocalTime(&now);
sceRtcGetTick(&now, &tick);
sprintf(local_file, "%s/%lu.pkg", DATA_PATH, tick.mytick);
sprintf(local_file, "%s/%lu.pkg", temp_folder, tick.mytick);
sprintf(activity_message, "%s %s to %s", lang_strings[STR_DOWNLOADING], filename.c_str(), local_file);
remoteclient->Size(filename, &bytes_to_download);
+5 -1
View File
@@ -56,7 +56,8 @@ enum ACTIONS
ACTION_VIEW_LOCAL_IMAGE,
ACTION_VIEW_REMOTE_IMAGE,
ACTION_VIEW_LOCAL_PKG,
ACTION_VIEW_REMOTE_PKG
ACTION_VIEW_REMOTE_PKG,
ACTION_EXTRACT_REMOTE_ZIP,
};
enum OverWriteType
@@ -103,6 +104,8 @@ namespace Actions
void *KeepAliveThread(void *argp);
void *ExtractZipThread(void *argp);
void ExtractLocalZips();
void *ExtractRemoteZipThread(void *argp);
void ExtractRemoteZips();
void *MakeZipThread(void *argp);
void MakeLocalZip();
void *MoveLocalFilesThread(void *argp);
@@ -116,6 +119,7 @@ namespace Actions
int DownloadAndInstallPkg(const std::string &filename, pkg_header *header);
void CreateLocalFile(char *filename);
void CreateRemoteFile(char *filename);
void *ExtractArchivePkg(void *argp);
}
#endif
+39 -11
View File
@@ -8,6 +8,7 @@
#include "windows.h"
using httplib::Client;
using httplib::DataSink;
using httplib::Headers;
using httplib::Result;
@@ -20,6 +21,29 @@ BaseClient::~BaseClient()
};
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password)
{
this->host_url = url;
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos + 3);
if (root_pos != std::string::npos)
{
this->host_url = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(this->host_url);
if (username.length() > 0)
client->set_basic_auth(username, password);
client->set_keep_alive(true);
client->set_follow_location(true);
client->set_connection_timeout(30);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
if (Ping())
this->connected = true;
return 1;
}
int BaseClient::Connect(const std::string &url, const std::string &api_key)
{
std::string scheme_host_port = url;
size_t scheme_pos = url.find("://");
@@ -29,9 +53,10 @@ int BaseClient::Connect(const std::string &url, const std::string &username, con
scheme_host_port = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(scheme_host_port);
if (username.length() > 0)
client->set_basic_auth(username, password);
if (api_key.length() > 0)
client->set_bearer_token_auth(api_key);
client->set_keep_alive(true);
client->set_follow_location(true);
client->set_connection_timeout(30);
@@ -58,10 +83,13 @@ int BaseClient::Size(const std::string &path, int64_t *size)
{
if (auto res = client->Head(GetFullPath(path)))
{
std::string content_length = res->get_header_value("Content-Length");
if (content_length.length() > 0)
*size = atoll(content_length.c_str());
return 1;
if (HTTP_SUCCESS(res->status))
{
std::string content_length = res->get_header_value("Content-Length");
if (content_length.length() > 0)
*size = atoll(content_length.c_str());
return 1;
}
}
else
{
@@ -95,7 +123,7 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
int BaseClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset+size-1);
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
Headers headers = {{"Range", range_header}};
size_t bytes_read = 0;
if (auto res = client->Get(GetFullPath(path), headers,
@@ -118,7 +146,7 @@ int BaseClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
int BaseClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset+size-1);
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
Headers headers = {{"Range", range_header}};
size_t bytes_read = 0;
std::vector<char> body;
@@ -280,10 +308,10 @@ ClientType BaseClient::clientType()
uint32_t BaseClient::SupportedActions()
{
return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL;
return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL | REMOTE_ACTION_EXTRACT;
}
std::string BaseClient::EncodeUrl(const std::string &url)
std::string BaseClient::Escape(const std::string &url)
{
CURL *curl = curl_easy_init();
if (curl)
@@ -300,7 +328,7 @@ std::string BaseClient::EncodeUrl(const std::string &url)
return "";
}
std::string BaseClient::DecodeUrl(const std::string &url)
std::string BaseClient::UnEscape(const std::string &url)
{
CURL *curl = curl_easy_init();
if (curl)
+4 -2
View File
@@ -16,6 +16,7 @@ public:
BaseClient();
~BaseClient();
int Connect(const std::string &url, const std::string &username, const std::string &password);
int Connect(const std::string &url, const std::string &api_key);
int Mkdir(const std::string &path);
int Rmdir(const std::string &path, bool recursive);
int Size(const std::string &path, int64_t *size);
@@ -38,12 +39,13 @@ public:
int Quit();
ClientType clientType();
uint32_t SupportedActions();
static std::string EncodeUrl(const std::string &url);
static std::string DecodeUrl(const std::string &url);
static std::string Escape(const std::string &url);
static std::string UnEscape(const std::string &url);
protected:
httplib::Client *client;
std::string base_path;
std::string host_url;
char response[512];
bool connected = false;
};
+21 -21
View File
@@ -111,7 +111,7 @@ int GDriveClient::RequestAuthorization()
std::string auth_url = std::string(GOOGLE_AUTH_URL "?client_id=") + gg_app.client_id + "&redirect_uri=" + GetRedirectUrl() +
"&response_type=code&access_type=offline&scope=" + GetScopes() + "&include_granted_scopes=true";
auth_url = EncodeUrl(auth_url);
auth_url = Escape(auth_url);
std::string launch_uri = std::string("pswebbrowser:search?url=") + auth_url;
int ret = sceShellUIUtilLaunchByUri(launch_uri.c_str(), &param);
@@ -222,11 +222,11 @@ int GDriveClient::Rename(const std::string &src, const std::string &dst)
if (src_id.compare("root") == 0 || dst_id.compare("root") == 0 || src_id.compare(src_drive_id) == 0 || dst_id.compare(dst_drive_id) == 0)
return 0;
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(src_id);
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(src_id);
if (!src_drive_id.empty())
url += "?supportsAllDrives=true";
std::string filename = dst.substr(dst.find_last_of("/") + 1);
std::string body = "{'name' : '" + filename + "'}";
std::string body = "{\"name\" : \"" + filename + "\"}";
if (auto res = client->Patch(url, body.c_str(), body.length(), "application/json; charset=UTF-8"))
{
sprintf(response, "%d", res->status);
@@ -276,7 +276,7 @@ int GDriveClient::Head(const std::string &path, void *buffer, uint64_t len)
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?alt=media";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
Headers headers;
@@ -310,7 +310,7 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?alt=media";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
if (auto res = client->Get(url,
@@ -337,7 +337,7 @@ int GDriveClient::GetRange(const std::string &path, DataSink &sink, uint64_t siz
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?alt=media";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
Headers headers;
@@ -367,7 +367,7 @@ int GDriveClient::GetRange(const std::string &path, void *buffer, uint64_t size,
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?alt=media";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
Headers headers;
@@ -406,7 +406,7 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = "/upload/drive/v3/files/" + BaseClient::EncodeUrl(id) + "?uploadType=resumable";
std::string url = "/upload/drive/v3/files/" + BaseClient::Escape(id) + "?uploadType=resumable";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
Headers headers;
@@ -492,9 +492,9 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
if (!drive_id.empty())
url += "&supportsAllDrives=true";
std::string post_data = std::string("{'name': '") + filename + "'," +
(drive_id.empty() ? "" : "'driveId' : '" + drive_id + "',") +
"'parents': ['" + parent_id + "']}";
std::string post_data = std::string("{\"name\": \"") + filename + "\"," +
(drive_id.empty() ? "" : "\"driveId\" : \"" + drive_id + "\",") +
"\"parents\": [\"" + parent_id + "\"]}";
Headers headers;
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
@@ -553,7 +553,7 @@ int GDriveClient::Size(const std::string &path, int64_t *size)
{
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?fields=size";
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?fields=size";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
if (auto res = client->Get(url))
@@ -605,10 +605,10 @@ int GDriveClient::Mkdir(const std::string &path)
std::string url = std::string("/drive/v3/files?fields=id");
if (!drive_id.empty())
url += "&supportsAllDrives=true";
std::string folder_metadata = "{'name' : '" + folder_name + "'," +
"'parents' : ['" + parent_id + "']," +
(drive_id.empty() ? "" : "'driveId' : '" + drive_id + "',") +
"'mimeType' : 'application/vnd.google-apps.folder'}";
std::string folder_metadata = "{\"name\" : \"" + folder_name + "\"," +
"\"parents\" : [\"" + parent_id + "\"]," +
(drive_id.empty() ? "" : "\"driveId\" : \"" + drive_id + "\",") +
"\"mimeType\" : \"application/vnd.google-apps.folder\"}";
if (auto res = client->Post(url, folder_metadata.c_str(), folder_metadata.length(), "application/json; charset=UTF-8"))
{
@@ -669,7 +669,7 @@ int GDriveClient::Delete(const std::string &path)
if (strcmp(id.c_str(), "root") == 0)
return 0;
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id);
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id);
if (!drive_id.empty())
url += "?supportsAllDrives=true";
if (auto res = client->Delete(url))
@@ -779,8 +779,8 @@ std::vector<DirEntry> GDriveClient::ListDir(const std::string &path)
}
std::string drive_id = GetDriveId(path);
std::string base_url = std::string("/drive/v3/files?q=") + BaseClient::EncodeUrl("\"" + id + "\" in parents") +
"&pageSize=1000&fields=" + BaseClient::EncodeUrl("files(id,mimeType,name,modifiedTime,size),nextPageToken");
std::string base_url = std::string("/drive/v3/files?q=") + BaseClient::Escape("\"" + id + "\" in parents") +
"&pageSize=1000&fields=" + BaseClient::Escape("files(id,mimeType,name,modifiedTime,size),nextPageToken");
if (!drive_id.empty())
{
base_url += "&driveId=" + drive_id + "&corpora=drive&includeItemsFromAllDrives=true&supportsAllDrives=true";
@@ -789,7 +789,7 @@ std::vector<DirEntry> GDriveClient::ListDir(const std::string &path)
bool find_no_parent = false;
if (id.compare(shared_with_me) == 0)
{
base_url = std::string("/drive/v3/files?q=sharedWithMe&pageSize=1000&fields=") + BaseClient::EncodeUrl("files(id,mimeType,name,modifiedTime,size),nextPageToken");
base_url = std::string("/drive/v3/files?q=sharedWithMe&pageSize=1000&fields=") + BaseClient::Escape("files(id,mimeType,name,modifiedTime,size),nextPageToken");
}
std::string next_page_url = base_url;
@@ -867,7 +867,7 @@ std::vector<DirEntry> GDriveClient::ListDir(const std::string &path)
}
}
if (next_page_token != nullptr)
next_page_url = base_url + "&pageToken=" + BaseClient::EncodeUrl(json_object_get_string(next_page_token));
next_page_url = base_url + "&pageToken=" + BaseClient::Escape(json_object_get_string(next_page_token));
else
break;
}
+1 -1
View File
@@ -84,7 +84,7 @@ std::vector<DirEntry> NginxClient::ListDir(const std::string &path)
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(node), (const lxb_char_t *)"href", 4, &value_len);
tmp = std::string((const char *)value, value_len);
tmp = Util::Rtrim(tmp, "/");
tmp = BaseClient::DecodeUrl(tmp);
tmp = BaseClient::UnEscape(tmp);
if (tmp.compare("..") != 0)
{
sprintf(entry.directory, "%s", path.c_str());
+2 -3
View File
@@ -8,7 +8,6 @@
#include "util.h"
#include "system.h"
#include "windows.h"
#include "dbglogger.h"
using httplib::Client;
using httplib::Headers;
@@ -142,7 +141,7 @@ std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
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);
tmp_string = BaseClient::UnEscape(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] == '/')
@@ -161,7 +160,7 @@ std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
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());
entry.file_size = atol(tmp_string.c_str());
DirEntry::SetDisplaySize(&entry);
}
+2 -1
View File
@@ -20,7 +20,8 @@ enum RemoteActions
REMOTE_ACTION_INSTALL = 256,
REMOTE_ACTION_EDIT = 512,
REMOTE_ACTION_NEW_FILE = 1024,
REMOTE_ACTION_ALL = 2047
REMOTE_ACTION_EXTRACT = 2048,
REMOTE_ACTION_ALL = 4095
};
enum ClientType
+283
View File
@@ -0,0 +1,283 @@
#include <fstream>
#include "common.h"
#include "clients/remote_client.h"
#include "clients/webdav.h"
#include "pugixml/pugiext.hpp"
#include "fs.h"
#include "lang.h"
#include "util.h"
#include "system.h"
#include "windows.h"
using httplib::Client;
using httplib::Headers;
using httplib::Progress;
using httplib::Result;
using httplib::ContentProvider;
static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
std::string WebDAVClient::GetHttpUrl(std::string url)
{
std::string http_url = std::regex_replace(url, std::regex("webdav://"), "http://");
http_url = std::regex_replace(http_url, std::regex("webdavs://"), "https://");
return http_url;
}
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass)
{
std::string url = GetHttpUrl(host);
return BaseClient::Connect(url, user, pass);
}
Result WebDAVClient::PropFind(const std::string &path, int depth)
{
Request req;
Headers header = {{"Accept", "*/*"}, {"Depth", std::to_string(depth)}};
req.method = "PROPFIND";
req.path = path;
req.headers = header;
req.progress = Progress();
return client->send(req);
}
std::vector<DirEntry> WebDAVClient::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 = PropFind(encoded_path, 1))
{
pugi::xml_document document;
document.load_buffer(res->body.c_str(), res->body.length());
auto multistatus = document.select_node("*[local-name()='multistatus']").node();
auto responses = multistatus.select_nodes("*[local-name()='response']");
for (auto response : responses)
{
pugi::xml_node href = response.node().select_node("*[local-name()='href']").node();
std::string resource_path = httplib::detail::decode_url(href.first_child().value(), true);
auto target_path_without_sep = GetFullPath(path);
if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/')
target_path_without_sep.resize(target_path_without_sep.length() - 1);
auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1);
size_t pos = resource_path_without_sep.find(this->host_url);
if (pos != std::string::npos)
resource_path_without_sep.erase(pos, this->host_url.length());
if (resource_path_without_sep == target_path_without_sep)
continue;
pos = resource_path_without_sep.find_last_of('/');
auto name = resource_path_without_sep.substr(pos + 1);
auto propstat = response.node().select_node("*[local-name()='propstat']").node();
auto prop = propstat.select_node("*[local-name()='prop']").node();
std::string creation_date = prop.select_node("*[local-name()='creationdate']").node().first_child().value();
std::string content_length = prop.select_node("*[local-name()='getcontentlength']").node().first_child().value();
std::string m_date = prop.select_node("*[local-name()='getlastmodified']").node().first_child().value();
std::string resource_type = prop.select_node("*[local-name()='resourcetype']").node().first_child().name();
DirEntry entry;
memset(&entry, 0, sizeof(entry));
entry.selectable = true;
sprintf(entry.directory, "%s", path.c_str());
sprintf(entry.name, "%s", name.c_str());
if (path.length() == 1 and path[0] == '/')
{
sprintf(entry.path, "%s%s", path.c_str(), name.c_str());
}
else
{
sprintf(entry.path, "%s/%s", path.c_str(), name.c_str());
}
entry.isDir = resource_type.find("collection") != std::string::npos;
entry.file_size = 0;
if (!entry.isDir)
{
entry.file_size = std::stoll(content_length);
DirEntry::SetDisplaySize(&entry);
}
else
{
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
}
char modified_date[32];
char *p_char = NULL;
sprintf(modified_date, "%s", m_date.c_str());
p_char = strchr(modified_date, ' ');
if (p_char)
{
OrbisDateTime gmt;
OrbisDateTime lt;
char month[5];
sscanf(p_char, "%hd %s %hd %hd:%hd:%hd", &gmt.day, month, &gmt.year, &gmt.hour, &gmt.minute, &gmt.second);
for (int k = 0; k < 12; k++)
{
if (strcmp(month, months[k]) == 0)
{
gmt.month = k + 1;
break;
}
}
convertUtcToLocalTime(&gmt, &lt);
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;
}
out.push_back(entry);
}
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
return out;
}
return out;
}
int WebDAVClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset)
{
size_t bytes_remaining = FS::GetSize(inputfile);
bytes_transfered = 0;
FILE* in = FS::OpenRead(inputfile);
if (auto res = client->Put(GetFullPath(path),
[&](size_t offset, DataSink &sink)
{
size_t buf_size = MIN(bytes_remaining, CPPHTTPLIB_RECV_BUFSIZ);
char* buf = (char*) malloc(buf_size);
FS::Seek(in, offset);
while (bytes_remaining > 0)
{
size_t bytes_read = FS::Read(in, buf, buf_size);
sink.write(buf, bytes_read);
bytes_transfered += bytes_read;
bytes_remaining -= bytes_read;
}
sink.done();
free(buf);
return true;
},
"application/octet-stream"))
{
if (HTTP_SUCCESS(res->status))
{
FS::Close(in);
return 1;
}
}
FS::Close(in);
return 0;
}
int WebDAVClient::Mkdir(const std::string &path)
{
Request req;
Headers header = {{"Accept", "*/*"}, {"Connection", "Keep-Alive"}};
req.method = "MKCOL";
req.path = httplib::detail::encode_url(GetFullPath((path)));
req.headers = header;
req.progress = Progress();
if (auto res = client->send(req))
{
if (HTTP_SUCCESS(res->status))
return 1;
}
return 0;
}
int WebDAVClient::Rmdir(const std::string &path, bool recursive)
{
return Delete(path);
}
int WebDAVClient::Rename(const std::string &src, const std::string &dst)
{
return Move(src, dst);
}
int WebDAVClient::Delete(const std::string &path)
{
Request req;
Headers header = {{"Accept", "*/*"}, {"Connection", "Keep-Alive"}};
req.method = "DELETE";
req.path = httplib::detail::encode_url(GetFullPath((path)));
req.headers = header;
req.progress = Progress();
if (auto res = client->send(req))
{
if (HTTP_SUCCESS(res->status))
return 1;
}
return 0;
}
int WebDAVClient::Copy(const std::string &from, const std::string &to)
{
Request req;
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }};
req.method = "COPY";
req.path = httplib::detail::encode_url(GetFullPath(from));
req.headers = header;
req.progress = Progress();
if (auto res = client->send(req))
{
if (HTTP_SUCCESS(res->status))
return 1;
}
return 0;
}
int WebDAVClient::Move(const std::string &from, const std::string &to)
{
Request req;
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }};
req.method = "MOVE";
req.path = httplib::detail::encode_url(GetFullPath(from));
req.headers = header;
req.progress = Progress();
if (auto res = client->send(req))
{
if (HTTP_SUCCESS(res->status))
return 1;
}
return 0;
}
ClientType WebDAVClient::clientType()
{
return CLIENT_TYPE_WEBDAV;
}
uint32_t WebDAVClient::SupportedActions()
{
return REMOTE_ACTION_ALL;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef WEBDAV_H
#define WEBDAV_H
#include <string>
#include <vector>
#include "http/httplib.h"
#include "clients/baseclient.h"
#include "clients/remote_client.h"
#include "common.h"
class WebDAVClient : public BaseClient
{
public:
int Connect(const std::string &url, const std::string &user, const std::string &pass);
int Mkdir(const std::string &path);
int Rmdir(const std::string &path, bool recursive);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
int Copy(const std::string &from, const std::string &to);
int Move(const std::string &from, const std::string &to);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
std::vector<DirEntry> ListDir(const std::string &path);
ClientType clientType();
uint32_t SupportedActions();
static std::string GetHttpUrl(std::string url);
private:
Result PropFind(const std::string &path, int depth);
};
#endif
-387
View File
@@ -1,387 +0,0 @@
#include <errno.h>
#include <unistd.h>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <fcntl.h>
#include "lang.h"
#include "webdav/client.hpp"
#include "clients/webdavclient.h"
#include "windows.h"
#include "util.h"
#include "system.h"
static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
namespace WebDAV
{
static int DownloadCallback(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
int64_t *bytes_transfered = (int64_t *)context;
*bytes_transfered = reinterpret_cast<int64_t>(dlnow);
return CURLE_OK;
}
static int UploadCallback(void *context, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
int64_t *bytes_transfered = (int64_t *)context;
*bytes_transfered = reinterpret_cast<int64_t>(ulnow);
return CURLE_OK;
}
int WebDavClient::Connect(const std::string &host, const std::string &user, const std::string &pass)
{
return Connect(host, user, pass, true);
}
WebDavClient::WebDavClient() {};
int WebDavClient::Connect(const std::string &host, const std::string &user, const std::string &pass, bool check_enabled)
{
std::string url = GetHttpUrl(host);
std::size_t scheme_pos = url.find_first_of("://");
std::string root_folder = "/";
if (scheme_pos != std::string::npos)
{
std::size_t root_folder_pos = url.find_first_of("/", scheme_pos + 3);
if (root_folder_pos != std::string::npos)
{
root_folder = url.substr(root_folder_pos);
url = url.substr(0, root_folder_pos);
}
}
WebDAV::dict_t options = {
{"webdav_hostname", url},
{"webdav_root", root_folder},
{"webdav_username", user},
{"webdav_password", pass},
{"check_enabled", check_enabled ? "1" : "0"}};
client = new WebDAV::Client(options);
connected = true;
return 1;
}
/*
* LastResponse - return a pointer to the last response received
*/
const char *WebDavClient::LastResponse()
{
return (const char *)response;
}
/*
* IsConnected - return true if connected to remote
*/
bool WebDavClient::IsConnected()
{
return connected;
}
/*
* Ping - return true if connected to remote
*/
bool WebDavClient::Ping()
{
connected = client->check();
sprintf(response, "Http Code %ld", client->status_code());
return connected;
}
/*
* Quit - disconnect from remote
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::Quit()
{
if (client != NULL)
delete (client);
client = NULL;
connected = false;
return 1;
}
/*
* Mkdir - create a directory at server
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::Mkdir(const std::string &ppath)
{
bool ret = client->create_directory(ppath);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
/*
* Rmdir - remove directory and all files under directory at remote
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::_Rmdir(const std::string &ppath)
{
bool ret = client->clean(ppath);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
/*
* Rmdir - remove directory and all files under directory at remote
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::Rmdir(const std::string &path, bool recursive)
{
if (stop_activity)
return 1;
std::vector<DirEntry> list = ListDir(path);
int ret;
for (int i = 0; i < list.size(); i++)
{
if (stop_activity)
return 1;
if (list[i].isDir && recursive)
{
if (strcmp(list[i].name, "..") == 0)
continue;
ret = Rmdir(list[i].path, recursive);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], list[i].path);
return 0;
}
}
else
{
sprintf(activity_message, "%s %s\n", lang_strings[STR_DELETING], list[i].path);
ret = Delete(list[i].path);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], list[i].path);
return 0;
}
}
}
ret = _Rmdir(path);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], path.c_str());
return 0;
}
return 1;
}
/*
* Get - issue a GET command and write received data to output
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::Get(const std::string &outputfile, const std::string &ppath, uint64_t offset)
{
bool ret = client->download(ppath, outputfile, &bytes_transfered, DownloadCallback);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
bool WebDavClient::FileExists(const std::string &ppath)
{
std::string path = ppath;
path = Util::Ltrim(path, "/");
bool ret = client->check(path);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
char *buffer_ptr = nullptr;
unsigned long long buffer_size = 0;
bool ret = client->download_range_to(path, buffer_ptr, buffer_size, offset, offset+size-1);
sprintf(response, "Http Code %ld", client->status_code());
if (buffer_size != size)
{
return 0;
}
memcpy(buffer, buffer_ptr, size);
return 1;
}
int WebDavClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
return client->download_range_to(path, sink, offset, offset+size-1);
}
/*
* Put - issue a PUT command and send data from input
*
* return 1 if successful, 0 otherwise
*/
int WebDavClient::Put(const std::string &inputfile, const std::string &ppath, uint64_t offset)
{
bool ret = client->upload(ppath, inputfile, &bytes_transfered, UploadCallback);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::Rename(const std::string &src, const std::string &dst)
{
bool ret = client->move(src, dst);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::Delete(const std::string &ppath)
{
bool ret = client->clean(ppath);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::Copy(const std::string &from, const std::string &to)
{
bool ret = client->copy(from, to);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::Move(const std::string &from, const std::string &to)
{
bool ret = client->move(from, to);
sprintf(response, "Http Code %ld", client->status_code());
return ret;
}
int WebDavClient::Size(const std::string &ppath, int64_t *size)
{
WebDAV::dict_t file_info = client->info(ppath);
std::string file_size = WebDAV::get(file_info, "size");
if (file_size.empty())
return 0;
*size = std::stoll(file_size);
return 1;
}
std::vector<DirEntry> WebDavClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
WebDAV::dict_items_t files = client->list(path);
for (int i = 0; i < files.size(); i++)
{
DirEntry entry;
memset(&entry, 0, sizeof(entry));
entry.selectable = true;
sprintf(entry.directory, "%s", path.c_str());
sprintf(entry.name, "%s", WebDAV::get(files[i], "name").c_str());
if (path.length() == 1 and path[0] == '/')
{
sprintf(entry.path, "%s%s", path.c_str(), WebDAV::get(files[i], "name").c_str());
}
else
{
sprintf(entry.path, "%s/%s", path.c_str(), WebDAV::get(files[i], "name").c_str());
}
std::string resource_type = WebDAV::get(files[i], "type");
entry.isDir = resource_type.find("collection") != std::string::npos;
entry.file_size = 0;
if (!entry.isDir)
{
entry.file_size = std::stoll(WebDAV::get(files[i], "size"));
DirEntry::SetDisplaySize(&entry);
}
else
{
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
}
char modified_date[32];
char *p_char = NULL;
sprintf(modified_date, "%s", WebDAV::get(files[i], "modified").c_str());
p_char = strchr(modified_date, ' ');
if (p_char)
{
OrbisDateTime gmt;
OrbisDateTime lt;
char month[5];
sscanf(p_char, "%hd %s %hd %hd:%hd:%hd", &gmt.day, month, &gmt.year, &gmt.hour, &gmt.minute, &gmt.second);
for (int k = 0; k < 12; k++)
{
if (strcmp(month, months[k]) == 0)
{
gmt.month = k + 1;
break;
}
}
convertUtcToLocalTime(&gmt, &lt);
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;
}
out.push_back(entry);
}
return out;
}
std::string WebDavClient::GetPath(std::string ppath1, std::string ppath2)
{
std::string path1 = ppath1;
std::string path2 = ppath2;
path1 = Util::Rtrim(Util::Trim(path1, " "), "/");
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
path1 = path1 + "/" + path2;
return path1;
}
int WebDavClient::Head(const std::string &path, void *buffer, uint64_t len)
{
char *buffer_ptr = nullptr;
unsigned long long buffer_size = 0;
bool ret = client->download_range_to(path, buffer_ptr, buffer_size, 0, len - 1);
sprintf(response, "Http Code %ld", client->status_code());
if (buffer_size != len)
{
return 0;
}
memcpy(buffer, buffer_ptr, len);
return 1;
}
bool WebDavClient::GetHeaders(const std::string &path, dict_t *headers)
{
return client->head(path, headers);
}
WebDAV::Client *WebDavClient::GetClient()
{
return this->client;
}
ClientType WebDavClient::clientType()
{
return CLIENT_TYPE_WEBDAV;
}
uint32_t WebDavClient::SupportedActions()
{
return REMOTE_ACTION_ALL;
}
}
-62
View File
@@ -1,62 +0,0 @@
#ifndef WEBDAVCLIENT_H
#define WEBDAVCLIENT_H
#include <time.h>
#include <string>
#include <vector>
#include <regex>
#include "http/httplib.h"
#include "webdav/client.hpp"
#include "clients/remote_client.h"
#include "common.h"
using namespace httplib;
namespace WebDAV
{
inline std::string GetHttpUrl(std::string url)
{
std::string http_url = std::regex_replace(url, std::regex("webdav://"), "http://");
http_url = std::regex_replace(http_url, std::regex("webdavs://"), "https://");
return http_url;
}
class WebDavClient : public RemoteClient
{
public:
WebDavClient();
int Connect(const std::string &url, const std::string &user, const std::string &pass);
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool check_enabled);
int Mkdir(const std::string &path);
int Rmdir(const std::string &path, bool recursive);
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
int Copy(const std::string &from, const std::string &to);
int Move(const std::string &from, const std::string &to);
bool FileExists(const std::string &path);
std::vector<DirEntry> ListDir(const std::string &path);
bool IsConnected();
bool Ping();
const char *LastResponse();
int Quit();
std::string GetPath(std::string path1, std::string path2);
int Head(const std::string &path, void *buffer, uint64_t len);
bool GetHeaders(const std::string &path, dict_t *headers);
WebDAV::Client *GetClient();
ClientType clientType();
uint32_t SupportedActions();
private:
int _Rmdir(const std::string &path);
WebDAV::Client *client;
char response[1024];
bool connected = false;
};
}
#endif
+47 -5
View File
@@ -38,7 +38,9 @@ bool auto_delete_tmp_pkg;
int max_edit_file_size;
GoogleAppInfo gg_app;
bool show_hidden_files;
char alldebrid_api_key[32];
char alldebrid_api_key[64];
char realdebrid_api_key[64];
char temp_folder[256];
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'};
@@ -187,22 +189,45 @@ namespace CONFIG
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
// 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);
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());
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());
// realdebrid api key
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_REALDEBRID_API_KEY, ""));
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(realdebrid_api_key, "%s", tmp_api_key);
else
sprintf(realdebrid_api_key, "%s", decrypted_api_key.c_str());
Encrypt(realdebrid_api_key, encrypted_api_key);
}
WriteString(CONFIG_GLOBAL, CONFIG_REALDEBRID_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);
@@ -383,11 +408,18 @@ namespace CONFIG
Encrypt(alldebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(alldebrid_api_key);
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
if (strlen(realdebrid_api_key) > 0)
Encrypt(realdebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(realdebrid_api_key);
WriteString(CONFIG_GLOBAL, CONFIG_REALDEBRID_API_KEY, encrypted_api_key.c_str());
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());
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
@@ -397,6 +429,16 @@ namespace CONFIG
WriteIniFile(CONFIG_INI_FILE);
CloseIniFile();
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
if (!FS::FolderExists(compressed_file_path))
{
FS::MkDirs(compressed_file_path);
}
}
void SaveLocalDirecotry(const std::string &path)
+6 -1
View File
@@ -17,6 +17,7 @@
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
#define TMP_SFO_PATH DATA_PATH "/tmp_pkg.sfo"
#define TMP_ICON_PATH DATA_PATH "/tmp_icon.png"
#define TMP_FOLDER_PATH DATA_PATH "/tmp"
#define CONFIG_GLOBAL "Global"
@@ -58,6 +59,7 @@
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
#define CONFIG_REALDEBRID_API_KEY "realdebrid_api_key"
#define CONFIG_VERSION "config_version"
#define CONFIG_VERSION_NUM 1
@@ -70,6 +72,7 @@
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
#define CONFIG_LOCAL_DIRECTORY "local_directory"
#define CONFIG_TMP_FOLDER_PATH "temp_folder"
#define CONFIG_LANGUAGE "language"
@@ -138,7 +141,9 @@ 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];
extern char alldebrid_api_key[64];
extern char realdebrid_api_key[64];
extern char temp_folder[256];
namespace CONFIG
{
+6 -13
View File
@@ -2,17 +2,16 @@
#include <string>
#include <vector>
#include <map>
#include "openssl/md5.h"
#include "filehost.h"
#include "1fichier.h"
#include "filehost/alldebrid.h"
#include "filehost/realdebrid.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\\/(.*)"
@@ -22,20 +21,12 @@
static std::map<std::string, std::string> cache_downloal_urls;
std::string FileHost::Hash()
std::string FileHost::GetUrl()
{
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;
return url;
}
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid, bool use_realdebrid)
{
std::regex google_re(GDRIVE_REGEX);
std::regex mediafire_re(MEDIAFIRE_REGEX);
@@ -44,6 +35,8 @@ FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
if (use_alldebrid)
return new AllDebridHost(url);
else if (use_realdebrid)
return new RealDebridHost(url);
else if (std::regex_match(url, google_re))
return new GDriveHost(url);
else if (std::regex_match(url, mediafire_re))
+2 -2
View File
@@ -11,9 +11,9 @@ public:
virtual ~FileHost(){};
virtual bool IsValidUrl() = 0;
virtual std::string GetDownloadUrl() = 0;
std::string GetUrl();
std::string Hash();
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false);
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false, bool use_realdebrid = false);
static std::string GetCachedDownloadUrl(std::string &hash);
static void AddCacheDownloadUrl(std::string &hash, std::string &url);
+68
View File
@@ -0,0 +1,68 @@
#include <http/httplib.h>
#include <json-c/json.h>
#include "config.h"
#include "common.h"
#include "realdebrid.h"
RealDebridHost::RealDebridHost(const std::string &url) : FileHost(url)
{
}
bool RealDebridHost::IsValidUrl()
{
httplib::Client tmp_client("https://api.real-debrid.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);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/check");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
uint64_t supported = json_object_get_uint64(json_object_object_get(jobj, "supported"));
if (supported == 1)
return true;
}
return false;
}
std::string RealDebridHost::GetDownloadUrl()
{
httplib::Client tmp_client("https://api.real-debrid.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);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/link");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=&remote=0";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *download = json_object_get_string(json_object_object_get(jobj, "download"));
if (download != nullptr)
{
return std::string(download);
}
else
{
return "";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef REALDEBRID_HOST_H
#define REALDEBRID_HOST_H
#include "filehost.h"
class RealDebridHost : public FileHost
{
public:
RealDebridHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+1 -1
View File
@@ -562,7 +562,7 @@ private:
size_t read_buff_off_ = 0;
size_t read_buff_content_size_ = 0;
static const size_t read_buff_size_ = 1024 * 16;
static const size_t read_buff_size_ = 1024 * 512;
};
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+2 -2
View File
@@ -87,11 +87,11 @@
#endif
#ifndef CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
#define CPPHTTPLIB_RECV_BUFSIZ size_t(524288u)
#endif
#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(524288u)
#endif
#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
+2 -2
View File
@@ -10692,7 +10692,7 @@ void ImGui::NavUpdateCreateMoveRequest()
// When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad all movements are relative
// (can't focus a visible object like we can with the mouse).
if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
/*if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
{
bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
@@ -10709,7 +10709,7 @@ void ImGui::NavUpdateCreateMoveRequest()
window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
}
}
}*/
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect scoring_rect;
+286 -27
View File
@@ -10,9 +10,8 @@
#include <orbis/AppInstUtil.h>
#include <orbis/UserService.h>
#include <orbis/SystemService.h>
#include <curl/curl.h>
#include <web/request.hpp>
#include <web/urn.hpp>
#include "clients/webdav.h"
#include "clients/remote_client.h"
#include "server/http_server.h"
#include "installer.h"
#include "util.h"
@@ -22,15 +21,22 @@
#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)
struct BgProgressCheck
{
ArchivePkgInstallData* pkg_data;
int task_id;
std::string hash;
};
static OrbisBgftInitParams s_bgft_init_params;
static bool s_bgft_initialized = false;
static std::map<std::string, ArchivePkgInstallData *> archive_pkg_install_data_list;
namespace INSTALLER
{
int Init(void)
@@ -196,7 +202,7 @@ namespace INSTALLER
if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 &&
(remoteclient->clientType() == CLIENT_TYPE_WEBDAV || remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER))
{
std::string full_url = WebDAV::GetHttpUrl(remote_settings->server + path);
std::string full_url = WebDAVClient::GetHttpUrl(remote_settings->server + path);
size_t scheme_pos = full_url.find("://");
if (scheme_pos == std::string::npos)
return "";
@@ -206,24 +212,15 @@ namespace INSTALLER
if (encodeUrl)
{
Web::Urn::Path uri(path);
CURL *curl = curl_easy_init();
path = uri.quote(curl);
curl_easy_cleanup(curl);
path = httplib::detail::encode_url(path);
}
return host + path;
}
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 encoded_path = httplib::detail::encode_url(path);
std::string encoded_site_name = httplib::detail::encode_url(remote_settings->site_name);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path;
return full_url;
@@ -232,6 +229,46 @@ namespace INSTALLER
return "";
}
void *CheckBgInstallTaskThread(void *argp)
{
bool completed = false;
OrbisBgftTaskProgress progress_info;
BgProgressCheck *bg_check_data = (BgProgressCheck*) argp;
int ret;
while (!completed)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(bg_check_data->task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
{
goto finish;
}
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
sceKernelUsleep(500000);
}
finish:
if (bg_check_data->pkg_data != nullptr)
{
bg_check_data->pkg_data->stop_write_thread = true;
pthread_join(bg_check_data->pkg_data->thread, NULL);
delete(bg_check_data->pkg_data->split_file);
free(bg_check_data->pkg_data);
RemoveArchivePkgInstallData(bg_check_data->hash);
free(bg_check_data);
}
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(false);
return nullptr;
}
bool canInstallRemotePkg(const std::string &url)
{
return true;
@@ -252,6 +289,7 @@ namespace INSTALLER
uint32_t content_type = BE32(header->pkg_content_type);
uint32_t flags = BE32(header->pkg_content_flags);
bool is_patch = false;
bool completed = false;
switch (content_type)
{
@@ -323,7 +361,9 @@ namespace INSTALLER
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
goto err;
}
goto retry;
}
}
@@ -336,8 +376,9 @@ namespace INSTALLER
}
}
else if (ret > 0)
{
goto err;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
@@ -351,16 +392,32 @@ namespace INSTALLER
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (bytes_transfered < 99)
while (!completed)
{
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);
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
}
}
else
{
BgProgressCheck *bg_check_data = (BgProgressCheck*) malloc(sizeof(BgProgressCheck));
memset(bg_check_data, 0, sizeof(BgProgressCheck));
bg_check_data->pkg_data = nullptr;
bg_check_data->task_id = task_id;
bg_check_data->hash = "";
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
return 1;
}
return 1;
err:
@@ -371,6 +428,8 @@ namespace INSTALLER
{
int ret;
pkg_header header;
bool completed = false;
memset(&header, 0, sizeof(header));
if (FS::Head(path.c_str(), (void *)&header, sizeof(header)) == 0)
return 0;
@@ -432,13 +491,19 @@ namespace INSTALLER
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (bytes_transfered < 99)
while (!completed)
{
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);
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
}
return 1;
@@ -450,6 +515,8 @@ namespace INSTALLER
int InstallLocalPkg(const std::string &path, pkg_header *header, bool remove_after_install)
{
int ret;
bool completed = false;
if (strncmp(path.c_str(), "/data/", 6) != 0 &&
strncmp(path.c_str(), "/user/data/", 11) != 0 &&
strncmp(path.c_str(), "/mnt/usb", 8) != 0)
@@ -535,15 +602,20 @@ namespace INSTALLER
sprintf(activity_message, "%s", lang_strings[STR_WAIT_FOR_INSTALL_MSG]);
bytes_to_download = 1;
bytes_transfered = 0;
while (prog < 99)
while (!completed)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
return -3;
prog = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
}
if (auto_delete_tmp_pkg)
FS::Rm(path);
@@ -699,4 +771,191 @@ namespace INSTALLER
return true;
}
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash)
{
return archive_pkg_install_data_list[hash];
}
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data)
{
std::pair<std::string, ArchivePkgInstallData*> pair = std::make_pair(hash, pkg_data);
archive_pkg_install_data_list.erase(hash);
archive_pkg_install_data_list.insert(pair);
}
void RemoveArchivePkgInstallData(const std::string &hash)
{
archive_pkg_install_data_list.erase(hash);
}
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg)
{
pkg_header header;
pkg_data->split_file->Read((char*)&header, sizeof(pkg_header), 0);
int ret;
std::string cid = std::string((char *)header.pkg_content_id);
cid = cid.substr(cid.find_first_of("-") + 1, 9);
std::string display_title = cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
uint32_t content_type = BE32(header.pkg_content_type);
uint32_t flags = BE32(header.pkg_content_flags);
bool is_patch = false;
bool completed = false;
switch (content_type)
{
case PKG_CONTENT_TYPE_GD:
package_type = "PS4GD";
break;
case PKG_CONTENT_TYPE_AC:
package_type = "PS4AC";
break;
case PKG_CONTENT_TYPE_AL:
package_type = "PS4AL";
break;
case PKG_CONTENT_TYPE_DP:
package_type = "PS4DP";
break;
default:
package_type = NULL;
return 0;
break;
}
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH ||
flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
flags & PKG_CONTENT_FLAGS_DELTA_PATCH ||
flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
{
is_patch = true;
}
std::string hash = Util::UrlHash(path);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
AddArchivePkgInstallData(hash, pkg_data);
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParam params;
memset(&params, 0, sizeof(params));
{
params.userId = user_id;
params.entitlementType = 5;
params.id = (char *)header.pkg_content_id;
params.contentUrl = full_url.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
params.packageType = package_type;
params.packageSubType = "";
params.packageSize = BE64(header.pkg_size);
}
retry:
int task_id = -1;
if (!is_patch)
ret = sceBgftServiceIntDownloadRegisterTask(&params, &task_id);
else
ret = sceBgftServiceIntDebugDownloadRegisterPkg(&params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
if (!bg)
{
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)
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
ret = 0;
goto finish;
}
goto retry;
}
}
else
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
ret = 0;
goto finish;
}
goto retry;
}
}
else if (ret > 0)
{
ret = 0;
goto finish;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
ret = 0;
goto finish;
}
Util::Notify("%s queued", display_title.c_str());
if (!bg)
{
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (!completed)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
{
ret = 0;
goto finish;
}
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
}
}
else
{
BgProgressCheck *bg_check_data = (BgProgressCheck*) malloc(sizeof(BgProgressCheck));
memset(bg_check_data, 0, sizeof(BgProgressCheck));
bg_check_data->pkg_data = pkg_data;
bg_check_data->task_id = task_id;
bg_check_data->hash = hash;
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
return 1;
}
ret = 1;
finish:
pkg_data->stop_write_thread = true;
pthread_join(pkg_data->thread, NULL);
delete(pkg_data->split_file);
free(pkg_data);
RemoveArchivePkgInstallData(hash);
return ret;
}
}
+19
View File
@@ -1,6 +1,9 @@
#pragma once
#include "clients/remote_client.h"
#include "zip_util.h"
#include "split_file.h"
#include "pthread.h"
#define SWAP16(x) \
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
@@ -46,6 +49,8 @@
#define PKG_ENTRY_ID__PARAM_SFO 0x1000
#define PKG_ENTRY_ID__ICON0_PNG 0x1200
#define INSTALL_ARCHIVE_PKG_SPLIT_SIZE 10485760
typedef struct
{
uint32_t pkg_magic; // 0x000 - 0x7F434E54
@@ -116,6 +121,16 @@ enum pkg_content_type
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
};
struct ArchivePkgInstallData
{
SplitFile *split_file;
ArchiveEntry *archive_entry;
pthread_t thread;
bool stop_write_thread;
};
static pthread_t bk_install_thid;
namespace INSTALLER
{
int Init(void);
@@ -130,4 +145,8 @@ namespace INSTALLER
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);
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash);
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data);
void RemoveArchivePkgInstallData(const std::string &hash);
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg = false);
}
+162 -159
View File
@@ -10,165 +10,168 @@ char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE] = {
// This is properly populated so that emulator won't crash if an user launches it without language INI files.
char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"Connection Settings", // STR_CONNECTION_SETTINGS
"Site", // STR_SITE
"Local", // STR_LOCAL
"Remote", // STR_REMOTE
"Messages", // STR_MESSAGES
"Update Software", // STR_UPDATE_SOFTWARE
"Connect", // STR_CONNECT
"Disconnect", // STR_DISCONNECT
"Search", // STR_SEARCH
"Refresh", // STR_REFRESH
"Server", // STR_SERVER
"Username", // STR_USERNAME
"Password", // STR_PASSWORD
"Port", // STR_PORT
"Pasv", // STR_PASV
"Directory", // STR_DIRECTORY
"Filter", // STR_FILTER
"Yes", // STR_YES
"No", // STR_NO
"Cancel", // STR_CANCEL
"Continue", // STR_CONTINUE
"Close", // STR_CLOSE
"Folder", // STR_FOLDER
"File", // STR_FILE
"Type", // STR_TYPE
"Name", // STR_NAME
"Size", // STR_SIZE
"Date", // STR_DATE
"New Folder", // STR_NEW_FOLDER
"Rename", // STR_RENAME
"Delete", // STR_DELETE
"Upload", // STR_UPLOAD
"Download", // STR_DOWNLOAD
"Select All", // STR_SELECT_ALL
"Clear All", // STR_CLEAR_ALL
"Uploading", // STR_UPLOADING
"Downloading", // STR_DOWNLOADING
"Overwrite", // STR_OVERWRITE
"Don't Overwrite", // STR_DONT_OVERWRITE
"Ask for Confirmation", // STR_ASK_FOR_CONFIRM
"Don't Ask for Confirmation", // STR_DONT_ASK_CONFIRM
"Always use this option and don't ask again", // STR_ALLWAYS_USE_OPTION
"Actions", // STR_ACTIONS
"Confirm", // STR_CONFIRM
"Overwrite Options", // STR_OVERWRITE_OPTIONS
"Properties", // STR_PROPERTIES
"Progress", // STR_PROGRESS
"Updates", // STR_UPDATES
"Are you sure you want to delete this file(s)/folder(s)?", // STR_DEL_CONFIRM_MSG
"Canceling. Waiting for last action to complete", // STR_CANCEL_ACTION_MSG
"Failed to upload file", // STR_FAIL_UPLOAD_MSG
"Failed to download file", // STR_FAIL_DOWNLOAD_MSG
"Failed to read contents of directory or folder does not exist.", // STR_FAIL_READ_LOCAL_DIR_MSG
"426 Connection closed.", // STR_CONNECTION_CLOSE_ERR_MSG
"426 Remote Server has terminated the connection.", // STR_REMOTE_TERM_CONN_MSG
"300 Failed Login. Please check your username or password.", // STR_FAIL_LOGIN_MSG
"426 Failed. Connection timeout.", // STR_FAIL_TIMEOUT_MSG
"Failed to delete directory", // STR_FAIL_DEL_DIR_MSG
"Deleting", // STR_DELETING
"Failed to delete file", // STR_FAIL_DEL_FILE_MSG
"Deleted", // STR_DELETED
"Link", // STR_LINK
"Share", // STR_SHARE
"310 Failed", // STR_FAILED
"310 Failed to create file on local", // STR_FAIL_CREATE_LOCAL_FILE_MSG
"Install", // STR_INSTALL
"Installing", // STR_INSTALLING
"Success", // STR_INSTALL_SUCCESS
"Failed", // STR_INSTALL_FAILED
"Skipped", // STR_INSTALL_SKIPPED
"Checking connection to remote HTTP Server", // STR_CHECK_HTTP_MSG
"Failed connecting to HTTP Server", // STR_FAILED_HTTP_CHECK
"Remote is not a HTTP Server", // STR_REMOTE_NOT_HTTP
"Package not in the /data or /mnt/usbX folder", // STR_INSTALL_FROM_DATA_MSG
"Package is already installed", // STR_ALREADY_INSTALLED_MSG
"Install from URL", // STR_INSTALL_FROM_URL
"Could not read package header info", // STR_CANNOT_READ_PKG_HDR_MSG
"Favorite URLs", // STR_FAVORITE_URLS
"Slot", // STR_SLOT
"Edit", // STR_EDIT
"One Time Url", // STR_ONETIME_URL
"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 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
"Extract", // STR_EXTRACT
"Extracting", // STR_EXTRACTING
"Failed to extract", // STR_FAILED_TO_EXTRACT
"Extract Location", // STR_EXTRACT_LOCATION
"Compress", // STR_COMPRESS
"Zip Filename", // STR_ZIP_FILE_PATH
"Compressing", // STR_COMPRESSING
"Error occured while creating zip", // STR_ERROR_CREATE_ZIP
"Unsupported compressed file format", // STR_UNSUPPORTED_FILE_FORMAT
"Cut", // STR_CUT
"Copy", // STR_COPY
"Paste", // STR_PASTE
"Moving", // STR_MOVING
"Copying", // STR_COPYING
"Failed to move file", // STR_FAIL_MOVE_MSG
"Failed to copy file", // STR_FAIL_COPY_MSG
"Cannot move parent directory to sub subdirectory", // STR_CANT_MOVE_TO_SUBDIR_MSG
"Cannot copy parent directory to sub subdirectory", // STR_CANT_COPY_TO_SUBDIR_MSG
"Operation not supported", // STR_UNSUPPORTED_OPERATION_MSG
"Http Port", // STR_HTTP_PORT
"The content has already been installed. Do you want to continue installing", // STR_REINSTALL_CONFIRM_MSG
"Remote package installation is not supported for protected servers.", // STR_REMOTE_NOT_SUPPORT_MSG
"Remote HTTP Server not reachable.", // STR_CANNOT_CONNECT_REMOTE_MSG
"Remote Package Install not possible. Would you like to download package and install?", // STR_DOWNLOAD_INSTALL_MSG
"Checking remote server for Remote Package Install.", // STR_CHECKING_REMOTE_SERVER_MSG
"RPI", // STR_ENABLE_RPI
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_FTP_SMB_MSG
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_WEBDAV_MSG
"Files", // STR_FILES
"Editor", // STR_EDITOR
"Save", // STR_SAVE
"Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG
"Delete Selected Line", // STR_DELETE_LINE
"Insert Below Selected Line", // STR_INSERT_LINE
"Modified", // STR_MODIFIED
"Failed to obtain an access token from", // STR_FAIL_GET_TOKEN_MSG
"Login Success. You may close the browser and return to the application", // STR_GET_TOKEN_SUCCESS_MSG
"See, edit, create, and delete all of your Google Drive files", // STR_PERM_DRIVE
"See, create, and delete its own configuration data in your Google Drive", // STR_PERM_DRIVE_APPDATA
"See, edit, create, and delete only the specific Google Drive files you use with this app", // STR_PERM_DRIVE_FILE
"View and manage metadata of files in your Google Drive", // STR_PERM_DRIVE_METADATA
"See information about your Google Drive files", // STR_PERM_DRIVE_METADATA_RO
"Google login failed", // STR_GOOGLE_LOGIN_FAIL_MSG
"Google login timed out", // STR_GOOGLE_LOGIN_TIMEOUT_MSG
"New File", // STR_NEW_FILE
"Settings", // STR_SETTINGS
"Client ID", // STR_CLIENT_ID
"Client Secret", // STR_CLIENT_SECRET
"Global", // STR_GLOBAL
"Google", // STR_GOOGLE
"Copy selected line", // STR_COPY_LINE
"Paste into selected line", // STR_PASTE_LINE
"Show hidden files", // STR_SHOW_HIDDEN_FILES
"Set Default Folder", // STR_SET_DEFAULT_DIRECTORY
"has being set as default direcotry", // STR_SET_DEFAULT_DIRECTORY_MSG
"View Image", // STR_VIEW_IMAGE
"Package Information", // STR_VIEW_PKG_INFO
"NFS export path missing in URL", // STR_NFS_EXP_PATH_MISSING_MSG
"Failed to init NFS context", // STR_FAIL_INIT_NFS_CONTEXT
"Failed to mount NFS share", // STR_FAIL_MOUNT_NFS_MSG
"Web Server", // STR_WEB_SERVER
"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
"Language", // STR_LANGUAGE
"Connection Settings", // STR_CONNECTION_SETTINGS
"Site", // STR_SITE
"Local", // STR_LOCAL
"Remote", // STR_REMOTE
"Messages", // STR_MESSAGES
"Update Software", // STR_UPDATE_SOFTWARE
"Connect", // STR_CONNECT
"Disconnect", // STR_DISCONNECT
"Search", // STR_SEARCH
"Refresh", // STR_REFRESH
"Server", // STR_SERVER
"Username", // STR_USERNAME
"Password", // STR_PASSWORD
"Port", // STR_PORT
"Pasv", // STR_PASV
"Directory", // STR_DIRECTORY
"Filter", // STR_FILTER
"Yes", // STR_YES
"No", // STR_NO
"Cancel", // STR_CANCEL
"Continue", // STR_CONTINUE
"Close", // STR_CLOSE
"Folder", // STR_FOLDER
"File", // STR_FILE
"Type", // STR_TYPE
"Name", // STR_NAME
"Size", // STR_SIZE
"Date", // STR_DATE
"New Folder", // STR_NEW_FOLDER
"Rename", // STR_RENAME
"Delete", // STR_DELETE
"Upload", // STR_UPLOAD
"Download", // STR_DOWNLOAD
"Select All", // STR_SELECT_ALL
"Clear All", // STR_CLEAR_ALL
"Uploading", // STR_UPLOADING
"Downloading", // STR_DOWNLOADING
"Overwrite", // STR_OVERWRITE
"Don't Overwrite", // STR_DONT_OVERWRITE
"Ask for Confirmation", // STR_ASK_FOR_CONFIRM
"Don't Ask for Confirmation", // STR_DONT_ASK_CONFIRM
"Always use this option and don't ask again", // STR_ALLWAYS_USE_OPTION
"Actions", // STR_ACTIONS
"Confirm", // STR_CONFIRM
"Overwrite Options", // STR_OVERWRITE_OPTIONS
"Properties", // STR_PROPERTIES
"Progress", // STR_PROGRESS
"Updates", // STR_UPDATES
"Are you sure you want to delete this file(s)/folder(s)?", // STR_DEL_CONFIRM_MSG
"Canceling. Waiting for last action to complete", // STR_CANCEL_ACTION_MSG
"Failed to upload file", // STR_FAIL_UPLOAD_MSG
"Failed to download file", // STR_FAIL_DOWNLOAD_MSG
"Failed to read contents of directory or folder does not exist.", // STR_FAIL_READ_LOCAL_DIR_MSG
"426 Connection closed.", // STR_CONNECTION_CLOSE_ERR_MSG
"426 Remote Server has terminated the connection.", // STR_REMOTE_TERM_CONN_MSG
"300 Failed Login. Please check your username or password.", // STR_FAIL_LOGIN_MSG
"426 Failed. Connection timeout.", // STR_FAIL_TIMEOUT_MSG
"Failed to delete directory", // STR_FAIL_DEL_DIR_MSG
"Deleting", // STR_DELETING
"Failed to delete file", // STR_FAIL_DEL_FILE_MSG
"Deleted", // STR_DELETED
"Link", // STR_LINK
"Share", // STR_SHARE
"310 Failed", // STR_FAILED
"310 Failed to create file on local", // STR_FAIL_CREATE_LOCAL_FILE_MSG
"Install", // STR_INSTALL
"Installing", // STR_INSTALLING
"Success", // STR_INSTALL_SUCCESS
"Failed", // STR_INSTALL_FAILED
"Skipped", // STR_INSTALL_SKIPPED
"Checking connection to remote HTTP Server", // STR_CHECK_HTTP_MSG
"Failed connecting to HTTP Server", // STR_FAILED_HTTP_CHECK
"Remote is not a HTTP Server", // STR_REMOTE_NOT_HTTP
"Package not in the /data or /mnt/usbX folder", // STR_INSTALL_FROM_DATA_MSG
"Package is already installed", // STR_ALREADY_INSTALLED_MSG
"Install from URL", // STR_INSTALL_FROM_URL
"Could not read package header info", // STR_CANNOT_READ_PKG_HDR_MSG
"Favorite URLs", // STR_FAVORITE_URLS
"Slot", // STR_SLOT
"Edit", // STR_EDIT
"One Time Url", // STR_ONETIME_URL
"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 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
"Extract", // STR_EXTRACT
"Extracting", // STR_EXTRACTING
"Failed to extract", // STR_FAILED_TO_EXTRACT
"Extract Location", // STR_EXTRACT_LOCATION
"Compress", // STR_COMPRESS
"Zip Filename", // STR_ZIP_FILE_PATH
"Compressing", // STR_COMPRESSING
"Error occured while creating zip", // STR_ERROR_CREATE_ZIP
"Unsupported compressed file format", // STR_UNSUPPORTED_FILE_FORMAT
"Cut", // STR_CUT
"Copy", // STR_COPY
"Paste", // STR_PASTE
"Moving", // STR_MOVING
"Copying", // STR_COPYING
"Failed to move file", // STR_FAIL_MOVE_MSG
"Failed to copy file", // STR_FAIL_COPY_MSG
"Cannot move parent directory to sub subdirectory", // STR_CANT_MOVE_TO_SUBDIR_MSG
"Cannot copy parent directory to sub subdirectory", // STR_CANT_COPY_TO_SUBDIR_MSG
"Operation not supported", // STR_UNSUPPORTED_OPERATION_MSG
"Http Port", // STR_HTTP_PORT
"The content has already been installed. Do you want to continue installing", // STR_REINSTALL_CONFIRM_MSG
"Remote package installation is not supported for protected servers.", // STR_REMOTE_NOT_SUPPORT_MSG
"Remote HTTP Server not reachable.", // STR_CANNOT_CONNECT_REMOTE_MSG
"Remote Package Install not possible. Would you like to download package and install?", // STR_DOWNLOAD_INSTALL_MSG
"Checking remote server for Remote Package Install.", // STR_CHECKING_REMOTE_SERVER_MSG
"RPI", // STR_ENABLE_RPI
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_FTP_SMB_MSG
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_WEBDAV_MSG
"Files", // STR_FILES
"Editor", // STR_EDITOR
"Save", // STR_SAVE
"Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG
"Delete Selected Line", // STR_DELETE_LINE
"Insert Below Selected Line", // STR_INSERT_LINE
"Modified", // STR_MODIFIED
"Failed to obtain an access token from", // STR_FAIL_GET_TOKEN_MSG
"Login Success. You may close the browser and return to the application", // STR_GET_TOKEN_SUCCESS_MSG
"See, edit, create, and delete all of your Google Drive files", // STR_PERM_DRIVE
"See, create, and delete its own configuration data in your Google Drive", // STR_PERM_DRIVE_APPDATA
"See, edit, create, and delete only the specific Google Drive files you use with this app", // STR_PERM_DRIVE_FILE
"View and manage metadata of files in your Google Drive", // STR_PERM_DRIVE_METADATA
"See information about your Google Drive files", // STR_PERM_DRIVE_METADATA_RO
"Google login failed", // STR_GOOGLE_LOGIN_FAIL_MSG
"Google login timed out", // STR_GOOGLE_LOGIN_TIMEOUT_MSG
"New File", // STR_NEW_FILE
"Settings", // STR_SETTINGS
"Client ID", // STR_CLIENT_ID
"Client Secret", // STR_CLIENT_SECRET
"Global", // STR_GLOBAL
"Google", // STR_GOOGLE
"Copy selected line", // STR_COPY_LINE
"Paste into selected line", // STR_PASTE_LINE
"Show hidden files", // STR_SHOW_HIDDEN_FILES
"Set Default Folder", // STR_SET_DEFAULT_DIRECTORY
"has being set as default direcotry", // STR_SET_DEFAULT_DIRECTORY_MSG
"View Image", // STR_VIEW_IMAGE
"Package Information", // STR_VIEW_PKG_INFO
"NFS export path missing in URL", // STR_NFS_EXP_PATH_MISSING_MSG
"Failed to init NFS context", // STR_FAIL_INIT_NFS_CONTEXT
"Failed to mount NFS share", // STR_FAIL_MOUNT_NFS_MSG
"Web Server", // STR_WEB_SERVER
"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
"Language", // STR_LANGUAGE
"Temp Directory", // STR_TEMP_DIRECTORY
"Real-Debrid", // STR_REALDEBRID
"Package install is running in the background. Don't close the app while install is in progress", // STR_BACKGROUND_INSTALL_INPROGRESS
};
bool needs_extended_font = false;
+5 -2
View File
@@ -162,7 +162,10 @@
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
FUNC(STR_INVALID_URL) \
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG) \
FUNC(STR_LANGUAGE)
FUNC(STR_LANGUAGE) \
FUNC(STR_TEMP_DIRECTORY) \
FUNC(STR_REALDEBRID) \
FUNC(STR_BACKGROUND_INSTALL_INPROGRESS)
#define GET_VALUE(x) x,
#define GET_STRING(x) #x,
@@ -172,7 +175,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 159
#define LANG_STRINGS_NUM 162
#define LANG_ID_SIZE 64
#define LANG_STR_SIZE 384
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
+132 -17
View File
@@ -15,6 +15,7 @@
#include "lang.h"
#include "system.h"
#include "zip_util.h"
#include "util.h"
#include "installer.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
@@ -1023,9 +1024,9 @@ namespace HttpServer
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 65536ul - req.ranges[0].first;
range_len = 524288ul;
res.set_header("Content-Length", std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-65535/"+std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
@@ -1048,19 +1049,80 @@ namespace HttpServer
}
});
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
RemoteSettings *tmp_settings;
std::string hash = req.matches[1];
ArchivePkgInstallData *pkg_data = INSTALLER::GetArchivePkgInstallData(hash);
if (req.method == "HEAD")
{
res.status = 204;
res.set_header("Content-Length", std::to_string(pkg_data->archive_entry->filesize));
res.set_header("Accept-Ranges", "bytes");
return;
}
if (req.ranges.empty())
{
res.status = 200;
res.set_content_provider(
131072, "application/octet-stream",
[pkg_data](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(131072);
size_t bytes_read = pkg_data->split_file->Read(buf, 131072, offset);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
else
{
res.status = 206;
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 524288ul;
res.set_header("Content-Length", std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[pkg_data, range, range_len](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(range_len);
size_t bytes_read = pkg_data->split_file->Read(buf, range_len, range.first);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
});
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
{
std::string url;
const char *url_param;
bool use_alldebrid;
bool use_alldebrid = false;
bool use_realdebrid = false;
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"));
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
if (url_param == nullptr)
{
bad_request(res, "Required url_param, use_alldebrid parameter missing");
bad_request(res, "Required url_param parameter missing");
return;
}
}
@@ -1070,14 +1132,14 @@ namespace HttpServer
return;
}
if (use_alldebrid && strlen(alldebrid_api_key) == 0)
if ((use_alldebrid && strlen(alldebrid_api_key) == 0) || (use_realdebrid && strlen(realdebrid_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);
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid, use_realdebrid);
if (!filehost->IsValidUrl())
{
@@ -1085,15 +1147,24 @@ namespace HttpServer
return;
}
std::string hash = filehost->Hash();
std::string hash = Util::UrlHash(filehost->GetUrl());
snprintf(activity_message, 1023, "%s %s", lang_strings[STR_INSTALLING], filehost->GetUrl().c_str());
activity_inprogess = true;
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
Windows::SetModalMode(true);
std::string download_url = filehost->GetDownloadUrl();
if (download_url.empty())
{
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(true);
return;
}
FileHost::AddCacheDownloadUrl(hash, download_url);
delete(filehost);
size_t scheme_pos = download_url.find("://");
@@ -1105,17 +1176,61 @@ namespace HttpServer
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;
if (BE32(header.pkg_magic) == 0x7F434E54)
{
FileHost::AddCacheDownloadUrl(hash, download_url);
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, false);
if (rc == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(true);
return;
}
}
else
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(path, baseclient);
if (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int ret = pthread_create(&install_data->thread, NULL, Actions::ExtractArchivePkg, install_data);
ret = INSTALLER::InstallArchivePkg(entry->filename, install_data, true);
if (ret == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(false);
return;
}
}
else
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(false);
return;
}
}
success(res);
});
+221
View File
@@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "split_file.h"
SplitFile::SplitFile(const std::string &path, size_t block_size)
{
this->block_size = block_size;
this->path = path;
this->complete = false;
sem_init(&this->block_ready, 0, 0);
}
SplitFile::~SplitFile()
{
for (int i = 0; i < this->file_blocks.size(); i++)
{
if (this->file_blocks[i] != nullptr && this->file_blocks[i]->status != BLOCK_STATUS_DELETED)
{
if (this->file_blocks[i]->fd != nullptr)
{
fclose(this->file_blocks[i]->fd);
}
remove(this->file_blocks[i]->block_file.c_str());
free(this->file_blocks[i]);
}
}
sem_destroy(&this->block_ready);
};
int SplitFile::Open()
{
this->block_in_progress = NewBlock();
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
return (block_in_progress->fd == nullptr);
}
size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
{
int first_block_num, block_num;
size_t block_offset;
size_t remaining;
size_t bytes_read;
size_t total_bytes_read;
FileBlock *block;
FILE *fd;
char *p;
first_block_num= offset / this->block_size;
block_num = first_block_num;
block_offset = offset % this->block_size;
while ((block_num >= this->file_blocks.size() && !this->complete) ||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
if (block->status == BLOCK_STATUS_DELETED)
{
return -1;
}
if (block_offset > block->size - 1 && this->complete)
{
// requested offset is pass the end of split file
return 0;
}
remaining = buf_size;
bool eof = false;
total_bytes_read = 0;
p = buf;
while (remaining > 0 && !eof)
{
fd = block->fd;
if (fd == nullptr)
{
fd = fopen(block->block_file.c_str(), "rb");
block->fd = fd;
}
fseek(fd, block_offset, SEEK_SET);
bytes_read = fread(p, 1, remaining, fd);
if (bytes_read == remaining)
{
p += bytes_read;
total_bytes_read += bytes_read;
}
else
{
if (feof(fd))
{
p += bytes_read;
total_bytes_read += bytes_read;
if (block->is_last)
{
eof = true;
continue;
}
}
else
return -1;
}
remaining -= bytes_read;
if (remaining == 0)
continue;
block_num++;
block_offset = 0;
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
}
// delete blocks before the first read offset block. Assumuption, that reads are always
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
for (int j=0; j < first_block_num - 2; j++)
{
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
{
if (this->file_blocks[j]->fd != nullptr)
{
fclose(this->file_blocks[j]->fd);
this->file_blocks[j]->fd = nullptr;
}
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
remove(this->file_blocks[j]->block_file.c_str());
}
}
return total_bytes_read;
}
size_t SplitFile::Write(char *buf, size_t buf_size)
{
size_t bytes_written;
size_t block_space_remaining;
size_t bytes_to_write;
char *p = buf;
size_t total_bytes_written = 0;
size_t remaining_to_write = buf_size;
while (remaining_to_write > 0)
{
block_space_remaining = this->block_size - block_in_progress->size;
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
bytes_written = fwrite(p, 1, bytes_to_write, block_in_progress->fd);
block_in_progress->size += bytes_written;
total_bytes_written += bytes_written;
remaining_to_write -= bytes_written;
block_space_remaining -= bytes_written;
p += bytes_written;
// error if bytes_to_write != bytes_written
if (bytes_written != bytes_to_write)
{
break;
}
if (block_space_remaining == 0)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
block_in_progress->status = BLOCK_STATUS_CREATED;
this->file_blocks.push_back(block_in_progress);
sem_post(&this->block_ready);
block_in_progress = NewBlock();
}
}
return total_bytes_written;
}
int SplitFile::Close()
{
if (block_in_progress->fd != nullptr)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
}
block_in_progress->status = BLOCK_STATUS_CREATED;
block_in_progress->is_last = true;
this->file_blocks.push_back(block_in_progress);
this->complete = true;
sem_post(&this->block_ready);
return 0;
}
FileBlock *SplitFile::NewBlock()
{
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
memset(block, 0, sizeof(FileBlock));
block->is_last = false;
block->size = 0;
block->block_file = this->path + "." + std::to_string(this->file_blocks.size());
block->fd = fopen(block->block_file.c_str(), "w");
return block;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef SPLIT_FILE_H
#define SPLIT_FILE_H
#include <string>
#include <vector>
#include <mutex>
#include <pthread.h>
enum FileBlockStatus
{
BLOCK_STATUS_NOT_EXISTS,
BLOCK_STATUS_CREATED,
BLOCK_STATUS_DELETED
};
typedef struct
{
std::string block_file;
size_t size;
FILE* fd;
bool is_last;
FileBlockStatus status;
} FileBlock;
class SplitFile
{
public:
SplitFile(const std::string& path, size_t block_size);
~SplitFile();
size_t Read(char* buf, size_t buf_size, size_t offset);
size_t Write(char* buf, size_t buf_size);
int Open();
int Close();
private:
std::vector<FileBlock*> file_blocks;
size_t write_offset;
size_t block_size;
std::string path;
int write_error;
bool complete;
FileBlock *block_in_progress;
sem_t block_ready;
FileBlock *NewBlock();
};
#endif
+22
View File
@@ -6,6 +6,8 @@
#include <algorithm>
#include <stdarg.h>
#include <orbis/libkernel.h>
#include "base64.h"
#include "openssl/md5.h"
#include "lang.h"
namespace Util
@@ -47,6 +49,13 @@ namespace Util
return s;
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
@@ -66,6 +75,19 @@ namespace Util
return tokens;
}
static inline std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
}
static inline void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
-120
View File
@@ -1,120 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#include <algorithm>
#include <fstream>
#include <cstring>
#include "http/httplib.h"
#include "callback.hpp"
using namespace httplib;
namespace Web
{
namespace Callback
{
namespace Read
{
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
{
auto in_stream = reinterpret_cast<std::istream*>(stream);
auto read_bytes = static_cast<unsigned long long>(item_size * item_count);
auto position = static_cast<unsigned long long>(in_stream->tellg());
in_stream->seekg(0, std::ios::end);
auto size = static_cast<unsigned long long>(in_stream->tellg());
in_stream->seekg(position, std::ios::beg);
auto rest_bytes = size - position;
read_bytes = std::min<unsigned long long>(read_bytes, rest_bytes);
in_stream->read(ptr, read_bytes);
return read_bytes;
}
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
{
auto data = (Data*)buffer;
auto size = static_cast<unsigned long long>(item_size * item_count);
auto rest_bytes = data->size - data->position;
auto copied_bytes = std::min<unsigned long long>(size, rest_bytes);
memcpy(ptr, data->buffer, copied_bytes);
data->position += copied_bytes;
return copied_bytes;
}
} // namespace Read
namespace Write
{
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
{
auto out_stream = reinterpret_cast<std::ostream*>(stream);
size_t write_bytes = item_size * item_count;
out_stream->write(ptr, write_bytes);
return write_bytes;
}
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
{
auto data = reinterpret_cast<Data*>(buffer);
auto size = static_cast<unsigned long long>(item_size * item_count);
auto rest_bytes = data->size - data->position;
auto copied_bytes = std::min<unsigned long long>(size, rest_bytes);
memcpy(data->buffer, ptr, copied_bytes);
data->position += copied_bytes;
return copied_bytes;
}
} // namespace Write
namespace Append
{
size_t buffer(char* ptr, size_t item_size, size_t item_count, void* buffer)
{
auto data = reinterpret_cast<Data*>(buffer);
auto append_size = item_size * item_count;
auto new_buffer_size = data->size + append_size;
auto new_buffer = new char[new_buffer_size];
if (data->size != 0) memcpy(new_buffer, data->buffer, data->size);
memcpy(new_buffer + data->size, ptr, append_size);
delete[] data->buffer;
data->buffer = new_buffer;
data->size = new_buffer_size;
return append_size;
}
size_t stream(char* ptr, size_t item_size, size_t item_count, void* stream)
{
auto out_stream = reinterpret_cast<std::ostream*>(stream);
size_t write_bytes = item_size * item_count;
out_stream->seekp(0, std::ios::end);
out_stream->write(ptr, write_bytes);
return write_bytes;
}
size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink)
{
auto ostream = reinterpret_cast<DataSink*>(sink);
size_t write_bytes = item_size * item_count;
ostream->write(ptr, write_bytes);
return write_bytes;
}
} // namespace Append
} // namespace Callback
} // namespace Web
-68
View File
@@ -1,68 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEB_CALLBACK_HPP
#define WEB_CALLBACK_HPP
namespace Web
{
struct Data
{
char* buffer;
unsigned long long position;
unsigned long long size;
void reset()
{
buffer = nullptr;
position = 0;
size = 0;
}
~Data()
{
delete[] buffer;
}
};
namespace Callback
{
namespace Read
{
size_t stream(char* data, size_t size, size_t count, void* stream);
size_t buffer(char* data, size_t size, size_t count, void* buffer);
}
namespace Write
{
size_t stream(char* data, size_t size, size_t count, void* stream);
size_t buffer(char* data, size_t size, size_t count, void* buffer);
}
namespace Append
{
size_t stream(char* data, size_t size, size_t count, void* stream);
size_t buffer(char* data, size_t size, size_t count, void* buffer);
size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink);
}
}
} // namespace Web
#endif
-42
View File
@@ -1,42 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#include "fsinfo.hpp"
#include <fstream>
namespace Web
{
namespace FileInfo
{
auto exists(const std::string& path) -> bool
{
std::ifstream file(path);
return file.good();
}
auto size(const std::string& path_file) -> unsigned long long
{
std::ifstream file(path_file, std::ios::binary | std::ios::ate);
return static_cast<unsigned long long>(file.tellg());
}
} // namespace FileInfo
} // namespace Web
-38
View File
@@ -1,38 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEB_FSINFO_HPP
#define WEB_FSINFO_HPP
#include <fstream>
#include <string>
namespace Web
{
namespace FileInfo
{
auto exists(const std::string& path) -> bool;
auto size(const std::string& path_file) -> unsigned long long;
} // namespace FileInfo
} // namespace Web
#endif
-69
View File
@@ -1,69 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#include "header.hpp"
#include <curl/curl.h>
namespace Web
{
Header::Header(const std::initializer_list<std::string>& init_list) noexcept : handle(nullptr)
{
for (auto& item : init_list)
{
this->append(item);
}
}
Header::~Header() noexcept
{
curl_slist_free_all(reinterpret_cast<curl_slist*>(this->handle));
}
Header::Header(Header&& other) noexcept
{
handle = other.handle;
other.handle = nullptr;
}
auto Header::operator=(Header&& other) noexcept -> Header&
{
if (this != &other)
{
Header(std::move(other)).swap(*this);
}
return *this;
}
auto Header::swap(Header& other) noexcept -> void
{
using std::swap;
swap(handle, other.handle);
}
void
Header::append(const std::string& item) noexcept
{
this->handle = curl_slist_append(reinterpret_cast<curl_slist*>(this->handle), item.c_str());
}
} // namespace Web
-51
View File
@@ -1,51 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEB_HEADER_HPP
#define WEB_HEADER_HPP
#include <initializer_list>
#include <string>
namespace Web
{
class Header final
{
public:
void* handle;
Header(const std::initializer_list<std::string>& init_list) noexcept;
Header(const Header& other) = delete;
Header(Header&& other) noexcept;
~Header() noexcept;
auto operator=(const Header& other) -> Header& = delete;
auto operator=(Header&& other) noexcept -> Header&;
void append(const std::string& item) noexcept;
private:
auto swap(Header& other) noexcept -> void;
};
} // namespace Web
#endif
-227
View File
@@ -1,227 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#include "request.hpp"
#include "fsinfo.hpp"
#include "util.h"
namespace Web
{
static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose)
{
int const size = 1048576;
if (setsockopt(curlfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1)
{
return CURL_SOCKOPT_ERROR;
}
if (setsockopt(curlfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
{
return CURL_SOCKOPT_ERROR;
}
return CURL_SOCKOPT_OK;
}
auto inline get(const dict_t &options, const std::string &&name) -> std::string
{
auto it = options.find(name);
if (it == options.end())
{
return std::string{""};
}
else
{
return it->second;
}
}
Request::Request(dict_t &&options_) : options(options_)
{
auto hostname = get(options, "hostname");
auto username = get(options, "username");
auto password = get(options, "password");
auto timeout = get(options, "password");
auto proxy_hostname = get(options, "proxy_hostname");
auto proxy_username = get(options, "proxy_username");
auto proxy_password = get(options, "proxy_password");
auto cert_path = get(options, "cert_path");
auto key_path = get(options, "key_path");
this->handle = curl_easy_init();
this->set(CURLOPT_SSL_VERIFYHOST, 0);
this->set(CURLOPT_SSL_VERIFYPEER, 0);
#ifdef _DEBUG
this->set(CURLOPT_VERBOSE, 1);
#else
this->set(CURLOPT_VERBOSE, 0);
#endif
if (this->cert_required())
{
this->set(CURLOPT_SSLCERTTYPE, "PEM");
this->set(CURLOPT_SSLKEYTYPE, "PEM");
this->set(CURLOPT_SSLCERT, const_cast<char *>(cert_path.c_str()));
this->set(CURLOPT_SSLKEY, const_cast<char *>(key_path.c_str()));
}
this->set(CURLOPT_URL, const_cast<char *>(hostname.c_str()));
if (!username.empty())
{
this->set(CURLOPT_HTTPAUTH, static_cast<int>(CURLAUTH_BASIC));
auto token = username + ":" + password;
this->set(CURLOPT_USERPWD, const_cast<char *>(token.c_str()));
}
this->set(CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
this->set(CURLOPT_FOLLOWLOCATION, 1);
this->set(CURLOPT_COOKIEJAR, "/data/ps4-webdav-client/cookies.txt");
this->set(CURLOPT_COOKIEFILE, "/data/ps4-webdav-client/cookies.txt");
if (timeout.empty())
{
this->set(CURLOPT_CONNECTTIMEOUT, 15L);
}
else
{
this->set(CURLOPT_CONNECTTIMEOUT, atoi(timeout.c_str()));
}
if (!this->proxy_enabled())
return;
this->set(CURLOPT_PROXY, const_cast<char *>(proxy_hostname.c_str()));
this->set(CURLOPT_PROXYAUTH, static_cast<int>(CURLAUTH_BASIC));
if (proxy_username.empty())
return;
if (proxy_password.empty())
{
this->set(CURLOPT_PROXYUSERNAME, const_cast<char *>(proxy_username.c_str()));
}
else
{
if (!username.empty() && !password.empty())
{
auto token = proxy_username + ":" + proxy_password;
this->set(CURLOPT_PROXYUSERPWD, const_cast<char *>(token.c_str()));
}
}
}
Request::~Request() noexcept
{
if (this->handle != nullptr)
curl_easy_cleanup(this->handle);
}
auto Request::swap(Request &other) noexcept -> void
{
using std::swap;
swap(handle, other.handle);
}
Request::Request(Request &&other) noexcept : handle{
other.handle}
{
other.handle = nullptr;
}
auto Request::operator=(Request &&other) noexcept -> Request &
{
if (this != &other)
{
Request(std::move(other)).swap(*this);
}
return *this;
}
bool Request::perform() noexcept
{
if (this->handle == nullptr)
return false;
this->res = curl_easy_perform(this->handle);
auto is_performed = this->res == CURLE_OK;
if (!is_performed)
return false;
this->http_code = 0;
curl_easy_getinfo(this->handle, CURLINFO_RESPONSE_CODE, &this->http_code);
if (this->http_code < 200 || this->http_code > 299)
return false;
return true;
}
bool Request::proxy_enabled() const noexcept
{
auto proxy_hostname = get(options, "proxy_hostname");
auto proxy_username = get(options, "proxy_username");
auto proxy_password = get(options, "proxy_password");
bool proxy_hostname_presented = !proxy_hostname.empty();
if (!proxy_hostname_presented)
return false;
bool proxy_username_presented = !proxy_username.empty();
bool proxy_password_presented = !proxy_password.empty();
if (proxy_password_presented && !proxy_username_presented)
return false;
return true;
}
bool Request::cert_required() const noexcept
{
const auto cert_path = get(options, "cert_path");
const auto key_path = get(options, "key_path");
if (cert_path.empty())
return false;
bool cert_is_existed = FileInfo::exists(cert_path);
if (!cert_is_existed)
return false;
if (key_path.empty())
return false;
return FileInfo::exists(key_path);
}
long Request::status_code() const noexcept
{
return this->http_code;
}
int Request::result() const noexcept
{
return this->res;
}
class Environment
{
public:
Environment()
{
curl_global_init(CURL_GLOBAL_ALL);
}
~Environment()
{
curl_global_cleanup();
}
};
} // namespace Web
static const Web::Environment env;
-74
View File
@@ -1,74 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEB_REQUEST_HPP
#define WEB_REQUEST_HPP
#include <curl/curl.h>
#include <map>
#include <string>
namespace Web
{
bool inline check_code(CURLcode code)
{
return code == CURLE_OK;
}
using dict_t = std::map<std::string, std::string>;
class Request
{
public:
explicit Request(dict_t &&options_);
Request(const Request &other) = delete;
Request(Request &&other) noexcept;
~Request() noexcept;
auto operator=(const Request &other) -> Request & = delete;
auto operator=(Request &&other) noexcept -> Request &;
template <typename T>
auto set(CURLoption option, T value) const noexcept -> bool
{
if (this->handle == nullptr)
return false;
return check_code(curl_easy_setopt(this->handle, option, value));
}
bool perform() noexcept;
long status_code() const noexcept;
int result() const noexcept;
void *handle;
private:
const dict_t options;
dict_t response_header = {};
long http_code;
int res;
bool proxy_enabled() const noexcept;
bool cert_required() const noexcept;
auto swap(Request &other) noexcept -> void;
};
} // namespace Web
#endif
-262
View File
@@ -1,262 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#include <curl/curl.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
using std::string;
using std::vector;
#include "urn.hpp"
namespace Web
{
namespace Urn
{
const string Path::separate = "/";
const string Path::root = "/";
const string Path::param_separate = "&";
const string Path::query_separate = "?";
string encodeUrl(const string &url, void *request)
{
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos+3);
if (root_pos == string::npos)
return url;
string uri = url.substr(root_pos);
auto path = Path(uri);
return url.substr(0, root_pos) + path.quote(request);
}
Path::Path(const string& path_, bool force_dir)
{
string path = path_;
if (path_.empty()) path = Path::root;
auto first_position = path.find(Path::separate);
if (first_position != 0) path = Path::root + path;
auto last_symbol_index = path.length() - 1;
auto last_symbol = path.substr(last_symbol_index, 1);
auto is_dir = last_symbol == Path::separate;
if (force_dir && !is_dir) path += Path::separate;
m_path = path;
auto double_separte = Path::separate + Path::separate;
bool is_find = false;
do
{
auto first_position = m_path.find(double_separte);
is_find = first_position != m_path.npos;
if (is_find)
{
m_path.replace(first_position, double_separte.size(), Path::separate);
}
}
while (is_find);
}
Path::Path(std::nullptr_t)
{
m_path = nullptr;
}
auto Path::path() const -> string
{
return m_path;
}
auto escape(void* request, const string& name) -> string
{
string path = curl_easy_escape(request, name.c_str(), static_cast<int>(name.length()));
return path;
}
auto split(const string& text, const string& delims) -> vector<string>
{
vector<string> tokens;
auto start = text.find_first_not_of(delims);
auto end = text.npos;
while ((end = text.find_first_of(delims, start)) != text.npos)
{
tokens.push_back(text.substr(start, end - start));
start = text.find_first_not_of(delims, end);
}
if (start != text.npos)
{
tokens.push_back(text.substr(start));
}
return tokens;
}
auto Path::quote(void* request) const -> string
{
if (this->is_root()) return m_path;
size_t query_pos = m_path.find_first_of(Path::query_separate);
string query;
string path;
if (query_pos != string::npos)
{
query = m_path.substr(query_pos+1);
path = m_path.substr(0, query_pos);
}
else
{
path = m_path;
}
auto names = split(path, Path::separate);
string quote_path;
std::for_each(names.begin(), names.end(), [&quote_path, request](string & name)
{
auto escape_name = escape(request, name);
quote_path.append(Path::separate);
quote_path.append(escape_name);
});
if (is_directory())
{
quote_path.append(Path::separate);
}
if (query.length()>0)
{
auto params = split(query, Path::param_separate);
if (params.size() > 0)
quote_path.append(Path::query_separate);
std::for_each(params.begin(), params.end(), [&quote_path, request](string & param)
{
auto param_pair = split(param, "=");
if (param_pair.size() == 0)
{
quote_path.append(Path::param_separate);
}
else
{
quote_path.append(escape(request, param_pair[0]));
quote_path.append("=");
if (param_pair.size() > 1)
{
quote_path.append(escape(request, param_pair[1]));
}
quote_path.append(Path::param_separate);
}
});
quote_path.pop_back();
}
return quote_path;
}
auto Path::name() const -> string
{
auto path = this->path();
auto is_root = path == Path::separate;
if (is_root) return string{""};
if (this->is_directory())
{
auto path_without_slash = path.substr(0, path.length() - 1);
auto pre_last_separate_position = path_without_slash.rfind(Path::separate);
auto name = path.substr(pre_last_separate_position + 1);
return name;
}
else
{
auto last_separate_position = path.rfind(Path::separate);
auto name = path.substr(last_separate_position + 1);
return name;
}
}
auto Path::parent() const -> Path
{
if (this->is_root()) return Path{m_path};
auto last_separate_position = m_path.rfind(Path::separate, m_path.length() - 2);
if (last_separate_position == 0) return Path{Path::separate};
auto parent = m_path.substr(0, last_separate_position + 1);
return Path{parent};
}
auto Path::is_directory() const -> bool
{
auto path = this->path();
auto last_symbol_index = path.length() - 1;
auto last_symbol = path.substr(last_symbol_index, 1);
auto is_equal = last_symbol == Path::separate;
return is_equal;
}
auto Path::is_root() const -> bool
{
return m_path == Path::separate;
}
auto Path::operator+(const string& rhs) const -> Path
{
return Path{ m_path + rhs };
}
auto Path::operator==(const Path& rhs) const -> bool
{
if (this->is_root() && rhs.is_root()) return true;
if (!this->is_root() && rhs.is_root()) return false;
string lhs_path;
bool is_dir = is_directory();
if (is_dir)
{
lhs_path = m_path.substr(0, m_path.length() - 1);
}
else
{
lhs_path = m_path;
}
string rhs_path;
if (rhs.is_directory())
{
rhs_path = rhs.path();
rhs_path = rhs_path.substr(0, rhs_path.length() - 1);
}
else
{
rhs_path = rhs.path();
}
return lhs_path == rhs_path;
}
} // namespace Urn
} // namespace Web
auto operator<<(std::ostream& stream, const Web::Urn::Path& path) -> std::ostream&
{
return stream << path.path();
}
-70
View File
@@ -1,70 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEB_URN_HPP
#define WEB_URN_HPP
#include <cstddef>
#include <iostream>
#include <string>
namespace Web
{
namespace Urn
{
using std::string;
using std::nullptr_t;
string encodeUrl(const string &url, void *request);
class Path
{
public:
explicit Path(const string& path_, bool force_dir = false);
explicit Path(nullptr_t);
auto operator+(const std::string& rhs) const -> Path;
auto operator==(const Path& rhs) const -> bool;
auto is_directory() const -> bool;
auto is_root() const -> bool;
auto name() const -> string;
auto parent() const -> Path;
auto path() const -> string;
auto quote(void* request) const -> string;
private:
string m_path;
static const string separate;
static const string root;
static const string param_separate;
static const string query_separate;
};
}
}
auto operator<<(std::ostream& stream, const Web::Urn::Path& path) -> std::ostream&;
#endif
File diff suppressed because it is too large Load Diff
-419
View File
@@ -1,419 +0,0 @@
/*#***************************************************************************
# __ __ _____ _____
# Project | | | | | \ / ___|
# | |__| | | |\ \ / /
# | | | | ) ) ( (
# | /\ | | |/ / \ \___
# \_/ \_/ |_____/ \_____|
#
# Copyright (C) 2018, The WDC Project, <rusdevops@gmail.com>, et al.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the LICENSE file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
############################################################################*/
#ifndef WEBDAV_CLIENT_HPP
#define WEBDAV_CLIENT_HPP
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <curl/curl.h>
#include "http/httplib.h"
using namespace httplib;
namespace WebDAV
{
using progress_data_t = void*;
using progress_t = int(void* context,
curl_off_t dltotal,
curl_off_t dlnow,
curl_off_t ultotal,
curl_off_t ulnow);
using callback_t = std::function<void(bool)> ;
using strings_t = std::vector<std::string>;
using dict_t = std::map<std::string, std::string>;
using dict_items_t = std::vector<dict_t>;
auto inline get(const dict_t& options, const std::string&& name) -> std::string
{
auto it = options.find(name);
if (it == options.end()) return "";
else return it->second;
}
///
/// \brief WebDAV Client
/// \author designerror
/// \version 1.1.4
/// \date 3/16/2018
///
class Client
{
public:
///
/// \param[in] webdav_hostname
/// \param[in] webdav_root
/// \param[in] webdav_username
/// \param[in] webdav_password
/// \param[in] proxy_hostname
/// \param[in] proxy_username
/// \param[in] proxy_password
/// \param[in] cert_path
/// \param[in] key_path
/// \include client/init.cpp
///
explicit Client(const dict_t& options);
///
/// Get free size of the WebDAV server
/// \return size in bytes
/// \include client/size.cpp
///
auto free_size() -> unsigned long long;
///
/// Check for existence of a remote resource
/// \param[in] remote_resource
/// \include client/check.cpp
///
auto check(const std::string& remote_resource = "/") -> bool;
///
/// Get information of a remote resource
/// \param[in] remote_resource
/// \include client/info.cpp
///
auto info(const std::string& remote_resource) -> dict_t;
///
/// Get information of a remote resource
/// \param[in] remote_resource
/// \include client/info.cpp
///
auto head(const std::string& remote_resource, dict_t *headers) -> bool;
///
/// Clean an remote resource
/// \param[in] remote_resource
/// \include client/clean.cpp
///
auto clean(const std::string& remote_resource) -> bool;
///
/// Checks whether the resource directory
/// \param[in] remote_resource
///
auto is_directory(const std::string& remote_resource) -> bool;
///
/// List a remote directory
/// \param[in] remote_directory
/// \include client/list.cpp
///
auto list(const std::string& remote_directory = "") -> dict_items_t;
///
/// Create a remote directory
/// \param[in] remote_directory
/// \param[in] recursive
/// \include client/mkdir.cpp
///
auto create_directory(
const std::string& remote_directory,
bool recursive = false
) -> bool;
///
/// Move a remote resource
/// \param[in] remote_source_resource
/// \param[in] remote_destination_resource
/// \include client/move.cpp
///
auto move(
const std::string& remote_source_resource,
const std::string& remote_destination_resource
) -> bool;
///
/// Copy a remote resource
/// \param[in] remote_source_resource
/// \param[in] remote_destination_resource
/// \include client/copy.cpp
///
auto copy(
const std::string& remote_source_resource,
const std::string& remote_destination_resource
) -> bool;
///
/// Download a remote file to a local file
/// \param[in] remote_file
/// \param[in] local_file
/// \param[in] progress
/// \snippet client/download.cpp download_to_file
///
auto download(
const std::string& remote_file,
const std::string& local_file,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a buffer
/// \param[in] remote_file
/// \param[out] buffer_ptr
/// \param[out] buffer_size
/// \param[in] progress
/// \snippet client/download.cpp download_to_buffer
///
auto download_to(
const std::string& remote_file,
char*& buffer_ptr,
unsigned long long& buffer_size,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a buffer for specified range
/// \param[in] remote_file
/// \param[out] buffer_ptr
/// \param[out] buffer_size
/// \param[in] range_from,
/// \param[in] range_to
/// \param[in] progress
/// \snippet client/download.cpp download_to_buffer
///
auto download_range_to(
const std::string& remote_file,
char*& buffer_ptr,
unsigned long long& buffer_size,
uint64_t range_from,
uint64_t range_to,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a buffer for specified range
/// \param[in] remote_file
/// \param[out] sink,
/// \param[in] range_from,
/// \param[in] range_to
/// \param[in] progress
/// \snippet client/download.cpp download_to_buffer
///
auto download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a stream
/// \param[in] remote_file
/// \param[out] stream
/// \param[in] progress
/// \snippet client/download.cpp download_to_stream
///
auto download_to(
const std::string& remote_file,
std::ostream& stream,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Asynchronously download a remote file to a local file
/// \param[in] remote_file
/// \param[in] local_file
/// \param[in] callback
/// \param[in] progress
/// \snippet client/download.cpp async_download_to_file
///
auto async_download(
const std::string& remote_file,
const std::string& local_file,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> void;
///
/// Upload a remote file from a local file
/// \param[in] remote_file
/// \param[in] local_file
/// \param[in] progress
/// \snippet client/upload.cpp upload_from_file
///
auto upload(
const std::string& remote_file,
const std::string& local_file,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Upload a remote file from a buffer
/// \param[in] remote_file
/// \param[in] buffer_ptr
/// \param[in] buffer_size
/// \param[in] progress
/// \snippet client/upload.cpp upload_from_buffer
///
auto upload_from(
const std::string& remote_file,
char* buffer_ptr,
unsigned long long buffer_size,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Upload a remote file from a stream
/// \param[in] remote_file
/// \param[in] stream
/// \param[in] progress
/// \snippet client/upload.cpp upload_from_stream
///
auto upload_from(
const std::string& remote_file,
std::istream& stream,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Asynchronously upload a remote file from a local file
/// \param[in] remote_file
/// \param[in] local_file
/// \param[in] callback
/// \param[in] progress
/// \snippet client/upload.cpp async_upload_from_file
///
auto async_upload(
const std::string& remote_file,
const std::string& local_file,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> void;
long status_code();
private:
auto sync_download(
const std::string& remote_file,
const std::string& local_file,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
auto sync_download_to(
const std::string& remote_file,
char*& buffer_ptr,
unsigned long long& buffer_size,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
auto sync_download_range_to(
const std::string& remote_file,
char*& buffer_ptr,
unsigned long long& buffer_size,
uint64_t range_from,
uint64_t range_to,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
auto sync_download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
callback_t callback,
progress_data_t progress_data,
progress_t progress
) -> bool;
bool sync_download_to(
const std::string& remote_file,
std::ostream& stream,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
);
bool sync_upload(
const std::string& remote_file,
const std::string& local_file,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
);
auto sync_upload_from(
const std::string& remote_file,
char* buffer_ptr,
unsigned long long buffer_size,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
auto sync_upload_from(
const std::string& remote_file,
std::istream& stream,
callback_t callback = nullptr,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
enum { buffer_size = 1000 * 1000 };
std::string webdav_hostname;
std::string webdav_root;
std::string webdav_username;
std::string webdav_password;
std::string proxy_hostname;
std::string proxy_username;
std::string proxy_password;
std::string cert_path;
std::string key_path;
dict_t options();
long http_code;
int result;
int check_enabled = 0;
};
} // namespace WebDAV
#endif
+112 -33
View File
@@ -243,20 +243,33 @@ namespace Windows
{
std::string zipfolder;
std::vector<DirEntry> files;
bool local_browser_selected = saved_selected_browser & LOCAL_BROWSER;
bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER;
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
if (local_browser_selected)
{
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
else
files.push_back(selected_local_file);
}
else
files.push_back(selected_local_file);
{
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
}
if (strncmp(files.begin()->directory, "/data", 5) != 0 &&
strncmp(files.begin()->directory, "/mnt/usb", 8) != 0)
if (strncmp(local_directory, "/data", 5) != 0 &&
strncmp(local_directory, "/mnt/usb", 8) != 0 &&
strncmp(local_directory, "/user/data", 10) != 0)
{
zipfolder = "/data";
}
else if (files.size() > 1)
{
zipfolder = files.begin()->directory;
zipfolder = local_directory;
}
else
{
@@ -1049,26 +1062,29 @@ namespace Windows
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_EXTRACT) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
if (local_browser_selected)
ime_after_update = AfterExtractFolderCallback;
else
ime_after_update = AfterExtractRemoteFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
if (local_browser_selected)
{
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
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 = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Compress##settings");
if (ImGui::Selectable(lang_strings[STR_COMPRESS], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
@@ -1605,9 +1621,13 @@ namespace Windows
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
ImGui::SetNextWindowPos(ImVec2(1050, 80));
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 650), NULL, NULL);
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 750), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
char id[192];
ImVec2 field_size;
float width;
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
@@ -1646,6 +1666,26 @@ namespace Windows
ImGui::Checkbox("##show_hidden_files", &show_hidden_files);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_TEMP_DIRECTORY]);
ImGui::SameLine();
field_size = ImGui::CalcTextSize(lang_strings[STR_TEMP_DIRECTORY]);
width = field_size.x + 45;
sprintf(id, "%s##temp_direcotry", temp_folder);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = temp_folder;
ime_field_size = 512;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
// Web Server settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_WEB_SERVER]);
ImGui::Separator();
@@ -1656,15 +1696,13 @@ namespace Windows
ImGui::Checkbox("##web_server_enabled", &web_server_enabled);
ImGui::Separator();
ImVec2 field_size;
field_size = ImGui::CalcTextSize(lang_strings[STR_PORT]);
float width = field_size.x + 45;
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_PORT]);
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
char id[192];
sprintf(id, "%s##http_server_port", txt_http_server_port);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
if (ImGui::Button(id, ImVec2(835-width, 0)))
@@ -1697,7 +1735,6 @@ namespace Windows
ImGui::PopStyleVar();
ImGui::Separator();
// Google settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
ImGui::Separator();
@@ -1712,14 +1749,41 @@ namespace Windows
if (strlen(alldebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##alldebrid_api_key");
else
sprintf(id, "%s", "##client_secret_input");
sprintf(id, "%s", "##alldebrid_api_key");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = alldebrid_api_key;
ime_field_size = 31;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 31, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 63, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_REALDEBRID]);
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(realdebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##realdebrid_api_key");
else
sprintf(id, "%s", "##realdebrid_api_key");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = realdebrid_api_key;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_API_KEY], realdebrid_api_key, 63, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
@@ -2023,10 +2087,19 @@ namespace Windows
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = false;
file_transfering = true;
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
case ACTION_EXTRACT_REMOTE_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
selected_action = ACTION_NONE;
Actions::ExtractRemoteZips();
break;
case ACTION_CREATE_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
@@ -2109,6 +2182,7 @@ namespace Windows
case ACTION_INSTALL_REMOTE_PKG:
sprintf(status_message, "%s", "");
activity_inprogess = true;
file_transfering = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
Actions::InstallRemotePkgs();
@@ -2406,6 +2480,11 @@ namespace Windows
selected_action = ACTION_EXTRACT_LOCAL_ZIP;
}
void AfterExtractRemoteFolderCallback(int ime_result)
{
selected_action = ACTION_EXTRACT_REMOTE_ZIP;
}
void AfterZipFileCallback(int ime_result)
{
selected_action = ACTION_CREATE_LOCAL_ZIP;
+1
View File
@@ -206,6 +206,7 @@ namespace Windows
void AfterPackageUrlCallback(int ime_result);
void AfterFavoriteUrlCallback(int ime_result);
void AfterExtractFolderCallback(int ime_result);
void AfterExtractRemoteFolderCallback(int ime_result);
void AfterZipFileCallback(int ime_result);
void AferServerChangeCallback(int ime_result);
void AfterHttpPortChangeCallback(int ime_result);
+318 -40
View File
@@ -12,16 +12,17 @@
#include <archive.h>
#include <archive_entry.h>
#include "clients/remote_client.h"
#include "config.h"
#include "common.h"
#include "fs.h"
#include "ime_dialog.h"
#include "lang.h"
#include "system.h"
#include "windows.h"
#include "util.h"
#include "zip_util.h"
#define TRANSFER_SIZE (16 * 1024)
namespace ZipUtil
{
static char filename_extracted[256];
@@ -95,12 +96,12 @@ namespace ZipUtil
}
// Add file to zip
void *buf = memalign(4096, TRANSFER_SIZE);
void *buf = memalign(4096, ARCHIVE_TRANSFER_SIZE);
uint64_t seek = 0;
while (1)
{
int read = FS::Read(fd, buf, TRANSFER_SIZE);
int read = FS::Read(fd, buf, ARCHIVE_TRANSFER_SIZE);
if (read < 0)
{
free(buf);
@@ -234,7 +235,8 @@ namespace ZipUtil
len = strlen(path);
while (len && path[len - 1] == '/')
len--;
if ((str = (char*) malloc(len + 1)) == NULL) {
if ((str = (char *)malloc(len + 1)) == NULL)
{
errno = ENOMEM;
}
memcpy(str, path, len);
@@ -252,21 +254,23 @@ namespace ZipUtil
prelen = prefix ? strlen(prefix) + 1 : 0;
len = strlen(path) + 1;
if ((str = (char*) malloc(prelen + len)) == NULL) {
if ((str = (char *)malloc(prelen + len)) == NULL)
{
errno = ENOMEM;
}
if (prefix) {
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
if (prefix)
{
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
}
memcpy(str + prelen, path, len); /* includes zero */
memcpy(str + prelen, path, len); /* includes zero */
return (str);
}
/*
* Extract a directory.
*/
* Extract a directory.
*/
static void extract_dir(struct archive *a, struct archive_entry *e, const std::string &path)
{
int mode;
@@ -279,39 +283,48 @@ namespace ZipUtil
}
/*
* Extract to a file descriptor
*/
* Extract to a file descriptor
*/
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
{
ssize_t len;
unsigned char buffer[TRANSFER_SIZE];
unsigned char *buffer = (unsigned char *) malloc(ARCHIVE_TRANSFER_SIZE);
bytes_transfered = 0;
/* loop over file contents and write to fd */
for (int n = 0; ; n++) {
len = archive_read_data(a, buffer, sizeof buffer);
for (int n = 0;; n++)
{
len = archive_read_data(a, buffer, ARCHIVE_TRANSFER_SIZE);
if (len == 0)
{
free(buffer);
return 1;
}
if (len < 0)
{
sprintf(status_message, "error archive_read_data('%s')", pathname.c_str());
free(buffer);
return 0;
}
bytes_transfered += len;
if (write(fd, buffer, len) != len)
{
sprintf(status_message, "error write('%s')", pathname.c_str());
free(buffer);
return 0;
}
}
free(buffer);
return 1;
}
/*
* Extract a regular file.
*/
* Extract a regular file.
*/
static void extract_file(struct archive *a, struct archive_entry *e, const std::string &path)
{
struct stat sb;
@@ -320,13 +333,15 @@ namespace ZipUtil
/* look for existing file of same name */
recheck:
if (lstat(path.c_str(), &sb) == 0) {
if (lstat(path.c_str(), &sb) == 0)
{
(void)unlink(path.c_str());
}
/* process symlinks */
linkname = archive_entry_symlink(e);
if (linkname != NULL) {
if (linkname != NULL)
{
if (symlink(linkname, path.c_str()) != 0)
{
sprintf(status_message, "error symlink('%s')", path.c_str());
@@ -337,7 +352,8 @@ namespace ZipUtil
return;
}
if ((fd = open(path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0777)) < 0)
bytes_to_download = archive_entry_size(e);
if ((fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0)
{
sprintf(status_message, "error open('%s')", path.c_str());
return;
@@ -356,9 +372,9 @@ namespace ZipUtil
{
char *pathname, *realpathname;
mode_t filetype;
char *p, *q;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
return;
}
@@ -367,14 +383,16 @@ namespace ZipUtil
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL) {
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)) {
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype))
{
archive_read_data_skip(a);
free(pathname);
return;
@@ -398,9 +416,9 @@ namespace ZipUtil
}
/*
* Callback function for reading passphrase.
* Originally from cpio.c and passphrase.c, libarchive.
*/
* 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);
@@ -422,14 +440,58 @@ namespace ZipUtil
return password;
}
static RemoteArchiveData *OpenRemoteArchive(const std::string &file, RemoteClient *client)
{
RemoteArchiveData *data;
data = (RemoteArchiveData *)malloc(sizeof(RemoteArchiveData));
memset(data, 0, sizeof(RemoteArchiveData));
data->offset = 0;
client->Size(file, &data->size);
data->client = client;
data->path = file;
return data;
}
static ssize_t ReadRemoteArchive(struct archive *a, void *client_data, const void **buff)
{
ssize_t to_read;
int ret;
RemoteArchiveData *data;
data = (RemoteArchiveData *)client_data;
*buff = data->buf;
to_read = data->size - data->offset;
if (to_read == 0)
return 0;
to_read = MIN(to_read, ARCHIVE_TRANSFER_SIZE);
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
if (ret == 0)
return -1;
data->offset = data->offset + to_read;
return to_read;
}
static int CloseRemoteArchive(struct archive *a, void *client_data)
{
if (client_data != nullptr)
free(client_data);
return 0;
}
/*
* 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)
* 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, RemoteClient *client)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
int ret;
uintmax_t total_size, file_count, error_count;
@@ -440,14 +502,38 @@ namespace ZipUtil
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)
if (client == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
ret = archive_read_open_filename(a, file.path, ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
}
else
{
client_data = OpenRemoteArchive(file.path, client);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open failed");
return 0;
}
}
for (;;) {
for (;;)
{
if (stop_activity)
break;
@@ -462,7 +548,7 @@ namespace ZipUtil
if (ret == ARCHIVE_EOF)
break;
extract(a, e, basepath);
}
@@ -471,4 +557,196 @@ namespace ZipUtil
return 1;
}
ArchiveEntry *GetPackageEntry(const std::string &zip_file, RemoteClient *client)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
char *pathname;
mode_t filetype;
ArchiveEntry *pkg_entry = nullptr;
int ret;
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);
if (client == nullptr)
{
ret = archive_read_open_filename(a, zip_file.c_str(), ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
else
{
client_data = OpenRemoteArchive(zip_file, client);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
for (;;)
{
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
if (client_data != nullptr)
{
free(client_data);
}
archive_read_free(a);
return nullptr;
}
if (ret == ARCHIVE_EOF)
break;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
continue;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
continue;
;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISREG(filetype))
{
archive_read_data_skip(a);
free(pathname);
continue;
}
if (Util::EndsWith(Util::ToLower(pathname), ".pkg"))
{
pkg_entry = (ArchiveEntry *)malloc(sizeof(ArchiveEntry));
memset(pkg_entry, 0, sizeof(ArchiveEntry));
pkg_entry->archive = a;
pkg_entry->entry = e;
pkg_entry->client_data = client_data;
pkg_entry->filename = pathname;
pkg_entry->filesize = archive_entry_size(e);
free(pathname);
return pkg_entry;
}
free(pathname);
}
archive_read_free(a);
return nullptr;
}
ArchiveEntry *GetNextPackageEntry(ArchiveEntry *archive_entry)
{
struct archive *a = archive_entry->archive;
struct archive_entry *e = nullptr;
RemoteArchiveData *client_data = archive_entry->client_data;
char *pathname;
mode_t filetype;
ArchiveEntry *pkg_entry = nullptr;
int ret;
for (;;)
{
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
if (client_data != nullptr)
{
free(client_data);
}
archive_read_free(a);
return nullptr;
}
if (ret == ARCHIVE_EOF)
break;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
continue;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
continue;
;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISREG(filetype))
{
archive_read_data_skip(a);
free(pathname);
continue;
}
if (Util::EndsWith(Util::ToLower(pathname), ".pkg"))
{
pkg_entry = (ArchiveEntry *)malloc(sizeof(ArchiveEntry));
memset(pkg_entry, 0, sizeof(ArchiveEntry));
pkg_entry->archive = a;
pkg_entry->entry = e;
pkg_entry->client_data = client_data;
pkg_entry->filename = pathname;
pkg_entry->filesize = archive_entry_size(e);
free(pathname);
return pkg_entry;
}
free(pathname);
}
archive_read_free(a);
return nullptr;
}
}
+25 -1
View File
@@ -5,9 +5,13 @@
#include <stdlib.h>
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include <archive.h>
#include <archive_entry.h>
#include "common.h"
#include "fs.h"
#define ARCHIVE_TRANSFER_SIZE 5242880
static uint8_t MAGIC_ZIP_1[4] = {0x50, 0x4B, 0x03, 0x04};
static uint8_t MAGIC_ZIP_2[4] = {0x50, 0x4B, 0x05, 0x06};
static uint8_t MAGIC_ZIP_3[4] = {0x50, 0x4B, 0x07, 0x08};
@@ -24,9 +28,29 @@ enum CompressFileType {
COMPRESS_FILE_TYPE_UNKNOWN
};
struct RemoteArchiveData
{
std::string path;
ssize_t size;
ssize_t offset;
uint8_t buf[ARCHIVE_TRANSFER_SIZE];
RemoteClient *client;
};
struct ArchiveEntry
{
struct archive *archive;
struct archive_entry *entry;
std::string filename;
size_t filesize;
RemoteArchiveData *client_data;
};
namespace ZipUtil
{
int ZipAddPath(zipFile zf, const std::string &path, int filename_start, int level);
int Extract(const DirEntry &file, const std::string &dir);
int Extract(const DirEntry &file, const std::string &dir, RemoteClient *client = nullptr);
ArchiveEntry *GetPackageEntry(const std::string &zip_file, RemoteClient *client = nullptr);
ArchiveEntry *GetNextPackageEntry(ArchiveEntry *archive_entry);
}
#endif