Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0feff205d2 | |||
| 5df5447eb0 | |||
| b87dc91c6f | |||
| 14b32504e0 | |||
| d35345a270 | |||
| f041172768 | |||
| 232a6233ca | |||
| c620478691 | |||
| 2615372288 | |||
| 0889b0923d | |||
| a2b26102de | |||
| dff469a9d7 | |||
| 37074f0102 | |||
| eb4184d488 | |||
| c328b26480 | |||
| 1e702aa0e2 | |||
| d35b311946 | |||
| f02944e596 | |||
| 338eacfd3f | |||
| 0bd0a0f273 | |||
| bf3f4330c0 | |||
| f16850fed9 | |||
| a30a20f6db | |||
| 54b9a80410 | |||
| fe55ddeb8a | |||
| a5a5f8d611 | |||
| 9854437c94 |
+4
-8
@@ -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
|
||||
@@ -67,11 +62,12 @@ add_executable(ezremote_client
|
||||
source/windows.cpp
|
||||
source/zip_util.cpp
|
||||
source/split_file.cpp
|
||||
source/mem_file.cpp
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.15" 32 0)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.24" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
c
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# 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.19**
|
||||
- Install PKG inside Zip files from both local hdd and remote servers.
|
||||
- Extact zip files directly from remote servers.
|
||||
|
||||
**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 +31,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 +118,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.
|
||||
|
||||
@@ -157,4 +157,6 @@ 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_TEMP_DIRECTORY=Temp Directory
|
||||
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
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+9
-15
@@ -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"
|
||||
@@ -723,7 +721,7 @@ namespace Actions
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") ||
|
||||
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") || Util::EndsWith(path,".7z") ||
|
||||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz"))
|
||||
{
|
||||
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path, remoteclient);
|
||||
@@ -778,6 +776,7 @@ namespace Actions
|
||||
if (res != 0)
|
||||
{
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
multi_selected_remote_files.clear();
|
||||
Windows::SetModalMode(false);
|
||||
}
|
||||
@@ -1101,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]);
|
||||
@@ -1118,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)
|
||||
{
|
||||
@@ -1212,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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
@@ -283,7 +311,7 @@ uint32_t BaseClient::SupportedActions()
|
||||
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)
|
||||
@@ -317,3 +345,26 @@ std::string BaseClient::DecodeUrl(const std::string &url)
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void *BaseClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BaseClient::Close(void *fp)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
}
|
||||
|
||||
int BaseClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BaseClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,15 @@ 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);
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, 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);
|
||||
@@ -32,18 +35,21 @@ public:
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
std::string GetFullPath(std::string path1);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -1744,7 +1744,7 @@ ClientType FtpClient::clientType()
|
||||
|
||||
uint32_t FtpClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
|
||||
std::string FtpClient::GetPath(std::string ppath1, std::string ppath2)
|
||||
@@ -1783,4 +1783,23 @@ int FtpClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
if (l != len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void *FtpClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FtpClient::Close(void *fp)
|
||||
{
|
||||
}
|
||||
|
||||
int FtpClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FtpClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -81,12 +81,16 @@ public:
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, 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);
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void SetCallbackXferFunction(FtpCallbackXfer pointer);
|
||||
void SetCallbackArg(void *arg);
|
||||
|
||||
+46
-23
@@ -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(), ¶m);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -887,7 +887,7 @@ ClientType GDriveClient::clientType()
|
||||
|
||||
uint32_t GDriveClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
|
||||
void *GDriveClient::RefreshTokenThread(void *argp)
|
||||
@@ -941,4 +941,27 @@ void GDriveClient::SetAccessToken(const std::string &token)
|
||||
{
|
||||
if (this->client != nullptr)
|
||||
this->client->set_bearer_token_auth(token);
|
||||
}
|
||||
}
|
||||
|
||||
void *GDriveClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GDriveClient::Close(void *fp)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
int Update(const std::string &inputfile, const std::string &path);
|
||||
@@ -32,6 +34,8 @@ public:
|
||||
bool FileExists(const std::string &path);
|
||||
void SetAccessToken(const std::string &token);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
static void *RefreshTokenThread(void *argp);
|
||||
static void StartRefreshToken();
|
||||
static void StopRefreshToken();
|
||||
|
||||
@@ -242,7 +242,17 @@ int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
ret = this->GetRange((void *)nfsfh, sink, size, offset);
|
||||
nfs_close(nfs, nfsfh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct nfsfh *nfsfh = (struct nfsfh *)fp;
|
||||
|
||||
int ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
return 0;
|
||||
@@ -262,7 +272,6 @@ int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
if (!ok)
|
||||
{
|
||||
free((void *)buff);
|
||||
nfs_close(nfs, nfsfh);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -273,18 +282,11 @@ int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
} while (1);
|
||||
|
||||
free((void *)buff);
|
||||
nfs_close(nfs, nfsfh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
if (!FileExists(ppath))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
int ret = nfs_open(nfs, ppath.c_str(), 0400, &nfsfh);
|
||||
if (ret != 0)
|
||||
@@ -293,7 +295,17 @@ int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
ret = this->GetRange(nfsfh, buffer, size, offset);
|
||||
nfs_close(nfs, nfsfh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct nfsfh *nfsfh = (struct nfsfh *) fp;
|
||||
|
||||
int ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
@@ -301,7 +313,6 @@ int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, u
|
||||
}
|
||||
|
||||
int count = nfs_read(nfs, nfsfh, size, buffer);
|
||||
nfs_close(nfs, nfsfh);
|
||||
if (count != size)
|
||||
return 0;
|
||||
|
||||
@@ -553,6 +564,18 @@ int NfsClient::Head(const std::string &ppath, void *buffer, uint64_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *NfsClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
nfs_open(nfs, path.c_str(), 0400, &nfsfh);;
|
||||
return nfsfh;
|
||||
}
|
||||
|
||||
void NfsClient::Close(void *fp)
|
||||
{
|
||||
nfs_close(nfs, (struct nfsfh*)fp);
|
||||
}
|
||||
|
||||
ClientType NfsClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_NFS;
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, 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);
|
||||
@@ -32,6 +34,8 @@ public:
|
||||
int Copy(const std::string &from, const std::string &to);
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -141,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] == '/')
|
||||
|
||||
@@ -21,7 +21,8 @@ enum RemoteActions
|
||||
REMOTE_ACTION_EDIT = 512,
|
||||
REMOTE_ACTION_NEW_FILE = 1024,
|
||||
REMOTE_ACTION_EXTRACT = 2048,
|
||||
REMOTE_ACTION_ALL = 4095
|
||||
REMOTE_ACTION_RAW_READ = 4096,
|
||||
REMOTE_ACTION_ALL = 8191
|
||||
};
|
||||
|
||||
enum ClientType
|
||||
@@ -56,8 +57,12 @@ public:
|
||||
virtual int Head(const std::string &path, void *buffer, uint64_t len) = 0;
|
||||
virtual int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset) = 0;
|
||||
virtual bool FileExists(const std::string &path) = 0;
|
||||
virtual std::vector<DirEntry> ListDir(const std::string &path) = 0;
|
||||
virtual void *Open(const std::string &path, int flags) = 0;
|
||||
virtual void Close(void *fp) = 0;
|
||||
virtual std::string GetPath(std::string path1, std::string path2) = 0;
|
||||
virtual bool IsConnected() = 0;
|
||||
virtual bool Ping() = 0;
|
||||
|
||||
@@ -313,6 +313,16 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange((void *)sftp_handle, sink, size, offset);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = (LIBSSH2_SFTP_HANDLE *) fp;
|
||||
|
||||
libssh2_sftp_seek64(sftp_handle, offset);
|
||||
|
||||
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
@@ -329,7 +339,6 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
if (!ok)
|
||||
{
|
||||
free((char *)buff);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -340,7 +349,6 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
} while (1);
|
||||
|
||||
free((char *)buff);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -359,9 +367,18 @@ int SFTPClient::GetRange(const std::string &path, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange(sftp_handle, buffer, size, offset);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = (LIBSSH2_SFTP_HANDLE *) fp;
|
||||
|
||||
libssh2_sftp_seek64(sftp_handle, offset);
|
||||
int count = libssh2_sftp_read(sftp_handle, (char *)buffer, size);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
if (count != size)
|
||||
return 0;
|
||||
|
||||
@@ -642,6 +659,16 @@ int SFTPClient::Quit()
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *SFTPClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
return libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
|
||||
}
|
||||
|
||||
void SFTPClient::Close(void *fp)
|
||||
{
|
||||
libssh2_sftp_close((LIBSSH2_SFTP_HANDLE *)fp);
|
||||
}
|
||||
|
||||
ClientType SFTPClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_SFTP;
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, 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);
|
||||
@@ -30,6 +32,8 @@ public:
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
bool FileExists(const std::string &path);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
|
||||
@@ -243,6 +243,16 @@ int SmbClient::GetRange(const std::string &ppath, DataSink &sink, uint64_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange((void *)in, sink, size, offset);
|
||||
smb2_close(smb2, in);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SmbClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct smb2fh* in = (struct smb2fh*)fp;
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
@@ -259,7 +269,6 @@ int SmbClient::GetRange(const std::string &ppath, DataSink &sink, uint64_t size,
|
||||
if (!ok)
|
||||
{
|
||||
free((uint8_t *)buff);
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -270,7 +279,6 @@ int SmbClient::GetRange(const std::string &ppath, DataSink &sink, uint64_t size,
|
||||
} while (1);
|
||||
|
||||
free((char *)buff);
|
||||
smb2_close(smb2, in);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -291,10 +299,19 @@ int SmbClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange(in, buffer, size, offset);
|
||||
smb2_close(smb2, in);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SmbClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct smb2fh* in = (struct smb2fh*) fp;
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
|
||||
int count = smb2_read(smb2, in, (uint8_t*)buffer, size);
|
||||
smb2_close(smb2, in);
|
||||
if (count != size)
|
||||
return 0;
|
||||
|
||||
@@ -567,6 +584,20 @@ int SmbClient::Head(const std::string &ppath, void *buffer, uint64_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *SmbClient::Open(const std::string &ppath, int flags)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), flags);
|
||||
return in;
|
||||
}
|
||||
|
||||
void SmbClient::Close(void *fp)
|
||||
{
|
||||
smb2_close(smb2, (struct smb2fh*)fp);
|
||||
}
|
||||
|
||||
ClientType SmbClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_SMB;
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
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 GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, 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);
|
||||
@@ -34,6 +36,8 @@ public:
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
int CopyToSocket(const std::string &path, int socket_fd);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
|
||||
@@ -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, <);
|
||||
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 ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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, <);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
+27
-5
@@ -38,7 +38,8 @@ 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'};
|
||||
@@ -202,16 +203,31 @@ namespace CONFIG
|
||||
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);
|
||||
@@ -392,11 +408,17 @@ 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);
|
||||
|
||||
+3
-1
@@ -59,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
|
||||
@@ -140,7 +141,8 @@ 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
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#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"
|
||||
@@ -25,7 +26,7 @@ std::string FileHost::GetUrl()
|
||||
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);
|
||||
@@ -34,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))
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
virtual std::string GetDownloadUrl() = 0;
|
||||
std::string GetUrl();
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+148
-56
@@ -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,11 +21,16 @@
|
||||
#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;
|
||||
@@ -198,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 "";
|
||||
@@ -208,32 +212,62 @@ 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 full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -254,6 +288,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)
|
||||
{
|
||||
@@ -350,22 +385,37 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
if (prompt)
|
||||
{
|
||||
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:
|
||||
@@ -376,6 +426,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;
|
||||
@@ -437,13 +489,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;
|
||||
@@ -455,6 +513,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)
|
||||
@@ -540,15 +600,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);
|
||||
@@ -722,7 +787,7 @@ namespace INSTALLER
|
||||
archive_pkg_install_data_list.erase(hash);
|
||||
}
|
||||
|
||||
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data)
|
||||
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);
|
||||
@@ -796,18 +861,31 @@ namespace INSTALLER
|
||||
ret = sceBgftServiceIntDebugDownloadRegisterPkg(¶ms, &task_id);
|
||||
if (ret == 0x80990088 || ret == 0x80990015)
|
||||
{
|
||||
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)
|
||||
if (!bg)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
while (confirm_state == CONFIRM_WAIT)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
@@ -833,26 +911,40 @@ namespace INSTALLER
|
||||
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_transfered = 0;
|
||||
while (!completed)
|
||||
if (!bg)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
|
||||
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_transfered = 0;
|
||||
while (!completed)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
+1
-1
@@ -148,5 +148,5 @@ namespace INSTALLER
|
||||
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 InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg = false);
|
||||
}
|
||||
+162
-160
@@ -10,166 +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
|
||||
"Temp Directory", // STR_TEMP_DIRECTORY
|
||||
"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;
|
||||
|
||||
+4
-2
@@ -163,7 +163,9 @@
|
||||
FUNC(STR_INVALID_URL) \
|
||||
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG) \
|
||||
FUNC(STR_LANGUAGE) \
|
||||
FUNC(STR_TEMP_DIRECTORY)
|
||||
FUNC(STR_TEMP_DIRECTORY) \
|
||||
FUNC(STR_REALDEBRID) \
|
||||
FUNC(STR_BACKGROUND_INSTALL_INPROGRESS)
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -173,7 +175,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 160
|
||||
#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];
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
#include "mem_file.h"
|
||||
|
||||
MemFile::MemFile(const std::string &path, size_t block_size)
|
||||
{
|
||||
this->block_size = block_size;
|
||||
this->complete = false;
|
||||
sem_init(&this->block_ready, 0, 0);
|
||||
}
|
||||
|
||||
MemFile::~MemFile()
|
||||
{
|
||||
for (int i = 0; i < this->mem_blocks.size(); i++)
|
||||
{
|
||||
if (this->mem_blocks[i] != nullptr && this->mem_blocks[i]->status != MEM_BLOCK_STATUS_DELETED)
|
||||
{
|
||||
if (this->mem_blocks[i]->buf != nullptr)
|
||||
{
|
||||
free(this->mem_blocks[i]->buf);
|
||||
this->mem_blocks[i]->buf = nullptr;
|
||||
}
|
||||
free(this->mem_blocks[i]);
|
||||
}
|
||||
}
|
||||
sem_destroy(&this->block_ready);
|
||||
};
|
||||
|
||||
int MemFile::Open()
|
||||
{
|
||||
this->block_in_progress = NewBlock();
|
||||
this->block_in_progress->buf = malloc(block_size);
|
||||
|
||||
return (block_in_progress->buf == nullptr);
|
||||
}
|
||||
|
||||
size_t MemFile::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;
|
||||
MemBlock *block;
|
||||
char *p;
|
||||
|
||||
first_block_num= offset / this->block_size;
|
||||
block_num = first_block_num;
|
||||
block_offset = offset % this->block_size;
|
||||
|
||||
while ((block_num >= this->mem_blocks.size() && !this->complete) ||
|
||||
(block_num < this->mem_blocks.size() && this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS))
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
}
|
||||
|
||||
block = this->mem_blocks[block_num];
|
||||
if (block->status == MEM_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)
|
||||
{
|
||||
uint8_t *src = (uint8_t*)block->buf;
|
||||
src += block_offset;
|
||||
bytes_read = block_size - block_offset;
|
||||
memcpy(p, src, bytes_read);
|
||||
|
||||
if (bytes_read == remaining)
|
||||
{
|
||||
p += bytes_read;
|
||||
total_bytes_read += bytes_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += bytes_read;
|
||||
total_bytes_read += bytes_read;
|
||||
if (block->is_last)
|
||||
{
|
||||
eof = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
remaining -= bytes_read;
|
||||
|
||||
if (remaining == 0)
|
||||
continue;
|
||||
|
||||
block_num++;
|
||||
block_offset = 0;
|
||||
|
||||
while ((block_num > this->mem_blocks.size() - 1 && !this->complete) ||
|
||||
this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS)
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
}
|
||||
|
||||
block = this->mem_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->mem_blocks[j]->status == MEM_BLOCK_STATUS_CREATED)
|
||||
{
|
||||
if (this->mem_blocks[j]->buf != nullptr)
|
||||
{
|
||||
free(this->mem_blocks[j]->buf);
|
||||
this->mem_blocks[j]->buf = nullptr;
|
||||
}
|
||||
this->mem_blocks[j]->status = MEM_BLOCK_STATUS_DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
return total_bytes_read;
|
||||
}
|
||||
|
||||
size_t MemFile::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);
|
||||
memcpy(block_in_progress->buf, p, bytes_to_write);
|
||||
bytes_written = bytes_to_write;
|
||||
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)
|
||||
{
|
||||
block_in_progress->status = MEM_BLOCK_STATUS_CREATED;
|
||||
this->mem_blocks.push_back(block_in_progress);
|
||||
sem_post(&this->block_ready);
|
||||
|
||||
block_in_progress = NewBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
int MemFile::Close()
|
||||
{
|
||||
block_in_progress->status = MEM_BLOCK_STATUS_CREATED;
|
||||
block_in_progress->is_last = true;
|
||||
this->mem_blocks.push_back(block_in_progress);
|
||||
this->complete = true;
|
||||
sem_post(&this->block_ready);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MemBlock *MemFile::NewBlock()
|
||||
{
|
||||
MemBlock *block = (MemBlock *)malloc(sizeof(MemBlock));
|
||||
memset(block, 0, sizeof(MemBlock));
|
||||
|
||||
block->is_last = false;
|
||||
block->size = 0;
|
||||
block->buf = malloc(block_size);
|
||||
|
||||
return block;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef MEM_FILE_H
|
||||
#define MEM_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
|
||||
enum MemBlockStatus
|
||||
{
|
||||
MEM_BLOCK_STATUS_NOT_EXISTS,
|
||||
MEM_BLOCK_STATUS_CREATED,
|
||||
MEM_BLOCK_STATUS_DELETED
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
void* buf;
|
||||
bool is_last;
|
||||
MemBlockStatus status;
|
||||
} MemBlock;
|
||||
|
||||
class MemFile
|
||||
{
|
||||
public:
|
||||
MemFile(const std::string& path, size_t block_size);
|
||||
~MemFile();
|
||||
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<MemBlock*> mem_blocks;
|
||||
size_t write_offset;
|
||||
size_t block_size;
|
||||
int write_error;
|
||||
bool complete;
|
||||
MemBlock *block_in_progress;
|
||||
sem_t block_ready;
|
||||
|
||||
MemBlock *NewBlock();
|
||||
};
|
||||
|
||||
#endif
|
||||
+242
-167
@@ -8,6 +8,12 @@
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/rclone.h"
|
||||
#include "filehost/filehost.h"
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
@@ -27,6 +33,14 @@
|
||||
|
||||
using namespace httplib;
|
||||
|
||||
struct RemoteDownloadData
|
||||
{
|
||||
RemoteClient *client = nullptr;
|
||||
std::map<std::string, void *> fp_handles;
|
||||
};
|
||||
|
||||
static RemoteDownloadData remote_data[100];
|
||||
|
||||
Server *svr;
|
||||
int http_server_port = 8080;
|
||||
char compressed_file_path[1024];
|
||||
@@ -91,22 +105,22 @@ namespace HttpServer
|
||||
return s;
|
||||
}
|
||||
|
||||
void failed(Response & res, int status, const std::string &msg)
|
||||
void failed(Response &res, int status, const std::string &msg)
|
||||
{
|
||||
res.status = status;
|
||||
char response_msg[msg.length()+strlen(FAILURE_MSG)+2];
|
||||
char response_msg[msg.length() + strlen(FAILURE_MSG) + 2];
|
||||
snprintf(response_msg, sizeof(response_msg), "{ \"result\": { \"success\": false, \"error\": \"%s\" } }", msg.c_str());
|
||||
res.set_content(response_msg, strlen(response_msg), "application/json");
|
||||
return;
|
||||
}
|
||||
|
||||
void bad_request(Response & res, const std::string &msg)
|
||||
void bad_request(Response &res, const std::string &msg)
|
||||
{
|
||||
failed(res, 200, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void success(Response & res)
|
||||
void success(Response &res)
|
||||
{
|
||||
res.status = 200;
|
||||
res.set_content(SUCCESS_MSG, SUCCESS_MSG_LEN, "application/json");
|
||||
@@ -182,15 +196,87 @@ namespace HttpServer
|
||||
return 1;
|
||||
}
|
||||
|
||||
static RemoteClient *GetRemoteClient(int site_idx, bool new_client)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteSettings *tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
if (!new_client)
|
||||
{
|
||||
tmp_client = remote_data[site_idx].client;
|
||||
if (tmp_client != nullptr)
|
||||
return tmp_client;
|
||||
}
|
||||
|
||||
if (tmp_settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_WEBDAV)
|
||||
{
|
||||
tmp_client = new WebDAVClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_GOOGLE)
|
||||
{
|
||||
if (remoteclient != nullptr && remoteclient->clientType() == CLIENT_TYPE_GOOGLE)
|
||||
tmp_client = remoteclient;
|
||||
else
|
||||
tmp_client = new GDriveClient();
|
||||
tmp_client->Connect("", "", "");
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0)
|
||||
tmp_client = new ApacheClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MS_IIS) == 0)
|
||||
tmp_client = new IISClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NGINX) == 0)
|
||||
tmp_client = new NginxClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
|
||||
tmp_client = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
tmp_client = new RCloneClient();
|
||||
}
|
||||
|
||||
if (tmp_client->clientType() != CLIENT_TYPE_GOOGLE)
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
|
||||
if (!new_client && tmp_client->clientType() != CLIENT_TYPE_FTP)
|
||||
{
|
||||
remote_data[site_idx].client = tmp_client;
|
||||
}
|
||||
|
||||
return tmp_client;
|
||||
}
|
||||
|
||||
static void DeleteRemoteClient(RemoteClient *tmp_client, int site_idx)
|
||||
{
|
||||
if (tmp_client != nullptr && tmp_client->clientType() != CLIENT_TYPE_GOOGLE)
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
}
|
||||
}
|
||||
|
||||
void *ServerThread(void *argp)
|
||||
{
|
||||
svr->Get("/", [&](const Request & req, Response & res)
|
||||
{
|
||||
res.set_redirect("/index.html");
|
||||
});
|
||||
svr->Get("/", [&](const Request &req, Response &res)
|
||||
{ res.set_redirect("/index.html"); });
|
||||
|
||||
svr->Get("/index.html", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/index.html", [&](const Request &req, Response &res)
|
||||
{
|
||||
FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html");
|
||||
size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html");
|
||||
res.set_content_provider(
|
||||
@@ -206,11 +292,10 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Get("/favicon.ico", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/favicon.ico", [&](const Request &req, Response &res)
|
||||
{
|
||||
FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico");
|
||||
size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico");
|
||||
res.set_content_provider(
|
||||
@@ -226,11 +311,10 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Post("/__local__/list", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/list", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *path;
|
||||
bool onlyFolders = false;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -276,11 +360,10 @@ namespace HttpServer
|
||||
json_object_object_add(results, "result", json_files);
|
||||
const char *results_str = json_object_to_json_string(results);
|
||||
res.status = 200;
|
||||
res.set_content(results_str, strlen(results_str), "application/json");
|
||||
});
|
||||
res.set_content(results_str, strlen(results_str), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/rename", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/rename", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
const char *newItemPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -302,11 +385,10 @@ namespace HttpServer
|
||||
|
||||
FS::Rename(item, newItemPath);
|
||||
success(res);
|
||||
return;
|
||||
});
|
||||
return; });
|
||||
|
||||
svr->Post("/__local__/move", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/move", [&](const Request &req, Response &res)
|
||||
{
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -357,11 +439,10 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/copy", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/copy", [&](const Request &req, Response &res)
|
||||
{
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
const char *singleFilename;
|
||||
@@ -432,11 +513,10 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/remove", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/remove", [&](const Request &req, Response &res)
|
||||
{
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -472,11 +552,10 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/install", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/install", [&](const Request &req, Response &res)
|
||||
{
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -509,11 +588,10 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/edit", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/edit", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
const char *content;
|
||||
size_t content_len;
|
||||
@@ -543,11 +621,10 @@ namespace HttpServer
|
||||
return;
|
||||
}
|
||||
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/getContent", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/getContent", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -570,11 +647,10 @@ namespace HttpServer
|
||||
json_object_object_add(result, "result", json_object_new_string(content.data()));
|
||||
const char *result_str = json_object_to_json_string(result);
|
||||
res.status = 200;
|
||||
res.set_content(result_str, strlen(result_str), "application/json");
|
||||
});
|
||||
res.set_content(result_str, strlen(result_str), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/createFolder", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/createFolder", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -593,16 +669,13 @@ namespace HttpServer
|
||||
}
|
||||
|
||||
FS::MkDirs(newPath);
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/permission", [&](const Request & req, Response & res)
|
||||
{
|
||||
failed(res, 200, "Operation not supported");
|
||||
});
|
||||
svr->Post("/__local__/permission", [&](const Request &req, Response &res)
|
||||
{ failed(res, 200, "Operation not supported"); });
|
||||
|
||||
svr->Post("/__local__/compress", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/compress", [&](const Request &req, Response &res)
|
||||
{
|
||||
json_object *items;
|
||||
const char* destination;
|
||||
const char* compressedFilename;
|
||||
@@ -652,11 +725,10 @@ namespace HttpServer
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Failed to create zip");
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/extract", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Post("/__local__/extract", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char* item;
|
||||
const char* destination;
|
||||
const char* folderName;
|
||||
@@ -692,11 +764,10 @@ namespace HttpServer
|
||||
else if (ret == -1)
|
||||
failed(res, 200, "Unsupported compressed file format");
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Get("/__local__/uploadResumeSize", [&](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string destination = req.get_param_value("destination");
|
||||
std::string filename = req.get_param_value("filename");
|
||||
std::string file_path = destination + "/" + filename;
|
||||
@@ -705,11 +776,10 @@ namespace HttpServer
|
||||
size = FS::GetSize(file_path);
|
||||
std::string result_str = "{\"size\":" + std::to_string(size) + "}";
|
||||
res.status = 200;
|
||||
res.set_content(result_str.c_str(), result_str.length(), "application/json");
|
||||
});
|
||||
res.set_content(result_str.c_str(), result_str.length(), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/upload", [&](const Request &req, Response &res, const ContentReader &content_reader)
|
||||
{
|
||||
{
|
||||
MultipartFormDataItems items;
|
||||
std::string destination;
|
||||
size_t chunk_size = 0;
|
||||
@@ -775,12 +845,11 @@ namespace HttpServer
|
||||
{
|
||||
FS::Close(out);
|
||||
}
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
// Download multiple files as ZIP
|
||||
svr->Get("/__local__/downloadMultiple", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/__local__/downloadMultiple", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (req.get_param_value_count("items") == 0 || req.get_param_value_count("toFilename") == 0)
|
||||
{
|
||||
failed(res, 200, "Required items and toFilename parameter missing");
|
||||
@@ -834,12 +903,11 @@ namespace HttpServer
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Failed to create zip");
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
// Download single file
|
||||
svr->Get("/__local__/downloadFile", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/__local__/downloadFile", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string path = req.get_param_value("path", 0);
|
||||
if (path.empty())
|
||||
{
|
||||
@@ -869,11 +937,10 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Get("/google_auth", [](const Request &req, Response &res)
|
||||
{
|
||||
{
|
||||
std::string auth_code = req.get_param_value("code");
|
||||
Client client(GOOGLE_OAUTH_HOST);
|
||||
client.set_follow_location(true);
|
||||
@@ -919,12 +986,11 @@ namespace HttpServer
|
||||
}
|
||||
login_state = -1;
|
||||
std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google";
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
});
|
||||
res.set_content(str.c_str(), "text/plain"); });
|
||||
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
RemoteSettings *tmp_settings;
|
||||
auto site_idx = std::stoi(req.matches[1])-1;
|
||||
std::string path;
|
||||
@@ -932,33 +998,6 @@ namespace HttpServer
|
||||
if (site_idx != 98)
|
||||
{
|
||||
path = std::string("/") + std::string(req.matches[3]);
|
||||
|
||||
tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
if (tmp_settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_client = remoteclient;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -973,33 +1012,34 @@ namespace HttpServer
|
||||
tmp_client->Connect(host, "", "");
|
||||
}
|
||||
|
||||
if (tmp_client == nullptr || !tmp_client->IsConnected())
|
||||
{
|
||||
res.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (req.method == "HEAD")
|
||||
{
|
||||
int64_t file_size;
|
||||
int ret;
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
|
||||
ret = tmp_client->Size(path, &file_size);
|
||||
if (!ret)
|
||||
{
|
||||
res.status = 500;
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
res.status = 204;
|
||||
res.set_header("Content-Length", std::to_string(file_size));
|
||||
res.set_header("Accept-Ranges", "bytes");
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.ranges.empty())
|
||||
{
|
||||
res.status = 200;
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
|
||||
res.set_content_provider(
|
||||
(1024*128), "application/octet-stream",
|
||||
[tmp_client, path](size_t offset, size_t length, DataSink &sink) {
|
||||
@@ -1007,15 +1047,7 @@ namespace HttpServer
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, path, site_idx](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
}
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -1024,33 +1056,60 @@ 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));
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, false);
|
||||
}
|
||||
|
||||
std::pair<ssize_t, ssize_t> range = req.ranges[0];
|
||||
res.set_content_provider(
|
||||
range_len, "application/octet-stream",
|
||||
[tmp_client, path, range, range_len](size_t offset, size_t length, DataSink &sink) {
|
||||
int ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, site_idx, path, range, range_len](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
[tmp_client, path, range, range_len, site_idx](size_t offset, size_t length, DataSink &sink) {
|
||||
int ret;
|
||||
if (range_len == 524288ul)
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
}
|
||||
else if ((tmp_client->SupportedActions() & REMOTE_ACTION_RAW_READ) == 0)
|
||||
{
|
||||
ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::string, void *>::iterator it = remote_data[site_idx].fp_handles.find(path);
|
||||
void *fp;
|
||||
if (it == remote_data[site_idx].fp_handles.end())
|
||||
{
|
||||
fp = tmp_client->Open(path, O_RDONLY);
|
||||
remote_data[site_idx].fp_handles[path] = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp = it->second;
|
||||
}
|
||||
ret = tmp_client->GetRange(fp, sink, range_len, range.first);
|
||||
}
|
||||
return (ret==1);
|
||||
},
|
||||
[tmp_client, path, range, site_idx](bool success) {
|
||||
if (range.second >= 18000000000000000000ul ||
|
||||
(tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98) ||
|
||||
tmp_client->clientType() == CLIENT_TYPE_FTP)
|
||||
{
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/archive_inst/(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteSettings *tmp_settings;
|
||||
std::string hash = req.matches[1];
|
||||
@@ -1087,9 +1146,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(
|
||||
@@ -1104,22 +1163,24 @@ namespace HttpServer
|
||||
[](bool success) {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1129,14 +1190,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())
|
||||
{
|
||||
@@ -1145,10 +1206,20 @@ namespace HttpServer
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1171,10 +1242,13 @@ namespace HttpServer
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1195,36 +1269,37 @@ namespace HttpServer
|
||||
|
||||
int ret = pthread_create(&install_data->thread, NULL, Actions::ExtractArchivePkg, install_data);
|
||||
|
||||
ret = INSTALLER::InstallArchivePkg(entry->filename, install_data);
|
||||
free(entry);
|
||||
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);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
|
||||
{
|
||||
svr->stop();
|
||||
});
|
||||
{ svr->stop(); });
|
||||
|
||||
svr->set_error_handler([](const Request & /*req*/, Response &res)
|
||||
{
|
||||
{
|
||||
const char *fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
|
||||
char buf[BUFSIZ];
|
||||
snprintf(buf, sizeof(buf), fmt, res.status);
|
||||
res.set_content(buf, "text/html");
|
||||
});
|
||||
res.set_content(buf, "text/html"); });
|
||||
|
||||
/*
|
||||
svr->set_logger([](const Request &req, const Response &res)
|
||||
@@ -1236,7 +1311,7 @@ namespace HttpServer
|
||||
svr->set_payload_max_length(1024 * 1024 * 12);
|
||||
svr->set_tcp_nodelay(true);
|
||||
svr->set_mount_point("/", "/");
|
||||
|
||||
|
||||
if (web_server_enabled)
|
||||
svr->listen("0.0.0.0", http_server_port);
|
||||
else
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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(), ["e_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(), ["e_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();
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
+37
-8
@@ -1356,8 +1356,10 @@ namespace Windows
|
||||
if (file_transfering)
|
||||
{
|
||||
static float progress = 0.0f;
|
||||
static char progress_text[32];
|
||||
progress = bytes_transfered * 1.0f / (float)bytes_to_download;
|
||||
ImGui::ProgressBar(progress, ImVec2(625, 0));
|
||||
sprintf(progress_text, "%.2f%%", progress*100.0f);
|
||||
ImGui::ProgressBar(progress, ImVec2(625, 0), progress_text);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -1621,7 +1623,7 @@ 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];
|
||||
@@ -1735,7 +1737,6 @@ namespace Windows
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
// Google settings
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -1750,14 +1751,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();
|
||||
@@ -2061,7 +2089,7 @@ 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;
|
||||
@@ -2070,7 +2098,7 @@ namespace Windows
|
||||
activity_inprogess = true;
|
||||
sprintf(activity_message, "%s", "");
|
||||
stop_activity = false;
|
||||
file_transfering = false;
|
||||
file_transfering = true;
|
||||
selected_action = ACTION_NONE;
|
||||
Actions::ExtractRemoteZips();
|
||||
break;
|
||||
@@ -2156,6 +2184,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();
|
||||
|
||||
+65
-4
@@ -289,6 +289,7 @@ namespace ZipUtil
|
||||
{
|
||||
ssize_t len;
|
||||
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++)
|
||||
@@ -307,7 +308,8 @@ namespace ZipUtil
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes_transfered += len;
|
||||
|
||||
if (write(fd, buffer, len) != len)
|
||||
{
|
||||
sprintf(status_message, "error write('%s')", pathname.c_str());
|
||||
@@ -350,6 +352,7 @@ namespace ZipUtil
|
||||
return;
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -448,6 +451,10 @@ namespace ZipUtil
|
||||
client->Size(file, &data->size);
|
||||
data->client = client;
|
||||
data->path = file;
|
||||
if (client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
{
|
||||
data->fp = client->Open(file, O_RDONLY);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -465,7 +472,11 @@ namespace ZipUtil
|
||||
return 0;
|
||||
|
||||
to_read = MIN(to_read, ARCHIVE_TRANSFER_SIZE);
|
||||
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
|
||||
if (data->client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
ret = data->client->GetRange((data->fp), data->buf, to_read, data->offset);
|
||||
else
|
||||
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
|
||||
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
data->offset = data->offset + to_read;
|
||||
@@ -476,10 +487,46 @@ namespace ZipUtil
|
||||
static int CloseRemoteArchive(struct archive *a, void *client_data)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
if (data->client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
data->client->Close(data->fp);
|
||||
free(client_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t SeekRemoteArchive(struct archive *, void *client_data, int64_t offset, int whence)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
|
||||
if (whence == SEEK_SET)
|
||||
{
|
||||
data->offset = offset;
|
||||
}
|
||||
else if (whence == SEEK_CUR)
|
||||
{
|
||||
data->offset = data->offset + offset - 1;
|
||||
}
|
||||
else if (whence == SEEK_END)
|
||||
{
|
||||
data->offset = data->size - 1;
|
||||
}
|
||||
else
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
return data->offset;
|
||||
}
|
||||
|
||||
int64_t SkipRemoteArchive(struct archive *, void *client_data, int64_t request)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
|
||||
data->offset = data->offset + request - 1;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop: open the zipfile, iterate over its contents and decide what
|
||||
* to do with each entry.
|
||||
@@ -517,7 +564,14 @@ namespace ZipUtil
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
|
||||
ret = archive_read_set_seek_callback(a, SeekRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "archive_read_set_seek_callback failed - %s", archive_error_string(a));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open2(a, client_data, NULL, ReadRemoteArchive, SkipRemoteArchive, CloseRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
@@ -589,7 +643,14 @@ namespace ZipUtil
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
|
||||
ret = archive_read_set_seek_callback(a, SeekRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "archive_read_set_seek_callback failed - %s", archive_error_string(a));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open2(a, client_data, NULL, ReadRemoteArchive, SkipRemoteArchive, CloseRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
|
||||
@@ -30,6 +30,7 @@ enum CompressFileType {
|
||||
|
||||
struct RemoteArchiveData
|
||||
{
|
||||
void *fp;
|
||||
std::string path;
|
||||
ssize_t size;
|
||||
ssize_t offset;
|
||||
|
||||
Reference in New Issue
Block a user